Skip to content

Commit

Permalink
initial check-in of intarray (#236)
Browse files Browse the repository at this point in the history
* initial check in of intarray

* add test for intarray

* fix check related config

* adding tests and fixing bugs

* remove commented out lines

* only build benchmarks on linxu

* unit tests and bug fixes
  • Loading branch information
Yao Yue authored Jul 24, 2019
1 parent 14050d3 commit 3408248
Show file tree
Hide file tree
Showing 22 changed files with 608 additions and 28 deletions.
28 changes: 16 additions & 12 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ if(BUILD_AND_INSTALL_CHECK)
set(CMAKE_REQUIRED_LIBRARIES "${CHECK_ROOT_DIR}/lib")
endif()

find_package(PkgConfig QUIET)

if(PKG_CONFIG_FOUND)
pkg_check_modules(CHECK QUIET check>=0.10)
endif()

if(NOT CHECK_FOUND)
find_package(Check QUIET 0.10)
endif()


if(${OS_PLATFORM} MATCHES "OS_LINUX")
set(CFLAGS_LIST "${CFLAGS_LIST} -lrt")
endif()
Expand All @@ -140,16 +151,6 @@ add_subdirectory(${CCOMMON_SOURCE_DIR} ${PROJECT_BINARY_DIR}/ccommon)
include(FindPackageHandleStandardArgs)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")

find_package(PkgConfig QUIET)

if(PKG_CONFIG_FOUND)
pkg_check_modules(CHECK QUIET check>=0.10)
endif()

if(NOT CHECK_FOUND)
find_package(Check QUIET 0.10)
endif()

if (USE_PMEM)
if(PKG_CONFIG_FOUND)
pkg_check_modules(LIBPMEM REQUIRED libpmem>=1.0)
Expand Down Expand Up @@ -179,11 +180,14 @@ add_subdirectory(src)

# tests: always build last
if(CHECK_FOUND)
include_directories(${include_directories} ${CHECK_INCLUDES})
include_directories(${CHECK_INCLUDE_DIRS})
link_directories(${CHECK_LIBRARY_DIRS})
add_subdirectory(test)
endif(CHECK_FOUND)

add_subdirectory(benchmarks)
if(${OS_PLATFORM} MATCHES "OS_LINUX")
add_subdirectory(benchmarks)
endif()

# print a summary

Expand Down
1 change: 1 addition & 0 deletions src/data_structure/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(bitmap)
add_subdirectory(intarray)
add_subdirectory(ziplist)
1 change: 1 addition & 0 deletions src/data_structure/intarray/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_library(ds_intarray intarray.c)
317 changes: 317 additions & 0 deletions src/data_structure/intarray/intarray.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
#include "intarray.h"

#include <cc_debug.h>


#define IA_BODY(_ia) ((uint8_t *)(_ia) + INTARRAY_HEADER_SIZE)
#define SCAN_THRESHOLD 64

static inline uint8_t *
_position(uint8_t *body, uint32_t esize, uint32_t idx)
{
return body + esize * idx;
}


/* false if value is out of range for entry size */
static inline bool
_validate_range(uint32_t esize, uint64_t val)
{
switch (esize) {
case 8:
return true;
case 4:
return val <= UINT32_MAX;
case 2:
return val <= UINT16_MAX;
case 1:
return val <= UINT8_MAX;
default:
NOT_REACHED();
return false;
}
}

static inline uint64_t
_get_value(uint8_t *p, uint32_t esize)
{
switch (esize) {
case 8:
return *((uint64_t *)p);
case 4:
return *((uint32_t *)p);
case 2:
return *((uint16_t *)p);
case 1:
return *p;
default:
NOT_REACHED();
return 0;
}
}

static inline void
_set_value(uint8_t *p, uint32_t esize, uint64_t val)
{
switch (esize) {
case 8:
*((uint64_t *)p) = val;
break;
case 4:
*((uint32_t *)p) = val;
break;
case 2:
*((uint16_t *)p) = val;
break;
case 1:
*p = val;
break;
default:
NOT_REACHED();
}
}

static inline bool
_should_scan(uint32_t nentry, uint32_t esize) {
return nentry * esize <= SCAN_THRESHOLD;
}

/* returns true if an exact match is found, false otherwise.
* If a match is found, the index of the element is stored in idx;
* otherwise, idx contains the index of the insertion spot
*/
static inline bool
_linear_search(uint32_t *idx, uint8_t *body, uint32_t nentry, uint32_t esize, uint64_t val)
{
uint32_t i;

*idx = 0;

if (nentry == 0) {
return false;
}


for (i = 0; i < nentry; ++i, ++*idx) {
if (val == _get_value(_position(body, esize, i), esize)) {
return true;
}
}

return false;
}

static inline bool
_binary_search(uint32_t *idx, uint8_t *body, uint32_t nentry, uint32_t esize, uint64_t val)
{
uint32_t id, imin, imax;
uint32_t curr;

*idx = 0;

if (nentry == 0) {
return false;
}

if (val == _get_value(_position(body, esize, 0), esize)) {
return true;
}

if (val > _get_value(_position(body, esize, nentry - 1), esize)) {
*idx = nentry;
return false;
}

imin = 1;
imax = nentry - 1;
while (imin <= imax) {
id = (imin + imax) / 2;
curr = _get_value(_position(body, esize, id), esize);
if (val == curr) {
*idx = id;
return true;
}

if (val > curr) {
imin = id + 1;
} else {
if (val <= _get_value(_position(body, esize, id - 1), esize)) {
imax = id - 1;
} else {
break;
}
}
}

*idx = id;

return false;
}

static inline bool
_locate(uint32_t *idx, uint8_t *body, uint32_t nentry, uint32_t esize, uint64_t val)
{
if (_should_scan(nentry, esize)) { /* linear scan */
return _linear_search(idx, body, nentry, esize, val);
} else { /* otherwise, binary search */
return _binary_search(idx, body, nentry, esize, val);
}
}


intarray_rstatus_e
intarray_init(intarray_p ia, uint32_t esize)
{
if (ia == NULL) {
return INTARRAY_ERROR;
}

if (esize != 1 && esize != 2 && esize != 4 && esize != 8) {
return INTARRAY_EINVALID;
}

IA_NENTRY(ia) = 0;
IA_ESIZE(ia) = esize;

return INTARRAY_OK;
}


intarray_rstatus_e
intarray_value(uint64_t *val, const intarray_p ia, uint32_t idx)
{
uint32_t esize, nentry;

if (val == NULL || ia == NULL) {
return INTARRAY_ERROR;
}

nentry = intarray_nentry(ia);
idx += (idx < 0) * nentry;
if (idx < 0 || idx >= nentry) {
return INTARRAY_EOOB;
}

esize = intarray_esize(ia);
*val = _get_value(_position(IA_BODY(ia), esize, idx), esize);

return INTARRAY_OK;
}

/* caller should discard values in idx if function returns ENOTFOUND */
intarray_rstatus_e
intarray_index(uint32_t *idx, const intarray_p ia, uint64_t val)
{
uint32_t esize;
bool found;

if (ia == NULL || idx == NULL) {
return INTARRAY_ERROR;
}

esize = intarray_esize(ia);
if (!_validate_range(esize, val)) {
return INTARRAY_EINVALID;
}

found = _locate(idx, IA_BODY(ia), intarray_nentry(ia), esize, val);
if (found) {
return INTARRAY_OK;
} else {
return INTARRAY_ENOTFOUND;
}
}


intarray_rstatus_e
intarray_insert(intarray_p ia, uint64_t val)
{
bool found;
uint8_t *body, *p;
uint32_t idx, esize, nentry;

if (ia == NULL) {
return INTARRAY_ERROR;
}

esize = intarray_esize(ia);
if (!_validate_range(esize, val)) {
return INTARRAY_EINVALID;
}

body = IA_BODY(ia);
nentry = intarray_nentry(ia);
found = _locate(&idx, body, nentry, esize, val);
if (found) {
return INTARRAY_EDUP;
}

p = _position(body, esize, idx);
cc_memmove(p + esize, p, esize * (nentry - idx));
_set_value(p, esize, val);
IA_NENTRY(ia)++;

return INTARRAY_OK;
}

intarray_rstatus_e
intarray_remove(intarray_p ia, uint64_t val)
{
bool found;
uint8_t *body, *p;
uint32_t idx, esize, nentry;

if (ia == NULL) {
return INTARRAY_ERROR;
}

esize = intarray_esize(ia);
if (!_validate_range(esize, val)) {
return INTARRAY_EINVALID;
}

body = IA_BODY(ia);
nentry = intarray_nentry(ia);
found = _locate(&idx, body, nentry, esize, val);
if (found) {
p = _position(body, esize, idx);
cc_memmove(p, p + esize, esize * (nentry - idx - 1));
IA_NENTRY(ia)--;

return INTARRAY_OK;
}

return INTARRAY_ENOTFOUND;
}

intarray_rstatus_e
intarray_truncate(intarray_p ia, int64_t count)
{
uint8_t *body;
uint32_t esize, nentry;

if (ia == NULL) {
return INTARRAY_ERROR;
}

if (count == 0) {
return INTARRAY_OK;
}

body = IA_BODY(ia);
esize = intarray_esize(ia);
nentry = intarray_nentry(ia);
/* if abs(count) >= num entries in the array, remove all */
if (count >= nentry || -count >= nentry) {
return intarray_init(ia, intarray_esize(ia));
}

if (count > 0) { /* only need to move data if truncating from left */
cc_memmove(body, body + esize * count, esize * (nentry - count));
IA_NENTRY(ia) -= count;
} else {
IA_NENTRY(ia) += count;
}

return INTARRAY_OK;
}
Loading

0 comments on commit 3408248

Please sign in to comment.