fix scan
This commit is contained in:
parent
6b6ed5290f
commit
c9ae042b40
4 changed files with 63 additions and 44 deletions
|
@ -533,6 +533,21 @@ verify_empty_sparsemap(sparsemap_t *map, pgno_t pg, unsigned len)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
verify_sm_is_first_available_span(sparsemap_t *map, sparsemap_idx_t idx, size_t len, bool value)
|
||||||
|
{
|
||||||
|
for (sparsemap_idx_t i = 0; i < idx + len; i++) {
|
||||||
|
sparsemap_idx_t j = 0;
|
||||||
|
while (sparsemap_is_set(map, i + j) == value && j < len && j < idx + len) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (j == len) {
|
||||||
|
return i == idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
verify_sm_eq_ml(sparsemap_t *map, MDB_IDL list)
|
verify_sm_eq_ml(sparsemap_t *map, MDB_IDL list)
|
||||||
{
|
{
|
||||||
|
@ -702,6 +717,7 @@ main(void)
|
||||||
sl = pgno;
|
sl = pgno;
|
||||||
e = nsts();
|
e = nsts();
|
||||||
td_add(b_span_loc, e - b, 1);
|
td_add(b_span_loc, e - b, 1);
|
||||||
|
assert(verify_sm_is_first_available_span(map, pgno, n, true));
|
||||||
}
|
}
|
||||||
assert(verify_span_midl(list, sl, n));
|
assert(verify_span_midl(list, sl, n));
|
||||||
assert(verify_span_sparsemap(map, sl, n));
|
assert(verify_span_sparsemap(map, sl, n));
|
||||||
|
@ -761,24 +777,25 @@ main(void)
|
||||||
// Once we've used half of the free list, let's replenish it a bit.
|
// Once we've used half of the free list, let's replenish it a bit.
|
||||||
if (list[0] < amt / 2) {
|
if (list[0] < amt / 2) {
|
||||||
do {
|
do {
|
||||||
pgno_t pg;
|
pgno_t pgno;
|
||||||
size_t len, retries = amt;
|
size_t len, retries = amt;
|
||||||
do {
|
do {
|
||||||
len = toss(15) + 1;
|
len = toss(15) + 1;
|
||||||
pg = sparsemap_span(map, 0, len, false);
|
pgno = sparsemap_span(map, 0, len, false);
|
||||||
|
assert(verify_sm_is_first_available_span(map, pgno, n, false));
|
||||||
//__diag("%zu\t%zu,%zu\n", iterations, replenish, retries);
|
//__diag("%zu\t%zu,%zu\n", iterations, replenish, retries);
|
||||||
} while (SPARSEMAP_NOT_FOUND(pg) && --retries);
|
} while (SPARSEMAP_NOT_FOUND(pgno) && --retries);
|
||||||
if (retries == 0) {
|
if (retries == 0) {
|
||||||
goto larger_please;
|
goto larger_please;
|
||||||
}
|
}
|
||||||
if (SPARSEMAP_FOUND(pg)) {
|
if (SPARSEMAP_FOUND(pgno)) {
|
||||||
assert(verify_empty_midl(list, pg, len));
|
assert(verify_empty_midl(list, pgno, len));
|
||||||
assert(verify_empty_sparsemap(map, pg, len));
|
assert(verify_empty_sparsemap(map, pgno, len));
|
||||||
assert(verify_sm_eq_ml(map, list));
|
assert(verify_sm_eq_ml(map, list));
|
||||||
if (list[-1] - list[0] < len) {
|
if (list[-1] - list[0] < len) {
|
||||||
mdb_midl_need(&list, list[-1] + len);
|
mdb_midl_need(&list, list[-1] + len);
|
||||||
}
|
}
|
||||||
for (size_t i = pg; i < pg + len; i++) {
|
for (size_t i = pgno; i < pgno + len; i++) {
|
||||||
assert(verify_midl_contains(list, i) == false);
|
assert(verify_midl_contains(list, i) == false);
|
||||||
assert(sparsemap_is_set(map, i) == false);
|
assert(sparsemap_is_set(map, i) == false);
|
||||||
mdb_midl_insert(list, i);
|
mdb_midl_insert(list, i);
|
||||||
|
@ -788,8 +805,8 @@ main(void)
|
||||||
}
|
}
|
||||||
mdb_midl_sort(list);
|
mdb_midl_sort(list);
|
||||||
assert(verify_midl_nodups(list));
|
assert(verify_midl_nodups(list));
|
||||||
assert(verify_span_midl(list, pg, len));
|
assert(verify_span_midl(list, pgno, len));
|
||||||
assert(verify_span_sparsemap(map, pg, len));
|
assert(verify_span_sparsemap(map, pgno, len));
|
||||||
}
|
}
|
||||||
assert(verify_sm_eq_ml(map, list));
|
assert(verify_sm_eq_ml(map, list));
|
||||||
replenish++;
|
replenish++;
|
||||||
|
|
|
@ -249,16 +249,14 @@ size_t sparsemap_get_size(sparsemap_t *map);
|
||||||
/** @brief Provides a method for a callback function to examine every bit set in
|
/** @brief Provides a method for a callback function to examine every bit set in
|
||||||
* the index.
|
* the index.
|
||||||
*
|
*
|
||||||
* This decompresses the whole bitmap and invokes #scanner() passing a 64bit
|
* This decompresses the whole bitmap and invokes #scanner() passing an array
|
||||||
* "vector" of bits in order from 0 index to the end of the map. Using standard
|
* of the positions of set bits in order from 0 index to the end of the map.
|
||||||
* bit masking techniques it is possible to read each bit from LSB to MSB in
|
|
||||||
* these vectors to read the entire content of the bitmap index (see
|
|
||||||
* examples/ex_4.c).
|
|
||||||
*
|
*
|
||||||
* @param[in] map The sparsemap reference.
|
* @param[in] map The sparsemap reference.
|
||||||
* @param[in] skip Start the scan after "skip" bits.
|
* @param[in] skip Start the scan after \b skip position in the map.
|
||||||
|
* @param[in] aux Auxiliary information passed to the scanner.
|
||||||
*/
|
*/
|
||||||
void sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t vec[], size_t n), size_t skip);
|
void sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t vec[], size_t n, void *aux), size_t skip, void *aux);
|
||||||
|
|
||||||
/** @brief Merges the values from \b other into the \b map, \b other is unchanged.
|
/** @brief Merges the values from \b other into the \b map, \b other is unchanged.
|
||||||
* \b other bitmap while removing them from \b map.
|
* \b other bitmap while removing them from \b map.
|
||||||
|
|
|
@ -680,24 +680,27 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, size_t *pos,
|
||||||
* @param[in] map The chunk in question.
|
* @param[in] map The chunk in question.
|
||||||
* @param[in] start
|
* @param[in] start
|
||||||
* @param[in] scanner
|
* @param[in] scanner
|
||||||
|
* @param[in] skip The number of
|
||||||
* @returns the number of (set) bits that were passed to the scanner
|
* @returns the number of (set) bits that were passed to the scanner
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[], size_t), size_t skip)
|
__sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[], size_t, void *aux), size_t skip, void *aux)
|
||||||
{
|
{
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
register uint8_t *p = (uint8_t *)map->m_data;
|
register uint8_t *p = (uint8_t *)map->m_data;
|
||||||
sm_idx_t buffer[SM_BITS_PER_VECTOR];
|
sm_idx_t buffer[SM_BITS_PER_VECTOR];
|
||||||
for (size_t i = 0; i < sizeof(sm_bitvec_t); i++, p++) {
|
for (size_t i = 0; i < sizeof(sm_bitvec_t); i++, p++) {
|
||||||
if (*p == 0) {
|
if (*p == 0) {
|
||||||
/* skip the zeroes */
|
/* Skip chunks that are all zeroes. */
|
||||||
|
skip -= skip > SM_BITS_PER_VECTOR ? SM_BITS_PER_VECTOR : skip;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < SM_FLAGS_PER_INDEX_BYTE; j++) {
|
for (int j = 0; j < SM_FLAGS_PER_INDEX_BYTE; j++) {
|
||||||
size_t flags = SM_CHUNK_GET_FLAGS(*p, j);
|
size_t flags = SM_CHUNK_GET_FLAGS(*p, j);
|
||||||
if (flags == SM_PAYLOAD_NONE || flags == SM_PAYLOAD_ZEROS) {
|
if (flags == SM_PAYLOAD_NONE || flags == SM_PAYLOAD_ZEROS) {
|
||||||
/* ignore the zeroes */
|
/* Skip when all zeroes. */
|
||||||
|
skip -= skip > SM_BITS_PER_VECTOR ? SM_BITS_PER_VECTOR : skip;
|
||||||
} else if (flags == SM_PAYLOAD_ONES) {
|
} else if (flags == SM_PAYLOAD_ONES) {
|
||||||
if (skip) {
|
if (skip) {
|
||||||
if (skip >= SM_BITS_PER_VECTOR) {
|
if (skip >= SM_BITS_PER_VECTOR) {
|
||||||
|
@ -709,26 +712,31 @@ __sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[
|
||||||
for (size_t b = skip; b < SM_BITS_PER_VECTOR; b++) {
|
for (size_t b = skip; b < SM_BITS_PER_VECTOR; b++) {
|
||||||
buffer[n++] = start + b;
|
buffer[n++] = start + b;
|
||||||
}
|
}
|
||||||
scanner(&buffer[0], n);
|
scanner(&buffer[0], n, aux);
|
||||||
ret += n;
|
ret += n;
|
||||||
skip = 0;
|
skip = 0;
|
||||||
} else {
|
} else {
|
||||||
for (size_t b = 0; b < SM_BITS_PER_VECTOR; b++) {
|
for (size_t b = 0; b < SM_BITS_PER_VECTOR; b++) {
|
||||||
buffer[b] = start + b;
|
buffer[b] = start + b;
|
||||||
}
|
}
|
||||||
scanner(&buffer[0], SM_BITS_PER_VECTOR);
|
scanner(&buffer[0], SM_BITS_PER_VECTOR, aux);
|
||||||
ret += SM_BITS_PER_VECTOR;
|
ret += SM_BITS_PER_VECTOR;
|
||||||
}
|
}
|
||||||
} else if (flags == SM_PAYLOAD_MIXED) {
|
} 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)];
|
sm_bitvec_t w = map->m_data[1 + __sm_chunk_map_get_position(map, i * SM_FLAGS_PER_INDEX_BYTE + j)];
|
||||||
int n = 0;
|
size_t n = 0;
|
||||||
if (skip) {
|
if (skip) {
|
||||||
|
if (skip >= SM_BITS_PER_VECTOR) {
|
||||||
|
skip -= SM_BITS_PER_VECTOR;
|
||||||
|
ret += SM_BITS_PER_VECTOR;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (int b = 0; b < SM_BITS_PER_VECTOR; b++) {
|
for (int b = 0; b < SM_BITS_PER_VECTOR; b++) {
|
||||||
if (w & ((sm_bitvec_t)1 << b)) {
|
if (skip > 0) {
|
||||||
|
|
||||||
skip--;
|
skip--;
|
||||||
continue;
|
continue;
|
||||||
// TODO: unreachable lines below... why?
|
}
|
||||||
|
if (w & ((sm_bitvec_t)1 << b)) {
|
||||||
buffer[n++] = start + b;
|
buffer[n++] = start + b;
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
|
@ -742,7 +750,7 @@ __sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[
|
||||||
ret += n;
|
ret += n;
|
||||||
}
|
}
|
||||||
__sm_assert(n > 0);
|
__sm_assert(n > 0);
|
||||||
scanner(&buffer[0], n);
|
scanner(&buffer[0], n, aux);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -993,10 +1001,6 @@ sparsemap_open(sparsemap_t *map, uint8_t *data, size_t size)
|
||||||
map->m_capacity = size;
|
map->m_capacity = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO/NOTE: This is a dangerous operation because we cannot verify that
|
|
||||||
* data_size is not exceeding the size of the underlying buffer.
|
|
||||||
*/
|
|
||||||
sparsemap_t *
|
sparsemap_t *
|
||||||
sparsemap_set_data_size(sparsemap_t *map, size_t size, uint8_t *data)
|
sparsemap_set_data_size(sparsemap_t *map, size_t size, uint8_t *data)
|
||||||
{
|
{
|
||||||
|
@ -1020,7 +1024,9 @@ sparsemap_set_data_size(sparsemap_t *map, size_t size, uint8_t *data)
|
||||||
m->m_data = (uint8_t *)(((uintptr_t)m + sizeof(sparsemap_t)) & ~(uintptr_t)7);
|
m->m_data = (uint8_t *)(((uintptr_t)m + sizeof(sparsemap_t)) & ~(uintptr_t)7);
|
||||||
__sm_when_diag({ __sm_assert(IS_8_BYTE_ALIGNED(m->m_data)); }) return m;
|
__sm_when_diag({ __sm_assert(IS_8_BYTE_ALIGNED(m->m_data)); }) return m;
|
||||||
} else {
|
} else {
|
||||||
if (data != NULL && data_size > sparsemap_get_capacity(map) && data != map->m_data) {
|
/* NOTE: It is up to the caller to realloc their buffer and provide it here
|
||||||
|
for reassignment. */
|
||||||
|
if (data != NULL && data_size > sparsemap_get_capacity(map) && data != map->m_data) {
|
||||||
map->m_data = data;
|
map->m_data = data;
|
||||||
}
|
}
|
||||||
map->m_capacity = size;
|
map->m_capacity = size;
|
||||||
|
@ -1240,7 +1246,7 @@ sparsemap_get_size(sparsemap_t *map)
|
||||||
* Decompresses the whole bitmap; calls scanner for all bits.
|
* Decompresses the whole bitmap; calls scanner for all bits.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t), size_t skip)
|
sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t, void *aux), size_t skip, void *aux)
|
||||||
{
|
{
|
||||||
uint8_t *p = __sm_get_chunk_map_data(map, 0);
|
uint8_t *p = __sm_get_chunk_map_data(map, 0);
|
||||||
size_t count = __sm_get_chunk_map_count(map);
|
size_t count = __sm_get_chunk_map_count(map);
|
||||||
|
@ -1250,7 +1256,7 @@ sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t), size_t ski
|
||||||
p += sizeof(sm_idx_t);
|
p += sizeof(sm_idx_t);
|
||||||
__sm_chunk_t chunk;
|
__sm_chunk_t chunk;
|
||||||
__sm_chunk_map_init(&chunk, p);
|
__sm_chunk_map_init(&chunk, p);
|
||||||
size_t skipped = __sm_chunk_map_scan(&chunk, start, scanner, skip);
|
size_t skipped = __sm_chunk_map_scan(&chunk, start, scanner, skip, aux);
|
||||||
if (skip) {
|
if (skip) {
|
||||||
assert(skip >= skipped);
|
assert(skip >= skipped);
|
||||||
skip -= skipped;
|
skip -= skipped;
|
||||||
|
|
20
tests/test.c
20
tests/test.c
|
@ -524,10 +524,7 @@ 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);
|
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);
|
||||||
sm_bitmap_from_uint64(map, 0, ((uint64_t)0xfeedface << 32) | 0xbadc0ffee);
|
|
||||||
|
|
||||||
return (void *)map;
|
return (void *)map;
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
|
@ -539,11 +536,14 @@ test_api_scan_tear_down(void *fixture)
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
scan_for_0xfeedfacebadcoffee(sm_idx_t v[], size_t n)
|
scan_for_0xfeedfacebadcoffee(sm_idx_t v[], size_t n, void *aux)
|
||||||
{
|
{
|
||||||
/* Called multiple times */
|
size_t bit_pos[] = {1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 22, 23, 24, 26, 27, 29, 31, 32, 33, 34, 35, 38, 39, 41, 43, 44, 45, 46, 47, 48, 50, 51, 53, 54, 55, 57, 58, 59, 60, 61, 62, 63};
|
||||||
((void)v);
|
(void)aux;
|
||||||
((void)n);
|
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
assert(v[i] == bit_pos[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_scan(const MunitParameter params[], void *data)
|
test_api_scan(const MunitParameter params[], void *data)
|
||||||
|
@ -552,10 +552,8 @@ test_api_scan(const MunitParameter params[], void *data)
|
||||||
(void)params;
|
(void)params;
|
||||||
|
|
||||||
assert_ptr_not_null(map);
|
assert_ptr_not_null(map);
|
||||||
|
sm_bitmap_from_uint64(map, 0, ((uint64_t)0xfeedface << 32) | 0xbadc0ffee);
|
||||||
sparsemap_set(map, 4200, true);
|
sparsemap_scan(map, scan_for_0xfeedfacebadcoffee, 0, NULL);
|
||||||
assert_true(sparsemap_is_set(map, 4200));
|
|
||||||
sparsemap_scan(map, scan_for_0xfeedfacebadcoffee, 0);
|
|
||||||
|
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue