select/rank for unset as well as set bits #4

Merged
greg merged 13 commits from gburd/select-neg-bool into main 2024-04-24 20:32:10 +00:00
7 changed files with 430 additions and 166 deletions
Showing only changes of commit d42126054f - Show all commits

View file

@ -5,11 +5,12 @@ SHARED_LIB = libsparsemap.so
#CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DSPARSEMAP_ASSERT -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC
#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=all -fhardened -std=c11 -Iinclude/ -fPIC
TEST_FLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -Itests/ -fPIC
#TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -Itests/ -fPIC
TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC
TESTS = tests/test
TEST_OBJS = tests/test.o tests/munit.o tests/tdigest.o tests/common.o

View file

@ -160,7 +160,7 @@ main()
sparsemap_set(map, i * 10, true);
}
for (size_t i = 0; i < 8; i++) {
assert(sparsemap_select(map, i, true) == (sm_loc_t)i * 10);
assert(sparsemap_select(map, i, true) == (sparsemap_idx_t)i * 10);
}
// split and move, aligned to MiniMap capacity

View file

@ -88,9 +88,10 @@ extern "C" {
*/
typedef struct sparsemap sparsemap_t;
typedef long sm_loc_t;
#define SM_LOC_MAX LONG_MAX
#define SM_LOC_MIN LONG_MIN
typedef long int sparsemap_idx_t;
#define SPARSEMAP_IDX_MAX ((1UL << (sizeof(long) * CHAR_BIT - 1)) - 1)
#define SPARSEMAP_IDX_MIN (-(SPARSEMAP_IDX_MAX)-1)
#define SPARSEMAP_NOT_FOUND(_x) ((_x) == SPARSEMAP_IDX_MAX || (_x) == SPARSEMAP_IDX_MIN)
typedef uint32_t sm_idx_t;
typedef uint64_t sm_bitvec_t;
@ -123,9 +124,12 @@ void sparsemap_open(sparsemap_t *, uint8_t *data, size_t data_size);
void sparsemap_clear(sparsemap_t *map);
/**
* Resizes the data range within the limits of the provided buffer.
* Resizes the data range within the limits of the provided buffer, the map may
* move to a new address returned iff the map was created with the sparsemap() API.
* Take care to use the new reference (think: realloc()). NOTE: If the returned
* value equals NULL then the map was not resized.
*/
void sparsemap_set_data_size(sparsemap_t *map, size_t data_size);
sparsemap_t *sparsemap_set_data_size(sparsemap_t *map, size_t data_size);
/**
* Calculate remaining capacity, approaches 0 when full.
@ -141,13 +145,14 @@ size_t sparsemap_get_capacity(sparsemap_t *map);
* Returns the value of a bit at index |idx|, either on/true/1 or off/false/0.
* When |idx| is negative it is an error.
*/
bool sparsemap_is_set(sparsemap_t *map, sm_loc_t idx);
bool sparsemap_is_set(sparsemap_t *map, sparsemap_idx_t idx);
/**
* Sets the bit at index |idx| to true or false, depending on |value|.
* When |idx| is negative is it an error.
* When |idx| is negative is it an error. Returns the |idx| supplied or
* SPARSEMAP_IDX_MAX on error with |errno| set to ENOSP when the map is full.
*/
void sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value);
sparsemap_idx_t sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value);
/**
* Returns the offset of the very first/last bit in the map.
@ -171,15 +176,15 @@ void sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t vec[], size_t n),
* Appends all chunk maps from |map| starting at |offset| to |other|, then
* reduces the chunk map-count appropriately.
*/
void sparsemap_split(sparsemap_t *map, sm_loc_t offset, sparsemap_t *other);
void sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other);
/**
* Finds the offset of the n'th bit either set (|value| is true) or unset
* (|value| is false) from the start (positive |n|), or end (negative |n|),
* of the bitmap and returns that (uses a 0-based index). Returns -inf or +inf
* if not found (where "inf" is SM_LOC_MAX and "-inf" is SM_LOC_MIN).
* if not found (where "inf" is SPARSEMAP_IDX_MAX and "-inf" is SPARSEMAP_IDX_MIN).
*/
sm_loc_t sparsemap_select(sparsemap_t *map, sm_loc_t n, bool value);
sparsemap_idx_t sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value);
/**
* Counts the set (|value| is true) or unset (|value| is false) bits starting
@ -192,7 +197,7 @@ size_t sparsemap_rank(sparsemap_t *map, size_t x, size_t y, bool value);
* are set (|value| is true) or unset (|value| is false) and returns the
* starting offset for the span (0-based).
*/
size_t sparsemap_span(sparsemap_t *map, sm_loc_t idx, size_t len, bool value);
size_t sparsemap_span(sparsemap_t *map, sparsemap_idx_t idx, size_t len, bool value);
#if defined(__cplusplus)
}

View file

@ -23,14 +23,15 @@
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <popcount.h>
#include <sparsemap.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#ifdef SPARSEMAP_DIAGNOSTIC
@ -48,19 +49,24 @@ void __attribute__((format(printf, 4, 5))) __sm_diag_(const char *file, int line
vfprintf(stderr, format, args);
va_end(args);
}
#else
#define __sm_diag(file, line, func, format, ...) ((void)0)
#endif
#ifndef SPARSEMAP_ASSERT
#define SPARSEMAP_ASSERT
#define __sm_assert(expr) \
if (!(expr)) \
fprintf(stderr, "%s:%d:%s(): assertion failed! %s", __FILE__, __LINE__, __func__, #expr)
#define __sm_when_diag(expr) \
if (1) \
expr
#else
#define __sm_diag(file, line, func, format, ...) ((void)0)
#define __sm_assert(expr) ((void)0)
#define __sm_when_diag(expr) \
if (0) \
expr
#endif
#define IS_8_BYTE_ALIGNED(addr) (((uintptr_t)(addr) & 0x7) == 0)
enum __SM_CHUNK_INFO {
/* metadata overhead: 4 bytes for __sm_chunk_t count */
SM_SIZEOF_OVERHEAD = sizeof(uint32_t),
@ -398,7 +404,6 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
{
size_t ret = 0;
register uint8_t *p;
(void)value; // TODO
p = (uint8_t *)map->m_data;
for (size_t i = 0; i < sizeof(sm_bitvec_t); i++, p++) {
@ -413,35 +418,59 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
continue;
}
if (flags == SM_PAYLOAD_ZEROS) {
ret += SM_BITS_PER_VECTOR;
continue;
if (value) {
ret += SM_BITS_PER_VECTOR;
continue;
} else {
if (n > SM_BITS_PER_VECTOR) {
n -= SM_BITS_PER_VECTOR;
ret += SM_BITS_PER_VECTOR;
continue;
}
*pnew_n = -1;
return (ret + n);
}
}
if (flags == SM_PAYLOAD_ONES) {
if (n > SM_BITS_PER_VECTOR) {
n -= SM_BITS_PER_VECTOR;
if (value) {
if (n > SM_BITS_PER_VECTOR) {
n -= SM_BITS_PER_VECTOR;
ret += SM_BITS_PER_VECTOR;
continue;
}
*pnew_n = -1;
return (ret + n);
} else {
ret += SM_BITS_PER_VECTOR;
continue;
}
*pnew_n = -1;
return (ret + n);
}
if (flags == SM_PAYLOAD_MIXED) {
sm_bitvec_t w = map->m_data[1 + __sm_chunk_map_get_position(map, i * SM_FLAGS_PER_INDEX_BYTE + j)];
for (int k = 0; k < SM_BITS_PER_VECTOR; k++) {
if (w & ((sm_bitvec_t)1 << k)) {
if (n == 0) {
*pnew_n = -1;
return (ret);
if (value) {
if (w & ((sm_bitvec_t)1 << k)) {
if (n == 0) {
*pnew_n = -1;
return (ret);
}
n--;
}
n--;
ret++;
} else {
if (!(w & ((sm_bitvec_t)1 << k))) {
if (n == 0) {
*pnew_n = -1;
return (ret);
}
n--;
}
ret++;
}
ret++;
}
}
}
}
*pnew_n = (ssize_t)n;
return (ret);
}
@ -659,7 +688,7 @@ __sm_get_aligned_offset(size_t idx)
* Returns the byte offset of a __sm_chunk_t in m_data.
*/
static ssize_t
__sm_get_chunk_map_offset(sparsemap_t *map, sm_loc_t idx)
__sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
{
int count;
@ -672,9 +701,9 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sm_loc_t idx)
uint8_t *start = __sm_get_chunk_map_data(map, 0);
uint8_t *p = start;
for (sm_loc_t i = 0; i < count - 1; i++) {
for (sparsemap_idx_t i = 0; i < count - 1; i++) {
sm_idx_t s = *(sm_idx_t *)p;
__sm_assert(s == __sm_get_aligned_offset(start));
__sm_assert(s == __sm_get_aligned_offset(s));
__sm_chunk_t chunk;
__sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t));
if (s >= idx || (unsigned long)idx < s + __sm_chunk_map_get_capacity(&chunk)) {
@ -688,9 +717,9 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sm_loc_t idx)
uint8_t *end = __sm_get_chunk_map_data(map, count - 1);
uint8_t *p = end;
for (sm_loc_t i = count - 1; i >= 0; i--) {
for (sparsemap_idx_t i = count - 1; i >= 0; i--) {
sm_idx_t e = *(sm_idx_t *)p;
__sm_assert(e == __sm_get_aligned_offset(end));
__sm_assert(e == __sm_get_aligned_offset(e));
__sm_chunk_t chunk;
__sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t));
if (e >= idx || (unsigned long)idx < e + __sm_chunk_map_get_capacity(&chunk)) {
@ -779,10 +808,21 @@ sparsemap(size_t size)
if (size == 0) {
size = 1024;
}
sparsemap_t *map = (sparsemap_t *)calloc(1, sizeof(sparsemap_t) + (size * sizeof(uint8_t)));
size_t data_size = (size * sizeof(uint8_t));
/* Ensure that m_data is 8-byte aligned. */
size_t total_size = sizeof(sparsemap_t) + data_size;
size_t padding = total_size % 8 == 0 ? 0 : 8 - (total_size % 8);
total_size += padding;
sparsemap_t *map = (sparsemap_t *)calloc(1, total_size);
if (map) {
sparsemap_init(map, (uint8_t *)map + sizeof(sparsemap_t), size);
sparsemap_init(map, (uint8_t *)((uintptr_t)map + sizeof(sparsemap_t) + padding), size);
__sm_when_diag({ __sm_assert(IS_8_BYTE_ALIGNED(map->m_data)); });
}
sparsemap_clear(map);
return map;
}
@ -801,7 +841,7 @@ sparsemap_init(sparsemap_t *map, uint8_t *data, size_t size)
{
map->m_data = data;
map->m_data_used = 0;
map->m_capacity = size == 0 ? UINT64_MAX : size;
map->m_capacity = size;
sparsemap_clear(map);
}
@ -809,7 +849,7 @@ void
sparsemap_open(sparsemap_t *map, uint8_t *data, size_t data_size)
{
map->m_data = data;
map->m_data_used = 0;
map->m_data_used = map->m_data_used > 0 ? map->m_data_used : 0;
map->m_capacity = data_size;
}
@ -817,10 +857,30 @@ sparsemap_open(sparsemap_t *map, uint8_t *data, size_t data_size)
* TODO/NOTE: This is a dangerous operation because we cannot verify that
* data_size is not exceeding the size of the underlying buffer.
*/
void
sparsemap_set_data_size(sparsemap_t *map, size_t data_size)
sparsemap_t *
sparsemap_set_data_size(sparsemap_t *map, size_t size)
{
map->m_capacity = data_size;
if ((uintptr_t)map->m_data == (uintptr_t)map + sizeof(sparsemap_t) && size > map->m_capacity) {
/* This sparsemap was allocated by the sparsemap() API, we can resize it. */
size_t data_size = (size * sizeof(uint8_t));
/* Ensure that m_data is 8-byte aligned. */
size_t total_size = sizeof(sparsemap_t) + data_size;
size_t padding = total_size % 8 == 0 ? 0 : 8 - (total_size % 8);
total_size += padding;
sparsemap_t *m = (sparsemap_t *)realloc(map, total_size);
if (!m) {
return NULL;
}
memset(m + sizeof(sparsemap_t) + (m->m_capacity * sizeof(uint8_t)), 0, total_size - m->m_capacity - padding);
m->m_capacity = data_size;
m->m_data = (uint8_t *)((uintptr_t)m + sizeof(sparsemap_t) + padding);
__sm_when_diag({ __sm_assert(IS_8_BYTE_ALIGNED(m->m_data)); }) return m;
} else {
map->m_capacity = size;
return map;
}
}
double
@ -842,7 +902,7 @@ sparsemap_get_capacity(sparsemap_t *map)
}
bool
sparsemap_is_set(sparsemap_t *map, sm_loc_t idx)
sparsemap_is_set(sparsemap_t *map, sparsemap_idx_t idx)
{
__sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
@ -874,15 +934,11 @@ sparsemap_is_set(sparsemap_t *map, sm_loc_t idx)
return (__sm_chunk_map_is_set(&chunk, idx - start));
}
void
sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value)
sparsemap_idx_t
sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
{
__sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
if (idx < 0) {
return;
}
/* Get the __sm_chunk_t which manages this index */
ssize_t offset = __sm_get_chunk_map_offset(map, idx);
bool dont_grow = false;
@ -891,7 +947,7 @@ sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value)
immediately; otherwise create an initial __sm_chunk_t. */
if (offset == -1) {
if (value == false) {
return;
return idx;
}
uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 };
@ -917,7 +973,7 @@ sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value)
if (idx < start) {
if (value == false) {
/* nothing to do */
return;
return idx;
}
uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 };
@ -944,10 +1000,10 @@ sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value)
else {
__sm_chunk_t chunk;
__sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t));
if (idx - (unsigned long)start >= __sm_chunk_map_get_capacity(&chunk)) {
if (idx - start >= (sparsemap_idx_t)__sm_chunk_map_get_capacity(&chunk)) {
if (value == false) {
/* nothing to do */
return;
return idx;
}
size_t size = __sm_chunk_map_get_size(&chunk);
@ -958,7 +1014,7 @@ sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value)
__sm_insert_data(map, offset, &buf[0], sizeof(buf));
start += __sm_chunk_map_get_capacity(&chunk);
if ((size_t)start + SM_CHUNK_MAX_CAPACITY < (unsigned long)idx) {
if ((sparsemap_idx_t)start + SM_CHUNK_MAX_CAPACITY < idx) {
start = __sm_get_fully_aligned_offset(idx);
}
*(sm_idx_t *)p = start;
@ -1009,6 +1065,7 @@ sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value)
break;
}
__sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
return idx;
}
sm_idx_t
@ -1059,7 +1116,7 @@ sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t), size_t ski
}
void
sparsemap_split(sparsemap_t *map, sm_loc_t offset, sparsemap_t *other)
sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
{
assert(offset % SM_BITS_PER_VECTOR == 0);
@ -1132,7 +1189,7 @@ sparsemap_split(sparsemap_t *map, sm_loc_t offset, sparsemap_t *other)
__sm_chunk_map_set_capacity(&d_chunk, capacity - (offset % capacity));
/* Now copy the bits. */
sm_loc_t d = offset;
sparsemap_idx_t d = offset;
for (size_t j = offset % capacity; j < capacity; j++, d++) {
if (__sm_chunk_map_is_set(&s_chunk, j)) {
sparsemap_set(other, d, true);
@ -1177,8 +1234,8 @@ sparsemap_split(sparsemap_t *map, sm_loc_t offset, sparsemap_t *other)
assert(sparsemap_get_size(other) > SM_SIZEOF_OVERHEAD);
}
sm_loc_t
sparsemap_select(sparsemap_t *map, sm_loc_t n, bool value)
sparsemap_idx_t
sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value)
{
assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
size_t result;
@ -1204,16 +1261,16 @@ sparsemap_select(sparsemap_t *map, sm_loc_t n, bool value)
#ifdef DEBUG
assert(!"shouldn't be here");
#endif
return SM_LOC_MAX;
return SPARSEMAP_IDX_MAX;
} else {
return SM_LOC_MIN; // TODO... sparsemap_select(map, -n, value);
return SPARSEMAP_IDX_MIN; // TODO... sparsemap_select(map, -n, value);
}
}
size_t
sparsemap_rank_vec(sparsemap_t *map, size_t x, size_t y, bool value, sm_bitvec_t *vec)
{
(void)value; //TODO
(void)value; // TODO
assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
size_t result = 0, prev = 0, count = __sm_get_chunk_map_count(map);
uint8_t *p = __sm_get_chunk_map_data(map, 0);
@ -1244,11 +1301,11 @@ sparsemap_rank(sparsemap_t *map, size_t x, size_t y, bool value)
}
size_t
sparsemap_span(sparsemap_t *map, sm_loc_t idx, size_t len, bool value)
sparsemap_span(sparsemap_t *map, sparsemap_idx_t idx, size_t len, bool value)
{
size_t count, nth = 0;
sm_bitvec_t vec = 0;
sm_loc_t offset;
sparsemap_idx_t offset;
offset = sparsemap_select(map, nth++, value);
if (len == 1) {
@ -1269,7 +1326,7 @@ sparsemap_span(sparsemap_t *map, sm_loc_t idx, size_t len, bool value)
nth++;
/* Use select to potentially jump very far forward in the map. */
offset = sparsemap_select(map, nth, value);
} while (offset != SM_LOC_MAX);
} while (offset != SPARSEMAP_IDX_MAX);
return idx > 0 ? SM_LOC_MAX : SM_LOC_MIN;
return idx >= 0 ? SPARSEMAP_IDX_MAX : SPARSEMAP_IDX_MIN;
}

