288 lines
6.8 KiB
C
288 lines
6.8 KiB
C
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#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];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
compare_ints(const void *a, const void *b)
|
|
{
|
|
return *(const int *)a - *(const int *)b;
|
|
}
|
|
|
|
void
|
|
print_array(int *array, size_t l)
|
|
{
|
|
int a[l];
|
|
memcpy(a, array, sizeof(int) * l);
|
|
qsort(a, l, sizeof(int), compare_ints);
|
|
|
|
printf("int a[] = {");
|
|
for (int i = 0; i < l; i++) {
|
|
printf("%d", a[i]);
|
|
if (i != l) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("};\n");
|
|
}
|
|
|
|
bool
|
|
has_span(int *array, size_t n, int x, int l)
|
|
{
|
|
if (n == 0 || l <= 0) {
|
|
return false;
|
|
}
|
|
|
|
int a[n];
|
|
memcpy(a, array, sizeof(int) * n);
|
|
qsort(a, n, sizeof(int), compare_ints);
|
|
|
|
// Iterate through the array to find a span starting at x of length l
|
|
for (size_t i = 0; i < n; i++) {
|
|
if (a[i] == x) {
|
|
// Check if the span can fit in the array
|
|
if (i + l - 1 < n && a[i + l - 1] == x + l - 1) {
|
|
return true; // Found the span
|
|
}
|
|
}
|
|
}
|
|
|
|
return false; // Span not found
|
|
}
|
|
|
|
void
|
|
print_spans(int *array, size_t n)
|
|
{
|
|
int a[n];
|
|
size_t start = 0;
|
|
size_t end = 0;
|
|
|
|
if (n == 0) {
|
|
printf("Array is empty\n");
|
|
return;
|
|
}
|
|
|
|
memcpy(a, array, sizeof(int) * n);
|
|
qsort(a, n, sizeof(int), compare_ints);
|
|
|
|
for (size_t i = 1; i < n; i++) {
|
|
if (a[i] == a[i - 1] + 1) {
|
|
end = i; // Extend the span
|
|
} else {
|
|
// Print the current span
|
|
if (start == end) {
|
|
printf("[%d] ", a[start]);
|
|
} else {
|
|
printf("[%d, %d] ", a[start], a[end]);
|
|
}
|
|
// Move to the next span
|
|
start = i;
|
|
end = i;
|
|
}
|
|
}
|
|
|
|
// Print the last span if needed
|
|
if (start == end) {
|
|
printf("[%d]\n", a[start]);
|
|
} else {
|
|
printf("[%d, %d]\n", a[start], a[end]);
|
|
}
|
|
}
|
|
|
|
bool
|
|
was_set(size_t bit, const int array[])
|
|
{
|
|
for (int i = 0; i < 1024; i++) {
|
|
if (array[i] == (int)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(stdout, 0);
|
|
setbuf(stderr, 0);
|
|
|
|
// int foo[] = {1, 2, 3, 5, 7, 8 ,9, 10, 21};
|
|
// print_spans(foo, sizeof(foo) / sizeof(foo[0]));
|
|
// exit(0);
|
|
|
|
// start with a 1KiB buffer, TEST_ARRAY_SIZE bits
|
|
uint8_t *buf = calloc(TEST_ARRAY_SIZE * 1, sizeof(uint8_t));
|
|
|
|
// create the sparse bitmap
|
|
sparsemap_t *map = sparsemap(buf, sizeof(uint8_t) * 1024 * 1, 0);
|
|
|
|
#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 {
|
|
__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 = 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
|
|
|
|
// 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++) {
|
|
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);
|
|
|
|
// 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 = 2; len <= 2; len++) {
|
|
__diag("================> %lu\n", len);
|
|
size_t l = sparsemap_span(map, 0, len);
|
|
__diag("found span of %lu at %lu\n", len, l);
|
|
__diag("is_span(%lu, %lu) == %s\n", l, len,
|
|
has_span(array, TEST_ARRAY_SIZE, l, len) ? "yes" : "no");
|
|
for (i = (int)l; i < l + len; 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, %s\n", i,
|
|
was_set(i, array) ? "but we thought it was" : "because it wasn't");
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|