WIP rank 0-bits, fixes, etc.
This commit is contained in:
parent
20b81983ae
commit
599284d5f5
6 changed files with 172 additions and 75 deletions
2
Makefile
2
Makefile
|
@ -78,6 +78,6 @@ examples/ex_4: examples/common.o examples/ex_4.o $(STATIC_LIB)
|
|||
$(CC) $^ -o $@ $(CFLAGS) $(TEST_FLAGS)
|
||||
|
||||
todo:
|
||||
rg -i 'todo|gsb'
|
||||
rg -i 'todo|gsb|abort'
|
||||
|
||||
# cp src/sparsemap.c /tmp && clang-tidy src/sparsemap.c -fix -fix-errors -checks="readability-braces-around-statements" -- -DDEBUG -DSPARSEMAP_DIAGNOSTIC -DSPARSEMAP_ASSERT -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
|
||||
/* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */
|
||||
struct sparsemap {
|
||||
uint8_t *m_data;
|
||||
size_t m_capacity;
|
||||
size_t m_data_used;
|
||||
uint8_t *m_data;
|
||||
};
|
||||
|
||||
int
|
||||
|
|
140
src/sparsemap.c
140
src/sparsemap.c
|
@ -115,9 +115,9 @@ typedef struct {
|
|||
} __sm_chunk_t;
|
||||
|
||||
struct __attribute__((aligned(8))) sparsemap {
|
||||
uint8_t *m_data; /* The serialized bitmap data */
|
||||
size_t m_capacity; /* The total size of m_data */
|
||||
size_t m_data_used; /* The used size of m_data */
|
||||
uint8_t *m_data; /* The serialized bitmap data */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -147,7 +147,7 @@ __sm_chunk_map_calc_vector_size(uint8_t b)
|
|||
0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 2, 1, 0, 0, 1, 0
|
||||
};
|
||||
// clang-format on
|
||||
return ((size_t)lookup[b]);
|
||||
return (size_t)lookup[b];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -173,7 +173,7 @@ __sm_chunk_map_get_position(__sm_chunk_t *map, size_t bv)
|
|||
}
|
||||
}
|
||||
|
||||
return (position);
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,7 +205,7 @@ __sm_chunk_map_get_capacity(__sm_chunk_t *map)
|
|||
}
|
||||
}
|
||||
}
|
||||
return (capacity);
|
||||
return capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,7 +244,7 @@ __sm_chunk_map_is_empty(__sm_chunk_t *map)
|
|||
{
|
||||
/* The __sm_chunk_t is empty if all flags (in m_data[0]) are zero. */
|
||||
if (map->m_data[0] == 0) {
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* It's also empty if all flags are Zero or None. */
|
||||
|
@ -254,12 +254,12 @@ __sm_chunk_map_is_empty(__sm_chunk_t *map)
|
|||
for (int j = 0; j < SM_FLAGS_PER_INDEX_BYTE; j++) {
|
||||
size_t flags = SM_CHUNK_GET_FLAGS(*p, j);
|
||||
if (flags != SM_PAYLOAD_NONE && flags != SM_PAYLOAD_ZEROS) {
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -276,7 +276,7 @@ __sm_chunk_map_get_size(__sm_chunk_t *map)
|
|||
size += sizeof(sm_bitvec_t) * __sm_chunk_map_calc_vector_size(*p);
|
||||
}
|
||||
|
||||
return (size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,9 +294,9 @@ __sm_chunk_map_is_set(__sm_chunk_t *map, size_t idx)
|
|||
switch (flags) {
|
||||
case SM_PAYLOAD_ZEROS:
|
||||
case SM_PAYLOAD_NONE:
|
||||
return (false);
|
||||
return false;
|
||||
case SM_PAYLOAD_ONES:
|
||||
return (true);
|
||||
return true;
|
||||
default:
|
||||
__sm_assert(flags == SM_PAYLOAD_MIXED);
|
||||
/* FALLTHROUGH */
|
||||
|
@ -305,7 +305,7 @@ __sm_chunk_map_is_set(__sm_chunk_t *map, size_t idx)
|
|||
/* get the sm_bitvec_t at |bv| */
|
||||
sm_bitvec_t w = map->m_data[1 + __sm_chunk_map_get_position(map, bv)];
|
||||
/* and finally check the bit in that sm_bitvec_t */
|
||||
return ((w & ((sm_bitvec_t)1 << (idx % SM_BITS_PER_VECTOR))) > 0);
|
||||
return (w & ((sm_bitvec_t)1 << (idx % SM_BITS_PER_VECTOR))) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -428,7 +428,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
|
|||
continue;
|
||||
}
|
||||
*pnew_n = -1;
|
||||
return (ret + n);
|
||||
return ret + n;
|
||||
}
|
||||
}
|
||||
if (flags == SM_PAYLOAD_ONES) {
|
||||
|
@ -439,7 +439,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
|
|||
continue;
|
||||
}
|
||||
*pnew_n = -1;
|
||||
return (ret + n);
|
||||
return ret + n;
|
||||
} else {
|
||||
ret += SM_BITS_PER_VECTOR;
|
||||
continue;
|
||||
|
@ -452,7 +452,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
|
|||
if (w & ((sm_bitvec_t)1 << k)) {
|
||||
if (n == 0) {
|
||||
*pnew_n = -1;
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
|
@ -461,7 +461,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
|
|||
if (!(w & ((sm_bitvec_t)1 << k))) {
|
||||
if (n == 0) {
|
||||
*pnew_n = -1;
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
|
@ -472,7 +472,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
|
|||
}
|
||||
}
|
||||
*pnew_n = (ssize_t)n;
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -482,7 +482,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
|
|||
* '*offset' has been reached 0.
|
||||
*/
|
||||
static size_t
|
||||
__sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, sm_bitvec_t *vec)
|
||||
__sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, sm_bitvec_t *vec, bool value)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
|
@ -499,11 +499,20 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, sm_bitvec_t *
|
|||
*offset = *offset - SM_BITS_PER_VECTOR;
|
||||
} else {
|
||||
idx -= SM_BITS_PER_VECTOR - *offset;
|
||||
if (*offset == 0) {
|
||||
if (value == false) {
|
||||
ret += SM_BITS_PER_VECTOR;
|
||||
}
|
||||
}
|
||||
*offset = 0;
|
||||
}
|
||||
} else {
|
||||
*vec = 0;
|
||||
return (ret);
|
||||
if (value == false) {
|
||||
return ret + idx;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else if (flags == SM_PAYLOAD_ONES) {
|
||||
if (idx > SM_BITS_PER_VECTOR) {
|
||||
|
@ -512,36 +521,53 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, sm_bitvec_t *
|
|||
} else {
|
||||
idx -= SM_BITS_PER_VECTOR - *offset;
|
||||
if (*offset == 0) {
|
||||
ret += SM_BITS_PER_VECTOR;
|
||||
if (value == true) {
|
||||
ret += SM_BITS_PER_VECTOR;
|
||||
}
|
||||
}
|
||||
*offset = 0;
|
||||
}
|
||||
} else {
|
||||
*vec = UINT64_MAX;
|
||||
return (ret + idx);
|
||||
if (value == true) {
|
||||
return ret + idx;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else if (flags == SM_PAYLOAD_MIXED) {
|
||||
sm_bitvec_t w = map->m_data[1 + __sm_chunk_map_get_position(map, i * SM_FLAGS_PER_INDEX_BYTE + j)];
|
||||
if (idx > SM_BITS_PER_VECTOR) {
|
||||
uint64_t mask_offset = ~(UINT64_MAX >> (SM_BITS_PER_VECTOR - *offset));
|
||||
uint64_t mask = ~(UINT64_MAX >> (SM_BITS_PER_VECTOR - *offset));
|
||||
idx -= SM_BITS_PER_VECTOR;
|
||||
ret += popcountll(w & mask_offset);
|
||||
size_t pc = popcountll(w & mask);
|
||||
if (value == true) {
|
||||
ret += pc;
|
||||
} else {
|
||||
ret += popcountll(mask) - pc;
|
||||
}
|
||||
*offset = (*offset > SM_BITS_PER_VECTOR) ? *offset - SM_BITS_PER_VECTOR : 0;
|
||||
} else {
|
||||
/* Create a mask for the range between offset and idx inclusive [*offset, idx]. */
|
||||
uint64_t offset_mask = (((uint64_t)1 << *offset) - 1);
|
||||
uint64_t idx_mask = idx >= 63 ? UINT64_MAX : ((uint64_t)1 << (idx + 1)) - 1;
|
||||
sm_bitvec_t mw = w & (idx_mask - offset_mask);
|
||||
ret += popcountll(mw);
|
||||
uint64_t mask = (idx_mask - offset_mask);
|
||||
sm_bitvec_t mw = w & mask;
|
||||
size_t pc = popcountll(mw);
|
||||
if (value == true) {
|
||||
ret += pc;
|
||||
} else {
|
||||
ret += popcountll(mask) - pc;
|
||||
}
|
||||
*offset = *offset > idx ? *offset - idx : 0;
|
||||
*vec = mw;
|
||||
(*vec) <<= *offset;
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -612,7 +638,7 @@ __sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[
|
|||
}
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -625,7 +651,7 @@ __sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[
|
|||
static size_t
|
||||
__sm_get_chunk_map_count(sparsemap_t *map)
|
||||
{
|
||||
return (*(uint32_t *)&map->m_data[0]);
|
||||
return *(uint32_t *)&map->m_data[0];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -634,7 +660,7 @@ __sm_get_chunk_map_count(sparsemap_t *map)
|
|||
static inline uint8_t *
|
||||
__sm_get_chunk_map_data(sparsemap_t *map, size_t offset)
|
||||
{
|
||||
return (&map->m_data[SM_SIZEOF_OVERHEAD + offset]);
|
||||
return &map->m_data[SM_SIZEOF_OVERHEAD + offset];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -652,7 +678,7 @@ __sm_get_chunk_map_end(sparsemap_t *map)
|
|||
__sm_chunk_map_init(&chunk, p);
|
||||
p += __sm_chunk_map_get_size(&chunk);
|
||||
}
|
||||
return (p);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -671,7 +697,7 @@ __sm_get_size_impl(sparsemap_t *map)
|
|||
__sm_chunk_map_init(&chunk, p);
|
||||
p += __sm_chunk_map_get_size(&chunk);
|
||||
}
|
||||
return (SM_SIZEOF_OVERHEAD + p - start);
|
||||
return SM_SIZEOF_OVERHEAD + p - start;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -681,7 +707,7 @@ static sm_idx_t
|
|||
__sm_get_aligned_offset(size_t idx)
|
||||
{
|
||||
const size_t capacity = SM_BITS_PER_VECTOR;
|
||||
return ((idx / capacity) * capacity);
|
||||
return (idx / capacity) * capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -694,7 +720,7 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
|
|||
|
||||
count = __sm_get_chunk_map_count(map);
|
||||
if (count == 0) {
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (idx > 0 || idx == 0) {
|
||||
|
@ -712,7 +738,7 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
|
|||
p += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&chunk);
|
||||
}
|
||||
|
||||
return ((ssize_t)(p - start));
|
||||
return (ssize_t)(p - start);
|
||||
} else {
|
||||
uint8_t *end = __sm_get_chunk_map_data(map, count - 1);
|
||||
uint8_t *p = end;
|
||||
|
@ -728,7 +754,7 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
|
|||
p += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&chunk);
|
||||
}
|
||||
|
||||
return ((ssize_t)(p - end));
|
||||
return (ssize_t)(p - end);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -739,7 +765,7 @@ static sm_idx_t
|
|||
__sm_get_fully_aligned_offset(size_t idx)
|
||||
{
|
||||
const size_t capacity = SM_CHUNK_MAX_CAPACITY;
|
||||
return ((idx / capacity) * capacity);
|
||||
return (idx / capacity) * capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -893,7 +919,7 @@ sparsemap_capacity_remaining(sparsemap_t *map)
|
|||
size_t
|
||||
sparsemap_get_capacity(sparsemap_t *map)
|
||||
{
|
||||
return (map->m_capacity);
|
||||
return map->m_capacity;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -902,7 +928,7 @@ sparsemap_is_set(sparsemap_t *map, sparsemap_idx_t idx)
|
|||
__sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
|
||||
|
||||
if (idx < 0) {
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the __sm_chunk_t which manages this index */
|
||||
|
@ -910,7 +936,7 @@ sparsemap_is_set(sparsemap_t *map, sparsemap_idx_t idx)
|
|||
|
||||
/* No __sm_chunk_t's available -> the bit is not set */
|
||||
if (offset == -1) {
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Otherwise load the __sm_chunk_t */
|
||||
|
@ -922,11 +948,11 @@ sparsemap_is_set(sparsemap_t *map, sparsemap_idx_t idx)
|
|||
/* Determine if the bit is out of bounds of the __sm_chunk_t; if yes then
|
||||
the bit is not set. */
|
||||
if (idx < start || (unsigned long)idx - start >= __sm_chunk_map_get_capacity(&chunk)) {
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Otherwise ask the __sm_chunk_t whether the bit is set. */
|
||||
return (__sm_chunk_map_is_set(&chunk, idx - start));
|
||||
return __sm_chunk_map_is_set(&chunk, idx - start);
|
||||
}
|
||||
|
||||
sparsemap_idx_t
|
||||
|
@ -1075,7 +1101,7 @@ sparsemap_get_starting_offset(sparsemap_t *map)
|
|||
{
|
||||
size_t count = __sm_get_chunk_map_count(map);
|
||||
if (count == 0) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
sm_idx_t *chunk = (sm_idx_t *)__sm_get_chunk_map_data(map, 0);
|
||||
return *chunk;
|
||||
|
@ -1088,10 +1114,13 @@ size_t
|
|||
sparsemap_get_size(sparsemap_t *map)
|
||||
{
|
||||
if (map->m_data_used) {
|
||||
assert(map->m_data_used == __sm_get_size_impl(map));
|
||||
return (map->m_data_used);
|
||||
__sm_when_diag({
|
||||
size_t used = __sm_get_size_impl(map);
|
||||
__sm_assert(map->m_data_used == used);
|
||||
});
|
||||
return map->m_data_used;
|
||||
}
|
||||
return (map->m_data_used = __sm_get_size_impl(map));
|
||||
return map->m_data_used = __sm_get_size_impl(map);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1254,7 +1283,7 @@ sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value)
|
|||
ssize_t new_n = (ssize_t)n;
|
||||
size_t index = __sm_chunk_map_select(&chunk, n, &new_n, value);
|
||||
if (new_n == -1) {
|
||||
return (result + index);
|
||||
return result + index;
|
||||
}
|
||||
n = new_n;
|
||||
|
||||
|
@ -1269,15 +1298,25 @@ sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value)
|
|||
size_t
|
||||
sparsemap_rank_vec(sparsemap_t *map, size_t x, size_t y, bool value, sm_bitvec_t *vec)
|
||||
{
|
||||
(void)value; // TODO
|
||||
assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
|
||||
size_t result = 0, prev = 0, count = __sm_get_chunk_map_count(map);
|
||||
uint8_t *p = __sm_get_chunk_map_data(map, 0);
|
||||
|
||||
/* The count/rank of zero bits in an empty map is inf, so what you requested is the answer. */
|
||||
if (count == 0 && value == false) {
|
||||
return y - x + 1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
sm_idx_t start = *(sm_idx_t *)p;
|
||||
/* Start of this chunk is greater than the end of the desired range. */
|
||||
if (start > y) {
|
||||
return (result);
|
||||
if (value == true) {
|
||||
return result;
|
||||
} else {
|
||||
/* This chunk starts after our range [x, y]. */
|
||||
return y - x + 1;
|
||||
}
|
||||
}
|
||||
x -= start - prev;
|
||||
prev = start;
|
||||
|
@ -1285,11 +1324,10 @@ sparsemap_rank_vec(sparsemap_t *map, size_t x, size_t y, bool value, sm_bitvec_t
|
|||
__sm_chunk_t chunk;
|
||||
__sm_chunk_map_init(&chunk, p);
|
||||
|
||||
result += __sm_chunk_map_rank(&chunk, &x, y - start, vec);
|
||||
result += __sm_chunk_map_rank(&chunk, &x, y - start, vec, value);
|
||||
p += __sm_chunk_map_get_size(&chunk);
|
||||
}
|
||||
return (result);
|
||||
// TODO: sparsemap_rank(map, x, y, false)
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
|
@ -381,9 +381,9 @@ sm_whats_set(sparsemap_t *map, int m)
|
|||
}
|
||||
|
||||
bool
|
||||
sm_is_span(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value)
|
||||
sm_is_span(sparsemap_t *map, sparsemap_idx_t m, int len, bool value)
|
||||
{
|
||||
for (sparsemap_idx_t i = m; i < (sparsemap_idx_t)len; i++) {
|
||||
for (sparsemap_idx_t i = m; i < m + len; i++) {
|
||||
if (sparsemap_is_set(map, i) != value) {
|
||||
return false;
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ sm_is_span(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value)
|
|||
}
|
||||
|
||||
bool
|
||||
sm_occupied(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value)
|
||||
sm_occupied(sparsemap_t *map, sparsemap_idx_t m, int len, bool value)
|
||||
{
|
||||
for (sparsemap_idx_t i = m; i < (sparsemap_idx_t)len; i++) {
|
||||
if (sparsemap_is_set(map, i) == value) {
|
||||
|
|
|
@ -50,5 +50,5 @@ int whats_set_uint64(uint64_t number, int bitPositions[64]);
|
|||
|
||||
void sm_whats_set(sparsemap_t *map, int m);
|
||||
|
||||
bool sm_is_span(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value);
|
||||
bool sm_occupied(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value);
|
||||
bool sm_is_span(sparsemap_t *map, sparsemap_idx_t m, int len, bool value);
|
||||
bool sm_occupied(sparsemap_t *map, sparsemap_idx_t m, int len, bool value);
|
||||
|
|
93
tests/test.c
93
tests/test.c
|
@ -29,9 +29,9 @@
|
|||
|
||||
/* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */
|
||||
struct sparsemap {
|
||||
uint8_t *m_data;
|
||||
size_t m_capacity;
|
||||
size_t m_data_used;
|
||||
uint8_t *m_data;
|
||||
};
|
||||
|
||||
struct user_data {
|
||||
|
@ -330,7 +330,7 @@ test_api_remaining_capacity(const MunitParameter params[], void *data)
|
|||
cap = sparsemap_capacity_remaining(map);
|
||||
} while (cap > 1.0 && errno != ENOSPC);
|
||||
errno = 0;
|
||||
assert_true(cap <= 1.0);
|
||||
assert_true(cap <= 2.0);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
@ -665,14 +665,15 @@ test_api_select_false(const MunitParameter params[], void *data)
|
|||
{
|
||||
sparsemap_t *map = (sparsemap_t *)data;
|
||||
(void)params;
|
||||
|
||||
assert_ptr_not_null(map);
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
sparsemap_set(map, i, true);
|
||||
/* First few 0/off/unset-bits in ((uint64_t)0xfeedface << 32) | 0xbadc0ffee) expressed as an array of offsets. */
|
||||
int off[] = { 0, 4, 16, 17, 18, 19, 20, 21, 25, 28, 30, 36, 37, 40, 42, 49, 52, 56, 64, 65};
|
||||
for (int i = 0; i < 20; i++) {
|
||||
sparsemap_idx_t f = sparsemap_select(map, i, false);
|
||||
assert_true(f == off[i]);
|
||||
assert_true(sparsemap_is_set(map, f) == false);
|
||||
}
|
||||
sparsemap_idx_t f = sparsemap_select(map, 0, false);
|
||||
assert_true(f == 1000);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
@ -726,7 +727,7 @@ test_api_select_neg(const MunitParameter params[], void *data)
|
|||
#endif
|
||||
|
||||
static void *
|
||||
test_api_rank_setup(const MunitParameter params[], void *user_data)
|
||||
test_api_rank_true_setup(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
|
||||
assert_ptr_not_null(buf);
|
||||
|
@ -737,7 +738,7 @@ test_api_rank_setup(const MunitParameter params[], void *user_data)
|
|||
return (void *)map;
|
||||
}
|
||||
static void
|
||||
test_api_rank_tear_down(void *fixture)
|
||||
test_api_rank_true_tear_down(void *fixture)
|
||||
{
|
||||
sparsemap_t *map = (sparsemap_t *)fixture;
|
||||
assert_ptr_not_null(map->m_data);
|
||||
|
@ -745,7 +746,7 @@ test_api_rank_tear_down(void *fixture)
|
|||
test_api_tear_down(fixture);
|
||||
}
|
||||
static MunitResult
|
||||
test_api_rank(const MunitParameter params[], void *data)
|
||||
test_api_rank_true(const MunitParameter params[], void *data)
|
||||
{
|
||||
int r1, r2;
|
||||
sparsemap_t *map = (sparsemap_t *)data;
|
||||
|
@ -782,6 +783,60 @@ test_api_rank(const MunitParameter params[], void *data)
|
|||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_api_rank_false_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_rank_false_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_rank_false(const MunitParameter params[], void *data)
|
||||
{
|
||||
int r;
|
||||
sparsemap_t *map = (sparsemap_t *)data;
|
||||
(void)params;
|
||||
|
||||
assert_ptr_not_null(map);
|
||||
|
||||
// empty map
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
for (int j = i; j < 10000; j++) {
|
||||
r = sparsemap_rank(map, i, j, false);
|
||||
assert_true(r == j - i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// one chunk means not so empty now!
|
||||
sparsemap_set(map, 4999, true);
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
for (int j = i; j < 10000; j++) {
|
||||
int amt = j - i + 1 - ((4999 > i && 4999 < j) ? 1 : 0);
|
||||
r = sparsemap_rank(map, i, j, false); // GSB
|
||||
assert_true(r == amt);
|
||||
}
|
||||
}
|
||||
|
||||
sparsemap_set(map, 1, true);
|
||||
sparsemap_set(map, 11, true);
|
||||
r = sparsemap_rank(map, 0, 11, false);
|
||||
assert_true(r == 10);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_api_span_setup(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
|
@ -865,7 +920,8 @@ static MunitTest api_test_suite[] = {
|
|||
#ifdef SELECT_NEG
|
||||
{ (char *)"/select/neg", test_api_select_neg, test_api_select_neg_setup, test_api_select_neg_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
#endif
|
||||
{ (char *)"/rank", test_api_rank, test_api_rank_setup, test_api_rank_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/rank/true", test_api_rank_true, test_api_rank_true_setup, test_api_rank_true_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/rank/false", test_api_rank_false, test_api_rank_false_setup, test_api_rank_false_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ (char *)"/span", test_api_span, test_api_span_setup, test_api_span_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
|
||||
};
|
||||
|
@ -942,7 +998,7 @@ test_scale_ondrej(const MunitParameter params[], void *data)
|
|||
sparsemap_idx_t stride = 18;
|
||||
sparsemap_idx_t top = 268435456;
|
||||
sparsemap_idx_t needle = munit_rand_int_range(1, top / stride);
|
||||
for (sparsemap_idx_t i = 0; i < top / stride; i++) {
|
||||
for (sparsemap_idx_t i = 0; i < top / stride; i += stride) {
|
||||
for (sparsemap_idx_t j = 0; j < stride; j++) {
|
||||
bool set = (i != needle) ? (j < 10) : (j < 9);
|
||||
sparsemap_set(map, i, set);
|
||||
|
@ -951,9 +1007,12 @@ test_scale_ondrej(const MunitParameter params[], void *data)
|
|||
errno = 0;
|
||||
}
|
||||
}
|
||||
assert_true(sm_is_span(map, i + ((i != needle) ? 10 : 9), (i != needle) ? 8 : 9, false));
|
||||
}
|
||||
sparsemap_idx_t a = sparsemap_span(map, 0, 9, false);
|
||||
assert_true((a / stride) == needle);
|
||||
sparsemap_idx_t l = a / stride;
|
||||
printf("%ld\t%ld\n", a, l);
|
||||
assert_true(l == needle);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
|
@ -962,7 +1021,7 @@ test_scale_spans_come_spans_go_setup(const MunitParameter params[], void *user_d
|
|||
{
|
||||
(void)params;
|
||||
(void)user_data;
|
||||
sparsemap_t *map = sparsemap(10 * 1024);
|
||||
sparsemap_t *map = sparsemap(1024);
|
||||
assert_ptr_not_null(map);
|
||||
return (void *)map;
|
||||
}
|
||||
|
@ -976,7 +1035,7 @@ test_scale_spans_come_spans_go_tear_down(void *fixture)
|
|||
static MunitResult
|
||||
test_scale_spans_come_spans_go(const MunitParameter params[], void *data)
|
||||
{
|
||||
size_t amt = 897915; // 268435456, ~5e7 interations due to 2e9 / avg(l)
|
||||
size_t amt = 8192; // 268435456, ~5e7 interations due to 2e9 / avg(l)
|
||||
sparsemap_t *map = (sparsemap_t *)data;
|
||||
(void)params;
|
||||
|
||||
|
@ -990,8 +1049,8 @@ test_scale_spans_come_spans_go(const MunitParameter params[], void *data)
|
|||
errno = 0;
|
||||
}
|
||||
|
||||
/* After 10,000 spans are in there we consume a span every iteration. */
|
||||
if (l > 10000) {
|
||||
/* After 1,000 spans are in the map start consuming a span every iteration. */
|
||||
if (l > 1000) {
|
||||
do {
|
||||
int s = munit_rand_int_range(1, 30);
|
||||
int o = munit_rand_int_range(1, 268435456 - s - 1);
|
||||
|
|
Loading…
Reference in a new issue