View file

@ -10,6 +10,7 @@
#include <time.h>
#include <unistd.h>
#ifdef X86_INTRIN
#include <errno.h>
#include <x86intrin.h>
#endif
@ -146,25 +147,25 @@ ensure_sequential_set(int a[], int l, int r)
return value;
}
int
create_sequential_set_in_empty_map(sparsemap_t *map, int s, int r)
sparsemap_idx_t
sm_add_span(sparsemap_t *map, int map_size, int span_length)
{
int attempts = map_size / span_length;
sparsemap_idx_t placed_at;
do {
int placed_at;
if (s >= r + 1) {
placed_at = 0;
placed_at = random_uint32() % (map_size - span_length - 1);
if (sm_occupied(map, placed_at, span_length, true)) {
attempts--;
} else {
placed_at = random_uint32() % (s - r - 1);
break;
}
for (int i = placed_at; i < placed_at + r; i++) {
sparsemap_is_set(map, i);
continue;
} while (attempts);
for (int i = placed_at; i < placed_at + span_length; i++) {
if (sparsemap_set(map, i, true) != i) {
return placed_at; // TODO error?
}
for (int i = placed_at; i < placed_at + r; i++) {
sparsemap_set(map, i, true);
}
return placed_at;
} while (true);
}
return placed_at;
}
void
@ -318,10 +319,10 @@ bitmap_from_uint32(sparsemap_t *map, uint32_t number)
}
void
bitmap_from_uint64(sparsemap_t *map, uint64_t number)
sm_bitmap_from_uint64(sparsemap_t *map, uint64_t number)
{
for (int i = 0; i < 64; i++) {
bool bit = number & (1 << i);
bool bit = number & ((uint64_t)1 << i);
sparsemap_set(map, i, bit);
}
}
@ -368,7 +369,7 @@ whats_set_uint64(uint64_t number, int pos[64])
}
void
whats_set(sparsemap_t *map, int m)
sm_whats_set(sparsemap_t *map, int m)
{
logf("what's set in the range [0, %d): ", m);
for (int i = 0; i < m; i++) {
@ -378,3 +379,25 @@ whats_set(sparsemap_t *map, int m)
}
logf("\n");
}
bool
sm_is_span(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value)
{
for (sparsemap_idx_t i = m; i < (sparsemap_idx_t)len; i++) {
if (sparsemap_is_set(map, i) != value) {
return false;
}
}
return true;
}
bool
sm_occupied(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value)
{
for (sparsemap_idx_t i = m; i < (sparsemap_idx_t)len; i++) {
if (sparsemap_is_set(map, i) == value) {
return true;
}
}
return false;
}

