many new API; fixes
This commit is contained in:
parent
0e348efaf6
commit
7494a9a3a2
6 changed files with 437 additions and 90 deletions
|
@ -8,6 +8,7 @@
|
|||
<sourceRoots>
|
||||
<file path="$PROJECT_DIR$/examples" />
|
||||
<file path="$PROJECT_DIR$/include" />
|
||||
<file path="$PROJECT_DIR$/lib" />
|
||||
<file path="$PROJECT_DIR$/src" />
|
||||
<file path="$PROJECT_DIR$/tests" />
|
||||
</sourceRoots>
|
||||
|
|
|
@ -125,7 +125,6 @@ sparsemap_t *sparsemap_copy(sparsemap_t *other);
|
|||
* and releasing the memory used for \b data. Resizing the buffer is only
|
||||
* supported when the heap object for the map includes the buffer and the
|
||||
* \b data offset supplied is relative to the object (see #sparsemap()).
|
||||
* This function calls #sparsemap_init().
|
||||
*
|
||||
* @param[in] data A heap or stack memory buffer of \b size for use storing
|
||||
* bitmap data.
|
||||
|
@ -252,6 +251,40 @@ sparsemap_idx_t sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
|
|||
*/
|
||||
size_t sparsemap_get_size(sparsemap_t *map);
|
||||
|
||||
/** @brief Returns a pointer to the data buffer used for the map.
|
||||
*
|
||||
* @param[in] map The sparsemap reference.
|
||||
* @returns a pointer to the data buffer used for the map
|
||||
*/
|
||||
void *sparsemap_get_data(sparsemap_t *map);
|
||||
|
||||
/** @brief Returns the number of elements in the map.
|
||||
*
|
||||
* @param[in] map The sparsemap reference.
|
||||
* @returns the number of elements in the map
|
||||
*/
|
||||
size_t sparsemap_count(sparsemap_t *map);
|
||||
|
||||
/** @brief Returns the offset of the first bit set in the map.
|
||||
*
|
||||
* This is the same as the value of the first set bit in the
|
||||
* map.
|
||||
*
|
||||
* @param[in] map The sparsemap reference.
|
||||
* @returns the offset of the first bit set in the map
|
||||
*/
|
||||
sparsemap_idx_t sparsemap_get_starting_offset(sparsemap_t *map);
|
||||
|
||||
/** @brief Returns the offset of the last bit set in the map.
|
||||
*
|
||||
* This is the same as the value of the last bit set in the
|
||||
* map.
|
||||
*
|
||||
* @param[in] map The sparsemap reference.
|
||||
* @returns the offset of the index bit set in the map
|
||||
*/
|
||||
sparsemap_idx_t sparsemap_get_ending_offset(sparsemap_t *map);
|
||||
|
||||
/** @brief Provides a method for a callback function to examine every bit set in
|
||||
* the index.
|
||||
*
|
||||
|
@ -279,10 +312,12 @@ int sparsemap_merge(sparsemap_t *map, sparsemap_t *other);
|
|||
* The \b other bitmap is expected to be empty.
|
||||
*
|
||||
* @param[in] map The sparsemap reference.
|
||||
* @param[in] offset The 0-based offset into the bitmap at which to split.
|
||||
* @param[in] offset The 0-based offset into the bitmap at which to split, if
|
||||
* set to SPARSEMAP_IDX_MAX then the bits will be evenly split.
|
||||
* @param[in] other The bitmap into which we place the split.
|
||||
* @returns the offset at which the map was split
|
||||
*/
|
||||
void sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other);
|
||||
sparsemap_idx_t sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other);
|
||||
|
||||
/** @brief Finds the index of the \b n'th bit set to \b value.
|
||||
*
|
||||
|
|
41
lib/common.c
41
lib/common.c
|
@ -18,8 +18,8 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "../include/common.h"
|
||||
#include "../include/sparsemap.h"
|
||||
#include "common.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
||||
|
@ -277,17 +277,6 @@ is_set(const int array[], int bit)
|
|||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
is_unique(int a[], int l, int value)
|
||||
{
|
||||
for (int i = 0; i < l; ++i) {
|
||||
if (a[i] == value) {
|
||||
return 0; // Not unique
|
||||
}
|
||||
}
|
||||
return 1; // Unique
|
||||
}
|
||||
|
||||
int
|
||||
whats_set_uint64(uint64_t number, int pos[64])
|
||||
{
|
||||
|
@ -302,19 +291,31 @@ whats_set_uint64(uint64_t number, int pos[64])
|
|||
return length;
|
||||
}
|
||||
|
||||
/** @brief Fills an array with unique random values between 0 and max_value.
|
||||
*
|
||||
* @param[in] a The array to fill.
|
||||
* @param[in] l The length of the array to fill.
|
||||
* @param[in] max_value The maximum value for the random numbers.
|
||||
*/
|
||||
void
|
||||
setup_test_array(int a[], int l, int max_value)
|
||||
{
|
||||
if (a == NULL || max_value < 0) {
|
||||
return; // Basic error handling and validation
|
||||
|
||||
// Create a set to store the unique values.
|
||||
int unique_values[max_value + 1];
|
||||
for (int i = 0; i <= max_value; ++i) {
|
||||
unique_values[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < l; ++i) {
|
||||
int candidate;
|
||||
do {
|
||||
candidate = random_uint32() % (max_value + 1); // Generate a new value within the specified range
|
||||
} while (!is_unique(a, i, candidate)); // Repeat until a unique value is found
|
||||
a[i] = candidate; // Assign the unique value to the array
|
||||
// Keep generating random numbers until we have l unique values.
|
||||
int count = 0;
|
||||
while (count < l) {
|
||||
int random_number = random_uint32() % (max_value + 1);
|
||||
if (unique_values[random_number] == 0) {
|
||||
unique_values[random_number] = 1;
|
||||
a[count] = random_number;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
170
src/sparsemap.c
170
src/sparsemap.c
|
@ -825,19 +825,17 @@ __sm_get_size_impl(sparsemap_t *map)
|
|||
return SM_SIZEOF_OVERHEAD + p - start;
|
||||
}
|
||||
|
||||
#ifdef SPARSEMAP_DIAGNOSTIC
|
||||
/** @brief Aligns to SM_BITS_PER_VECTOR a given index \b idx.
|
||||
*
|
||||
* @param[in] idx The index to align.
|
||||
* @returns the aligned offset (aligned to sm_bitvec_t capacity).
|
||||
*/
|
||||
static sm_idx_t
|
||||
__sm_get_aligned_offset(size_t idx)
|
||||
__sm_get_vector_aligned_offset(size_t idx)
|
||||
{
|
||||
const size_t capacity = SM_BITS_PER_VECTOR;
|
||||
return (idx / capacity) * capacity;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @brief Aligns to SM_CHUNK_CAPACITY a given index \b idx.
|
||||
*
|
||||
|
@ -845,7 +843,7 @@ __sm_get_aligned_offset(size_t idx)
|
|||
* @returns the aligned offset (aligned to __sm_chunk_t capacity)
|
||||
*/
|
||||
static sm_idx_t
|
||||
__sm_get_fully_aligned_offset(size_t idx)
|
||||
__sm_get_chunk_aligned_offset(size_t idx)
|
||||
{
|
||||
const size_t capacity = SM_CHUNK_MAX_CAPACITY;
|
||||
return (idx / capacity) * capacity;
|
||||
|
@ -871,7 +869,7 @@ __sm_get_chunk_offset(sparsemap_t *map, sparsemap_idx_t idx)
|
|||
|
||||
for (sparsemap_idx_t i = 0; i < count - 1; i++) {
|
||||
sm_idx_t s = *(sm_idx_t *)p;
|
||||
__sm_assert(s == __sm_get_aligned_offset(s));
|
||||
__sm_assert(s == __sm_get_vector_aligned_offset(s));
|
||||
__sm_chunk_t chunk;
|
||||
__sm_chunk_init(&chunk, p + sizeof(sm_idx_t));
|
||||
if (s >= idx || idx < s + __sm_chunk_get_capacity(&chunk)) {
|
||||
|
@ -999,7 +997,9 @@ sparsemap_wrap(uint8_t *data, size_t size)
|
|||
{
|
||||
sparsemap_t *map = (sparsemap_t *)calloc(1, sizeof(sparsemap_t));
|
||||
if (map) {
|
||||
sparsemap_init(map, data, size);
|
||||
map->m_data = data;
|
||||
map->m_data_used = 0;
|
||||
map->m_capacity = size;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
@ -1125,7 +1125,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
|
|||
__sm_append_data(map, &buf[0], sizeof(buf));
|
||||
|
||||
uint8_t *p = __sm_get_chunk_data(map, 0);
|
||||
*(sm_idx_t *)p = __sm_get_fully_aligned_offset(idx);
|
||||
*(sm_idx_t *)p = __sm_get_vector_aligned_offset(idx); // TODO: get_fully_aligned_offset?
|
||||
|
||||
__sm_set_chunk_count(map, 1);
|
||||
|
||||
|
@ -1150,7 +1150,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
|
|||
uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 };
|
||||
__sm_insert_data(map, offset, &buf[0], sizeof(buf));
|
||||
|
||||
size_t aligned_idx = __sm_get_fully_aligned_offset(idx);
|
||||
size_t aligned_idx = __sm_get_chunk_aligned_offset(idx);
|
||||
if (start - aligned_idx < SM_CHUNK_MAX_CAPACITY) {
|
||||
__sm_chunk_t chunk;
|
||||
__sm_chunk_init(&chunk, p + sizeof(sm_idx_t));
|
||||
|
@ -1186,7 +1186,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
|
|||
|
||||
start += __sm_chunk_get_capacity(&chunk);
|
||||
if ((sparsemap_idx_t)start + SM_CHUNK_MAX_CAPACITY < idx) {
|
||||
start = __sm_get_fully_aligned_offset(idx);
|
||||
start = __sm_get_chunk_aligned_offset(idx);
|
||||
}
|
||||
*(sm_idx_t *)p = start;
|
||||
|
||||
|
@ -1241,12 +1241,93 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
|
|||
sparsemap_idx_t
|
||||
sparsemap_get_starting_offset(sparsemap_t *map)
|
||||
{
|
||||
sparsemap_idx_t offset = 0;
|
||||
size_t count = __sm_get_chunk_count(map);
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
sm_idx_t *chunk = (sm_idx_t *)__sm_get_chunk_data(map, 0);
|
||||
return (sparsemap_idx_t)*chunk;
|
||||
uint8_t *p = __sm_get_chunk_data(map, 0);
|
||||
sm_idx_t start = *(sm_idx_t *)p;
|
||||
p += sizeof(sm_idx_t);
|
||||
__sm_chunk_t chunk;
|
||||
__sm_chunk_init(&chunk, p);
|
||||
sparsemap_idx_t relative_position = start;
|
||||
for (size_t m = 0; m < sizeof(sm_bitvec_t); m++, p++) {
|
||||
for (int n = 0; n < SM_FLAGS_PER_INDEX_BYTE; n++) {
|
||||
size_t flags = SM_CHUNK_GET_FLAGS(*p, n);
|
||||
if (flags == SM_PAYLOAD_NONE) {
|
||||
continue;
|
||||
} else if (flags == SM_PAYLOAD_ZEROS) {
|
||||
relative_position += SM_BITS_PER_VECTOR;
|
||||
} else if (flags == SM_PAYLOAD_ONES) {
|
||||
offset = relative_position;
|
||||
goto done;
|
||||
} else if (flags == SM_PAYLOAD_MIXED) {
|
||||
sm_bitvec_t w = chunk.m_data[1 + __sm_chunk_get_position(&chunk, m * SM_FLAGS_PER_INDEX_BYTE + n)];
|
||||
for (int k = 0; k < SM_BITS_PER_VECTOR; k++) {
|
||||
if (w & ((sm_bitvec_t)1 << k)) {
|
||||
offset = relative_position + k;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
relative_position += SM_BITS_PER_VECTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:;
|
||||
return offset;
|
||||
}
|
||||
|
||||
sparsemap_idx_t
|
||||
sparsemap_get_ending_offset(sparsemap_t *map)
|
||||
{
|
||||
sparsemap_idx_t offset = 0;
|
||||
size_t count = __sm_get_chunk_count(map);
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t *p = __sm_get_chunk_data(map, 0);
|
||||
for (size_t i = 0; i < count - 1; i++) {
|
||||
p += sizeof(sm_idx_t);
|
||||
__sm_chunk_t chunk;
|
||||
__sm_chunk_init(&chunk, p);
|
||||
p += __sm_chunk_get_size(&chunk);
|
||||
}
|
||||
sm_idx_t start = *(sm_idx_t *)p;
|
||||
p += sizeof(sm_idx_t);
|
||||
__sm_chunk_t chunk;
|
||||
__sm_chunk_init(&chunk, p);
|
||||
sparsemap_idx_t relative_position = start;
|
||||
for (size_t m = 0; m < sizeof(sm_bitvec_t); m++, p++) {
|
||||
for (int n = 0; n < SM_FLAGS_PER_INDEX_BYTE; n++) {
|
||||
size_t flags = SM_CHUNK_GET_FLAGS(*p, n);
|
||||
if (flags == SM_PAYLOAD_NONE) {
|
||||
continue;
|
||||
} else if (flags == SM_PAYLOAD_ZEROS) {
|
||||
relative_position += SM_BITS_PER_VECTOR;
|
||||
} else if (flags == SM_PAYLOAD_ONES) {
|
||||
relative_position += SM_BITS_PER_VECTOR;
|
||||
offset = relative_position;
|
||||
} else if (flags == SM_PAYLOAD_MIXED) {
|
||||
sm_bitvec_t w = chunk.m_data[1 + __sm_chunk_get_position(&chunk, m * SM_FLAGS_PER_INDEX_BYTE + n)];
|
||||
int idx = 0;
|
||||
for (int k = 0; k < SM_BITS_PER_VECTOR; k++) {
|
||||
if (w & ((sm_bitvec_t)1 << k)) {
|
||||
idx = k;
|
||||
}
|
||||
}
|
||||
offset = relative_position + idx;
|
||||
relative_position += SM_BITS_PER_VECTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
void *
|
||||
sparsemap_get_data(sparsemap_t *map)
|
||||
{
|
||||
return map->m_data;
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -1259,6 +1340,41 @@ sparsemap_get_size(sparsemap_t *map)
|
|||
return map->m_data_used = __sm_get_size_impl(map);
|
||||
}
|
||||
|
||||
size_t
|
||||
sparsemap_count(sparsemap_t *map)
|
||||
{
|
||||
return sparsemap_rank(map, 0, SPARSEMAP_IDX_MAX, true);
|
||||
#if 0
|
||||
size_t c = 0, count = __sm_get_chunk_count(map);
|
||||
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t *p = __sm_get_chunk_data(map, 0);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
p += sizeof(sm_idx_t);
|
||||
__sm_chunk_t chunk;
|
||||
__sm_chunk_init(&chunk, p);
|
||||
for (size_t m = 0; m < sizeof(sm_bitvec_t); m++, p++) {
|
||||
for (int n = 0; n < SM_FLAGS_PER_INDEX_BYTE; n++) {
|
||||
size_t flags = SM_CHUNK_GET_FLAGS(*p, n);
|
||||
if (flags == SM_PAYLOAD_NONE) {
|
||||
continue;
|
||||
} else if (flags == SM_PAYLOAD_ZEROS) {
|
||||
continue;
|
||||
} else if (flags == SM_PAYLOAD_ONES) {
|
||||
c += SM_BITS_PER_VECTOR;
|
||||
} else if (flags == SM_PAYLOAD_MIXED) {
|
||||
sm_bitvec_t w = chunk.m_data[1 + __sm_chunk_get_position(&chunk, m * SM_FLAGS_PER_INDEX_BYTE + n)];
|
||||
c += popcountll(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t, void *aux), size_t skip, void *aux)
|
||||
{
|
||||
|
@ -1299,8 +1415,8 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other)
|
|||
for (size_t i = 0; i < max_chunk_count && src_count; i++) {
|
||||
sm_idx_t src_start = *(sm_idx_t *)src;
|
||||
sm_idx_t dst_start = *(sm_idx_t *)dst;
|
||||
src_start = __sm_get_fully_aligned_offset(src_start);
|
||||
dst_start = __sm_get_fully_aligned_offset(dst_start);
|
||||
src_start = __sm_get_chunk_aligned_offset(src_start);
|
||||
dst_start = __sm_get_chunk_aligned_offset(dst_start);
|
||||
if (src_start > dst_start && dst_count > 0) {
|
||||
__sm_chunk_t dst_chunk;
|
||||
__sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
||||
|
@ -1315,7 +1431,7 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other)
|
|||
__sm_chunk_t dst_chunk;
|
||||
__sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
||||
__sm_merge_chunk(map, src_start, src_chunk);
|
||||
*(sm_idx_t *)dst = __sm_get_fully_aligned_offset(src_start);
|
||||
*(sm_idx_t *)dst = __sm_get_chunk_aligned_offset(src_start);
|
||||
src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk);
|
||||
dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk);
|
||||
dst_count--;
|
||||
|
@ -1347,10 +1463,23 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sparsemap_idx_t
|
||||
sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
|
||||
{
|
||||
assert(offset % SM_BITS_PER_VECTOR == 0);
|
||||
if (offset == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (offset == SPARSEMAP_IDX_MAX) {
|
||||
sparsemap_idx_t begin = sparsemap_get_starting_offset(map);
|
||||
sparsemap_idx_t end = sparsemap_get_ending_offset(map);
|
||||
if (begin != end) {
|
||||
size_t count = sparsemap_rank(map, begin, end, true);
|
||||
offset = sparsemap_select(map, count / 2, true);
|
||||
} else {
|
||||
return SPARSEMAP_IDX_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
/* |dst| points to the destination buffer */
|
||||
uint8_t *dst = __sm_get_chunk_end(other);
|
||||
|
@ -1388,7 +1517,7 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
|
|||
if (i == count) {
|
||||
__sm_assert(sparsemap_get_size(map) > SM_SIZEOF_OVERHEAD);
|
||||
__sm_assert(sparsemap_get_size(other) > SM_SIZEOF_OVERHEAD);
|
||||
return;
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* Now copy all the remaining chunks. */
|
||||
|
@ -1399,7 +1528,7 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
|
|||
uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 };
|
||||
memcpy(dst, &buf[0], sizeof(buf));
|
||||
|
||||
*(sm_idx_t *)dst = offset;
|
||||
*(sm_idx_t *)dst = __sm_get_chunk_aligned_offset(offset); //TODO: was simply "offset"
|
||||
dst += sizeof(sm_idx_t);
|
||||
|
||||
/* the |other| sparsemap_t now has one additional chunk */
|
||||
|
@ -1422,6 +1551,7 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
|
|||
for (size_t j = offset % capacity; j < capacity; j++, d++) {
|
||||
if (__sm_chunk_is_set(&s_chunk, j)) {
|
||||
sparsemap_set(other, d, true);
|
||||
sparsemap_set(map, d, false); //TODO remove, and fix set_capacity below
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1431,7 +1561,7 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
|
|||
i++;
|
||||
|
||||
/* Reduce the capacity of the source-chunk. */
|
||||
__sm_chunk_set_capacity(&s_chunk, offset % capacity);
|
||||
//__sm_chunk_set_capacity(&s_chunk, offset % capacity); //TODO see comment above
|
||||
}
|
||||
|
||||
/* Now continue with all remaining chunks. */
|
||||
|
@ -1461,6 +1591,8 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
|
|||
|
||||
__sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
|
||||
__sm_assert(sparsemap_get_size(other) > SM_SIZEOF_OVERHEAD);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
sparsemap_idx_t
|
||||
|
|
272
tests/test.c
272
tests/test.c
|
@ -44,14 +44,17 @@ void
|
|||
populate_map(sparsemap_t *map, int size, int max_value)
|
||||
{
|
||||
int array[size];
|
||||
size_t before;
|
||||
|
||||
setup_test_array(array, size, max_value);
|
||||
shuffle(array, size);
|
||||
before = sparsemap_count(map);
|
||||
for (int i = 0; i < size; i++) {
|
||||
sparsemap_set(map, array[i], true);
|
||||
bool set = sparsemap_is_set(map, array[i]);
|
||||
munit_assert_true(set);
|
||||
assert_true(set);
|
||||
}
|
||||
assert_true(sparsemap_count(map) == before + size);
|
||||
}
|
||||
|
||||
static void *
|
||||
|
@ -444,45 +447,6 @@ test_api_set(const MunitParameter params[], void *data)
|
|||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
// TODO remove? not public API anymore...
|
||||
extern sparsemap_idx_t sparsemap_get_starting_offset(sparsemap_t *map);
|
||||
|
||||
static void *
|
||||
test_api_get_starting_offset_setup(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
|
||||
assert_ptr_not_null(buf);
|
||||
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
|
||||
|
||||
sparsemap_init(map, buf, 1024);
|
||||
populate_map(map, 1024, 3 * 1024);
|
||||
|
||||
return (void *)map;
|
||||
}
|
||||
static void
|
||||
test_api_get_starting_offset_tear_down(void *fixture)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)fixture;
|
||||
assert_ptr_not_null(map->m_data);
|
||||
munit_free(map->m_data);
|
||||
test_api_tear_down(fixture);
|
||||
}
|
||||
static MunitResult
|
||||
test_api_get_starting_offset(const MunitParameter params[], void *data)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)data;
|
||||
(void)params;
|
||||
|
||||
assert_ptr_not_null(map);
|
||||
|
||||
sparsemap_set(map, 42, true);
|
||||
assert_true(sparsemap_is_set(map, 42));
|
||||
size_t offset = sparsemap_get_starting_offset(map);
|
||||
assert_true(offset == 0);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_api_get_size_setup(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
|
@ -517,6 +481,174 @@ test_api_get_size(const MunitParameter params[], void *data)
|
|||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_api_count_setup(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
|
||||
assert_ptr_not_null(buf);
|
||||
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
|
||||
|
||||
sparsemap_init(map, buf, 1024);
|
||||
populate_map(map, 1024, 3 * 1024);
|
||||
|
||||
return (void *)map;
|
||||
}
|
||||
static void
|
||||
test_api_count_tear_down(void *fixture)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)fixture;
|
||||
assert_ptr_not_null(map->m_data);
|
||||
munit_free(map->m_data);
|
||||
test_api_tear_down(fixture);
|
||||
}
|
||||
static MunitResult
|
||||
test_api_count(const MunitParameter params[], void *data)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)data;
|
||||
(void)params;
|
||||
|
||||
assert_ptr_not_null(map);
|
||||
|
||||
assert_true(sparsemap_count(map) == 1024);
|
||||
|
||||
sparsemap_clear(map);
|
||||
sparsemap_set(map, 0, true);
|
||||
assert_true(sparsemap_count(map) == 1);
|
||||
|
||||
sparsemap_set(map, 8675309, true);
|
||||
assert_true(sparsemap_count(map) == 2);
|
||||
|
||||
sparsemap_clear(map);
|
||||
for (int i = 0; i < 512; i++) {
|
||||
sparsemap_set(map, i + 13, true);
|
||||
}
|
||||
assert_true(sparsemap_count(map) == 512);
|
||||
|
||||
sparsemap_clear(map);
|
||||
assert_true(sparsemap_count(map) == 0);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_api_get_data(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)data;
|
||||
(void)params;
|
||||
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
|
||||
assert_ptr_not_null(buf);
|
||||
sparsemap_t *map = (sparsemap_t *)sparsemap_wrap(buf, 1024);
|
||||
assert_ptr_not_null(map);
|
||||
populate_map(map, 1024, 3 * 1024);
|
||||
|
||||
assert_true(sparsemap_get_data(map) == buf);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_api_get_starting_offset_setup(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
|
||||
assert_ptr_not_null(buf);
|
||||
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
|
||||
|
||||
sparsemap_init(map, buf, 1024);
|
||||
|
||||
return (void *)map;
|
||||
}
|
||||
static void
|
||||
test_api_get_starting_offset_tear_down(void *fixture)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)fixture;
|
||||
assert_ptr_not_null(map->m_data);
|
||||
munit_free(map->m_data);
|
||||
test_api_tear_down(fixture);
|
||||
}
|
||||
static MunitResult
|
||||
test_api_get_starting_offset(const MunitParameter params[], void *data)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)data;
|
||||
(void)params;
|
||||
|
||||
assert_ptr_not_null(map);
|
||||
|
||||
sparsemap_set(map, 0, true);
|
||||
assert_true(sparsemap_get_starting_offset(map) == 0);
|
||||
sparsemap_clear(map);
|
||||
|
||||
sparsemap_set(map, 1, true);
|
||||
assert_true(sparsemap_get_starting_offset(map) == 1);
|
||||
sparsemap_clear(map);
|
||||
|
||||
sparsemap_set(map, 1025, true);
|
||||
assert_true(sparsemap_get_starting_offset(map) == 1025);
|
||||
sparsemap_clear(map);
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
sparsemap_set(map, i, true);
|
||||
}
|
||||
assert_true(sparsemap_get_starting_offset(map) == 0);
|
||||
sparsemap_clear(map);
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
sparsemap_set(map, i + 1024, true);
|
||||
}
|
||||
assert_true(sparsemap_get_starting_offset(map) == 1024);
|
||||
sparsemap_clear(map);
|
||||
|
||||
sparsemap_set(map, 13012, true);
|
||||
assert_true(sparsemap_get_starting_offset(map) == 13012);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_api_get_ending_offset_setup(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
|
||||
assert_ptr_not_null(buf);
|
||||
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
|
||||
|
||||
sparsemap_init(map, buf, 1024);
|
||||
|
||||
return (void *)map;
|
||||
}
|
||||
static void
|
||||
test_api_get_ending_offset_tear_down(void *fixture)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)fixture;
|
||||
assert_ptr_not_null(map->m_data);
|
||||
munit_free(map->m_data);
|
||||
test_api_tear_down(fixture);
|
||||
}
|
||||
static MunitResult
|
||||
test_api_get_ending_offset(const MunitParameter params[], void *data)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)data;
|
||||
(void)params;
|
||||
|
||||
assert_ptr_not_null(map);
|
||||
|
||||
sparsemap_set(map, 0, true);
|
||||
assert_true(sparsemap_get_ending_offset(map) == 0);
|
||||
sparsemap_clear(map);
|
||||
|
||||
sparsemap_set(map, 0, true);
|
||||
sparsemap_set(map, 1, true);
|
||||
assert_true(sparsemap_get_ending_offset(map) == 1);
|
||||
sparsemap_clear(map);
|
||||
|
||||
sparsemap_set(map, 0, true);
|
||||
sparsemap_set(map, 67, true);
|
||||
sparsemap_set(map, 1002, true);
|
||||
sparsemap_set(map, 3087, true);
|
||||
sparsemap_set(map, 13012, true);
|
||||
assert_true(sparsemap_get_ending_offset(map) == 13012);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_api_scan_setup(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
|
@ -566,9 +698,6 @@ test_api_split_setup(const MunitParameter params[], void *user_data)
|
|||
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
|
||||
|
||||
sparsemap_init(map, buf, 1024);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
sparsemap_set(map, i, true);
|
||||
}
|
||||
return (void *)map;
|
||||
}
|
||||
static void
|
||||
|
@ -589,7 +718,15 @@ test_api_split(const MunitParameter params[], void *data)
|
|||
|
||||
assert_ptr_not_null(map);
|
||||
|
||||
sparsemap_init(&portion, buf, 512);
|
||||
sparsemap_init(&portion, buf, 1024);
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
sparsemap_set(map, i, true);
|
||||
}
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
assert_true(sparsemap_is_set(map, i));
|
||||
assert_false(sparsemap_is_set(&portion, i));
|
||||
}
|
||||
sparsemap_split(map, 512, &portion);
|
||||
for (int i = 0; i < 512; i++) {
|
||||
assert_true(sparsemap_is_set(map, i));
|
||||
|
@ -600,6 +737,45 @@ test_api_split(const MunitParameter params[], void *data)
|
|||
assert_true(sparsemap_is_set(&portion, i));
|
||||
}
|
||||
|
||||
sparsemap_clear(map);
|
||||
sparsemap_clear(&portion);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
sparsemap_set(map, i, true);
|
||||
}
|
||||
for (int i = 0; i < 100; i++) {
|
||||
assert_true(sparsemap_is_set(map, i));
|
||||
assert_false(sparsemap_is_set(&portion, i));
|
||||
}
|
||||
|
||||
sparsemap_idx_t offset = sparsemap_split(map, SPARSEMAP_IDX_MAX, &portion);
|
||||
for (int i = 0; i < offset; i++) {
|
||||
assert_true(sparsemap_is_set(map, i));
|
||||
assert_false(sparsemap_is_set(&portion, i));
|
||||
}
|
||||
for (int i = offset; i < 100; i++) {
|
||||
assert_false(sparsemap_is_set(map, i));
|
||||
assert_true(sparsemap_is_set(&portion, i));
|
||||
}
|
||||
|
||||
sparsemap_clear(&portion);
|
||||
sparsemap_clear(map);
|
||||
|
||||
sparsemap_init(&portion, buf, 1024);
|
||||
for (int i = 0; i < 13; i++) {
|
||||
sparsemap_set(map, i + 24, true);
|
||||
}
|
||||
|
||||
offset = sparsemap_split(map, SPARSEMAP_IDX_MAX, &portion);
|
||||
for (int i = 0; i < offset - 24; i++) {
|
||||
assert_true(sparsemap_is_set(map, i + 24));
|
||||
assert_false(sparsemap_is_set(&portion, i + 24));
|
||||
}
|
||||
for (int i = offset - 24; i < 13; i++) {
|
||||
assert_false(sparsemap_is_set(map, i + 24));
|
||||
assert_true(sparsemap_is_set(&portion, i + 24));
|
||||
}
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
|
@ -707,7 +883,7 @@ test_api_merge(const MunitParameter params[], void *data)
|
|||
assert(sparsemap_is_set(map, i));
|
||||
}
|
||||
|
||||
free(other);
|
||||
munit_free(other);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
|
@ -1012,9 +1188,11 @@ static MunitTest api_test_suite[] = {
|
|||
{ (char *)"/get_capacity", test_api_get_capacity, test_api_get_capacity_setup, test_api_get_capacity_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/is_set", test_api_is_set, test_api_is_set_setup, test_api_is_set_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/set", test_api_set, test_api_set_setup, test_api_set_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/get_starting_offset", test_api_get_starting_offset, test_api_get_starting_offset_setup, test_api_get_starting_offset_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
//TODO { (char *)"/get_ending_offset", test_api_get_ending_offset, test_api_get_ending_offset_setup, test_api_get_ending_offset_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/get_size", test_api_get_size, test_api_get_size_setup, test_api_get_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/count", test_api_count, test_api_count_setup, test_api_count_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/get_data", test_api_get_data, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/get_starting_offset", test_api_get_starting_offset, test_api_get_starting_offset_setup, test_api_get_starting_offset_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/get_ending_offset", test_api_get_ending_offset, test_api_get_ending_offset_setup, test_api_get_ending_offset_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/scan", test_api_scan, test_api_scan_setup, test_api_scan_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/split", test_api_split, test_api_split_setup, test_api_split_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/merge", test_api_merge, test_api_merge_setup, test_api_merge_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
|
|
Loading…
Reference in a new issue