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 <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../include/sparsemap.h"
|
#include "../include/sparsemap.h"
|
||||||
|
|
||||||
|
@ -15,43 +19,30 @@
|
||||||
|
|
||||||
#define SEED
|
#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
|
uint32_t
|
||||||
__random(rnd_ctx_t *x)
|
xorshift(int *state)
|
||||||
{
|
{
|
||||||
uint32_t e = x->a - __rot(x->b, 27);
|
if (!state) {
|
||||||
x->a = x->b ^ __rot(x->c, 17);
|
return 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
// 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
|
void
|
||||||
shuffle(rnd_ctx_t *prng, int *array, size_t n)
|
shuffle(int *array, size_t n, int *prng)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
if (n > 1) {
|
if (n > 1) {
|
||||||
for (i = n - 1; i > 0; i--) {
|
for (i = n - 1; i > 0; i--) {
|
||||||
j = (unsigned int)(__random(prng) % (i + 1));
|
j = (unsigned int)(xorshift(prng) % (i + 1));
|
||||||
// XOR swap algorithm
|
// XOR swap algorithm
|
||||||
if (i != j) { // avoid self-swap leading to zero-ing the element
|
if (i != j) { // avoid self-swap leading to zero-ing the element
|
||||||
array[i] = array[i] ^ array[j];
|
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;
|
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
|
void
|
||||||
print_array(int *array, size_t l)
|
print_array(int *array, size_t l)
|
||||||
{
|
{
|
||||||
|
@ -86,7 +119,7 @@ print_array(int *array, size_t l)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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) {
|
if (n == 0 || l == 0 || n > l) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -105,6 +138,11 @@ has_span(int *array, size_t l, size_t n)
|
||||||
}
|
}
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
#endif
|
#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);
|
__diag("Found span: [%d, %d], length: %zu\n", sorted[i], sorted[i + n - 1], n);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -187,17 +225,48 @@ was_set(size_t bit, const int array[])
|
||||||
|
|
||||||
#define TEST_ARRAY_SIZE 1024
|
#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
|
int
|
||||||
main(void)
|
main(void)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
size_t rank;
|
size_t rank;
|
||||||
rnd_ctx_t prng;
|
|
||||||
int array[TEST_ARRAY_SIZE];
|
int array[TEST_ARRAY_SIZE];
|
||||||
|
int prng;
|
||||||
|
|
||||||
|
// seed the PRNG
|
||||||
|
#ifdef SEED
|
||||||
|
prng = 8675309;
|
||||||
|
#else
|
||||||
|
prng = (unsigned int)time(NULL) ^ getpid();
|
||||||
|
#endif
|
||||||
|
|
||||||
// disable buffering
|
// disable buffering
|
||||||
setbuf(stdout, 0);
|
setvbuf(stdout, NULL, _IONBF, 0); // Disable buffering for stdout
|
||||||
setbuf(stderr, 0);
|
setvbuf(stderr, NULL, _IONBF, 0); // Disable buffering for stdout
|
||||||
|
|
||||||
// start with a 3KiB buffer, TEST_ARRAY_SIZE bits
|
// start with a 3KiB buffer, TEST_ARRAY_SIZE bits
|
||||||
uint8_t *buf = calloc(3 * 1024, sizeof(uint8_t));
|
uint8_t *buf = calloc(3 * 1024, sizeof(uint8_t));
|
||||||
|
@ -205,109 +274,56 @@ main(void)
|
||||||
// create the sparse bitmap
|
// create the sparse bitmap
|
||||||
sparsemap_t *map = sparsemap(buf, sizeof(uint8_t) * 3 * 1024, 0);
|
sparsemap_t *map = sparsemap(buf, sizeof(uint8_t) * 3 * 1024, 0);
|
||||||
|
|
||||||
// seed the PRNG
|
// create an array of ints
|
||||||
#ifdef SEED
|
setup_test_array(array, TEST_ARRAY_SIZE, 1024 * 3, &prng);
|
||||||
__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
|
// randomize setting the bits on
|
||||||
shuffle(&prng, array, TEST_ARRAY_SIZE);
|
shuffle(array, TEST_ARRAY_SIZE, &prng);
|
||||||
print_spans(array, TEST_ARRAY_SIZE);
|
//print_array(array, TEST_ARRAY_SIZE);
|
||||||
|
//print_spans(array, TEST_ARRAY_SIZE);
|
||||||
|
|
||||||
// set all the bits on in a random order
|
// set all the bits on in a random order
|
||||||
for (i = 0; i < TEST_ARRAY_SIZE; i++) {
|
for (i = 0; i < TEST_ARRAY_SIZE; i++) {
|
||||||
//__diag("set %d\n", array[i]);
|
|
||||||
sparsemap_set(map, array[i], true);
|
sparsemap_set(map, array[i], true);
|
||||||
assert(sparsemap_is_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 = 1; len <= 1; len++) {
|
||||||
// for (size_t len = 2; len <= 2; len++) {
|
// for (size_t len = 2; len <= 2; len++) {
|
||||||
// for (size_t len = 3; len <= 3; 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 = 8; len <= 8; len++) {
|
||||||
|
for (size_t len = 372; len <= 372; len++) {
|
||||||
__diag("================> %lu\n", 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);
|
size_t l = sparsemap_span(map, 0, len);
|
||||||
__diag("Found span in map starting at %lu of length %lu\n", l, len);
|
if (l != (size_t)-1) {
|
||||||
__diag("is_span(%lu, %lu) == %s\n", l, len, is_span(array, TEST_ARRAY_SIZE, l, len) ? "yes" : "no");
|
__diag("Found span in map starting at %lu of length %lu\n", l, len);
|
||||||
i = (int)l;
|
__diag("is_span(%lu, %lu) == %s\n", l, len, is_span(array, TEST_ARRAY_SIZE, l, len) ? "yes" : "no");
|
||||||
do {
|
i = (int)l;
|
||||||
bool set = sparsemap_is_set(map, i);
|
do {
|
||||||
if (set) {
|
bool set = sparsemap_is_set(map, i);
|
||||||
__diag("verified %d was set\n", i);
|
if (set) {
|
||||||
} else {
|
__diag("verified %d was set\n", i);
|
||||||
__diag("darn, %d was not really 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");
|
||||||
} while (++i < l + len);
|
}
|
||||||
}
|
} 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");
|
|
||||||
} else {
|
} else {
|
||||||
__diag("darn, %d was not really set, %s\n", i,
|
__diag("UNABLE TO FIND SPAN in map of length %lu\n", len);
|
||||||
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
|
|
||||||
|
|
||||||
return 0;
|
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) {
|
if (amt <= *after) {
|
||||||
*after = *after - amt;
|
*after = *after - amt;
|
||||||
} else {
|
} else {
|
||||||
after = 0;
|
*after = 0;
|
||||||
ret += popcountll(w & ~mask);
|
ret += popcountll(w & ~mask);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1167,8 +1167,10 @@ sparsemap_select(sparsemap_t *map, size_t n)
|
||||||
|
|
||||||
p += __sm_chunk_map_get_size(&chunk);
|
p += __sm_chunk_map_get_size(&chunk);
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
assert(!"shouldn't be here");
|
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
|
* 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.
|
* 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
|
size_t
|
||||||
sparsemap_span(sparsemap_t *map, size_t loc, size_t len)
|
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);
|
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