View file

@ -41,11 +41,14 @@ int is_unique(int a[], int l, int value);
void setup_test_array(int a[], int l, int max_value);
void shuffle(int *array, size_t n);
int ensure_sequential_set(int a[], int l, int r);
int create_sequential_set_in_empty_map(sparsemap_t *map, int s, int r);
sparsemap_idx_t sm_add_span(sparsemap_t *map, int map_size, int span_length);
void bitmap_from_uint32(sparsemap_t *map, uint32_t number);
void bitmap_from_uint64(sparsemap_t *map, uint64_t number);
void sm_bitmap_from_uint64(sparsemap_t *map, uint64_t number);
uint32_t rank_uint64(uint64_t number, int n, int p);
int whats_set_uint64(uint64_t number, int bitPositions[64]);
void whats_set(sparsemap_t *map, int m);
void sm_whats_set(sparsemap_t *map, int m);
bool sm_is_span(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value);
bool sm_occupied(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value);

View file

@ -10,6 +10,7 @@
#define MUNIT_NO_FORK (1)
#define MUNIT_ENABLE_ASSERT_ALIASES (1)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -18,10 +19,14 @@
#include "common.h"
#include "munit.h"
#define munit_free free
#if defined(_MSC_VER)
#pragma warning(disable : 4127)
#endif
#define SELECT_FALSE
/* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */
struct sparsemap {
uint8_t *m_data;
@ -66,7 +71,7 @@ test_api_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map);
free(map);
munit_free(map);
}
/* -------------------------- API Tests */
@ -93,6 +98,7 @@ static void *
test_api_clear_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -103,7 +109,8 @@ static void
test_api_clear_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -126,6 +133,7 @@ static void *
test_api_open_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -137,7 +145,8 @@ static void
test_api_open_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -160,6 +169,7 @@ static void *
test_api_set_data_size_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -171,7 +181,8 @@ static void
test_api_set_data_size_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -193,6 +204,7 @@ static void *
test_api_remaining_capacity_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -203,7 +215,8 @@ static void
test_api_remaining_capacity_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -241,6 +254,7 @@ static void *
test_api_get_capacity_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -252,7 +266,8 @@ static void
test_api_get_capacity_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -274,6 +289,7 @@ static void *
test_api_is_set_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -285,7 +301,8 @@ static void
test_api_is_set_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -306,6 +323,7 @@ static void *
test_api_set_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -316,7 +334,8 @@ static void
test_api_set_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -345,6 +364,7 @@ static void *
test_api_get_starting_offset_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -356,7 +376,8 @@ static void
test_api_get_starting_offset_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -379,6 +400,7 @@ static void *
test_api_get_size_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -390,7 +412,8 @@ static void
test_api_get_size_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -411,10 +434,11 @@ static void *
test_api_scan_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
bitmap_from_uint64(map, ((uint64_t)0xfeedface << 32) | 0xbadc0ffee);
sm_bitmap_from_uint64(map, ((uint64_t)0xfeedface << 32) | 0xbadc0ffee);
return (void *)map;
}
@ -422,7 +446,8 @@ static void
test_api_scan_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
void
@ -441,7 +466,7 @@ test_api_scan(const MunitParameter params[], void *data)
assert_ptr_not_null(map);
sparsemap_set(map, 4200, true);
assert_true(sparsemap_is_set(map, 42));
assert_true(sparsemap_is_set(map, 4200));
sparsemap_scan(map, scan_for_0xfeedfacebadcoffee, 0);
return MUNIT_OK;
@ -451,6 +476,7 @@ static void *
test_api_split_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -463,7 +489,8 @@ static void
test_api_split_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -494,10 +521,11 @@ static void *
test_api_select_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
bitmap_from_uint64(map, ((uint64_t)0xfeedface << 32) | 0xbadc0ffee);
sm_bitmap_from_uint64(map, ((uint64_t)0xfeedface << 32) | 0xbadc0ffee);
return (void *)map;
}
@ -505,7 +533,8 @@ static void
test_api_select_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -522,22 +551,76 @@ test_api_select(const MunitParameter params[], void *data)
assert_true(sparsemap_select(map, 4, true) == 6);
assert_true(sparsemap_select(map, 17, true) == 26);
#if 0 // TODO
size_t f = sparsemap_select(map, 0, false);
for (int i = 0; i <= f; i++) {
assert_false(sparsemap_is_set(map, i % 2));
}
return MUNIT_OK;
}
sparsemap_clear(map);
#ifdef SELECT_FALSE
static void *
test_api_select_false_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
sm_bitmap_from_uint64(map, ((uint64_t)0xfeedface << 32) | 0xbadc0ffee);
return (void *)map;
}
static void
test_api_select_false_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
test_api_select_false(const MunitParameter params[], void *data)
{
sparsemap_t *map = (sparsemap_t *)data;
(void)params;
assert_ptr_not_null(map);
for (int i = 0; i < 1000; i++) {
sparsemap_set(map, i, i % 2 ? true : false);
sparsemap_set(map, i, true);
}
f = sparsemap_select(map, 0, false);
sparsemap_idx_t f = sparsemap_select(map, 0, false);
assert_true(f == 1000);
sparsemap_clear(map);
return MUNIT_OK;
}
#endif
#ifdef SELECT_NEG
static void *
test_api_select_neg_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
sm_bitmap_from_uint64(map, ((uint64_t)0xfeedface << 32) | 0xbadc0ffee);
return (void *)map;
}
static void
test_api_select_neg_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
test_api_select_neg(const MunitParameter params[], void *data)
{
sparsemap_t *map = (sparsemap_t *)data;
(void)params;
assert_ptr_not_null(map);
sparsemap_set(map, 42, true);
sparsemap_set(map, 420, true);
@ -552,14 +635,16 @@ test_api_select(const MunitParameter params[], void *data)
assert_true(f == 420);
f = sparsemap_select(map, -3, true);
assert_true(f == 42);
#endif
return MUNIT_OK;
}
#endif
static void *
test_api_rank_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -570,7 +655,8 @@ static void
test_api_rank_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -615,6 +701,7 @@ static void *
test_api_span_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -625,7 +712,8 @@ static void
test_api_span_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -638,26 +726,26 @@ test_api_span(const MunitParameter params[], void *data)
int located_at, placed_at, amt = 10000;
placed_at = create_sequential_set_in_empty_map(map, amt, 1);
placed_at = sm_add_span(map, amt, 1);
located_at = sparsemap_span(map, 0, 1, true);
assert_true(located_at == placed_at);
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, 50);
placed_at = sm_add_span(map, amt, 50);
located_at = sparsemap_span(map, 0, 50, true);
assert_true(located_at == placed_at);
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, 50);
placed_at = sm_add_span(map, amt, 50);
located_at = sparsemap_span(map, placed_at / 2, 50, true);
assert_true(located_at == placed_at);
/* TODO
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, amt - 1);
placed_at = sm_add_span(map, amt, amt - 1);
located_at = sparsemap_span(map, 0, amt - 1, true);
assert_true(located_at == placed_at);
*/
@ -681,7 +769,13 @@ static MunitTest api_test_suite[] = {
{ (char *)"/get_size", test_api_get_size, test_api_get_size_setup, test_api_get_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/scan", test_api_scan, test_api_scan_setup, test_api_scan_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/split", test_api_split, test_api_split_setup, test_api_split_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/select", test_api_select, test_api_select_setup, test_api_select_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/select/true", test_api_select, test_api_select_setup, test_api_select_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
#ifdef SELECT_FALSE
{ (char *)"/select/false", test_api_select_false, test_api_select_false_setup, test_api_select_false_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
#endif
#ifdef SELECT_NEG
{ (char *)"/select/neg", test_api_select_neg, test_api_select_neg_setup, test_api_select_neg_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
#endif
{ (char *)"/rank", test_api_rank, test_api_rank_setup, test_api_rank_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/span", test_api_span, test_api_span_setup, test_api_span_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
@ -693,10 +787,10 @@ static MunitTest api_test_suite[] = {
static void *
test_scale_lots_o_spans_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
(void)params;
(void)user_data;
sparsemap_t *map = sparsemap(1024);
assert_ptr_not_null(map);
return (void *)map;
}
@ -704,8 +798,8 @@ static void
test_scale_lots_o_spans_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
test_api_tear_down(fixture);
assert_ptr_not_null(map);
munit_free(map);
}
static MunitResult
test_scale_lots_o_spans(const MunitParameter params[], void *data)
@ -717,21 +811,82 @@ test_scale_lots_o_spans(const MunitParameter params[], void *data)
for (int i = 0; i < 268435456;) {
int l = i % 31 + 16;
create_sequential_set_in_empty_map(map, 268435456, l);
sm_add_span(map, 268435456, l);
if (errno == ENOSPC) {
map = sparsemap_set_data_size(map, sparsemap_get_capacity(map) * 2);
errno = 0;
}
i += l;
/* ANSI esc code to clear line, carrage return, then print on the same line */
//printf("\033[2K\r%d", i);
//printf("%d\t%d\n", l, i);
//fflush(stdout);
// printf("\033[2K\r%d", i);
// printf("%d\t%d\n", l, i);
// fflush(stdout);
}
return MUNIT_OK;
}
static void *
test_scale_ondrej_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
return (void *)map;
}
static void
test_scale_ondrej_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
test_scale_ondrej(const MunitParameter params[], void *data)
{
sparsemap_t *map = (sparsemap_t *)data;
(void)params;
assert_ptr_not_null(map);
sparsemap_idx_t stride = 18;
sparsemap_idx_t top = 268435456;
sparsemap_idx_t needle = munit_rand_int_range(1, top / stride);
for (sparsemap_idx_t i = 0; i < top / stride; i++) {
for (sparsemap_idx_t j = 0; j < stride; j++) {
bool set = (i != needle) ? (j < 10) : (j < 9);
sparsemap_set(map, i, set);
}
}
#if 0
// sm_add_span(map, 268435456, 9);
size_t b = sparsemap_span(map, 0, 8, true);
if (SPARSEMAP_NOT_FOUND(b)) {
printf("%ld\n", b);
printf("%ld / %ld == %ld %ld\n", b, stride, b / stride, needle);
} else {
printf("not found\n");
}
/*
size_t b = sparsemap_span(map, 0, 9, false); TODO
printf("%ld (%d) / %d == %d", b, (int)b, stride, needle);
fflush(stdout);
assert_true(((int)b / stride) == needle);
*/
#endif
return MUNIT_OK;
}
static void *
test_scale_spans_come_spans_go_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -742,7 +897,8 @@ static void
test_scale_spans_come_spans_go_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -753,32 +909,33 @@ test_scale_spans_come_spans_go(const MunitParameter params[], void *data)
assert_ptr_not_null(map);
/* ~5e7 interations due to 2e9 / avg(l) */
for (int i = 0; i < 268435456;) {
int l = i % 31 + 16;
create_sequential_set_in_empty_map(map, 268435456, l);
i += l;
sm_add_span(map, 268435456, l);
/* After 10,000 spans are in there we consume a span every iteration. */
if (l > 10000) {
do {
int s = munit_rand_int_range(1, 30);
int o = munit_rand_int_range(1, 268435456 - s - 1);
size_t b = sparsemap_span(map, o, s, true);
if (b == SM_LOC_MAX) {
continue;
}
for (int j = b; j < s; j++) {
assert_true(sparsemap_is_set(map, j) == true);
}
for (int j = b; j < s; j++) {
sparsemap_set(map, j, false);
}
for (int j = b; j < s; j++) {
assert_true(sparsemap_is_set(map, j) == false);
}
break;
int s = munit_rand_int_range(1, 30);
int o = munit_rand_int_range(1, 268435456 - s - 1);
size_t b = sparsemap_span(map, o, s, true);
if (b == SPARSEMAP_IDX_MAX) {
continue;
}
for (int j = b; j < s; j++) {
assert_true(sparsemap_is_set(map, j) == true);
}
for (int j = b; j < s; j++) {
sparsemap_set(map, j, false);
}
for (int j = b; j < s; j++) {
assert_true(sparsemap_is_set(map, j) == false);
}
break;
} while (true);
}
i += l;
}
return MUNIT_OK;
@ -788,6 +945,7 @@ static void *
test_scale_best_case_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -798,7 +956,8 @@ static void
test_scale_best_case_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -818,7 +977,8 @@ test_scale_best_case(const MunitParameter params[], void *data)
*/
/* Set every bit on, that should be the best case. */
for (int i = 0; i < 268435456; i++) {
// for (int i = 0; i < 268435456; i++) {
for (int i = 0; i < 172032; i++) {
/* ANSI esc code to clear line, carrage return, then print on the same line */
// printf("\033[2K\r%d", i);
// fflush(stdout);
@ -832,6 +992,7 @@ static void *
test_scale_worst_case_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
@ -842,7 +1003,8 @@ static void
test_scale_worst_case_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -862,7 +1024,8 @@ test_scale_worst_case(const MunitParameter params[], void *data)
*/
/* Set every other bit, that has to be the "worst case" for this index. */
for (int i = 0; i < 8134407; i += 2) {
// for (int i = 0; i < 8134407; i += 2) {
for (int i = 0; i < 7744; i += 2) {
/* ANSI esc code to clear line, carrage return, then print on the same line */
// printf("\033[2K\r%d", i);
// fflush(stdout);
@ -878,6 +1041,7 @@ static void *
test_perf_span_solo_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024 * 3, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 3 * 1024);
@ -888,7 +1052,8 @@ static void
test_perf_span_solo_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -904,9 +1069,9 @@ test_perf_span_solo(const MunitParameter params[], void *data)
for (int i = 1; i < amt; i++) {
for (int j = 1; j <= 100; j++) {
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, j);
placed_at = sm_add_span(map, amt, j);
// logf("i = %d, j = %d\tplaced_at %d\n", i, j, placed_at);
// whats_set(map, 5000);
// sm_whats_set(map, 5000);
// start = nsts();
located_at = sparsemap_span(map, 0, j, true);
// stop = nsts();
@ -925,6 +1090,7 @@ static void *
test_perf_span_tainted_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024 * 3, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 3 * 1024);
@ -935,7 +1101,8 @@ static void
test_perf_span_tainted_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
}
static MunitResult
@ -952,7 +1119,7 @@ test_perf_span_tainted(const MunitParameter params[], void *data)
for (int j = 100; j <= 10; j++) {
sparsemap_clear(map);
populate_map(map, 1024, 1 * 1024);
placed_at = create_sequential_set_in_empty_map(map, amt, j);
placed_at = sm_add_span(map, amt, j);
// start = nsts();
located_at = sparsemap_span(map, 0, j, true);
// stop = nsts();
@ -971,6 +1138,7 @@ test_perf_span_tainted(const MunitParameter params[], void *data)
// clang-format off
static MunitTest scale_test_suite[] = {
{ (char *)"/lots-o-spans", test_scale_lots_o_spans, test_scale_lots_o_spans_setup, test_scale_lots_o_spans_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/ondrej", test_scale_ondrej, test_scale_ondrej_setup, test_scale_ondrej_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/spans_come_spans_go", test_scale_spans_come_spans_go, test_scale_spans_come_spans_go_setup, test_scale_spans_come_spans_go_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/best-case", test_scale_best_case, test_scale_best_case_setup, test_scale_best_case_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/worst-case", test_scale_worst_case, test_scale_worst_case_setup, test_scale_worst_case_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
@ -986,12 +1154,19 @@ static MunitTest perf_test_suite[] = {
// clang-format off
static MunitSuite other_test_suite[] = {
{ "/api", api_test_suite, NULL, 1, MUNIT_SUITE_OPTION_NONE },
{ "/perf", perf_test_suite, NULL, 1, MUNIT_SUITE_OPTION_NONE },
{ "/scale", scale_test_suite, NULL, 1, MUNIT_SUITE_OPTION_NONE },
{ NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } };
// clang-format on
static const MunitSuite main_test_suite = { (char *)"/api", api_test_suite, other_test_suite, 1, MUNIT_SUITE_OPTION_NONE };
// clang-format off
static MunitTest sparsemap_test_suite[] = {
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
// clang-format on
static const MunitSuite main_test_suite = { (char *)"/sparsemap", sparsemap_test_suite, other_test_suite, 1, MUNIT_SUITE_OPTION_NONE };
int
main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)])