From 62967c455ad3c4864d5a3f092192b238a6285346 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Sun, 28 Apr 2024 17:29:36 -0400 Subject: [PATCH 01/12] WIP --- Makefile | 8 ++++---- include/sparsemap.h | 15 +++++++++++++-- src/sparsemap.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 805302d..fef99e2 100644 --- a/Makefile +++ b/Makefile @@ -5,13 +5,13 @@ SHARED_LIB = libsparsemap.so #CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC -#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -fPIC -CFLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC +CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -fPIC +#CFLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC #CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=all -fhardened -std=c11 -Iinclude/ -fPIC -#TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -Itests/ -fPIC -TEST_FLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -Itests/ -fPIC +TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -Itests/ -fPIC +#TEST_FLAGS = -Wall -Wextra -Wpedantic -Ofast -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 diff --git a/include/sparsemap.h b/include/sparsemap.h index 4c8dc7c..67b9364 100644 --- a/include/sparsemap.h +++ b/include/sparsemap.h @@ -260,11 +260,22 @@ size_t sparsemap_get_size(sparsemap_t *map); */ void sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t vec[], size_t n), size_t skip); -/** @brief Splits the bitmap by assigning all bits starting at \b offset to the +/** @brief Merges the values from \b other into the \b map, \b other is unchanged. * \b other bitmap while removing them from \b map. * * @param[in] map The sparsemap reference. - * @param[in] skip Start the scan after "skip" bits. +* @param[in] other The bitmap to merge into \b map. + */ +void sparsemap_merge(sparsemap_t *map, sparsemap_t *other); + +/** @brief Splits the bitmap by assigning all bits starting at \b offset to the + * \b other bitmap while removing them from \b map. + * + * The split must occur on a vector boundary. + * + * @param[in] map The sparsemap reference. + * @param[in] offset The 0-based offset into the bitmap at which to split. + * @param[in] other The bitmap into which we place the split. */ void sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other); diff --git a/src/sparsemap.c b/src/sparsemap.c index f439fe4..58d42c5 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1247,6 +1247,35 @@ sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t), size_t ski } } +void +sparsemap_merge(sparsemap_t *map, sparsemap_t *other) +{ + uint8_t *next_dst, *dst = __sm_get_chunk_map_data(map, 0); + + /* |src| points to the |other| (source) chunk map */ + 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); + for (i = 0; i < dst_count; i++) { + sm_idx_t src_start = *(sm_idx_t *)src; + 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(&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 { + + } + } + } +} + void sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other) { -- 2.43.4 From e5e4a0f960422b5745df66cd3b76a8a6104b9996 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 29 Apr 2024 14:28:54 -0400 Subject: [PATCH 02/12] WIP --- include/sparsemap.h | 2 +- src/sparsemap.c | 59 +++++++++++++++++++++++++++++++++------------ tests/test.c | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 17 deletions(-) diff --git a/include/sparsemap.h b/include/sparsemap.h index 67b9364..bf749aa 100644 --- a/include/sparsemap.h +++ b/include/sparsemap.h @@ -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. * * @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); diff --git a/src/sparsemap.c b/src/sparsemap.c index 58d42c5..726a047 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -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_NEXT_CHUNK_ADDR(chunk) (uint8_t *)((chunk) + sizeof(sm_idx_t) + __sm_chunk_map_get_size((__sm_chunk_t *)&(chunk))); typedef struct { 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. * @returns a pointer after the end of the used data - * @todo could this simply use m_data_used? */ static uint8_t * __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 sparsemap_merge(sparsemap_t *map, sparsemap_t *other) { - uint8_t *next_dst, *dst = __sm_get_chunk_map_data(map, 0); - - /* |src| points to the |other| (source) chunk map */ - uint8_t *next_src, *src = __sm_get_chunk_map_data(other, 0); + uint8_t *dst = __sm_get_chunk_map_data(map, 0), + *dst_tail = __sm_get_chunk_map_end(map), + *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); - 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 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(&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 { - + /* 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); } - /* Now continue with all remaining minimaps. */ + /* Now continue with all remaining chunk maps. */ for (; i < count; i++) { sm_idx_t start = *(sm_idx_t *)src; src += sizeof(sm_idx_t); diff --git a/tests/test.c b/tests/test.c index 1e930d9..ac226da 100644 --- a/tests/test.c +++ b/tests/test.c @@ -605,6 +605,56 @@ test_api_split(const MunitParameter params[], void *data) 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 * 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 *)"/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 *)"/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 }, #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 }, -- 2.43.4 From 1ab6c90257a18992957466728b6b29b025793628 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 29 Apr 2024 17:01:45 -0400 Subject: [PATCH 03/12] WIP --- src/sparsemap.c | 66 +++++++++++++++++++++++++++---------------------- tests/test.c | 18 ++++++++++++++ 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 726a047..874c7cf 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -52,7 +52,7 @@ void __attribute__((format(printf, 4, 5))) __sm_diag_(const char *file, int line #define __sm_assert(expr) \ if (!(expr)) \ - fprintf(stderr, "%s:%d:%s(): assertion failed! %s", __FILE__, __LINE__, __func__, #expr) + fprintf(stderr, "%s:%d:%s(): assertion failed! %s\n", __FILE__, __LINE__, __func__, #expr) #define __sm_when_diag(expr) \ if (1) \ @@ -1260,45 +1260,51 @@ __sm_chunk_map_merge(sparsemap_t *map, sparsemap_idx_t offset, __sm_chunk_t src) void sparsemap_merge(sparsemap_t *map, sparsemap_t *other) { - uint8_t *dst = __sm_get_chunk_map_data(map, 0), - *dst_tail = __sm_get_chunk_map_end(map), - *src = __sm_get_chunk_map_data(other, 0); + uint8_t *src, *dst, *dst_tail; + size_t 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 < src_count + dst_count;) { - __sm_chunk_t src_chunk, dst_chunk; - sm_idx_t src_start = *(sm_idx_t *)src; + dst = __sm_get_chunk_map_data(map, 0); + src = __sm_get_chunk_map_data(other, 0); + /* Foreach destination chunk, is there a source chunk with the same starting + offset? If so, if so let's merge them. */ + for (size_t i = 0; i < dst_count + src_count; i++) { + __sm_chunk_t dst_chunk; sm_idx_t dst_start = *(sm_idx_t *)dst; - __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); - - 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); + size_t j = 0; + if (i < dst_count) { + while (j < src_count) { + __sm_chunk_t src_chunk; + sm_idx_t src_start = *(sm_idx_t *)src; + __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); + if (src_start == dst_start) { + /* Chunks overlap, merge them. */ + __sm_chunk_map_merge(map, src_start, src_chunk); + dst = SM_NEXT_CHUNK_ADDR(dst); + src = SM_NEXT_CHUNK_ADDR(src); + j = SIZE_MAX; + break; + } + dst = SM_NEXT_CHUNK_ADDR(dst); + j++; + } + } + if (j != SIZE_MAX) { + __sm_chunk_t src_chunk; + sm_idx_t src_start = *(sm_idx_t *)src; + __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); /* Copy the chunk data to the buffer. */ - memcpy(dst_tail, src, s); + dst_tail = __sm_get_chunk_map_end(map); + *(sm_idx_t *)dst_tail = src_start; + size_t size = __sm_chunk_map_get_size(&src_chunk); + memcpy(dst_tail + sizeof(sm_idx_t), src + sizeof(sm_idx_t), size); /* 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; - } } } } diff --git a/tests/test.c b/tests/test.c index ac226da..6494d31 100644 --- a/tests/test.c +++ b/tests/test.c @@ -631,11 +631,29 @@ test_api_merge(const MunitParameter params[], void *data) assert_ptr_not_null(map); assert_ptr_not_null(other); + sparsemap_set(other, 0, true); + sparsemap_merge(map, other); + + assert_true(sparsemap_is_set(other, 0)); + assert_true(sparsemap_is_set(map, 0)); + + sparsemap_clear(map); + sparsemap_clear(other); + + sparsemap_set(other, 2049, true); + sparsemap_merge(map, other); + + assert_true(sparsemap_is_set(map, 2049)); + + sparsemap_clear(map); + sparsemap_clear(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)); -- 2.43.4 From 90c81c73630e992235dd5eb7982f41b7eb8d7799 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 29 Apr 2024 17:48:01 -0400 Subject: [PATCH 04/12] WIP --- src/sparsemap.c | 37 ++++++++++++++++++------------------- tests/test.c | 10 +++++----- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 874c7cf..4a1fc55 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1269,11 +1269,12 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) /* Foreach destination chunk, is there a source chunk with the same starting offset? If so, if so let's merge them. */ for (size_t i = 0; i < dst_count + src_count; i++) { + next_iteration:; __sm_chunk_t dst_chunk; sm_idx_t dst_start = *(sm_idx_t *)dst; __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); - size_t j = 0; if (i < dst_count) { + size_t j = 0; while (j < src_count) { __sm_chunk_t src_chunk; sm_idx_t src_start = *(sm_idx_t *)src; @@ -1281,31 +1282,29 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) if (src_start == dst_start) { /* Chunks overlap, merge them. */ __sm_chunk_map_merge(map, src_start, src_chunk); - dst = SM_NEXT_CHUNK_ADDR(dst); src = SM_NEXT_CHUNK_ADDR(src); - j = SIZE_MAX; - break; + dst = SM_NEXT_CHUNK_ADDR(dst); + i++; + goto next_iteration; } - dst = SM_NEXT_CHUNK_ADDR(dst); + src = __sm_get_chunk_map_data(other, 0); j++; } } - if (j != SIZE_MAX) { - __sm_chunk_t src_chunk; - sm_idx_t src_start = *(sm_idx_t *)src; - __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); + __sm_chunk_t src_chunk; + sm_idx_t src_start = *(sm_idx_t *)src; + __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); - /* Copy the chunk data to the buffer. */ - dst_tail = __sm_get_chunk_map_end(map); - *(sm_idx_t *)dst_tail = src_start; - size_t size = __sm_chunk_map_get_size(&src_chunk); - memcpy(dst_tail + sizeof(sm_idx_t), src + sizeof(sm_idx_t), size); + /* Copy the chunk data to the buffer. */ + dst_tail = __sm_get_chunk_map_end(map); + *(sm_idx_t *)dst_tail = src_start; + size_t size = __sm_chunk_map_get_size(&src_chunk); + memcpy(dst_tail + sizeof(sm_idx_t), src + sizeof(sm_idx_t), size); - /* 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); - } + /* 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); } } diff --git a/tests/test.c b/tests/test.c index 6494d31..ab4e834 100644 --- a/tests/test.c +++ b/tests/test.c @@ -648,22 +648,22 @@ test_api_merge(const MunitParameter params[], void *data) sparsemap_clear(map); sparsemap_clear(other); - sparsemap_set(map, 0, true); sparsemap_set(other, 1, true); sparsemap_set(other, 2049, true); + sparsemap_set(map, 2050, true); + sparsemap_set(other, 4097, 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, 2050)); + assert_true(sparsemap_is_set(map, 4097)); 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) + if (i == 2050 || i == 1 || i == 2049 || i == 4097 || i == 8193) continue; else assert_false(sparsemap_is_set(map, i)); -- 2.43.4 From e30cb230abcd95e4522079611bd51dc25145ec90 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 29 Apr 2024 18:05:13 -0400 Subject: [PATCH 05/12] WIP --- src/sparsemap.c | 57 ++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 4a1fc55..4ccd1c6 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1262,49 +1262,42 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) { uint8_t *src, *dst, *dst_tail; size_t src_count = __sm_get_chunk_map_count(other), - dst_count = __sm_get_chunk_map_count(map); + dst_count = __sm_get_chunk_map_count(map), + max_chunk_count = src_count + dst_count; dst = __sm_get_chunk_map_data(map, 0); src = __sm_get_chunk_map_data(other, 0); - /* Foreach destination chunk, is there a source chunk with the same starting - offset? If so, if so let's merge them. */ - for (size_t i = 0; i < dst_count + src_count; i++) { - next_iteration:; + for (size_t i = 0; i < max_chunk_count && src_count; i++) { __sm_chunk_t dst_chunk; sm_idx_t dst_start = *(sm_idx_t *)dst; __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); - if (i < dst_count) { - size_t j = 0; - while (j < src_count) { - __sm_chunk_t src_chunk; - sm_idx_t src_start = *(sm_idx_t *)src; - __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); - 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++; - goto next_iteration; - } - src = __sm_get_chunk_map_data(other, 0); - j++; - } - } + __sm_chunk_t src_chunk; sm_idx_t src_start = *(sm_idx_t *)src; __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); - /* Copy the chunk data to the buffer. */ - dst_tail = __sm_get_chunk_map_end(map); - *(sm_idx_t *)dst_tail = src_start; - size_t size = __sm_chunk_map_get_size(&src_chunk); - memcpy(dst_tail + sizeof(sm_idx_t), src + sizeof(sm_idx_t), size); + if (dst_count > 0 && 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); + dst_count--; + src_count--; + continue; + } else { + /* Copy the chunk data directly into the buffer. */ + // TODO capacity check? ENOMEM + dst_tail = __sm_get_chunk_map_end(map); + *(sm_idx_t *)dst_tail = src_start; + size_t size = __sm_chunk_map_get_size(&src_chunk); + memcpy(dst_tail + sizeof(sm_idx_t), src + sizeof(sm_idx_t), size); - /* 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); + /* 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); + src_count--; + } } } -- 2.43.4 From 47aa5c4801df857db41b22daf21f5ccb8482ae9b Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 29 Apr 2024 19:30:36 -0400 Subject: [PATCH 06/12] WIP --- src/sparsemap.c | 54 ++++++++++++++++++++++++++----------------------- tests/test.c | 2 +- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 4ccd1c6..f8db713 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -109,7 +109,6 @@ enum __SM_CHUNK_INFO { }; #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 { sm_bitvec_t *m_data; @@ -1216,9 +1215,7 @@ size_t sparsemap_get_size(sparsemap_t *map) { if (map->m_data_used) { - __sm_when_diag({ - __sm_assert(map->m_data_used == __sm_get_size_impl(map)); - }); + __sm_when_diag({ __sm_assert(map->m_data_used == __sm_get_size_impl(map)); }); return map->m_data_used; } return map->m_data_used = __sm_get_size_impl(map); @@ -1248,7 +1245,8 @@ 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) { +__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)) { @@ -1261,41 +1259,47 @@ void sparsemap_merge(sparsemap_t *map, sparsemap_t *other) { uint8_t *src, *dst, *dst_tail; - size_t src_count = __sm_get_chunk_map_count(other), - dst_count = __sm_get_chunk_map_count(map), - max_chunk_count = src_count + dst_count; + size_t src_count = __sm_get_chunk_map_count(other), dst_count = __sm_get_chunk_map_count(map), max_chunk_count = src_count + dst_count; dst = __sm_get_chunk_map_data(map, 0); src = __sm_get_chunk_map_data(other, 0); for (size_t i = 0; i < max_chunk_count && src_count; i++) { - __sm_chunk_t dst_chunk; sm_idx_t dst_start = *(sm_idx_t *)dst; - __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); - - __sm_chunk_t src_chunk; sm_idx_t src_start = *(sm_idx_t *)src; - __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); - - if (dst_count > 0 && src_start == dst_start) { + if (src_start == dst_start && dst_count > 0) { /* Chunks overlap, merge them. */ + __sm_chunk_t src_chunk; + __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); + __sm_chunk_t dst_chunk; + __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); __sm_chunk_map_merge(map, src_start, src_chunk); - src = SM_NEXT_CHUNK_ADDR(src); - dst = SM_NEXT_CHUNK_ADDR(dst); + src += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&src_chunk); + dst += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&dst_chunk); dst_count--; src_count--; continue; - } else { - /* Copy the chunk data directly into the buffer. */ - // TODO capacity check? ENOMEM - dst_tail = __sm_get_chunk_map_end(map); - *(sm_idx_t *)dst_tail = src_start; + } + if (src_start < dst_start || dst_count == 0) { + __sm_chunk_t src_chunk; + __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); + uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; size_t size = __sm_chunk_map_get_size(&src_chunk); - memcpy(dst_tail + sizeof(sm_idx_t), src + sizeof(sm_idx_t), size); + memcpy(buf, src + sizeof(sm_idx_t), size); + __sm_insert_data(map, src_start, &buf[0], sizeof(buf)); + + size_t aligned_idx = __sm_get_fully_aligned_offset(src_start); + if (src_start - aligned_idx < SM_CHUNK_MAX_CAPACITY) { + __sm_chunk_t dst_chunk; + __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); + __sm_chunk_map_set_capacity(&dst_chunk, src_start - aligned_idx); + } + *(sm_idx_t *)src = src_start = aligned_idx; /* 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); + + /* Carry on to the next chunk. */ + src += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&src_chunk); src_count--; } } diff --git a/tests/test.c b/tests/test.c index ab4e834..4eeba93 100644 --- a/tests/test.c +++ b/tests/test.c @@ -654,7 +654,7 @@ test_api_merge(const MunitParameter params[], void *data) sparsemap_set(other, 4097, true); sparsemap_set(other, 8193, true); - sparsemap_merge(map,other); + sparsemap_merge(map, other); assert_true(sparsemap_is_set(map, 1)); assert_true(sparsemap_is_set(map, 2049)); -- 2.43.4 From aeebfdd928d7e02a5e48c20f941bac6f53a2b3d7 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 29 Apr 2024 22:49:34 -0400 Subject: [PATCH 07/12] WIP --- src/sparsemap.c | 45 +++++++++++++++++++++++++-------------------- tests/test.c | 17 +++++++++++++++++ 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index f8db713..4e2b826 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -438,7 +438,7 @@ __sm_chunk_map_set(__sm_chunk_t *map, size_t idx, bool value, size_t *pos, sm_bi * SM_BITS_PER_VECTOR */ static size_t -__sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *offset, bool value) +__sm_chunk_map_select(__sm_chunk_t *map, size_t n, sparsemap_idx_t *offset, bool value) { size_t ret = 0; register uint8_t *p; @@ -509,12 +509,10 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *offset, bool value) } } } - *offset = (ssize_t)n; + *offset = n; return ret; } -extern void print_bits(char *name, uint64_t value); // GSB - /** @brief Counts the bits matching \b value in the range [0, \b idx] * inclusive after ignoring the first \b offset bits in the chunk. * @@ -1067,7 +1065,6 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value) /* Get the __sm_chunk_t which manages this index */ ssize_t offset = __sm_get_chunk_map_offset(map, idx); bool dont_grow = false; - if (map->m_data_used + sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2 > map->m_capacity) { errno = ENOSPC; return SPARSEMAP_IDX_MAX; @@ -1137,7 +1134,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value) } size_t size = __sm_chunk_map_get_size(&chunk); - offset += (ssize_t)(sizeof(sm_idx_t) + size); + offset += (sizeof(sm_idx_t) + size); p += sizeof(sm_idx_t) + size; uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; @@ -1170,7 +1167,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value) break; case SM_NEEDS_TO_GROW: if (!dont_grow) { - offset += (ssize_t)(sizeof(sm_idx_t) + position * sizeof(sm_bitvec_t)); + offset += (sizeof(sm_idx_t) + position * sizeof(sm_bitvec_t)); __sm_insert_data(map, offset, (uint8_t *)&fill, sizeof(sm_bitvec_t)); } __sm_chunk_map_set(&chunk, idx - start, value, &position, &fill, true); @@ -1182,7 +1179,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value) __sm_remove_data(map, offset, sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2); __sm_set_chunk_map_count(map, __sm_get_chunk_map_count(map) - 1); } else { - offset += (ssize_t)(sizeof(sm_idx_t) + position * sizeof(sm_bitvec_t)); + offset += (sizeof(sm_idx_t) + position * sizeof(sm_bitvec_t)); __sm_remove_data(map, offset, sizeof(sm_bitvec_t)); } break; @@ -1258,7 +1255,7 @@ __sm_chunk_map_merge(sparsemap_t *map, sparsemap_idx_t offset, __sm_chunk_t src) void sparsemap_merge(sparsemap_t *map, sparsemap_t *other) { - uint8_t *src, *dst, *dst_tail; + uint8_t *src, *dst; size_t src_count = __sm_get_chunk_map_count(other), dst_count = __sm_get_chunk_map_count(map), max_chunk_count = src_count + dst_count; dst = __sm_get_chunk_map_data(map, 0); @@ -1283,20 +1280,28 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) __sm_chunk_t src_chunk; __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; - size_t size = __sm_chunk_map_get_size(&src_chunk); - memcpy(buf, src + sizeof(sm_idx_t), size); - __sm_insert_data(map, src_start, &buf[0], sizeof(buf)); + size_t src_size = __sm_chunk_map_get_size(&src_chunk); + size_t offset = src_start + (sizeof(sm_idx_t) + src_size); + __sm_insert_data(map, offset, &buf[0], sizeof(buf)); + *(sm_idx_t *)dst = src_start; - size_t aligned_idx = __sm_get_fully_aligned_offset(src_start); - if (src_start - aligned_idx < SM_CHUNK_MAX_CAPACITY) { - __sm_chunk_t dst_chunk; - __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); - __sm_chunk_map_set_capacity(&dst_chunk, src_start - aligned_idx); - } - *(sm_idx_t *)src = src_start = aligned_idx; + __sm_chunk_t dst_chunk; + __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); /* Update the chunk count and data_used. */ __sm_set_chunk_map_count(map, __sm_get_chunk_map_count(map) + 1); + if (other->m_data_used != 0) { + other->m_data_used += sizeof(sm_idx_t) + sizeof(sm_bitvec_t); + } + size_t capacity = __sm_chunk_map_get_capacity(&src_chunk); + + /* Reduce the capacity of the source-chunk map. */ + __sm_chunk_map_set_capacity(&dst_chunk, offset % capacity); + + /* + uint8_t *src_data = __sm_get_chunk_map_data(other, src_start); + memcpy(&buf, src_data, src_size); + */ /* Carry on to the next chunk. */ src += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&src_chunk); @@ -1441,7 +1446,7 @@ sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value) __sm_chunk_t chunk; __sm_chunk_map_init(&chunk, p); - ssize_t new_n = (ssize_t)n; + ssize_t new_n = n; size_t index = __sm_chunk_map_select(&chunk, n, &new_n, value); if (new_n == -1) { return start + index; diff --git a/tests/test.c b/tests/test.c index 4eeba93..f1feeb8 100644 --- a/tests/test.c +++ b/tests/test.c @@ -631,6 +631,8 @@ test_api_merge(const MunitParameter params[], void *data) assert_ptr_not_null(map); assert_ptr_not_null(other); + sparsemap_merge(map, other); + sparsemap_set(other, 0, true); sparsemap_merge(map, other); @@ -640,6 +642,21 @@ test_api_merge(const MunitParameter params[], void *data) sparsemap_clear(map); sparsemap_clear(other); + sparsemap_set(map, 0, true); + sparsemap_set(other, 0, true); + sparsemap_merge(map, other); + + sparsemap_clear(map); + sparsemap_clear(other); + + sparsemap_set(map, 0, true); + sparsemap_merge(map, other); + + assert_true(sparsemap_is_set(map, 0)); + + sparsemap_clear(map); + sparsemap_clear(other); + sparsemap_set(other, 2049, true); sparsemap_merge(map, other); -- 2.43.4 From fbf122fbda0b143f6ed77169b0e1f114a42432e0 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 29 Apr 2024 23:06:41 -0400 Subject: [PATCH 08/12] WIP --- src/sparsemap.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 4e2b826..a34ad6c 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1279,29 +1279,12 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) if (src_start < dst_start || dst_count == 0) { __sm_chunk_t src_chunk; __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); - uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; size_t src_size = __sm_chunk_map_get_size(&src_chunk); - size_t offset = src_start + (sizeof(sm_idx_t) + src_size); - __sm_insert_data(map, offset, &buf[0], sizeof(buf)); + __sm_insert_data(map, src_start, src, src_size); *(sm_idx_t *)dst = src_start; - __sm_chunk_t dst_chunk; - __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); - /* Update the chunk count and data_used. */ __sm_set_chunk_map_count(map, __sm_get_chunk_map_count(map) + 1); - if (other->m_data_used != 0) { - other->m_data_used += sizeof(sm_idx_t) + sizeof(sm_bitvec_t); - } - size_t capacity = __sm_chunk_map_get_capacity(&src_chunk); - - /* Reduce the capacity of the source-chunk map. */ - __sm_chunk_map_set_capacity(&dst_chunk, offset % capacity); - - /* - uint8_t *src_data = __sm_get_chunk_map_data(other, src_start); - memcpy(&buf, src_data, src_size); - */ /* Carry on to the next chunk. */ src += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&src_chunk); -- 2.43.4 From bd8a1f0b0cbc01a8ea02708bb933553fd6666850 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 29 Apr 2024 23:09:37 -0400 Subject: [PATCH 09/12] WIP --- src/sparsemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index a34ad6c..1636d63 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1280,7 +1280,7 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) __sm_chunk_t src_chunk; __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); size_t src_size = __sm_chunk_map_get_size(&src_chunk); - __sm_insert_data(map, src_start, src, src_size); + __sm_insert_data(map, dst_start, src, src_size); *(sm_idx_t *)dst = src_start; /* Update the chunk count and data_used. */ -- 2.43.4 From b399e8af7813a9bd3f0f217a0ccff5f2ea793f9c Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 30 Apr 2024 10:44:43 -0400 Subject: [PATCH 10/12] WIP --- src/sparsemap.c | 20 ++++++++++++++++---- tests/test.c | 26 +++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 1636d63..8c4530d 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -825,7 +825,8 @@ __sm_get_fully_aligned_offset(size_t idx) * * @param[in] map The sparsemap_t in question. * @param[in] idx The index of the chunk map to locate. - * @returns the byte offset of a __sm_chunk_t in m_data. + * @returns the byte offset of a __sm_chunk_t in m_data, or -1 there + * are no chunks. */ static size_t __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx) @@ -843,7 +844,7 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx) __sm_assert(s == __sm_get_aligned_offset(s)); __sm_chunk_t chunk; __sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t)); - if (s >= idx || (unsigned long)idx < s + __sm_chunk_map_get_capacity(&chunk)) { + if (s >= idx || idx < s + __sm_chunk_map_get_capacity(&chunk)) { break; } p += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&chunk); @@ -1070,7 +1071,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value) return SPARSEMAP_IDX_MAX; } - /* If there is no __sm_chunk_t and the bit is set to zero then return + /* If there are no __sm_chunk_t and the bit is set to zero then return immediately; otherwise create an initial __sm_chunk_t. */ if (offset == -1) { if (value == false) { @@ -1270,6 +1271,7 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) __sm_chunk_t dst_chunk; __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); __sm_chunk_map_merge(map, src_start, src_chunk); + *(sm_idx_t *)dst = __sm_get_aligned_offset(src_start); src += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&src_chunk); dst += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&dst_chunk); dst_count--; @@ -1280,14 +1282,24 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) __sm_chunk_t src_chunk; __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); size_t src_size = __sm_chunk_map_get_size(&src_chunk); - __sm_insert_data(map, dst_start, src, src_size); + uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; + if (dst_count == 0) { + __sm_append_data(map, &buf[0], sizeof(buf)); + } else { + size_t offset = __sm_get_chunk_map_offset(map, dst_start); + __sm_insert_data(map, offset, &buf[0], sizeof(buf)); + } + memcpy(dst + sizeof(sm_idx_t), &src_chunk, src_size); *(sm_idx_t *)dst = src_start; /* Update the chunk count and data_used. */ __sm_set_chunk_map_count(map, __sm_get_chunk_map_count(map) + 1); /* Carry on to the next chunk. */ + __sm_chunk_t dst_chunk; + __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); src += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&src_chunk); + dst += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&dst_chunk); src_count--; } } diff --git a/tests/test.c b/tests/test.c index f1feeb8..82bef5c 100644 --- a/tests/test.c +++ b/tests/test.c @@ -631,8 +631,10 @@ test_api_merge(const MunitParameter params[], void *data) assert_ptr_not_null(map); assert_ptr_not_null(other); + // Merge two empty maps to get an empty map. sparsemap_merge(map, other); + // Merge a single set bit in the first chunk into the empty map. sparsemap_set(other, 0, true); sparsemap_merge(map, other); @@ -642,6 +644,7 @@ test_api_merge(const MunitParameter params[], void *data) sparsemap_clear(map); sparsemap_clear(other); + // Merge two maps with the same single bit set. sparsemap_set(map, 0, true); sparsemap_set(other, 0, true); sparsemap_merge(map, other); @@ -649,6 +652,7 @@ test_api_merge(const MunitParameter params[], void *data) sparsemap_clear(map); sparsemap_clear(other); + // Merge an empty map with one that has the first bit set. sparsemap_set(map, 0, true); sparsemap_merge(map, other); @@ -680,12 +684,32 @@ test_api_merge(const MunitParameter params[], void *data) assert_true(sparsemap_is_set(map, 8193)); for (int i = 0; i < 10000; i++) { - if (i == 2050 || i == 1 || i == 2049 || i == 4097 || i == 8193) + if (i == 2049 || i == 1 || i == 2050 || i == 4097 || i == 8193) continue; else assert_false(sparsemap_is_set(map, i)); } + sparsemap_clear(map); + sparsemap_clear(other); + + sparsemap_set(map, 0, true); + sparsemap_set(map, 2048, true); + sparsemap_set(map, 2049, true); + sparsemap_set(map, 8193, true); + for (int i = 2049; i < 4096; i++) { + sparsemap_set(other, i, true); + } + + sparsemap_merge(map, other); + + assert(sparsemap_is_set(map, 0)); + assert(sparsemap_is_set(map, 2048)); + assert(sparsemap_is_set(map, 8193)); + for (int i = 2049; i < 4096; i++) { + assert(sparsemap_is_set(map, i)); + } + free(other); return MUNIT_OK; } -- 2.43.4 From 9a6ea9519a793d04c199ee1fbdd1c7de1df843aa Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 30 Apr 2024 10:51:23 -0400 Subject: [PATCH 11/12] WIP --- src/sparsemap.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 8c4530d..552de55 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1282,15 +1282,12 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) __sm_chunk_t src_chunk; __sm_chunk_map_init(&src_chunk, src + sizeof(sm_idx_t)); size_t src_size = __sm_chunk_map_get_size(&src_chunk); - uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; if (dst_count == 0) { - __sm_append_data(map, &buf[0], sizeof(buf)); + __sm_append_data(map, src, sizeof(sm_idx_t) + src_size); } else { size_t offset = __sm_get_chunk_map_offset(map, dst_start); - __sm_insert_data(map, offset, &buf[0], sizeof(buf)); + __sm_insert_data(map, offset, src, sizeof(sm_idx_t) + src_size); } - memcpy(dst + sizeof(sm_idx_t), &src_chunk, src_size); - *(sm_idx_t *)dst = src_start; /* Update the chunk count and data_used. */ __sm_set_chunk_map_count(map, __sm_get_chunk_map_count(map) + 1); -- 2.43.4 From 3e3ca8db5e7549e8dbd722626c4695d1368260df Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 30 Apr 2024 11:17:37 -0400 Subject: [PATCH 12/12] WIP --- src/sparsemap.c | 6 ++++++ tests/test.c | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 552de55..57d1e79 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1264,6 +1264,12 @@ sparsemap_merge(sparsemap_t *map, sparsemap_t *other) for (size_t i = 0; i < max_chunk_count && src_count; i++) { sm_idx_t dst_start = *(sm_idx_t *)dst; sm_idx_t src_start = *(sm_idx_t *)src; + if (src_start > dst_start && dst_count > 0) { + __sm_chunk_t dst_chunk; + __sm_chunk_map_init(&dst_chunk, dst + sizeof(sm_idx_t)); + dst += sizeof(sm_idx_t) + __sm_chunk_map_get_size(&dst_chunk); + continue; + } if (src_start == dst_start && dst_count > 0) { /* Chunks overlap, merge them. */ __sm_chunk_t src_chunk; diff --git a/tests/test.c b/tests/test.c index 82bef5c..ffc7138 100644 --- a/tests/test.c +++ b/tests/test.c @@ -702,7 +702,6 @@ test_api_merge(const MunitParameter params[], void *data) } sparsemap_merge(map, other); - assert(sparsemap_is_set(map, 0)); assert(sparsemap_is_set(map, 2048)); assert(sparsemap_is_set(map, 8193)); -- 2.43.4