return max value on error
This commit is contained in:
parent
cb2981cb25
commit
ed026b4bff
2 changed files with 138 additions and 121 deletions
248
examples/ex_4.c
248
examples/ex_4.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue