From ed026b4bff304d9ebb28b4ea7b7d0147f3f38ca1 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Sun, 7 Apr 2024 16:35:49 -0400 Subject: [PATCH] return max value on error --- examples/ex_4.c | 248 ++++++++++++++++++++++++++---------------------- src/sparsemap.c | 11 ++- 2 files changed, 138 insertions(+), 121 deletions(-) diff --git a/examples/ex_4.c b/examples/ex_4.c index bafadda..ac1bc84 100644 --- a/examples/ex_4.c +++ b/examples/ex_4.c @@ -1,6 +1,10 @@ #include +#include +#include #include #include +#include +#include #include "../include/sparsemap.h" @@ -15,43 +19,30 @@ #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) +xorshift(int *state) { - 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); + if (!state) { + return 0; } + // Xorshift algorithm + uint32_t x = *state; // Dereference state to get the current state value + if (x == 0) x = 123456789; // Ensure the state is never zero; use a default seed if so + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + *state = x; // Update the state + return x; // Return the new state as the next pseudo-random number } void -shuffle(rnd_ctx_t *prng, int *array, size_t n) +shuffle(int *array, size_t n, int *prng) { size_t i, j; if (n > 1) { for (i = n - 1; i > 0; i--) { - j = (unsigned int)(__random(prng) % (i + 1)); + j = (unsigned int)(xorshift(prng) % (i + 1)); // XOR swap algorithm if (i != j) { // avoid self-swap leading to zero-ing the element array[i] = array[i] ^ array[j]; @@ -68,6 +59,48 @@ compare_ints(const void *a, const void *b) return *(const int *)a - *(const int *)b; } +// Check if there's already a sequence of 'r' sequential integers +int has_sequential_set(int *a, size_t l, int r) { + int count = 1; // Start with a count of 1 for the first number + for (size_t i = 1; i < l; ++i) { + if (a[i] - a[i - 1] == 1) { // Check if the current and previous elements are sequential + count++; + if (count >= r) return 1; // Found a sequential set of length 'r' + } else { + count = 1; // Reset count if the sequence breaks + } + } + return 0; // No sequential set of length 'r' found +} + +// Function to ensure an array contains a set of 'r' sequential integers +void ensure_sequential_set(int *a, size_t l, int r, uint32_t *prng) { + if (r > l) return; // If 'r' is greater than array length, cannot satisfy the condition + + // Sort the array to check for existing sequences + qsort(a, l, sizeof(int), compare_ints); + + // Check if a sequential set of length 'r' already exists + if (has_sequential_set(a, l, r)) { + return; // Sequence already exists, no modification needed + } + + // Find the minimum and maximum values in the array + int min_value = a[0]; + int max_value = a[l - 1]; + + // Generate a random value between min_value and max_value + int value = xorshift(prng) % (max_value - min_value - r + 1); + + // Generate a random location between 0 and l - r + int offset = xorshift(prng) % (l + r + 1); + + // Adjust the array to include a sequential set of 'r' integers at the random offset + for (int i = 0; i < r; ++i) { + a[i + offset] = value + i; + } +} + void print_array(int *array, size_t l) { @@ -86,7 +119,7 @@ print_array(int *array, size_t l) } bool -has_span(int *array, size_t l, size_t n) +has_span(sparsemap_t *map, int *array, size_t l, size_t n) { if (n == 0 || l == 0 || n > l) { return false; @@ -105,6 +138,11 @@ has_span(int *array, size_t l, size_t n) } fprintf(stderr, "\n"); #endif + for (size_t j = 0; j < n; j++) { + size_t pos = sorted[j + i]; + bool set = sparsemap_is_set(map, pos); + assert(set); + } __diag("Found span: [%d, %d], length: %zu\n", sorted[i], sorted[i + n - 1], n); return true; } @@ -187,17 +225,48 @@ was_set(size_t bit, const int array[]) #define TEST_ARRAY_SIZE 1024 +int +is_unique(int a[], size_t l, int value) { + for (size_t i = 0; i < l; ++i) { + if (a[i] == value) { + return 0; // Not unique + } + } + return 1; // Unique +} + +void +setup_test_array(int a[], size_t l, int max_value, int *prng) +{ + if (a == NULL || prng == NULL || max_value < 0) return; // Basic error handling and validation + + for (size_t i = 0; i < l; ++i) { + int candidate; + do { + candidate = xorshift(prng) % (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 + } +} + int main(void) { int i = 0; size_t rank; - rnd_ctx_t prng; int array[TEST_ARRAY_SIZE]; + int prng; + +// seed the PRNG +#ifdef SEED + prng = 8675309; +#else + prng = (unsigned int)time(NULL) ^ getpid(); +#endif // disable buffering - setbuf(stdout, 0); - setbuf(stderr, 0); + setvbuf(stdout, NULL, _IONBF, 0); // Disable buffering for stdout + setvbuf(stderr, NULL, _IONBF, 0); // Disable buffering for stdout // start with a 3KiB buffer, TEST_ARRAY_SIZE bits uint8_t *buf = calloc(3 * 1024, sizeof(uint8_t)); @@ -205,109 +274,56 @@ main(void) // create the sparse bitmap sparsemap_t *map = sparsemap(buf, sizeof(uint8_t) * 3 * 1024, 0); - // seed the PRNG -#ifdef SEED - __random_seed(&prng, 8675309); -#else - __random_seed(&prng, (unsigned int)time(NULL) ^ getpid()); -#endif + // create an array of ints + setup_test_array(array, TEST_ARRAY_SIZE, 1024 * 3, &prng); - 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); + shuffle(array, TEST_ARRAY_SIZE, &prng); + //print_array(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 = 1; len < TEST_ARRAY_SIZE; len++) { + // for (size_t len = 1; len < 20; len++) { + // for (size_t len = 1; len < TEST_ARRAY_SIZE - 1; 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 = 4; len <= 4; len++) { + // for (size_t len = 5; len <= 5; len++) { // for (size_t len = 8; len <= 8; len++) { + for (size_t len = 372; len <= 372; len++) { __diag("================> %lu\n", len); - has_span(array, TEST_ARRAY_SIZE, len); + sparsemap_clear(map); + // set all the bits on in a random order + ensure_sequential_set(array, TEST_ARRAY_SIZE, len, &prng); + shuffle(array, TEST_ARRAY_SIZE, &prng); + print_spans(array, TEST_ARRAY_SIZE); + for (i = 0; i < TEST_ARRAY_SIZE; i++) { + sparsemap_set(map, array[i], true); + assert(sparsemap_is_set(map, array[i]) == true); + } + has_span(map, array, TEST_ARRAY_SIZE, len); size_t l = sparsemap_span(map, 0, len); - __diag("Found span in map starting at %lu of length %lu\n", l, len); - __diag("is_span(%lu, %lu) == %s\n", l, len, is_span(array, TEST_ARRAY_SIZE, l, len) ? "yes" : "no"); - i = (int)l; - do { - 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"); - } - } while (++i < l + len); - } - -#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"); + if (l != (size_t)-1) { + __diag("Found span in map starting at %lu of length %lu\n", l, len); + __diag("is_span(%lu, %lu) == %s\n", l, len, is_span(array, TEST_ARRAY_SIZE, l, len) ? "yes" : "no"); + i = (int)l; + do { + 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"); + } + } while (++i < l + len); } 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("UNABLE TO FIND SPAN in map of length %lu\n", len); } } - __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 - return 0; } diff --git a/src/sparsemap.c b/src/sparsemap.c index aea13a3..8cfeaca 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -480,7 +480,7 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t first, size_t last, size_t *after) if (amt <= *after) { *after = *after - amt; } else { - after = 0; + *after = 0; ret += popcountll(w & ~mask); } } else { @@ -1167,8 +1167,10 @@ sparsemap_select(sparsemap_t *map, size_t n) p += __sm_chunk_map_get_size(&chunk); } +#ifdef DEBUG assert(!"shouldn't be here"); - return (0); +#endif + return (size_t)-1; } /** @@ -1199,7 +1201,6 @@ sparsemap_rank(sparsemap_t *map, size_t first, size_t last) /** * Finds a span of set bits of at least |len| after |loc|. Returns the index of * the n'th set bit that starts a span of at least |len| bits set to true. - * Returns ???TODO??? when a span of suitable length was not found. */ size_t sparsemap_span(sparsemap_t *map, size_t loc, size_t len) @@ -1221,7 +1222,7 @@ sparsemap_span(sparsemap_t *map, size_t loc, size_t len) } } offset = sparsemap_select(map, nth); - } while (1); // TODO...until what? + } while (offset != ((size_t)-1)); - return 0; + return offset; }