This commit is contained in:
Gregory Burd 2024-04-15 22:46:05 -04:00
parent 5e83f660ea
commit d42126054f
7 changed files with 430 additions and 166 deletions

View file

@ -5,11 +5,12 @@ SHARED_LIB = libsparsemap.so
#CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -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 = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -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 -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 #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 TESTS = tests/test
TEST_OBJS = tests/test.o tests/munit.o tests/tdigest.o tests/common.o 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); sparsemap_set(map, i * 10, true);
} }
for (size_t i = 0; i < 8; i++) { 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 // split and move, aligned to MiniMap capacity

View file

@ -88,9 +88,10 @@ extern "C" {
*/ */
typedef struct sparsemap sparsemap_t; typedef struct sparsemap sparsemap_t;
typedef long sm_loc_t; typedef long int sparsemap_idx_t;
#define SM_LOC_MAX LONG_MAX #define SPARSEMAP_IDX_MAX ((1UL << (sizeof(long) * CHAR_BIT - 1)) - 1)
#define SM_LOC_MIN LONG_MIN #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 uint32_t sm_idx_t;
typedef uint64_t sm_bitvec_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); 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. * 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. * 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. * 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|. * 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. * 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 * Appends all chunk maps from |map| starting at |offset| to |other|, then
* reduces the chunk map-count appropriately. * 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 * 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|), * (|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 * 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 * 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 * are set (|value| is true) or unset (|value| is false) and returns the
* starting offset for the span (0-based). * 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) #if defined(__cplusplus)
} }

View file

