WIP rank 0-bits, fixes, etc.

This commit is contained in:
Gregory Burd 2024-04-16 18:57:28 -04:00
parent 20b81983ae
commit 599284d5f5
6 changed files with 172 additions and 75 deletions

View file

@ -78,6 +78,6 @@ examples/ex_4: examples/common.o examples/ex_4.o $(STATIC_LIB)
$(CC) $^ -o $@ $(CFLAGS) $(TEST_FLAGS)
todo:
rg -i 'todo|gsb'
rg -i 'todo|gsb|abort'
# cp src/sparsemap.c /tmp && clang-tidy src/sparsemap.c -fix -fix-errors -checks="readability-braces-around-statements" -- -DDEBUG -DSPARSEMAP_DIAGNOSTIC -DSPARSEMAP_ASSERT -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC

View file

@ -17,9 +17,9 @@
/* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */
struct sparsemap {
uint8_t *m_data;
size_t m_capacity;
size_t m_data_used;
uint8_t *m_data;
};
int

View file

@ -115,9 +115,9 @@ typedef struct {
} __sm_chunk_t;
struct __attribute__((aligned(8))) sparsemap {
uint8_t *m_data; /* The serialized bitmap data */
size_t m_capacity; /* The total size of m_data */
size_t m_data_used; /* The used size of m_data */
uint8_t *m_data; /* The serialized bitmap data */
};
/**
@ -147,7 +147,7 @@ __sm_chunk_map_calc_vector_size(uint8_t b)
0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 2, 1, 0, 0, 1, 0
};
// clang-format on
return ((size_t)lookup[b]);
return (size_t)lookup[b];
}
/**
@ -173,7 +173,7 @@ __sm_chunk_map_get_position(__sm_chunk_t *map, size_t bv)
}
}
return (position);
return position;
}
/**
@ -205,7 +205,7 @@ __sm_chunk_map_get_capacity(__sm_chunk_t *map)
}
}
}
return (capacity);
return capacity;
}
/**
@ -244,7 +244,7 @@ __sm_chunk_map_is_empty(__sm_chunk_t *map)
{
/* The __sm_chunk_t is empty if all flags (in m_data[0]) are zero. */
if (map->m_data[0] == 0) {
return (true);
return true;
}
/* It's also empty if all flags are Zero or None. */
@ -254,12 +254,12 @@ __sm_chunk_map_is_empty(__sm_chunk_t *map)
for (int j = 0; j < SM_FLAGS_PER_INDEX_BYTE; j++) {
size_t flags = SM_CHUNK_GET_FLAGS(*p, j);
if (flags != SM_PAYLOAD_NONE && flags != SM_PAYLOAD_ZEROS) {
return (false);
return false;
}
}
}
}
return (true);
return true;
}
/**
@ -276,7 +276,7 @@ __sm_chunk_map_get_size(__sm_chunk_t *map)
size += sizeof(sm_bitvec_t) * __sm_chunk_map_calc_vector_size(*p);
}
return (size);
return size;
}
/**
@ -294,9 +294,9 @@ __sm_chunk_map_is_set(__sm_chunk_t *map, size_t idx)
switch (flags) {
case SM_PAYLOAD_ZEROS:
case SM_PAYLOAD_NONE:
return (false);
return false;
case SM_PAYLOAD_ONES:
return (true);
return true;
default:
__sm_assert(flags == SM_PAYLOAD_MIXED);
/* FALLTHROUGH */
@ -305,7 +305,7 @@ __sm_chunk_map_is_set(__sm_chunk_t *map, size_t idx)
/* get the sm_bitvec_t at |bv| */
sm_bitvec_t w = map->m_data[1 + __sm_chunk_map_get_position(map, bv)];
/* and finally check the bit in that sm_bitvec_t */
return ((w & ((sm_bitvec_t)1 << (idx % SM_BITS_PER_VECTOR))) > 0);
return (w & ((sm_bitvec_t)1 << (idx % SM_BITS_PER_VECTOR))) > 0;
}
/**
@ -428,7 +428,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
continue;
}
*pnew_n = -1;
return (ret + n);
return ret + n;
}
}
if (flags == SM_PAYLOAD_ONES) {
@ -439,7 +439,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
continue;
}
*pnew_n = -1;
return (ret + n);
return ret + n;
} else {
ret += SM_BITS_PER_VECTOR;
continue;
@ -452,7 +452,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
if (w & ((sm_bitvec_t)1 << k)) {
if (n == 0) {
*pnew_n = -1;
return (ret);
return ret;
}
n--;
}
@ -461,7 +461,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
if (!(w & ((sm_bitvec_t)1 << k))) {
if (n == 0) {
*pnew_n = -1;
return (ret);
return ret;
}
n--;
}
@ -472,7 +472,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
}
}
*pnew_n = (ssize_t)n;
return (ret);
return ret;
}
/**
@ -482,7 +482,7 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *pnew_n, bool value)
* '*offset' has been reached 0.
*/
static size_t
__sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, sm_bitvec_t *vec)
__sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, sm_bitvec_t *vec, bool value)
{
size_t ret = 0;
@ -499,11 +499,20 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, sm_bitvec_t *
*offset = *offset - SM_BITS_PER_VECTOR;
} else {
idx -= SM_BITS_PER_VECTOR - *offset;
if (*offset == 0) {
if (value == false) {
ret += SM_BITS_PER_VECTOR;
}
}
*offset = 0;
}
} else {
*vec = 0;
return (ret);
if (value == false) {
return ret + idx;
} else {
return ret;
}
}
} else if (flags == SM_PAYLOAD_ONES) {
if (idx > SM_BITS_PER_VECTOR) {
@ -512,36 +521,53 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, sm_bitvec_t *
} else {
idx -= SM_BITS_PER_VECTOR - *offset;
if (*offset == 0) {
ret += SM_BITS_PER_VECTOR;
if (value == true) {
ret += SM_BITS_PER_VECTOR;
}
}
*offset = 0;
}
} else {
*vec = UINT64_MAX;
return (ret + idx);
if (value == true) {
return ret + idx;
} else {
return ret;
}
}
} else 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)];
if (idx > SM_BITS_PER_VECTOR) {
uint64_t mask_offset = ~(UINT64_MAX >> (SM_BITS_PER_VECTOR - *offset));
uint64_t mask = ~(UINT64_MAX >> (SM_BITS_PER_VECTOR - *offset));
idx -= SM_BITS_PER_VECTOR;
ret += popcountll(w & mask_offset);
size_t pc = popcountll(w & mask);
if (value == true) {
ret += pc;
} else {
ret += popcountll(mask) - pc;
}
*offset = (*offset > SM_BITS_PER_VECTOR) ? *offset - SM_BITS_PER_VECTOR : 0;
} else {
/* Create a mask for the range between offset and idx inclusive [*offset, idx]. */
uint64_t offset_mask = (((uint64_t)1 << *offset) - 1);
uint64_t idx_mask = idx >= 63 ? UINT64_MAX : ((uint64_t)1 << (idx + 1)) - 1;
sm_bitvec_t mw = w & (idx_mask - offset_mask);
ret += popcountll(mw);
uint64_t mask = (idx_mask - offset_mask);
sm_bitvec_t mw = w & mask;
size_t pc = popcountll(mw);
if (value == true) {
ret += pc;
} else {
ret += popcountll(mask) - pc;
}
*offset = *offset > idx ? *offset - idx : 0;
*vec = mw;
(*vec) <<= *offset;
return (ret);
return ret;
}
}
}
}
return (ret);
return ret;
}
/**
@ -612,7 +638,7 @@ __sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[
}
}
}
return (ret);
return ret;
}
/*
@ -625,7 +651,7 @@ __sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[
static size_t
__sm_get_chunk_map_count(sparsemap_t *map)
{
return (*(uint32_t *)&map->m_data[0]);
return *(uint32_t *)&map->m_data[0];
}
/**
@ -634,7 +660,7 @@ __sm_get_chunk_map_count(sparsemap_t *map)
static inline uint8_t *
__sm_get_chunk_map_data(sparsemap_t *map, size_t offset)
{
return (&map->m_data[SM_SIZEOF_OVERHEAD + offset]);
return &map->m_data[SM_SIZEOF_OVERHEAD + offset];
}
/**
@ -652,7 +678,7 @@ __sm_get_chunk_map_end(sparsemap_t *map)
__sm_chunk_map_init(&chunk, p);
p += __sm_chunk_map_get_size(&chunk);
}
return (p);
return p;
}
/**
@ -671,7 +697,7 @@ __sm_get_size_impl(sparsemap_t *map)
__sm_chunk_map_init(&chunk, p);
p += __sm_chunk_map_get_size(&chunk);
}
return (SM_SIZEOF_OVERHEAD + p - start);
return SM_SIZEOF_OVERHEAD + p - start;
}
/**
@ -681,7 +707,7 @@ static sm_idx_t
__sm_get_aligned_offset(size_t idx)
{
const size_t capacity = SM_BITS_PER_VECTOR;
return ((idx / capacity) * capacity);
return (idx / capacity) * capacity;
}
/**
@ -694,7 +720,7 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
count = __sm_get_chunk_map_count(map);
if (count == 0) {
return (-1);
return -1;
}
if (idx > 0 || idx == 0) {
@ -712,7 +738,7 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
p += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&chunk);
}
return ((ssize_t)(p - start));
return (ssize_t)(p - start);
} else {
uint8_t *end = __sm_get_chunk_map_data(map, count - 1);
uint8_t *p = end;
@ -728,7 +754,7 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
p += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&chunk);
}
return ((ssize_t)(p - end));
return (ssize_t)(p - end);
}
}
@ -739,7 +765,7 @@ static sm_idx_t
__sm_get_fully_aligned_offset(size_t idx)
{
const size_t capacity = SM_CHUNK_MAX_CAPACITY;
return ((idx / capacity) * capacity);
return (idx / capacity) * capacity;
}
/**
@ -893,7 +919,7 @@ sparsemap_capacity_remaining(sparsemap_t *map)
size_t
sparsemap_get_capacity(sparsemap_t *map)
{
return (map->m_capacity);
return map->m_capacity;
}
bool
@ -902,7 +928,7 @@ sparsemap_is_set(sparsemap_t *map, sparsemap_idx_t idx)
__sm_assert(sparsemap_get_size(map) >= SM_SIZEOF_OVERHEAD);
if (idx < 0) {
return (false);
return false;
}
/* Get the __sm_chunk_t which manages this index */
@ -910,7 +936,7 @@ sparsemap_is_set(sparsemap_t *map, sparsemap_idx_t idx)
/* No __sm_chunk_t's available -> the bit is not set */
if (offset == -1) {
return (false);
return false;
}
/* Otherwise load the __sm_chunk_t */
@ -922,11 +948,11 @@ sparsemap_is_set(sparsemap_t *map, sparsemap_idx_t idx)
/* Determine if the bit is out of bounds of the __sm_chunk_t; if yes then
the bit is not set. */
if (idx < start || (unsigned long)idx - start >= __sm_chunk_map_get_capacity(&chunk)) {
return (false);
return false;
}
/* Otherwise ask the __sm_chunk_t whether the bit is set. */
return (__sm_chunk_map_is_set(&chunk, idx - start));
return __sm_chunk_map_is_set(&chunk, idx - start);
}
sparsemap_idx_t
@ -1075,7 +1101,7 @@ sparsemap_get_starting_offset(sparsemap_t *map)
{
size_t count = __sm_get_chunk_map_count(map);
if (count == 0) {
return (0);
return 0;
}
sm_idx_t *chunk = (sm_idx_t *)__sm_get_chunk_map_data(map, 0);
return *chunk;
@ -1088,10 +1114,13 @@ size_t
sparsemap_get_size(sparsemap_t *map)
{
if (map->m_data_used) {
assert(map->m_data_used == __sm_get_size_impl(map));
return (map->m_data_used);
__sm_when_diag({
size_t used = __sm_get_size_impl(map);
__sm_assert(map->m_data_used == used);
});
return map->m_data_used;
}
return (map->m_data_used = __sm_get_size_impl(map));
return map->m_data_used = __sm_get_size_impl(map);
}
/**
@ -1254,7 +1283,7 @@ sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value)
ssize_t new_n = (ssize_t)n;
size_t index = __sm_chunk_map_select(&chunk, n, &new_n, value);
if (new_n == -1) {
return (result + index);
return result + index;
}
n = new_n;
@ -1269,15 +1298,25 @@ sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value)
size_t
sparsemap_rank_vec(sparsemap_t *map, size_t x, size_t y, bool value, sm_bitvec_t *vec)
{
(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);
/* The count/rank of zero bits in an empty map is inf, so what you requested is the answer. */
if (count == 0 && value == false) {
return y - x + 1;
}
for (size_t i = 0; i < count; i++) {
sm_idx_t start = *(sm_idx_t *)p;
/* Start of this chunk is greater than the end of the desired range. */
if (start > y) {
return (result);
if (value == true) {
return result;
} else {
/* This chunk starts after our range [x, y]. */
return y - x + 1;
}
}
x -= start - prev;
prev = start;
@ -1285,11 +1324,10 @@ sparsemap_rank_vec(sparsemap_t *map, size_t x, size_t y, bool value, sm_bitvec_t
__sm_chunk_t chunk;
__sm_chunk_map_init(&chunk, p);
result += __sm_chunk_map_rank(&chunk, &x, y - start, vec);
result += __sm_chunk_map_rank(&chunk, &x, y - start, vec, value);
p += __sm_chunk_map_get_size(&chunk);
}
return (result);
// TODO: sparsemap_rank(map, x, y, false)
return result;
}
size_t

View file

@ -381,9 +381,9 @@ sm_whats_set(sparsemap_t *map, int m)
}
bool
sm_is_span(sparsemap_t *map, sparsemap_idx_t m, size_t len, bool value)
sm_is_span(sparsemap_t *map, sparsemap_idx_t m, int len, bool value)
{
for (sparsemap_idx_t i = m; i < (sparsemap_idx_t)len; i++) {
for (sparsemap_idx_t i = m; i < m + len; i++) {
if (sparsemap_is_set(map, i) != value) {
return false;
}
@ -392,7 +392,7 @@ 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)
sm_occupied(sparsemap_t *map, sparsemap_idx_t m, int len, bool value)
{
for (sparsemap_idx_t i = m; i < (sparsemap_idx_t)len; i++) {
if (sparsemap_is_set(map, i) == value) {

View file

@ -50,5 +50,5 @@ int whats_set_uint64(uint64_t number, int bitPositions[64]);
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);
bool sm_is_span(sparsemap_t *map, sparsemap_idx_t m, int len, bool value);
bool sm_occupied(sparsemap_t *map, sparsemap_idx_t m, int len, bool value);

View file

@ -29,9 +29,9 @@
/* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */
struct sparsemap {
uint8_t *m_data;
size_t m_capacity;
size_t m_data_used;
uint8_t *m_data;
};
struct user_data {
@ -330,7 +330,7 @@ test_api_remaining_capacity(const MunitParameter params[], void *data)
cap = sparsemap_capacity_remaining(map);
} while (cap > 1.0 && errno != ENOSPC);
errno = 0;
assert_true(cap <= 1.0);
assert_true(cap <= 2.0);
return MUNIT_OK;
}
@ -665,14 +665,15 @@ 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, true);
/* First few 0/off/unset-bits in ((uint64_t)0xfeedface << 32) | 0xbadc0ffee) expressed as an array of offsets. */
int off[] = { 0, 4, 16, 17, 18, 19, 20, 21, 25, 28, 30, 36, 37, 40, 42, 49, 52, 56, 64, 65};
for (int i = 0; i < 20; i++) {
sparsemap_idx_t f = sparsemap_select(map, i, false);
assert_true(f == off[i]);
assert_true(sparsemap_is_set(map, f) == false);
}
sparsemap_idx_t f = sparsemap_select(map, 0, false);
assert_true(f == 1000);
return MUNIT_OK;
}
@ -726,7 +727,7 @@ test_api_select_neg(const MunitParameter params[], void *data)
#endif
static void *
test_api_rank_setup(const MunitParameter params[], void *user_data)
test_api_rank_true_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
@ -737,7 +738,7 @@ test_api_rank_setup(const MunitParameter params[], void *user_data)
return (void *)map;
}
static void
test_api_rank_tear_down(void *fixture)
test_api_rank_true_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map->m_data);
@ -745,7 +746,7 @@ test_api_rank_tear_down(void *fixture)
test_api_tear_down(fixture);
}
static MunitResult
test_api_rank(const MunitParameter params[], void *data)
test_api_rank_true(const MunitParameter params[], void *data)
{
int r1, r2;
sparsemap_t *map = (sparsemap_t *)data;
@ -782,6 +783,60 @@ test_api_rank(const MunitParameter params[], void *data)
return MUNIT_OK;
}
static void *
test_api_rank_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);
return (void *)map;
}
static void
test_api_rank_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_rank_false(const MunitParameter params[], void *data)
{
int r;
sparsemap_t *map = (sparsemap_t *)data;
(void)params;
assert_ptr_not_null(map);
// empty map
for (int i = 0; i < 10000; i++) {
for (int j = i; j < 10000; j++) {
r = sparsemap_rank(map, i, j, false);
assert_true(r == j - i + 1);
}
}
// one chunk means not so empty now!
sparsemap_set(map, 4999, true);
for (int i = 0; i < 10000; i++) {
for (int j = i; j < 10000; j++) {
int amt = j - i + 1 - ((4999 > i && 4999 < j) ? 1 : 0);
r = sparsemap_rank(map, i, j, false); // GSB
assert_true(r == amt);
}
}
sparsemap_set(map, 1, true);
sparsemap_set(map, 11, true);
r = sparsemap_rank(map, 0, 11, false);
assert_true(r == 10);
return MUNIT_OK;
}
static void *
test_api_span_setup(const MunitParameter params[], void *user_data)
{
@ -865,7 +920,8 @@ static MunitTest api_test_suite[] = {
#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/true", test_api_rank_true, test_api_rank_true_setup, test_api_rank_true_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/rank/false", test_api_rank_false, test_api_rank_false_setup, test_api_rank_false_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 }
};
@ -942,7 +998,7 @@ test_scale_ondrej(const MunitParameter params[], void *data)
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 i = 0; i < top / stride; i += stride) {
for (sparsemap_idx_t j = 0; j < stride; j++) {
bool set = (i != needle) ? (j < 10) : (j < 9);
sparsemap_set(map, i, set);
@ -951,9 +1007,12 @@ test_scale_ondrej(const MunitParameter params[], void *data)
errno = 0;
}
}
assert_true(sm_is_span(map, i + ((i != needle) ? 10 : 9), (i != needle) ? 8 : 9, false));
}
sparsemap_idx_t a = sparsemap_span(map, 0, 9, false);
assert_true((a / stride) == needle);
sparsemap_idx_t l = a / stride;
printf("%ld\t%ld\n", a, l);
assert_true(l == needle);
return MUNIT_OK;
}
@ -962,7 +1021,7 @@ test_scale_spans_come_spans_go_setup(const MunitParameter params[], void *user_d
{
(void)params;
(void)user_data;
sparsemap_t *map = sparsemap(10 * 1024);
sparsemap_t *map = sparsemap(1024);
assert_ptr_not_null(map);
return (void *)map;
}
@ -976,7 +1035,7 @@ test_scale_spans_come_spans_go_tear_down(void *fixture)
static MunitResult
test_scale_spans_come_spans_go(const MunitParameter params[], void *data)
{
size_t amt = 897915; // 268435456, ~5e7 interations due to 2e9 / avg(l)
size_t amt = 8192; // 268435456, ~5e7 interations due to 2e9 / avg(l)
sparsemap_t *map = (sparsemap_t *)data;
(void)params;
@ -990,8 +1049,8 @@ test_scale_spans_come_spans_go(const MunitParameter params[], void *data)
errno = 0;
}
/* After 10,000 spans are in there we consume a span every iteration. */
if (l > 10000) {
/* After 1,000 spans are in the map start consuming a span every iteration. */
if (l > 1000) {
do {
int s = munit_rand_int_range(1, 30);
int o = munit_rand_int_range(1, 268435456 - s - 1);