#include #include #include #include "../include/sparsemap.h" #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 #define SEED /* https://burtleburtle.net/bob/rand/smallprng.html */ typedef struct rnd_ctx { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } rnd_ctx_t; #define __rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) uint32_t __random(rnd_ctx_t *x) { uint32_t e = x->a - __rot(x->b, 27); x->a = x->b ^ __rot(x->c, 17); x->b = x->c + x->d; x->c = x->d + e; x->d = e + x->a; return x->d; } void __random_seed(rnd_ctx_t *x, uint32_t seed) { uint32_t i; x->a = 0xf1ea5eed, x->b = x->c = x->d = seed; for (i = 0; i < 20; ++i) { (void)__random(x); } } void shuffle(rnd_ctx_t *prng, int *array, size_t n) { size_t i, j; if (n > 1) { for (i = n - 1; i > 0; i--) { j = (unsigned int)(__random(prng) % (i + 1)); // XOR swap algorithm if (i != j) { // avoid self-swap leading to zero-ing the element array[i] = array[i] ^ array[j]; array[j] = array[i] ^ array[j]; array[i] = array[i] ^ array[j]; } } } } int compare_ints(const void *a, const void *b) { return *(const int *)a - *(const int *)b; } void print_array(int *array, size_t l) { int a[l]; memcpy(a, array, sizeof(int) * l); qsort(a, l, sizeof(int), compare_ints); printf("int a[] = {"); for (int i = 0; i < l; i++) { printf("%d", a[i]); if (i != l) { printf(", "); } } printf("};\n"); } bool has_span(int *array, size_t n, int x, int l) { if (n == 0 || l <= 0) { return false; } int a[n]; memcpy(a, array, sizeof(int) * n); qsort(a, n, sizeof(int), compare_ints); // Iterate through the array to find a span starting at x of length l for (size_t i = 0; i < n; i++) { if (a[i] == x) { // Check if the span can fit in the array if (i + l - 1 < n && a[i + l - 1] == x + l - 1) { return true; // Found the span } } } return false; // Span not found } void print_spans(int *array, size_t n) { int a[n]; size_t start = 0; size_t end = 0; if (n == 0) { printf("Array is empty\n"); return; } memcpy(a, array, sizeof(int) * n); qsort(a, n, sizeof(int), compare_ints); for (size_t i = 1; i < n; i++) { if (a[i] == a[i - 1] + 1) { end = i; // Extend the span } else { // Print the current span if (start == end) { printf("[%d] ", a[start]); } else { printf("[%d, %d] ", a[start], a[end]); } // Move to the next span start = i; end = i; } } // Print the last span if needed if (start == end) { printf("[%d]\n", a[start]); } else { printf("[%d, %d]\n", a[start], a[end]); } } bool was_set(size_t bit, const int array[]) { for (int i = 0; i < 1024; i++) { if (array[i] == (int)bit) { return true; } } return false; } #define TEST_ARRAY_SIZE 1024 int main(void) { int i = 0; size_t rank; rnd_ctx_t prng; int array[TEST_ARRAY_SIZE]; // disable buffering setbuf(stdout, 0); setbuf(stderr, 0); // int foo[] = {1, 2, 3, 5, 7, 8 ,9, 10, 21}; // print_spans(foo, sizeof(foo) / sizeof(foo[0])); // exit(0); // start with a 1KiB buffer, TEST_ARRAY_SIZE bits uint8_t *buf = calloc(TEST_ARRAY_SIZE * 3, sizeof(uint8_t)); // create the sparse bitmap sparsemap_t *map = sparsemap(buf, sizeof(uint8_t) * 1024 * 3, 0); #if 0 for (i = 0; i < 8; i++) sparsemap_set(map, i, true); rank = sparsemap_rank(map, 0, 8); __diag("rank was %lu at offset 0\n", rank); assert(rank == 8); for (i = 0; i < 8; i++) { bool set = sparsemap_is_set(map, i); if (set) { __diag("verified %d was set, %s\n", i, was_set(i, array) ? "but we thought it was" : "because it wasn't"); } else { __diag("darn, %d was not really set, %s\n", i, was_set(i, array) ? "but we thought it was" : "because it wasn't"); } } __diag("and %d was %s", i, sparsemap_is_set(map, i + 1) ? "set" : "not set"); rank = sparsemap_span(map, 0, 8); __diag("span was found at %lu\n", rank); sparsemap_clear(map); for (i = 2; i < 7; i++) sparsemap_set(map, i, true); rank = sparsemap_rank(map, 0, 10); __diag("rank was %lu between [0, 10]\n", rank); assert(rank == 5); sparsemap_clear(map); for (i = 2049; i < 2057; i++) sparsemap_set(map, i, true); rank = sparsemap_rank(map, 2049, 2058); __diag("rank was %lu at offset 108\n", rank); assert(rank == 8); for (i = 2049; i < 2057; i++) { bool set = sparsemap_is_set(map, i); if (set) { __diag("verified %d was set\n", i); } else { __diag("darn, %d was not really set\n", i); } } __diag("and %d was %s", i, sparsemap_is_set(map, i + 1) ? "set" : "not set"); rank = sparsemap_rank(map, 2048, 2060); __diag("rank was %lu at offset 109\n", rank); // rank = sparsemap_span(map, 2048, 8); //__diag("span was found at %lu\n", rank); sparsemap_clear(map); #endif // seed the PRNG #ifdef SEED __random_seed(&prng, 8675309); #else __random_seed(&prng, (unsigned int)time(NULL) ^ getpid()); #endif for (i = 0; i < TEST_ARRAY_SIZE; i++) { uint32_t r = __random(&prng); array[i] = (int)r % (4 * TEST_ARRAY_SIZE); if (array[i] < 0) { i--; } for (int j = 0; j < i; j++) { if (array[j] == array[i]) { i--; } } } // create a span of at least 8 for testing between 141 and 153 int j = 143; for (i = 0; i < 8; i++) { uint32_t r = __random(&prng) % TEST_ARRAY_SIZE; array[r] = j++; } // randomize setting the bits on shuffle(&prng, array, TEST_ARRAY_SIZE); print_spans(array, TEST_ARRAY_SIZE); // set all the bits on in a random order for (i = 0; i < TEST_ARRAY_SIZE; i++) { //__diag("set %d\n", array[i]); sparsemap_set(map, array[i], true); assert(sparsemap_is_set(map, array[i]) == true); } for (size_t len = 0; len < TEST_ARRAY_SIZE; len++) { //for (size_t len = 1; len <= 1; len++) { //for (size_t len = 2; len <= 2; len++) { //for (size_t len = 3; len <= 3; len++) { //for (size_t len = 8; len <= 8; len++) { __diag("================> %lu\n", len); size_t l = sparsemap_span(map, 0, len); __diag("found span of %lu at %lu\n", len, l); __diag("is_span(%lu, %lu) == %s\n", l, len, has_span(array, TEST_ARRAY_SIZE, l, len) ? "yes" : "no"); for (i = (int)l; i < l + len; i++) { bool set = sparsemap_is_set(map, i); if (set) { __diag("verified %d was set\n", i); } else { __diag("darn, %d was not really set, %s\n", i, was_set(i, array) ? "but we thought it was" : "because it wasn't"); } } } return 0; }