@ -23,14 +23,15 @@
#include <sys/types.h> #include <sys/types.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <popcount.h> #include <popcount.h>
#include <sparsemap.h> #include <sparsemap.h>
#include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h> #include <string.h>
#ifdef SPARSEMAP_DIAGNOSTIC #ifdef SPARSEMAP_DIAGNOSTIC
@ -48,19 +49,24 @@ void __attribute__((format(printf, 4, 5))) __sm_diag_(const char *file, int line
vfprintf(stderr, format, args); vfprintf(stderr, format, args);
va_end(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) \ #define __sm_assert(expr) \
if (!(expr)) \ if (!(expr)) \
fprintf(stderr, "%s:%d:%s(): assertion failed! %s", __FILE__, __LINE__, __func__, #expr) fprintf(stderr, "%s:%d:%s(): assertion failed! %s", __FILE__, __LINE__, __func__, #expr)
#define __sm_when_diag(expr) \
if (1) \
expr
#else #else
#define __sm_diag(file, line, func, format, ...) ((void)0)
#define __sm_assert(expr) ((void)0) #define __sm_assert(expr) ((void)0)
#define __sm_when_diag(expr) \
if (0) \
expr
#endif #endif
#define IS_8_BYTE_ALIGNED(addr) (((uintptr_t)(addr) & 0x7) == 0)
enum __SM_CHUNK_INFO { enum __SM_CHUNK_INFO {
/* metadata overhead: 4 bytes for __sm_chunk_t count */ /* metadata overhead: 4 bytes for __sm_chunk_t count */
SM_SIZEOF_OVERHEAD = sizeof(uint32_t), 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; size_t ret = 0;
register uint8_t *p; register uint8_t *p;
(void)value; // TODO
p = (uint8_t *)map->m_data; p = (uint8_t *)map->m_data;
for (size_t i = 0; i < sizeof(sm_bitvec_t); i++, p++) { 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; continue;
} }
if (flags == SM_PAYLOAD_ZEROS) { if (flags == SM_PAYLOAD_ZEROS) {
ret += SM_BITS_PER_VECTOR; if (value) {
continue; 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 (flags == SM_PAYLOAD_ONES) {
if (n > SM_BITS_PER_VECTOR) { if (value) {
n -= SM_BITS_PER_VECTOR; 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; ret += SM_BITS_PER_VECTOR;
continue; continue;
} }
*pnew_n = -1;
return (ret + n);
} }
if (flags == SM_PAYLOAD_MIXED) { 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)]; 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++) { for (int k = 0; k < SM_BITS_PER_VECTOR; k++) {
if (w & ((sm_bitvec_t)1 << k)) { if (value) {
if (n == 0) { if (w & ((sm_bitvec_t)1 << k)) {
*pnew_n = -1; if (n == 0) {
return (ret); *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; *pnew_n = (ssize_t)n;
return (ret); 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. * Returns the byte offset of a __sm_chunk_t in m_data.
*/ */
static ssize_t 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; 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 *start = __sm_get_chunk_map_data(map, 0);
uint8_t *p = start; 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_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_t chunk;
__sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t)); __sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t));
if (s >= idx || (unsigned long)idx < s + __sm_chunk_map_get_capacity(&chunk)) { 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 *end = __sm_get_chunk_map_data(map, count - 1);
uint8_t *p = end; 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_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_t chunk;
__sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t)); __sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t));
if (e >= idx || (unsigned long)idx < e + __sm_chunk_map_get_capacity(&chunk)) { if (e >= idx || (unsigned long)idx < e + __sm_chunk_map_get_capacity(&chunk)) {
@ -779,10 +808,21 @@ sparsemap(size_t size)
if (size == 0) { if (size == 0) {
size = 1024; 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) { 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; return map;
} }
@ -801,7 +841,7 @@ sparsemap_init(sparsemap_t *map, uint8_t *data, size_t size)
{ {
map->m_data = data; map->m_data = data;
map->m_data_used = 0; map->m_data_used = 0;
map->m_capacity = size == 0 ? UINT64_MAX : size; map->m_capacity = size;
sparsemap_clear(map); sparsemap_clear(map);
} }
@ -809,7 +849,7 @@ void
sparsemap_open(sparsemap_t *map, uint8_t *data, size_t data_size) sparsemap_open(sparsemap_t *map, uint8_t *data, size_t data_size)
{ {
map->m_data = data; 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; 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 * TODO/NOTE: This is a dangerous operation because we cannot verify that
* data_size is not exceeding the size of the underlying buffer. * data_size is not exceeding the size of the underlying buffer.
*/ */
void sparsemap_t *
sparsemap_set_data_size(sparsemap_t *map, size_t data_size) 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 double
@ -842,7 +902,7 @@ sparsemap_get_capacity(sparsemap_t *map)
} }
bool 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); __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)); return (__sm_chunk_map_is_set(&chunk, idx - start));
} }
void sparsemap_idx_t
sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value) sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
{ {
__sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD); __sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
if (idx < 0) {
return;
}
/* Get the __sm_chunk_t which manages this index */ /* Get the __sm_chunk_t which manages this index */
ssize_t offset = __sm_get_chunk_map_offset(map, idx); ssize_t offset = __sm_get_chunk_map_offset(map, idx);
bool dont_grow = false; 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. */ immediately; otherwise create an initial __sm_chunk_t. */
if (offset == -1) { if (offset == -1) {
if (value == false) { if (value == false) {
return; return idx;
} }
uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; 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 (idx < start) {
if (value == false) { if (value == false) {
/* nothing to do */ /* nothing to do */
return; return idx;
} }
uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; 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 { else {
__sm_chunk_t chunk; __sm_chunk_t chunk;
__sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t)); __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) { if (value == false) {
/* nothing to do */ /* nothing to do */
return; return idx;
} }
size_t size = __sm_chunk_map_get_size(&chunk); 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)); __sm_insert_data(map, offset, &buf[0], sizeof(buf));
start += __sm_chunk_map_get_capacity(&chunk); 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); start = __sm_get_fully_aligned_offset(idx);
} }
*(sm_idx_t *)p = start; *(sm_idx_t *)p = start;
@ -1009,6 +1065,7 @@ sparsemap_set(sparsemap_t *map, sm_loc_t idx, bool value)
break; break;
} }
__sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD); __sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
return idx;
} }
sm_idx_t sm_idx_t
@ -1059,7 +1116,7 @@ sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t), size_t ski
} }
void 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); 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)); __sm_chunk_map_set_capacity(&d_chunk, capacity - (offset % capacity));
/* Now copy the bits. */ /* Now copy the bits. */
sm_loc_t d = offset; sparsemap_idx_t d = offset;
for (size_t j = offset % capacity; j < capacity; j++, d++) { for (size_t j = offset % capacity; j < capacity; j++, d++) {
if (__sm_chunk_map_is_set(&s_chunk, j)) { if (__sm_chunk_map_is_set(&s_chunk, j)) {
sparsemap_set(other, d, true); 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); assert(sparsemap_get_size(other) > SM_SIZEOF_OVERHEAD);
} }
sm_loc_t sparsemap_idx_t
sparsemap_select(sparsemap_t *map, sm_loc_t n, bool value) sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value)
{ {
assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD); assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
size_t result; size_t result;
@ -1204,16 +1261,16 @@ sparsemap_select(sparsemap_t *map, sm_loc_t n, bool value)
#ifdef DEBUG #ifdef DEBUG
assert(!"shouldn't be here"); assert(!"shouldn't be here");
#endif #endif
return SM_LOC_MAX; return SPARSEMAP_IDX_MAX;
} else { } else {
return SM_LOC_MIN; // TODO... sparsemap_select(map, -n, value); return SPARSEMAP_IDX_MIN; // TODO... sparsemap_select(map, -n, value);
} }
} }
size_t size_t
sparsemap_rank_vec(sparsemap_t *map, size_t x, size_t y, bool value, sm_bitvec_t *vec) 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); assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
size_t result = 0, prev = 0, count = __sm_get_chunk_map_count(map); size_t result = 0, prev = 0, count = __sm_get_chunk_map_count(map);
uint8_t *p = __sm_get_chunk_map_data(map, 0); 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 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; size_t count, nth = 0;
sm_bitvec_t vec = 0; sm_bitvec_t vec = 0;
sm_loc_t offset; sparsemap_idx_t offset;
offset = sparsemap_select(map, nth++, value); offset = sparsemap_select(map, nth++, value);
if (len == 1) { if (len == 1) {
@ -1269,7 +1326,7 @@ sparsemap_span(sparsemap_t *map, sm_loc_t idx, size_t len, bool value)
nth++; nth++;
/* Use select to potentially jump very far forward in the map. */ /* Use select to potentially jump very far forward in the map. */
offset = sparsemap_select(map, nth, value); 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 <time.h>
#include <unistd.h> #include <unistd.h>
#ifdef X86_INTRIN #ifdef X86_INTRIN
#include <errno.h>
#include <x86intrin.h> #include <x86intrin.h>
#endif #endif
@ -146,25 +147,25 @@ ensure_sequential_set(int a[], int l, int r)
return value; return value;
} }
int sparsemap_idx_t
create_sequential_set_in_empty_map(sparsemap_t *map, int s, int r) sm_add_span(sparsemap_t *map, int map_size, int span_length)
{ {
int attempts = map_size / span_length;
sparsemap_idx_t placed_at;
do { do {
int placed_at; placed_at = random_uint32() % (map_size - span_length - 1);
if (s >= r + 1) { if (sm_occupied(map, placed_at, span_length, true)) {
placed_at = 0; attempts--;
} else { } else {
placed_at = random_uint32() % (s - r - 1); break;
} }
for (int i = placed_at; i < placed_at + r; i++) { } while (attempts);
sparsemap_is_set(map, i); for (int i = placed_at; i < placed_at + span_length; i++) {
continue; 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;
}
return placed_at;
} while (true);
} }
void void
@ -318,10 +319,10 @@ bitmap_from_uint32(sparsemap_t *map, uint32_t number)
} }
void 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++) { for (int i = 0; i < 64; i++) {
bool bit = number & (1 << i); bool bit = number & ((uint64_t)1 << i);
sparsemap_set(map, i, bit); sparsemap_set(map, i, bit);
} }
} }
@ -368,7 +369,7 @@ whats_set_uint64(uint64_t number, int pos[64])
} }
void 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); logf("what's set in the range [0, %d): ", m);
for (int i = 0; i < m; i++) { for (int i = 0; i < m; i++) {
@ -378,3 +379,25 @@ whats_set(sparsemap_t *map, int m)
} }
logf("\n"); 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 setup_test_array(int a[], int l, int max_value);
void shuffle(int *array, size_t n); void shuffle(int *array, size_t n);
int ensure_sequential_set(int a[], int l, int r); 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_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); uint32_t rank_uint64(uint64_t number, int n, int p);
int whats_set_uint64(uint64_t number, int bitPositions[64]); 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_NO_FORK (1)
#define MUNIT_ENABLE_ASSERT_ALIASES (1) #define MUNIT_ENABLE_ASSERT_ALIASES (1)
#include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -18,10 +19,14 @@
#include "common.h" #include "common.h"
#include "munit.h" #include "munit.h"
#define munit_free free
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(disable : 4127) #pragma warning(disable : 4127)
#endif #endif
#define SELECT_FALSE
/* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */ /* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */
struct sparsemap { struct sparsemap {
uint8_t *m_data; uint8_t *m_data;
@ -66,7 +71,7 @@ test_api_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)fixture; sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map); assert_ptr_not_null(map);
free(map); munit_free(map);
} }
/* -------------------------- API Tests */ /* -------------------------- API Tests */
@ -93,6 +98,7 @@ static void *
test_api_clear_setup(const MunitParameter params[], void *user_data) test_api_clear_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -103,7 +109,8 @@ static void
test_api_clear_tear_down(void *fixture) test_api_clear_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -126,6 +133,7 @@ static void *
test_api_open_setup(const MunitParameter params[], void *user_data) test_api_open_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -137,7 +145,8 @@ static void
test_api_open_tear_down(void *fixture) test_api_open_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -160,6 +169,7 @@ static void *
test_api_set_data_size_setup(const MunitParameter params[], void *user_data) test_api_set_data_size_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -171,7 +181,8 @@ static void
test_api_set_data_size_tear_down(void *fixture) test_api_set_data_size_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -193,6 +204,7 @@ static void *
test_api_remaining_capacity_setup(const MunitParameter params[], void *user_data) test_api_remaining_capacity_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -203,7 +215,8 @@ static void
test_api_remaining_capacity_tear_down(void *fixture) test_api_remaining_capacity_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -241,6 +254,7 @@ static void *
test_api_get_capacity_setup(const MunitParameter params[], void *user_data) test_api_get_capacity_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -252,7 +266,8 @@ static void
test_api_get_capacity_tear_down(void *fixture) test_api_get_capacity_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -274,6 +289,7 @@ static void *
test_api_is_set_setup(const MunitParameter params[], void *user_data) test_api_is_set_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -285,7 +301,8 @@ static void
test_api_is_set_tear_down(void *fixture) test_api_is_set_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -306,6 +323,7 @@ static void *
test_api_set_setup(const MunitParameter params[], void *user_data) test_api_set_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -316,7 +334,8 @@ static void
test_api_set_tear_down(void *fixture) test_api_set_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -345,6 +364,7 @@ static void *
test_api_get_starting_offset_setup(const MunitParameter params[], void *user_data) test_api_get_starting_offset_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -356,7 +376,8 @@ static void
test_api_get_starting_offset_tear_down(void *fixture) test_api_get_starting_offset_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -379,6 +400,7 @@ static void *
test_api_get_size_setup(const MunitParameter params[], void *user_data) test_api_get_size_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -390,7 +412,8 @@ static void
test_api_get_size_tear_down(void *fixture) test_api_get_size_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -411,10 +434,11 @@ static void *
test_api_scan_setup(const MunitParameter params[], void *user_data) test_api_scan_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); 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; return (void *)map;
} }
@ -422,7 +446,8 @@ static void
test_api_scan_tear_down(void *fixture) test_api_scan_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
void void
@ -441,7 +466,7 @@ test_api_scan(const MunitParameter params[], void *data)
assert_ptr_not_null(map); assert_ptr_not_null(map);
sparsemap_set(map, 4200, true); 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); sparsemap_scan(map, scan_for_0xfeedfacebadcoffee, 0);
return MUNIT_OK; return MUNIT_OK;
@ -451,6 +476,7 @@ static void *
test_api_split_setup(const MunitParameter params[], void *user_data) test_api_split_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -463,7 +489,8 @@ static void
test_api_split_tear_down(void *fixture) test_api_split_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -494,10 +521,11 @@ static void *
test_api_select_setup(const MunitParameter params[], void *user_data) test_api_select_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); 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; return (void *)map;
} }
@ -505,7 +533,8 @@ static void
test_api_select_tear_down(void *fixture) test_api_select_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult 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, 4, true) == 6);
assert_true(sparsemap_select(map, 17, true) == 26); assert_true(sparsemap_select(map, 17, true) == 26);
#if 0 // TODO return MUNIT_OK;
size_t f = sparsemap_select(map, 0, false); }
for (int i = 0; i <= f; i++) {
assert_false(sparsemap_is_set(map, i % 2));
}
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++) { for (int i = 0; i < 1000; i++) {
sparsemap_set(map, i, i % 2 ? true : false); sparsemap_set(map, i, true);
} }
sparsemap_idx_t f = sparsemap_select(map, 0, false);
f = sparsemap_select(map, 0, false);
assert_true(f == 1000); 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, 42, true);
sparsemap_set(map, 420, true); sparsemap_set(map, 420, true);
@ -552,14 +635,16 @@ test_api_select(const MunitParameter params[], void *data)
assert_true(f == 420); assert_true(f == 420);
f = sparsemap_select(map, -3, true); f = sparsemap_select(map, -3, true);
assert_true(f == 42); assert_true(f == 42);
#endif
return MUNIT_OK; return MUNIT_OK;
} }
#endif
static void * static void *
test_api_rank_setup(const MunitParameter params[], void *user_data) test_api_rank_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -570,7 +655,8 @@ static void
test_api_rank_tear_down(void *fixture) test_api_rank_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -615,6 +701,7 @@ static void *
test_api_span_setup(const MunitParameter params[], void *user_data) test_api_span_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -625,7 +712,8 @@ static void
test_api_span_tear_down(void *fixture) test_api_span_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -638,26 +726,26 @@ test_api_span(const MunitParameter params[], void *data)
int located_at, placed_at, amt = 10000; 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); located_at = sparsemap_span(map, 0, 1, true);
assert_true(located_at == placed_at); assert_true(located_at == placed_at);
sparsemap_clear(map); 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); located_at = sparsemap_span(map, 0, 50, true);
assert_true(located_at == placed_at); assert_true(located_at == placed_at);
sparsemap_clear(map); 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); located_at = sparsemap_span(map, placed_at / 2, 50, true);
assert_true(located_at == placed_at); assert_true(located_at == placed_at);
/* TODO /* TODO
sparsemap_clear(map); 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); located_at = sparsemap_span(map, 0, amt - 1, true);
assert_true(located_at == placed_at); 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 *)"/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 *)"/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 *)"/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 *)"/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 }, { (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 } { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
@ -693,10 +787,10 @@ static MunitTest api_test_suite[] = {
static void * static void *
test_scale_lots_o_spans_setup(const MunitParameter params[], void *user_data) test_scale_lots_o_spans_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); (void)params;
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data); (void)user_data;
sparsemap_t *map = sparsemap(1024);
sparsemap_init(map, buf, 1024); assert_ptr_not_null(map);
return (void *)map; return (void *)map;
} }
@ -704,8 +798,8 @@ static void
test_scale_lots_o_spans_tear_down(void *fixture) test_scale_lots_o_spans_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)fixture; sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data); assert_ptr_not_null(map);
test_api_tear_down(fixture); munit_free(map);
} }
static MunitResult static MunitResult
test_scale_lots_o_spans(const MunitParameter params[], void *data) 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;) { for (int i = 0; i < 268435456;) {
int l = i % 31 + 16; 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; i += l;
/* ANSI esc code to clear line, carrage return, then print on the same line */ /* ANSI esc code to clear line, carrage return, then print on the same line */
//printf("\033[2K\r%d", i); // printf("\033[2K\r%d", i);
//printf("%d\t%d\n", l, i); // printf("%d\t%d\n", l, i);
//fflush(stdout); // fflush(stdout);
} }
return MUNIT_OK; 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 * static void *
test_scale_spans_come_spans_go_setup(const MunitParameter params[], void *user_data) test_scale_spans_come_spans_go_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -742,7 +897,8 @@ static void
test_scale_spans_come_spans_go_tear_down(void *fixture) test_scale_spans_come_spans_go_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -753,32 +909,33 @@ test_scale_spans_come_spans_go(const MunitParameter params[], void *data)
assert_ptr_not_null(map); assert_ptr_not_null(map);
/* ~5e7 interations due to 2e9 / avg(l) */
for (int i = 0; i < 268435456;) { for (int i = 0; i < 268435456;) {
int l = i % 31 + 16; int l = i % 31 + 16;
create_sequential_set_in_empty_map(map, 268435456, l); sm_add_span(map, 268435456, l);
i += l;
/* After 10,000 spans are in there we consume a span every iteration. */ /* After 10,000 spans are in there we consume a span every iteration. */
if (l > 10000) { if (l > 10000) {
do { do {
int s = munit_rand_int_range(1, 30); int s = munit_rand_int_range(1, 30);
int o = munit_rand_int_range(1, 268435456 - s - 1); int o = munit_rand_int_range(1, 268435456 - s - 1);
size_t b = sparsemap_span(map, o, s, true); size_t b = sparsemap_span(map, o, s, true);
if (b == SM_LOC_MAX) { if (b == SPARSEMAP_IDX_MAX) {
continue; continue;
} }
for (int j = b; j < s; j++) { for (int j = b; j < s; j++) {
assert_true(sparsemap_is_set(map, j) == true); assert_true(sparsemap_is_set(map, j) == true);
} }
for (int j = b; j < s; j++) { for (int j = b; j < s; j++) {
sparsemap_set(map, j, false); sparsemap_set(map, j, false);
} }
for (int j = b; j < s; j++) { for (int j = b; j < s; j++) {
assert_true(sparsemap_is_set(map, j) == false); assert_true(sparsemap_is_set(map, j) == false);
} }
break; break;
} while (true); } while (true);
} }
i += l;
} }
return MUNIT_OK; return MUNIT_OK;
@ -788,6 +945,7 @@ static void *
test_scale_best_case_setup(const MunitParameter params[], void *user_data) test_scale_best_case_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -798,7 +956,8 @@ static void
test_scale_best_case_tear_down(void *fixture) test_scale_best_case_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult 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. */ /* 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 */ /* ANSI esc code to clear line, carrage return, then print on the same line */
// printf("\033[2K\r%d", i); // printf("\033[2K\r%d", i);
// fflush(stdout); // fflush(stdout);
@ -832,6 +992,7 @@ static void *
test_scale_worst_case_setup(const MunitParameter params[], void *user_data) test_scale_worst_case_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024); sparsemap_init(map, buf, 1024);
@ -842,7 +1003,8 @@ static void
test_scale_worst_case_tear_down(void *fixture) test_scale_worst_case_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult 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. */ /* 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 */ /* ANSI esc code to clear line, carrage return, then print on the same line */
// printf("\033[2K\r%d", i); // printf("\033[2K\r%d", i);
// fflush(stdout); // fflush(stdout);
@ -878,6 +1041,7 @@ static void *
test_perf_span_solo_setup(const MunitParameter params[], void *user_data) test_perf_span_solo_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024 * 3, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 3 * 1024); sparsemap_init(map, buf, 3 * 1024);
@ -888,7 +1052,8 @@ static void
test_perf_span_solo_tear_down(void *fixture) test_perf_span_solo_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -904,9 +1069,9 @@ test_perf_span_solo(const MunitParameter params[], void *data)
for (int i = 1; i < amt; i++) { for (int i = 1; i < amt; i++) {
for (int j = 1; j <= 100; j++) { for (int j = 1; j <= 100; j++) {
sparsemap_clear(map); 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); // logf("i = %d, j = %d\tplaced_at %d\n", i, j, placed_at);
// whats_set(map, 5000); // sm_whats_set(map, 5000);
// start = nsts(); // start = nsts();
located_at = sparsemap_span(map, 0, j, true); located_at = sparsemap_span(map, 0, j, true);
// stop = nsts(); // stop = nsts();
@ -925,6 +1090,7 @@ static void *
test_perf_span_tainted_setup(const MunitParameter params[], void *user_data) test_perf_span_tainted_setup(const MunitParameter params[], void *user_data)
{ {
uint8_t *buf = munit_calloc(1024 * 3, sizeof(uint8_t)); 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_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 3 * 1024); sparsemap_init(map, buf, 3 * 1024);
@ -935,7 +1101,8 @@ static void
test_perf_span_tainted_tear_down(void *fixture) test_perf_span_tainted_tear_down(void *fixture)
{ {
sparsemap_t *map = (sparsemap_t *)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); test_api_tear_down(fixture);
} }
static MunitResult static MunitResult
@ -952,7 +1119,7 @@ test_perf_span_tainted(const MunitParameter params[], void *data)
for (int j = 100; j <= 10; j++) { for (int j = 100; j <= 10; j++) {
sparsemap_clear(map); sparsemap_clear(map);
populate_map(map, 1024, 1 * 1024); 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(); // start = nsts();
located_at = sparsemap_span(map, 0, j, true); located_at = sparsemap_span(map, 0, j, true);
// stop = nsts(); // stop = nsts();
@ -971,6 +1138,7 @@ test_perf_span_tainted(const MunitParameter params[], void *data)
// clang-format off // clang-format off
static MunitTest scale_test_suite[] = { 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 *)"/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 *)"/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 *)"/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 }, { (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 // clang-format off
static MunitSuite other_test_suite[] = { 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 }, { "/perf", perf_test_suite, NULL, 1, MUNIT_SUITE_OPTION_NONE },
{ "/scale", scale_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 } }; { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } };
// clang-format on // 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 int
main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)]) main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)])