adding a merge map function #6
3 changed files with 95 additions and 17 deletions
|
@ -264,7 +264,7 @@ void sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t vec[], size_t n),
|
||||||
* \b other bitmap while removing them from \b map.
|
* \b other bitmap while removing them from \b map.
|
||||||
*
|
*
|
||||||
* @param[in] map The sparsemap reference.
|
* @param[in] map The sparsemap reference.
|
||||||
* @param[in] other The bitmap to merge into \b map.
|
* @param[in] other The bitmap to merge into \b map.
|
||||||
*/
|
*/
|
||||||
void sparsemap_merge(sparsemap_t *map, sparsemap_t *other);
|
void sparsemap_merge(sparsemap_t *map, sparsemap_t *other);
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,7 @@ enum __SM_CHUNK_INFO {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SM_CHUNK_GET_FLAGS(from, at) (((from)) & ((sm_bitvec_t)SM_FLAG_MASK << ((at)*2))) >> ((at)*2)
|
#define SM_CHUNK_GET_FLAGS(from, at) (((from)) & ((sm_bitvec_t)SM_FLAG_MASK << ((at)*2))) >> ((at)*2)
|
||||||
|
#define SM_NEXT_CHUNK_ADDR(chunk) (uint8_t *)((chunk) + sizeof(sm_idx_t) + __sm_chunk_map_get_size((__sm_chunk_t *)&(chunk)));
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sm_bitvec_t *m_data;
|
sm_bitvec_t *m_data;
|
||||||
|
@ -763,7 +764,6 @@ __sm_get_chunk_map_data(sparsemap_t *map, size_t offset)
|
||||||
*
|
*
|
||||||
* @param[in] map The sparsemap_t in question.
|
* @param[in] map The sparsemap_t in question.
|
||||||
* @returns a pointer after the end of the used data
|
* @returns a pointer after the end of the used data
|
||||||
* @todo could this simply use m_data_used?
|
|
||||||
*/
|
*/
|
||||||
static uint8_t *
|
static uint8_t *
|
||||||
__sm_get_chunk_map_end(sparsemap_t *map)
|
__sm_get_chunk_map_end(sparsemap_t *map)
|
||||||
|
@ -1247,30 +1247,57 @@ sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t), size_t ski
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__sm_chunk_map_merge(sparsemap_t *map, sparsemap_idx_t offset, __sm_chunk_t src) {
|
||||||
|
size_t capacity = __sm_chunk_map_get_capacity(&src);
|
||||||
|
for (sparsemap_idx_t j = 0; j < capacity; j++, offset++) {
|
||||||
|
if (__sm_chunk_map_is_set(&src, j)) {
|
||||||
|
sparsemap_set(map, offset, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sparsemap_merge(sparsemap_t *map, sparsemap_t *other)
|
sparsemap_merge(sparsemap_t *map, sparsemap_t *other)
|
||||||
{
|
{
|
||||||
uint8_t *next_dst, *dst = __sm_get_chunk_map_data(map, 0);
|
uint8_t *dst = __sm_get_chunk_map_data(map, 0),
|
||||||
|
*dst_tail = __sm_get_chunk_map_end(map),
|
||||||
/* |src| points to the |other| (source) chunk map */
|
*src = __sm_get_chunk_map_data(other, 0);
|
||||||
uint8_t *next_src, *src = __sm_get_chunk_map_data(other, 0);
|
|
||||||
|
|
||||||
size_t i, src_count = __sm_get_chunk_map_count(other), dst_count = __sm_get_chunk_map_count(map);
|
size_t i, src_count = __sm_get_chunk_map_count(other), dst_count = __sm_get_chunk_map_count(map);
|
||||||
for (i = 0; i < dst_count; i++) {
|
for (i = 0; i < src_count + dst_count;) {
|
||||||
|
__sm_chunk_t src_chunk, dst_chunk;
|
||||||
sm_idx_t src_start = *(sm_idx_t *)src;
|
sm_idx_t src_start = *(sm_idx_t *)src;
|
||||||
sm_idx_t dst_start = *(sm_idx_t *)dst;
|
sm_idx_t dst_start = *(sm_idx_t *)dst;
|
||||||
__sm_chunk_t src_chunk, dst_chunk;
|
|
||||||
__sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t));
|
__sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t));
|
||||||
__sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
__sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
||||||
if (src_start == dst_start) {
|
|
||||||
__sm_chunk_map_merge(dst, src);
|
|
||||||
} else {
|
|
||||||
next_dst = dst + sizeof(sm_idx_t) + __sm_chunk_map_get_size(&dst_chunk);
|
|
||||||
next_src = dst + sizeof(sm_idx_t) + __sm_chunk_map_get_size(&src_chunk);
|
|
||||||
if (src_start != next_dst) {
|
|
||||||
// Copy the chunk.
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
if (src_start == dst_start) {
|
||||||
|
/* Chunks overlap, merge them. */
|
||||||
|
__sm_chunk_map_merge(map, src_start, src_chunk);
|
||||||
|
src = SM_NEXT_CHUNK_ADDR(src);
|
||||||
|
dst = SM_NEXT_CHUNK_ADDR(dst);
|
||||||
|
i += 2;
|
||||||
|
} else if (src_start < dst_start || i > dst_count) {
|
||||||
|
/* Copy the src chunk into the dest map. */
|
||||||
|
size_t s = __sm_chunk_map_get_size(&src_chunk);
|
||||||
|
|
||||||
|
/* Copy the index (sm_idx_t) */
|
||||||
|
*(sm_idx_t *)dst_tail = src_start;
|
||||||
|
dst_tail += sizeof(sm_idx_t);
|
||||||
|
|
||||||
|
/* Copy the chunk data to the buffer. */
|
||||||
|
memcpy(dst_tail, src, s);
|
||||||
|
|
||||||
|
/* Update the chunk count and data_used. */
|
||||||
|
map->m_data_used = 0;
|
||||||
|
__sm_set_chunk_map_count(map, __sm_get_chunk_map_count(map) + 1);
|
||||||
|
|
||||||
|
src = SM_NEXT_CHUNK_ADDR(src);
|
||||||
|
i += 1;
|
||||||
|
if (i > dst_count) {
|
||||||
|
dst = SM_NEXT_CHUNK_ADDR(dst);
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1363,7 +1390,7 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
|
||||||
__sm_chunk_map_set_capacity(&s_chunk, offset % capacity);
|
__sm_chunk_map_set_capacity(&s_chunk, offset % capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now continue with all remaining minimaps. */
|
/* Now continue with all remaining chunk maps. */
|
||||||
for (; i < count; i++) {
|
for (; i < count; i++) {
|
||||||
sm_idx_t start = *(sm_idx_t *)src;
|
sm_idx_t start = *(sm_idx_t *)src;
|
||||||
src += sizeof(sm_idx_t);
|
src += sizeof(sm_idx_t);
|
||||||
|
|
51
tests/test.c
51
tests/test.c
|
@ -605,6 +605,56 @@ test_api_split(const MunitParameter params[], void *data)
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
test_api_merge_setup(const MunitParameter params[], void *user_data)
|
||||||
|
{
|
||||||
|
(void)params;
|
||||||
|
(void)user_data;
|
||||||
|
sparsemap_t *map = sparsemap(10 * 1024);
|
||||||
|
assert_ptr_not_null(map);
|
||||||
|
return (void *)map;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
test_api_merge_tear_down(void *fixture)
|
||||||
|
{
|
||||||
|
sparsemap_t *map = (sparsemap_t *)fixture;
|
||||||
|
assert_ptr_not_null(map);
|
||||||
|
munit_free(map);
|
||||||
|
}
|
||||||
|
static MunitResult
|
||||||
|
test_api_merge(const MunitParameter params[], void *data)
|
||||||
|
{
|
||||||
|
sparsemap_t *map = (sparsemap_t *)data;
|
||||||
|
sparsemap_t *other = sparsemap(1024);
|
||||||
|
(void)params;
|
||||||
|
|
||||||
|
assert_ptr_not_null(map);
|
||||||
|
assert_ptr_not_null(other);
|
||||||
|
|
||||||
|
sparsemap_set(map, 0, true);
|
||||||
|
sparsemap_set(other, 1, true);
|
||||||
|
sparsemap_set(other, 2049, true);
|
||||||
|
sparsemap_set(other, 8193, true);
|
||||||
|
sparsemap_set(other, 8194, true);
|
||||||
|
sparsemap_merge(map,other);
|
||||||
|
|
||||||
|
assert_true(sparsemap_is_set(map, 0));
|
||||||
|
assert_true(sparsemap_is_set(map, 1));
|
||||||
|
assert_true(sparsemap_is_set(map, 2049));
|
||||||
|
assert_true(sparsemap_is_set(map, 8193));
|
||||||
|
assert_true(sparsemap_is_set(map, 8194));
|
||||||
|
|
||||||
|
for (int i = 0; i < 10000; i++) {
|
||||||
|
if (i == 0 || i == 1 || i == 2049 || i == 8193 || i == 8194)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
assert_false(sparsemap_is_set(map, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(other);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_select_setup(const MunitParameter params[], void *user_data)
|
test_api_select_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
|
@ -919,6 +969,7 @@ 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 *)"/merge", test_api_merge, test_api_merge_setup, test_api_merge_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 },
|
{ (char *)"/select/true", test_api_select, test_api_select_setup, test_api_select_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
#ifdef SELECT_FALSE
|
#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 },
|
{ (char *)"/select/false", test_api_select_false, test_api_select_false_setup, test_api_select_false_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
|
|
Loading…
Reference in a new issue