return max value on error

This commit is contained in:
Gregory Burd 2024-04-07 16:35:49 -04:00
parent cb2981cb25
commit ed026b4bff
2 changed files with 138 additions and 121 deletions

View file

@ -1,6 +1,10 @@
#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#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;
}

View file

@ -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;
}