diff --git a/examples/ex_4.c b/examples/ex_4.c new file mode 100644 index 0000000..f8e97d9 --- /dev/null +++ b/examples/ex_4.c @@ -0,0 +1,192 @@ +#include +#include +#include +#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]; + } + } + } +} + +bool +was_set(size_t bit, int array[]) +{ + for (int i = 0; i < 1024; i++) { + if (array[i] == 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(stderr, 0); + + // start with a 1KiB buffer, TEST_ARRAY_SIZE bits + uint8_t *buf = calloc(TEST_ARRAY_SIZE, sizeof(uint8_t)); + + // create the sparse bitmap + sparsemap_t *map = sparsemap(buf, sizeof(uint8_t) * TEST_ARRAY_SIZE, 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 = 1; i < 9; i++) + sparsemap_set(map, i, true); + rank = sparsemap_rank(map, 0, 10); + __diag("rank was %lu at offset 1\n", rank); + assert(rank == 8); + for (i = 100; i < 108; i++) { + bool set = sparsemap_is_set(map, i); + if (set) + __diag("verified %d was set, %s\n", i, + was_set(i, array) ? "but knew that" : "because it wasn't"); + else + __diag("darn, %d was not set, %s\n", i, + was_set(i, array) ? "and yet we did set it" : "because it wasn't"); + } + __diag("and %d was %s", i, sparsemap_is_set(map, i + 1) ? "set" : "not set"); + rank = sparsemap_rank(map, 109, 8); + __diag("rank was %lu at offset 109\n", rank); + rank = sparsemap_span(map, 0, 8); + __diag("span was found at %lu\n", rank); + sparsemap_clear(map); + + for (i = 2049; i < 2057; i++) + sparsemap_set(map, i, true); + rank = sparsemap_rank(map, 2048, 8); + __diag("rank was %lu at offset 108\n", rank); + assert(rank == 8); + for (i = 100; i < 108; 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_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); + + // 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++) { + array[i] = (int)__random(&prng) % 7000 + 1; + if (array[i] < 0) + i--; + } + // randomize setting the bits on + shuffle(&prng, 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); + } + + size_t l = sparsemap_span(map, 0, 8); + __diag("found span of 8 at %lu starting from 0\n", l); + for (i = l; i < l + 8; i++) { + bool set = sparsemap_is_set(map, l + i); + if (set) + __diag("verified %lu was set\n", l + i); + else + __diag("darn, %lu was not really set, %s\n", l + i, + was_set(l + i, array) ? "but we thought it was" : "because it wasn't"); + } + + return 0; +} diff --git a/include/sparsemap.h b/include/sparsemap.h index 23d32b9..786e642 100644 --- a/include/sparsemap.h +++ b/include/sparsemap.h @@ -118,4 +118,6 @@ size_t sparsemap_select(sparsemap_t *map, size_t n); /* Counts the set bits in the range [offset, idx]. */ size_t sparsemap_rank(sparsemap_t *map, size_t offset, size_t idx); +size_t sparsemap_span(sparsemap_t *map, size_t loc, size_t len); + #endif