test suite for the sparse bitmap data structure #1
4 changed files with 129 additions and 44 deletions
|
@ -467,44 +467,39 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t first, size_t last, size_t *after)
|
||||||
return (ret + last);
|
return (ret + last);
|
||||||
}
|
}
|
||||||
} else if (flags == SM_PAYLOAD_MIXED) {
|
} 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 (last > SM_BITS_PER_VECTOR) {
|
if (last > SM_BITS_PER_VECTOR) {
|
||||||
last -= SM_BITS_PER_VECTOR;
|
last -= SM_BITS_PER_VECTOR;
|
||||||
|
/* Create a mask for the range of bits except those we don't want to consider. */
|
||||||
|
uint64_t mask = ~(UINT64_MAX >> (SM_BITS_PER_VECTOR - *after));
|
||||||
|
uint64_t mw = w & mask;
|
||||||
|
ret += popcountll(mw);
|
||||||
if (*after > SM_BITS_PER_VECTOR) {
|
if (*after > SM_BITS_PER_VECTOR) {
|
||||||
*after = *after - SM_BITS_PER_VECTOR;
|
*after -= SM_BITS_PER_VECTOR;
|
||||||
} else {
|
|
||||||
sm_bitvec_t w = map->m_data[1 + __sm_chunk_map_get_position(map, i * SM_FLAGS_PER_INDEX_BYTE + j)];
|
|
||||||
uint64_t mask = UINT64_MAX;
|
|
||||||
if (*after > 0) {
|
|
||||||
mask = ~(mask >> (SM_BITS_PER_VECTOR - *after));
|
|
||||||
size_t amt = popcountll(w & mask);
|
|
||||||
if (amt <= *after) {
|
|
||||||
*after = *after - amt;
|
|
||||||
} else {
|
} else {
|
||||||
*after = 0;
|
*after = 0;
|
||||||
ret += popcountll(w & ~mask);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret += popcountll(w);
|
uint64_t mask_l, mask_r, mask;
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sm_bitvec_t w = map->m_data[1 + __sm_chunk_map_get_position(map, i * SM_FLAGS_PER_INDEX_BYTE + j)];
|
|
||||||
size_t ks = 0;
|
|
||||||
if (*after > 0) {
|
if (*after > 0) {
|
||||||
if (*after > last) {
|
if (*after > last) {
|
||||||
ks = last;
|
|
||||||
*after = *after - last;
|
*after = *after - last;
|
||||||
|
/* This gives us 'last' number of ones on the right. */
|
||||||
|
mask_r = ((uint64_t)1 << last) - 1;
|
||||||
} else {
|
} else {
|
||||||
ks += *after;
|
/* This gives us '*after' number of ones on the right. */
|
||||||
|
mask_r = (((uint64_t)1 << *after) - 1);
|
||||||
*after = 0;
|
*after = 0;
|
||||||
}
|
}
|
||||||
|
/* Used to shift the mask_r block to the left 'last' times. */
|
||||||
|
mask_l = ((uint64_t)1 << (last + 1));
|
||||||
|
mask = mask_l - 1 - mask_r;
|
||||||
|
} else {
|
||||||
|
mask = UINT64_MAX >> (SM_BITS_PER_VECTOR - last - 1);
|
||||||
}
|
}
|
||||||
uint64_t mask = ((uint64_t)1 << (last + 1)) - 1 - (((uint64_t)1 << ks) - 1);
|
/* Create a mask for the range between *after and last. */
|
||||||
uint64_t masked = w & mask;
|
uint64_t mw = w & mask;
|
||||||
while (masked) {
|
ret += popcountll(mw);
|
||||||
ret += masked & 1;
|
|
||||||
masked >>= 1;
|
|
||||||
}
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1198,7 +1193,7 @@ size_t
|
||||||
sparsemap_rank(sparsemap_t *map, size_t first, size_t last)
|
sparsemap_rank(sparsemap_t *map, size_t first, size_t last)
|
||||||
{
|
{
|
||||||
assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
|
assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
|
||||||
size_t result = 0, after = first, count = __sm_get_chunk_map_count(map);
|
size_t result = 0, after = first, prev = 0, count = __sm_get_chunk_map_count(map);
|
||||||
uint8_t *p = __sm_get_chunk_map_data(map, 0);
|
uint8_t *p = __sm_get_chunk_map_data(map, 0);
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
@ -1206,6 +1201,8 @@ sparsemap_rank(sparsemap_t *map, size_t first, size_t last)
|
||||||
if (start > last) {
|
if (start > last) {
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
after -= start - prev;
|
||||||
|
prev = start;
|
||||||
p += sizeof(sm_idx_t);
|
p += sizeof(sm_idx_t);
|
||||||
__sm_chunk_t chunk;
|
__sm_chunk_t chunk;
|
||||||
__sm_chunk_map_init(&chunk, p);
|
__sm_chunk_map_init(&chunk, p);
|
||||||
|
|
|
@ -42,7 +42,7 @@ xorshift32_seed()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
shuffle(int *array, size_t n)
|
shuffle(int *array, size_t n) // TODO working?
|
||||||
{
|
{
|
||||||
for (size_t i = n - 1; i > 0; --i) {
|
for (size_t i = n - 1; i > 0; --i) {
|
||||||
size_t j = xorshift32() % (i + 1);
|
size_t j = xorshift32() % (i + 1);
|
||||||
|
@ -64,32 +64,40 @@ compare_ints(const void *a, const void *b)
|
||||||
int
|
int
|
||||||
has_sequential_set(int a[], int l, int r)
|
has_sequential_set(int a[], int l, int r)
|
||||||
{
|
{
|
||||||
int count = 1; // Start with a count of 1 for the first number
|
// Start with a count of 1 for the first number
|
||||||
|
int count = 1;
|
||||||
for (int i = 1; i < l; ++i) {
|
for (int i = 1; i < l; ++i) {
|
||||||
if (a[i] - a[i - 1] == 1) { // Check if the current and previous elements are sequential
|
// Check if the current and previous elements are sequential
|
||||||
|
if (a[i] - a[i - 1] == 1) {
|
||||||
count++;
|
count++;
|
||||||
if (count >= r)
|
if (count >= r) {
|
||||||
return 1; // Found a sequential set of length 'r'
|
// Found a sequential set of length 'r' starting at 'i'
|
||||||
|
return i;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
count = 1; // Reset count if the sequence breaks
|
// Reset count if the sequence breaks
|
||||||
|
count = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0; // No sequential set of length 'r' found
|
// No sequential set of length 'r' found
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to ensure an array contains a set of 'r' sequential integers
|
// Function to ensure an array contains a set of 'r' sequential integers
|
||||||
void
|
int
|
||||||
ensure_sequential_set(int *a, int l, int r)
|
ensure_sequential_set(int a[], int l, int r)
|
||||||
{
|
{
|
||||||
if (!a || l == 0 || r > l)
|
if (!a || l == 0 || r < 1 || r > l) {
|
||||||
return;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Sort the array to check for existing sequences
|
// Sort the array to check for existing sequences
|
||||||
qsort(a, l, sizeof(int), compare_ints);
|
qsort(a, l, sizeof(int), compare_ints);
|
||||||
|
|
||||||
// Check if a sequential set of length 'r' already exists
|
// Check if a sequential set of length 'r' already exists
|
||||||
if (has_sequential_set(a, l, r)) {
|
int offset = has_sequential_set(a, l, r);
|
||||||
return; // Sequence already exists, no modification needed
|
if (offset >= 0) {
|
||||||
|
return offset; // Sequence already exists, no modification needed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the minimum and maximum values in the array
|
// Find the minimum and maximum values in the array
|
||||||
|
@ -98,14 +106,25 @@ ensure_sequential_set(int *a, int l, int r)
|
||||||
|
|
||||||
// Generate a random value between min_value and max_value
|
// Generate a random value between min_value and max_value
|
||||||
int value = random_uint32() % (max_value - min_value - r + 1);
|
int value = random_uint32() % (max_value - min_value - r + 1);
|
||||||
|
|
||||||
// Generate a random location between 0 and l - r
|
// Generate a random location between 0 and l - r
|
||||||
int offset = random_uint32() % (l + r + 1);
|
offset = random_uint32() % (l - r - 1);
|
||||||
|
|
||||||
// Adjust the array to include a sequential set of 'r' integers at the random offset
|
// Adjust the array to include a sequential set of 'r' integers at the random offset
|
||||||
for (int i = 0; i < r; ++i) {
|
for (int i = 0; i < r; ++i) {
|
||||||
a[i + offset] = value + i;
|
a[i + offset] = value + i;
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
create_sequential_set_in_empty_map(sparsemap_t *map, int s, int r)
|
||||||
|
{
|
||||||
|
int placed_at;
|
||||||
|
placed_at = random_uint32() % (s - r - 1);
|
||||||
|
for (int i = placed_at; i < placed_at + r; i++) {
|
||||||
|
sparsemap_set(map, i, true);
|
||||||
|
}
|
||||||
|
return placed_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -305,3 +324,15 @@ whats_set_uint64(uint64_t number, int pos[64])
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
whats_set(sparsemap_t *map, int m)
|
||||||
|
{
|
||||||
|
logf("what's set in the range [0, %d): ", m);
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
if (sparsemap_is_set(map, i)) {
|
||||||
|
logf("%d ", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logf("\n");
|
||||||
|
}
|
||||||
|
|
47
tests/common.h
Normal file
47
tests/common.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
||||||
|
#define __diag(...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, "%s:%d:%s(): ", __FILE__, __LINE__, __func__); \
|
||||||
|
fprintf(stderr, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
#ifdef MUNIT_VERSION
|
||||||
|
#define random_uint32 munit_rand_uint32
|
||||||
|
#define logf(...) munit_logf(MUNIT_LOG_INFO, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define random_uint32 xorshift32
|
||||||
|
#define logf(...) fprintf(stderr, __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Stable seeds make for stable "random" sequences for repeatable tests. */
|
||||||
|
#ifdef STABLE_SEED
|
||||||
|
#define XORSHIFT_SEED_VALUE (8675309)
|
||||||
|
#else
|
||||||
|
#define XORSHIFT_SEED_VALUE ((unsigned int)time(NULL) ^ getpid())
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void xorshift32_seed();
|
||||||
|
uint32_t xorshift32();
|
||||||
|
|
||||||
|
void print_array(int *array, int l);
|
||||||
|
void print_spans(int *array, int n);
|
||||||
|
|
||||||
|
bool is_span(int *array, int n, int x, int l);
|
||||||
|
bool is_set(const int array[], int bit);
|
||||||
|
bool has_span(sparsemap_t *map, int *array, int l, int n);
|
||||||
|
int is_unique(int a[], int l, int value);
|
||||||
|
|
||||||
|
void setup_test_array(int a[], int l, int max_value);
|
||||||
|
void shuffle(int *array, size_t n);
|
||||||
|
int ensure_sequential_set(int a[], int l, int r);
|
||||||
|
int create_sequential_set_in_empty_map(sparsemap_t *map, int s, int r);
|
||||||
|
|
||||||
|
void bitmap_from_uint32(sparsemap_t *map, uint32_t number);
|
||||||
|
void bitmap_from_uint64(sparsemap_t *map, uint64_t number);
|
||||||
|
uint32_t rank_uint64(uint64_t number, int n, int p);
|
||||||
|
int whats_set_uint64(uint64_t number, int bitPositions[64]);
|
||||||
|
|
||||||
|
void whats_set(sparsemap_t *map, int m);
|
16
tests/test.c
16
tests/test.c
|
@ -31,7 +31,7 @@ populate_map(sparsemap_t *map, int size, int max_value)
|
||||||
int array[size];
|
int array[size];
|
||||||
|
|
||||||
setup_test_array(array, size, max_value);
|
setup_test_array(array, size, max_value);
|
||||||
ensure_sequential_set(array, size, 10);
|
//TODO ensure_sequential_set(array, size, 10);
|
||||||
shuffle(array, size);
|
shuffle(array, size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
sparsemap_set(map, array[i], true);
|
sparsemap_set(map, array[i], true);
|
||||||
|
@ -574,7 +574,6 @@ test_api_span_setup(const MunitParameter params[], void *user_data)
|
||||||
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
|
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
|
||||||
|
|
||||||
sparsemap_init(map, buf, 1024, 0);
|
sparsemap_init(map, buf, 1024, 0);
|
||||||
populate_map(map, 1024, 3 * 1024);
|
|
||||||
|
|
||||||
return (void *)map;
|
return (void *)map;
|
||||||
}
|
}
|
||||||
|
@ -593,7 +592,18 @@ test_api_span(const MunitParameter params[], void *data)
|
||||||
|
|
||||||
assert_ptr_not_null(map);
|
assert_ptr_not_null(map);
|
||||||
|
|
||||||
sparsemap_span(map, 0, 1);
|
int located_at, placed_at, amt = 5000;
|
||||||
|
for (int i = 1; i < amt; i++) {
|
||||||
|
for (int j = 1; j < amt / 10; j++) {
|
||||||
|
sparsemap_clear(map);
|
||||||
|
placed_at = create_sequential_set_in_empty_map(map, amt, j);
|
||||||
|
// whats_set(map, amt);
|
||||||
|
located_at = sparsemap_span(map, 0, j);
|
||||||
|
assert_true(located_at == placed_at);
|
||||||
|
located_at = sparsemap_span(map, (placed_at < j ? 0 : placed_at / 2), i);
|
||||||
|
assert_true(placed_at == located_at);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue