From 4eb1d463b29b122f440e37662506aa4316f3d758 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 14 May 2024 21:00:02 -0400 Subject: [PATCH 1/4] WIP --- Makefile | 8 +- src/sparsemap.c | 319 ++++++++++++++++++++++++++---------------------- tests/test.c | 51 ++++---- 3 files changed, 210 insertions(+), 168 deletions(-) diff --git a/Makefile b/Makefile index 1eb2aa4..1f7f43e 100644 --- a/Makefile +++ b/Makefile @@ -6,15 +6,15 @@ SHARED_LIB = libsparsemap.so LIBS = -lm #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 = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC +CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -fPIC +#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Og -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 = -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 diff --git a/src/sparsemap.c b/src/sparsemap.c index 0da2391..bc2ae1a 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -264,15 +264,15 @@ __sm_chunk_increase_capacity(__sm_chunk_t *chunk, size_t capacity) size_t increased = 0; register uint8_t *p = (uint8_t *)chunk->m_data; - for (size_t i = 0; i < sizeof(sm_bitvec_t); i++) { + for (size_t i = 0; i < sizeof(sm_bitvec_t); i++, p++) { if (!*p || *p == 0xff) { continue; } 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) { - p[i] &= ~((sm_bitvec_t)SM_PAYLOAD_ONES << (j * 2)); - p[i] |= ((sm_bitvec_t)SM_PAYLOAD_ZEROS << (j * 2)); + *p &= ~((sm_bitvec_t)SM_PAYLOAD_ONES << (j * 2)); + *p |= ((sm_bitvec_t)SM_PAYLOAD_ZEROS << (j * 2)); increased += SM_BITS_PER_VECTOR; if (increased + initial_capacity == capacity) { __sm_assert(__sm_chunk_get_capacity(chunk) == capacity); @@ -962,8 +962,8 @@ __sm_remove_data(sparsemap_t *map, size_t offset, size_t gap_size) * * @param[in] chunk The chunk in question. * @param[in] offset The offset of the first bit in the chunk to be merged. - * @todo merge vectors rather than call sparsemap_set() in a loop */ +#if 0 void __sm_merge_chunk(sparsemap_t *chunk, sparsemap_idx_t offset, __sm_chunk_t src) { @@ -974,7 +974,7 @@ __sm_merge_chunk(sparsemap_t *chunk, sparsemap_idx_t offset, __sm_chunk_t src) } } } -#if 0 +#endif void __sm_merge_chunk(sparsemap_t *map, sparsemap_idx_t idx, sparsemap_idx_t capacity, __sm_chunk_t *dst_chunk, __sm_chunk_t *src_chunk) { @@ -1003,7 +1003,6 @@ __sm_merge_chunk(sparsemap_t *map, sparsemap_idx_t idx, sparsemap_idx_t capacity } } } -#endif /* * The following is the "Sparsemap" implementation, it uses chunks (code above) @@ -1190,7 +1189,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value) __sm_append_data(map, &buf[0], sizeof(buf)); uint8_t *p = __sm_get_chunk_data(map, 0); - *(sm_idx_t *)p = __sm_get_chunk_aligned_offset(idx); // TODO: vector aligned? + *(sm_idx_t *)p = __sm_get_vector_aligned_offset(idx); // TODO: vector or chunk aligned? __sm_set_chunk_count(map, 1); @@ -1411,35 +1410,6 @@ size_t sparsemap_count(sparsemap_t *map) { return sparsemap_rank(map, 0, SPARSEMAP_IDX_MAX, true); -#if 0 - size_t c = 0, count = __sm_get_chunk_count(map); - - if (count == 0) { - return 0; - } - uint8_t *p = __sm_get_chunk_data(map, 0); - for (size_t i = 0; i < count; i++) { - p += sizeof(sm_idx_t); - __sm_chunk_t chunk; - __sm_chunk_init(&chunk, p); - for (size_t m = 0; m < sizeof(sm_bitvec_t); m++, p++) { - for (int n = 0; n < SM_FLAGS_PER_INDEX_BYTE; n++) { - size_t flags = SM_CHUNK_GET_FLAGS(*p, n); - if (flags == SM_PAYLOAD_NONE) { - continue; - } else if (flags == SM_PAYLOAD_ZEROS) { - continue; - } else if (flags == SM_PAYLOAD_ONES) { - c += SM_BITS_PER_VECTOR; - } else if (flags == SM_PAYLOAD_MIXED) { - sm_bitvec_t w = chunk.m_data[1 + __sm_chunk_get_position(&chunk, m * SM_FLAGS_PER_INDEX_BYTE + n)]; - c += popcountll(w); - } - } - } - } - return c; -#endif } void @@ -1463,75 +1433,121 @@ sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t, void *aux), } int -sparsemap_merge(sparsemap_t *map, sparsemap_t *other) +sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) { uint8_t *src, *dst; - size_t src_count = __sm_get_chunk_count(other); - size_t dst_count = __sm_get_chunk_count(map); - size_t max_chunk_count = src_count + dst_count; - ssize_t difference = map->m_capacity - (other->m_data_used + src_count * (sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2)); + size_t src_count = __sm_get_chunk_count(source); + sparsemap_idx_t src_starting_offset = sparsemap_get_starting_offset(source); + sparsemap_idx_t src_ending_offset = sparsemap_get_ending_offset(source); + sparsemap_idx_t dst_ending_offset = sparsemap_get_ending_offset(destination); - /* Estimate worst-case overhead required for merge. */ - if (difference <= 0) { - errno = ENOSPC; - return -difference; + if (src_count == 0) { + return 0; } - dst = __sm_get_chunk_data(map, 0); - src = __sm_get_chunk_data(other, 0); - for (size_t i = 0; i < max_chunk_count && src_count; i++) { + ssize_t remaining_capacity = destination->m_capacity - destination->m_data_used - + (source->m_data_used + src_count * (sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2)); + + /* Estimate worst-case overhead required for merge. */ + if (remaining_capacity <= 0) { + errno = ENOSPC; + return -remaining_capacity; + } + + size_t i = src_starting_offset; + size_t merge_end_offset = __sm_get_chunk_aligned_offset(src_ending_offset) + SM_CHUNK_MAX_CAPACITY; + while (i <= merge_end_offset) { + ssize_t src_offset = __sm_get_chunk_offset(source, i); + src = __sm_get_chunk_data(source, src_offset); sm_idx_t src_start = *(sm_idx_t *)src; - sm_idx_t dst_start = *(sm_idx_t *)dst; - src_start = __sm_get_chunk_aligned_offset(src_start); - dst_start = __sm_get_chunk_aligned_offset(dst_start); - if (src_start > dst_start && dst_count > 0) { + __sm_chunk_t src_chunk; + __sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t)); + size_t src_capacity = __sm_chunk_get_capacity(&src_chunk); + ssize_t dst_offset = __sm_get_chunk_offset(destination, src_start); + if (dst_offset >= 0) { + dst = __sm_get_chunk_data(destination, dst_offset); + sm_idx_t dst_start = *(sm_idx_t *)dst; __sm_chunk_t dst_chunk; __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); - dst_count--; - continue; - } - if (src_start == dst_start && dst_count > 0) { - /* Chunks overlap, merge them. */ - __sm_chunk_t src_chunk; - __sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t)); - __sm_chunk_t dst_chunk; - __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); - __sm_merge_chunk(map, src_start, src_chunk); - *(sm_idx_t *)dst = __sm_get_chunk_aligned_offset(src_start); - src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); - dst_count--; - src_count--; - continue; - } - if (src_start < dst_start || dst_count == 0) { - __sm_chunk_t src_chunk; - __sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t)); - size_t src_size = __sm_chunk_get_size(&src_chunk); - if (dst_count == 0) { - __sm_append_data(map, src, sizeof(sm_idx_t) + src_size); - } else { - size_t offset = __sm_get_chunk_offset(map, dst_start); - __sm_insert_data(map, offset, src, sizeof(sm_idx_t) + src_size); + size_t dst_capacity = __sm_chunk_get_capacity(&dst_chunk); + + /* Source chunk precedes next destination chunk. */ + if ((src_start + src_capacity) <= dst_start) { + size_t src_size = __sm_chunk_get_size(&src_chunk); + size_t offset = __sm_get_chunk_offset(destination, dst_start); + __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); + /* Update the chunk count and data_used. */ + __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); + i += src_capacity; + continue; } - /* Update the chunk count and data_used. */ - __sm_set_chunk_count(map, __sm_get_chunk_count(map) + 1); + /* Source chunk follows next destination chunk. */ + if (src_start >= (dst_start + dst_capacity)) { + size_t src_size = __sm_chunk_get_size(&src_chunk); + __sm_append_data(destination, src, sizeof(sm_idx_t) + src_size); + /* Update the chunk count and data_used. */ + __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); + i += src_capacity; + continue; + } - /* Carry on to the next chunk. */ - __sm_chunk_t dst_chunk; - __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); - src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); - src_count--; + if (src_start == dst_start) { + if (dst_capacity < src_capacity) { + __sm_chunk_increase_capacity(&dst_chunk, src_capacity); + dst_capacity = __sm_chunk_get_capacity(&dst_chunk); + } + __sm_merge_chunk(destination, src_start, dst_capacity, &dst_chunk, &src_chunk); + i += dst_capacity; + continue; + } + + if (dst_start < src_start) { + if (dst_capacity < src_capacity) { + __sm_chunk_increase_capacity(&dst_chunk, src_capacity); + } + size_t src_end = src_start + src_capacity; + sparsemap_idx_t n = src_start; + while (n < src_end) { + if (sparsemap_is_set(source, n)) { + sparsemap_set(destination, n, true); + } + n++; + } + i = src_end; + continue; + } + assert(!"shouldn't be here"); // TODO... + } else { + if (src_start > dst_ending_offset || dst_offset == -1) { + /* Starting offset is after destination chunks, so append data. */ + size_t src_size = __sm_chunk_get_size(&src_chunk); + __sm_append_data(destination, src, sizeof(sm_idx_t) + src_size); + + /* Update the chunk count and data_used. */ + __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); + + i += src_capacity; + continue; + } else { + /* Source chunk precedes next destination chunk. */ + size_t src_size = __sm_chunk_get_size(&src_chunk); + size_t offset = __sm_get_chunk_offset(destination, src_start); + __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); + + /* Update the chunk count and data_used. */ + __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); + + i += src_capacity; + continue; + } } } return 0; } -#if 0 + int -sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) +__sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) { uint8_t *src, *dst; size_t src_count = __sm_get_chunk_count(source); @@ -1551,66 +1567,80 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) for (size_t i = 0; i < max_chunk_count && src_count; i++) { sm_idx_t src_start = *(sm_idx_t *)src; sm_idx_t dst_start = *(sm_idx_t *)dst; - src_start = __sm_get_chunk_aligned_offset(src_start); - dst_start = __sm_get_chunk_aligned_offset(dst_start); - if (src_start > dst_start && dst_count > 0) { - __sm_chunk_t dst_chunk; - __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); - dst_count--; - continue; - } - if (src_start == dst_start && dst_count > 0) { - /* Chunks overlap, merge them. */ - __sm_chunk_t src_chunk; - __sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t)); - __sm_chunk_t dst_chunk; - __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); - size_t src_capacity = __sm_chunk_get_capacity(&src_chunk); - size_t dst_capacity = __sm_chunk_get_capacity(&dst_chunk); - if (dst_capacity < src_capacity) { - __sm_chunk_increase_capacity(&dst_chunk, src_capacity); - } - if (*(sm_idx_t *)dst > *(sm_idx_t *)src) { - *(sm_idx_t *)dst = *(sm_idx_t *)src; - } - __sm_merge_chunk(destination, src_start, src_capacity, &dst_chunk, &src_chunk); - src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); - dst_count--; - src_count--; - continue; - } - if (src_start < dst_start || dst_count == 0) { - __sm_chunk_t src_chunk; - __sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t)); + __sm_chunk_t src_chunk; + __sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t)); + __sm_chunk_t dst_chunk; + __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); + size_t src_capacity = __sm_chunk_get_capacity(&src_chunk); + size_t dst_capacity = __sm_chunk_get_capacity(&dst_chunk); + /* Chunks do not overlap. */ + if (dst_count == 0) { + /* No destination chunks, so append data. */ size_t src_size = __sm_chunk_get_size(&src_chunk); - if (dst_count == 0) { - __sm_append_data(destination, src, sizeof(sm_idx_t) + src_size); - } else { - size_t offset = __sm_get_chunk_offset(destination, dst_start); - __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); - } + __sm_append_data(destination, src, sizeof(sm_idx_t) + src_size); /* Update the chunk count and data_used. */ __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); - - /* Carry on to the next chunk. */ - __sm_chunk_t dst_chunk; - __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); - src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); src_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); + } else if (src_start >= (dst_start + dst_capacity) || dst_start >= (src_start + src_capacity)) { + if (src_start < dst_start) { + /* Source chunk precedes next destination chunk. */ + size_t src_size = __sm_chunk_get_size(&src_chunk); + size_t offset = __sm_get_chunk_offset(destination, dst_start); + __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); + + /* Update the chunk count and data_used. */ + __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); + src_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); + } else { + /* Source chunk follows destination chunk. */ + dst_count--; + dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); + continue; + } + } else { + /* Chunks overlap to some degree, determine the overlapping range. */ + if (dst_capacity < src_capacity) { + __sm_chunk_increase_capacity(&dst_chunk, src_capacity); + dst_capacity = __sm_chunk_get_capacity(&dst_chunk); + } + sparsemap_idx_t src_end = src_start + src_capacity; + sparsemap_idx_t dst_end = dst_start + dst_capacity; + sparsemap_idx_t overlap_start = (src_start > dst_start) ? src_start : dst_start; + sparsemap_idx_t overlap_end = (src_end < dst_end) ? src_end : dst_end; + size_t overlap_length = overlap_end - overlap_start; + if (overlap_length == src_capacity) { + /* 100% overlap */ + __sm_merge_chunk(destination, src_start, overlap_length, &dst_chunk, &src_chunk); + src_count--; + dst_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); + dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); + } else { + /* Potentially three sections to merge. */ + if (src_start < overlap_start) { + __sm_merge_chunk(destination, src_start, overlap_length - src_start, &dst_chunk, &src_chunk); + } + __sm_merge_chunk(destination, overlap_start, overlap_end - overlap_start, &dst_chunk, &src_chunk); + if (overlap_end < dst_end) { + __sm_merge_chunk(destination, overlap_end, dst_end - overlap_end, &dst_chunk, &src_chunk); + } + src_count--; + dst_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); + dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); + } } } return 0; } -#endif sparsemap_idx_t sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other) { - if (!(offset == SPARSEMAP_IDX_MAX) && (offset < 0 || offset >= sparsemap_get_ending_offset(map))) { + if (!(offset == SPARSEMAP_IDX_MAX) && offset >= sparsemap_get_ending_offset(map)) { return 0; } @@ -1677,6 +1707,7 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other) other->m_data_used += sizeof(sm_idx_t) + sizeof(sm_bitvec_t); } + sm_idx_t start = *(sm_idx_t *)src; src += sizeof(sm_idx_t); __sm_chunk_t s_chunk; __sm_chunk_init(&s_chunk, src); @@ -1687,13 +1718,14 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other) __sm_chunk_reduce_capacity(&d_chunk, __sm_get_vector_aligned_offset(capacity - (offset % capacity))); /* Now copy the bits. */ - sparsemap_idx_t d = offset; sparsemap_idx_t b = __sm_get_vector_aligned_offset(offset % capacity); - for (size_t j = offset % capacity; j < capacity; j++, d++) { - if (__sm_chunk_is_set(&s_chunk, j)) { - assert(sparsemap_set(other, d, true) == d); - if (j > b && (j - b) % capacity < SM_BITS_PER_VECTOR) { - sparsemap_set(map, d, false); + for (size_t j = start; j < capacity + start; j++) { + if (j >= offset) { + if (__sm_chunk_is_set(&s_chunk, j - start)) { + sparsemap_set(other, j, true); + if (j >= b && (j - b) % capacity < SM_BITS_PER_VECTOR) { + sparsemap_set(map, j, false); + } } } } @@ -1704,7 +1736,8 @@ sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other) i++; /* Reduce the capacity of the source-chunk effectively erases bits. */ - __sm_chunk_reduce_capacity(&s_chunk, b + SM_BITS_PER_VECTOR); + size_t r = __sm_get_vector_aligned_offset(((offset - start) % capacity) + SM_BITS_PER_VECTOR); + __sm_chunk_reduce_capacity(&s_chunk, r); } /* Now continue with all remaining chunks. */ diff --git a/tests/test.c b/tests/test.c index a4f461d..34e37ab 100644 --- a/tests/test.c +++ b/tests/test.c @@ -733,15 +733,15 @@ test_api_split(const MunitParameter params[], void *data) sparsemap_split(map, seg + off, &portion); - for (sparsemap_idx_t i = 0; i < off; i++) { - assert_true(sparsemap_is_set(map, i + seg)); - assert_false(sparsemap_is_set(&portion, i + seg)); + for (sparsemap_idx_t i = seg; i < seg + 1024; i++) { + if (i < seg + off) { + assert_true(sparsemap_is_set(map, i)); + assert_false(sparsemap_is_set(&portion, i)); + } else { + assert_false(sparsemap_is_set(map, i)); + assert_true(sparsemap_is_set(&portion, i)); + } } - for (sparsemap_idx_t i = off + 1; i < 1024; i++) { - assert_false(sparsemap_is_set(map, i + seg)); - assert_true(sparsemap_is_set(&portion, i + seg)); - } - sparsemap_clear(map); sparsemap_clear(&portion); } @@ -820,10 +820,8 @@ test_api_merge(const MunitParameter params[], void *data) // Merge a single set bit in the first chunk into the empty map. 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); @@ -831,49 +829,42 @@ test_api_merge(const MunitParameter params[], void *data) sparsemap_set(map, 0, true); sparsemap_set(other, 0, true); sparsemap_merge(map, other); - + assert_true(sparsemap_is_set(map, 0)); 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); - 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(other, 1, true); sparsemap_set(other, 2049, true); sparsemap_set(map, 2050, true); sparsemap_set(other, 4097, true); sparsemap_set(map, 6113, true); sparsemap_set(other, 8193, true); - sparsemap_merge(map, other); - 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, 6113)); assert_true(sparsemap_is_set(map, 8193)); - for (int i = 0; i < 10000; i++) { if (i == 2049 || i == 1 || i == 2050 || i == 4097 || i == 6113 || i == 8193) continue; else assert_false(sparsemap_is_set(map, i)); } - sparsemap_clear(map); sparsemap_clear(other); @@ -883,15 +874,33 @@ test_api_merge(const MunitParameter params[], void *data) 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)); } + sparsemap_clear(map); + sparsemap_clear(other); + + for (int i = 2049; i < 4096; i++) { + sparsemap_set(map, i, true); + } + sparsemap_split(map, 2051, other); + for (int i = 2049; i < 4096; i++) { + if (i < 2051) { + assert_true(sparsemap_is_set(map, i)); + assert_false(sparsemap_is_set(other, i)); + } else { + assert_false(sparsemap_is_set(map, i)); + assert_true(sparsemap_is_set(other, i)); + } + } + sparsemap_merge(map, other); + for (int i = 2049; i < 4096; i++) { + sparsemap_is_set(map, i); + } munit_free(other); return MUNIT_OK; -- 2.45.2 From 79a91f0864e0f27a592aae8cde73a25220ca2e19 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 14 May 2024 22:30:02 -0400 Subject: [PATCH 2/4] WIP --- src/sparsemap.c | 129 ++++++------------------------------------------ 1 file changed, 15 insertions(+), 114 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index bc2ae1a..71b366a 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -960,34 +960,24 @@ __sm_remove_data(sparsemap_t *map, size_t offset, size_t gap_size) /** @brief Merges into the chunk at \b offset all set bits from \b src. * - * @param[in] chunk The chunk in question. + * @param[in] map The map the chunk belongs too. * @param[in] offset The offset of the first bit in the chunk to be merged. */ -#if 0 void -__sm_merge_chunk(sparsemap_t *chunk, sparsemap_idx_t offset, __sm_chunk_t src) -{ - size_t capacity = __sm_chunk_get_capacity(&src); - for (sparsemap_idx_t j = 0; j < capacity; j++, offset++) { - if (__sm_chunk_is_set(&src, j)) { - sparsemap_set(chunk, offset, true); - } - } -} -#endif -void -__sm_merge_chunk(sparsemap_t *map, sparsemap_idx_t idx, sparsemap_idx_t capacity, __sm_chunk_t *dst_chunk, __sm_chunk_t *src_chunk) +__sm_merge_chunk(sparsemap_t *map, sparsemap_idx_t src_start, sparsemap_idx_t dst_start, sparsemap_idx_t capacity, __sm_chunk_t *dst_chunk, + __sm_chunk_t *src_chunk) { + ssize_t delta = src_start - dst_start; for (sparsemap_idx_t j = 0; j < capacity; j++) { - sparsemap_idx_t offset = __sm_get_chunk_offset(map, idx + j); - if (__sm_chunk_is_set(src_chunk, j) && !__sm_chunk_is_set(dst_chunk, j)) { + sparsemap_idx_t offset = __sm_get_chunk_offset(map, src_start + j); + if (__sm_chunk_is_set(src_chunk, j) && !__sm_chunk_is_set(dst_chunk, j + delta)) { size_t position; sm_bitvec_t fill; - switch (__sm_chunk_set(dst_chunk, j, true, &position, &fill, false)) { + switch (__sm_chunk_set(dst_chunk, j + delta, true, &position, &fill, false)) { case SM_NEEDS_TO_GROW: offset += sizeof(sm_idx_t) + position * sizeof(sm_bitvec_t); __sm_insert_data(map, offset, (uint8_t *)&fill, sizeof(sm_bitvec_t)); - __sm_chunk_set(dst_chunk, j, true, &position, &fill, true); + __sm_chunk_set(dst_chunk, j + delta, true, &position, &fill, true); break; case SM_NEEDS_TO_SHRINK: if (__sm_chunk_is_empty(src_chunk)) { @@ -1497,7 +1487,7 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) __sm_chunk_increase_capacity(&dst_chunk, src_capacity); dst_capacity = __sm_chunk_get_capacity(&dst_chunk); } - __sm_merge_chunk(destination, src_start, dst_capacity, &dst_chunk, &src_chunk); + __sm_merge_chunk(destination, src_start, dst_start, dst_capacity, &dst_chunk, &src_chunk); i += dst_capacity; continue; } @@ -1507,14 +1497,16 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) __sm_chunk_increase_capacity(&dst_chunk, src_capacity); } size_t src_end = src_start + src_capacity; - sparsemap_idx_t n = src_start; - while (n < src_end) { + size_t dst_end = dst_start + dst_capacity; + size_t overlap = src_end > dst_end ? src_capacity - (src_end - dst_end) : src_capacity; + __sm_merge_chunk(destination, src_start, dst_start, overlap, &dst_chunk, &src_chunk); + i = src_start + overlap; + for (size_t n = i; n < src_end; n++) { if (sparsemap_is_set(source, n)) { sparsemap_set(destination, n, true); } - n++; + i++; } - i = src_end; continue; } assert(!"shouldn't be here"); // TODO... @@ -1546,97 +1538,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) return 0; } -int -__sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) -{ - uint8_t *src, *dst; - size_t src_count = __sm_get_chunk_count(source); - size_t dst_count = __sm_get_chunk_count(destination); - size_t max_chunk_count = src_count + dst_count; - ssize_t remaining_capacity = destination->m_capacity - destination->m_data_used - - (source->m_data_used + src_count * (sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2)); - - /* Estimate worst-case overhead required for merge. */ - if (remaining_capacity <= 0) { - errno = ENOSPC; - return -remaining_capacity; - } - - src = __sm_get_chunk_data(source, 0); - dst = __sm_get_chunk_data(destination, 0); - for (size_t i = 0; i < max_chunk_count && src_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; - __sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t)); - __sm_chunk_t dst_chunk; - __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); - size_t src_capacity = __sm_chunk_get_capacity(&src_chunk); - size_t dst_capacity = __sm_chunk_get_capacity(&dst_chunk); - /* Chunks do not overlap. */ - if (dst_count == 0) { - /* No destination chunks, so append data. */ - size_t src_size = __sm_chunk_get_size(&src_chunk); - __sm_append_data(destination, src, sizeof(sm_idx_t) + src_size); - - /* Update the chunk count and data_used. */ - __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); - src_count--; - src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); - } else if (src_start >= (dst_start + dst_capacity) || dst_start >= (src_start + src_capacity)) { - if (src_start < dst_start) { - /* Source chunk precedes next destination chunk. */ - size_t src_size = __sm_chunk_get_size(&src_chunk); - size_t offset = __sm_get_chunk_offset(destination, dst_start); - __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); - - /* Update the chunk count and data_used. */ - __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); - src_count--; - src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); - } else { - /* Source chunk follows destination chunk. */ - dst_count--; - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); - continue; - } - } else { - /* Chunks overlap to some degree, determine the overlapping range. */ - if (dst_capacity < src_capacity) { - __sm_chunk_increase_capacity(&dst_chunk, src_capacity); - dst_capacity = __sm_chunk_get_capacity(&dst_chunk); - } - sparsemap_idx_t src_end = src_start + src_capacity; - sparsemap_idx_t dst_end = dst_start + dst_capacity; - sparsemap_idx_t overlap_start = (src_start > dst_start) ? src_start : dst_start; - sparsemap_idx_t overlap_end = (src_end < dst_end) ? src_end : dst_end; - size_t overlap_length = overlap_end - overlap_start; - if (overlap_length == src_capacity) { - /* 100% overlap */ - __sm_merge_chunk(destination, src_start, overlap_length, &dst_chunk, &src_chunk); - src_count--; - dst_count--; - src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); - } else { - /* Potentially three sections to merge. */ - if (src_start < overlap_start) { - __sm_merge_chunk(destination, src_start, overlap_length - src_start, &dst_chunk, &src_chunk); - } - __sm_merge_chunk(destination, overlap_start, overlap_end - overlap_start, &dst_chunk, &src_chunk); - if (overlap_end < dst_end) { - __sm_merge_chunk(destination, overlap_end, dst_end - overlap_end, &dst_chunk, &src_chunk); - } - src_count--; - dst_count--; - src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); - dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk); - } - } - } - return 0; -} - sparsemap_idx_t sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other) { -- 2.45.2 From b0c74459ab35c0aa6572c49cf394efe6c08a3e40 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Wed, 15 May 2024 11:39:31 -0400 Subject: [PATCH 3/4] WIP --- src/sparsemap.c | 74 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/src/sparsemap.c b/src/sparsemap.c index 71b366a..0df933d 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -871,10 +871,10 @@ __sm_get_chunk_aligned_offset(size_t idx) * * @param[in] map The sparsemap_t in question. * @param[in] idx The index of the chunk to locate. - * @returns the byte offset of a __sm_chunk_t in m_data, or -1 there + * @returns the byte offset of a __sm_chunk_t in m_data, or -1 if there * are no chunks. */ -static size_t +static ssize_t __sm_get_chunk_offset(sparsemap_t *map, sparsemap_idx_t idx) { size_t count = __sm_get_chunk_count(map); @@ -962,6 +962,7 @@ __sm_remove_data(sparsemap_t *map, size_t offset, size_t gap_size) * * @param[in] map The map the chunk belongs too. * @param[in] offset The offset of the first bit in the chunk to be merged. + * @todo merge at the vector level not offset */ void __sm_merge_chunk(sparsemap_t *map, sparsemap_idx_t src_start, sparsemap_idx_t dst_start, sparsemap_idx_t capacity, __sm_chunk_t *dst_chunk, @@ -969,7 +970,7 @@ __sm_merge_chunk(sparsemap_t *map, sparsemap_idx_t src_start, sparsemap_idx_t ds { ssize_t delta = src_start - dst_start; for (sparsemap_idx_t j = 0; j < capacity; j++) { - sparsemap_idx_t offset = __sm_get_chunk_offset(map, src_start + j); + ssize_t offset = __sm_get_chunk_offset(map, src_start + j); if (__sm_chunk_is_set(src_chunk, j) && !__sm_chunk_is_set(dst_chunk, j + delta)) { size_t position; sm_bitvec_t fill; @@ -989,6 +990,9 @@ __sm_merge_chunk(sparsemap_t *map, sparsemap_idx_t src_start, sparsemap_idx_t ds __sm_remove_data(map, offset, sizeof(sm_bitvec_t)); } break; + case SM_OK: + default: + break; } } } @@ -1205,7 +1209,7 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value) uint8_t buf[sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2] = { 0 }; __sm_insert_data(map, offset, &buf[0], sizeof(buf)); - size_t aligned_idx = __sm_get_chunk_aligned_offset(idx); + size_t aligned_idx = __sm_get_chunk_aligned_offset(idx); // TODO: vector or chunk alignment? if (start - aligned_idx < SM_CHUNK_MAX_CAPACITY) { __sm_chunk_t chunk; __sm_chunk_init(&chunk, p + sizeof(sm_idx_t)); @@ -1446,9 +1450,8 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) size_t i = src_starting_offset; size_t merge_end_offset = __sm_get_chunk_aligned_offset(src_ending_offset) + SM_CHUNK_MAX_CAPACITY; - while (i <= merge_end_offset) { - ssize_t src_offset = __sm_get_chunk_offset(source, i); - src = __sm_get_chunk_data(source, src_offset); + src = __sm_get_chunk_data(source, 0); + while (src_count) { sm_idx_t src_start = *(sm_idx_t *)src; __sm_chunk_t src_chunk; __sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t)); @@ -1461,57 +1464,74 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) __sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t)); size_t dst_capacity = __sm_chunk_get_capacity(&dst_chunk); + /* Try to expand the capacity if there's room before the start of the next chunk. */ + if (src_start == dst_start && dst_capacity < src_capacity) { + ssize_t nxt_offset = __sm_get_chunk_offset(destination, dst_start + dst_capacity + 1); + uint8_t *nxt_dst = __sm_get_chunk_data(destination, nxt_offset); + sm_idx_t nxt_dst_start = *(sm_idx_t *)nxt_dst; + if (nxt_dst_start > dst_start + src_capacity) { + __sm_chunk_increase_capacity(&dst_chunk, src_capacity); + dst_capacity = __sm_chunk_get_capacity(&dst_chunk); + } + } + /* Source chunk precedes next destination chunk. */ if ((src_start + src_capacity) <= dst_start) { size_t src_size = __sm_chunk_get_size(&src_chunk); - size_t offset = __sm_get_chunk_offset(destination, dst_start); + ssize_t offset = __sm_get_chunk_offset(destination, dst_start); __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); /* Update the chunk count and data_used. */ __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); i += src_capacity; + src_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; } /* Source chunk follows next destination chunk. */ if (src_start >= (dst_start + dst_capacity)) { size_t src_size = __sm_chunk_get_size(&src_chunk); - __sm_append_data(destination, src, sizeof(sm_idx_t) + src_size); + if (dst_offset == __sm_get_chunk_offset(destination, SPARSEMAP_IDX_MAX)) { + __sm_append_data(destination, src, sizeof(sm_idx_t) + src_size); + } else { + ssize_t offset = __sm_get_chunk_offset(destination, src_start); + __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); + } /* Update the chunk count and data_used. */ __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); i += src_capacity; + src_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; } - if (src_start == dst_start) { - if (dst_capacity < src_capacity) { - __sm_chunk_increase_capacity(&dst_chunk, src_capacity); - dst_capacity = __sm_chunk_get_capacity(&dst_chunk); - } + /* Source and destination and a perfect overlapping pair. */ + if (src_start == dst_start && src_capacity == dst_capacity) { __sm_merge_chunk(destination, src_start, dst_start, dst_capacity, &dst_chunk, &src_chunk); - i += dst_capacity; + i += src_capacity; + src_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; } - if (dst_start < src_start) { - if (dst_capacity < src_capacity) { - __sm_chunk_increase_capacity(&dst_chunk, src_capacity); - } + /* Non-uniform overlapping chunks. */ + if (dst_start < src_start || (dst_start == src_start && dst_capacity != src_capacity)) { size_t src_end = src_start + src_capacity; size_t dst_end = dst_start + dst_capacity; size_t overlap = src_end > dst_end ? src_capacity - (src_end - dst_end) : src_capacity; __sm_merge_chunk(destination, src_start, dst_start, overlap, &dst_chunk, &src_chunk); - i = src_start + overlap; - for (size_t n = i; n < src_end; n++) { + for (size_t n = src_start + overlap; n <= src_end; n++) { if (sparsemap_is_set(source, n)) { sparsemap_set(destination, n, true); } - i++; } + i += src_capacity; + src_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; } - assert(!"shouldn't be here"); // TODO... } else { - if (src_start > dst_ending_offset || dst_offset == -1) { + if (src_start >= dst_ending_offset) { /* Starting offset is after destination chunks, so append data. */ size_t src_size = __sm_chunk_get_size(&src_chunk); __sm_append_data(destination, src, sizeof(sm_idx_t) + src_size); @@ -1520,17 +1540,21 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); i += src_capacity; + src_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; } else { /* Source chunk precedes next destination chunk. */ size_t src_size = __sm_chunk_get_size(&src_chunk); - size_t offset = __sm_get_chunk_offset(destination, src_start); + ssize_t offset = __sm_get_chunk_offset(destination, src_start); __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); /* Update the chunk count and data_used. */ __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); i += src_capacity; + src_count--; + src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; } } -- 2.45.2 From c8e0e51b8dc67e1310fab793d5d02fe33a4a660b Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Wed, 15 May 2024 13:56:08 -0400 Subject: [PATCH 4/4] working --- Makefile | 8 ++++---- src/sparsemap.c | 10 ---------- tests/test.c | 3 +++ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 1f7f43e..1eb2aa4 100644 --- a/Makefile +++ b/Makefile @@ -6,15 +6,15 @@ SHARED_LIB = libsparsemap.so LIBS = -lm #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 = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC +#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -fPIC +CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Og -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 = -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 diff --git a/src/sparsemap.c b/src/sparsemap.c index 0df933d..ac11708 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1431,8 +1431,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) { uint8_t *src, *dst; size_t src_count = __sm_get_chunk_count(source); - sparsemap_idx_t src_starting_offset = sparsemap_get_starting_offset(source); - sparsemap_idx_t src_ending_offset = sparsemap_get_ending_offset(source); sparsemap_idx_t dst_ending_offset = sparsemap_get_ending_offset(destination); if (src_count == 0) { @@ -1448,8 +1446,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) return -remaining_capacity; } - size_t i = src_starting_offset; - size_t merge_end_offset = __sm_get_chunk_aligned_offset(src_ending_offset) + SM_CHUNK_MAX_CAPACITY; src = __sm_get_chunk_data(source, 0); while (src_count) { sm_idx_t src_start = *(sm_idx_t *)src; @@ -1482,7 +1478,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) __sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size); /* Update the chunk count and data_used. */ __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); - i += src_capacity; src_count--; src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; @@ -1499,7 +1494,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) } /* Update the chunk count and data_used. */ __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); - i += src_capacity; src_count--; src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; @@ -1508,7 +1502,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) /* Source and destination and a perfect overlapping pair. */ if (src_start == dst_start && src_capacity == dst_capacity) { __sm_merge_chunk(destination, src_start, dst_start, dst_capacity, &dst_chunk, &src_chunk); - i += src_capacity; src_count--; src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; @@ -1525,7 +1518,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) sparsemap_set(destination, n, true); } } - i += src_capacity; src_count--; src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; @@ -1539,7 +1531,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) /* Update the chunk count and data_used. */ __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); - i += src_capacity; src_count--; src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; @@ -1552,7 +1543,6 @@ sparsemap_merge(sparsemap_t *destination, sparsemap_t *source) /* Update the chunk count and data_used. */ __sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1); - i += src_capacity; src_count--; src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk); continue; diff --git a/tests/test.c b/tests/test.c index 34e37ab..87c7c06 100644 --- a/tests/test.c +++ b/tests/test.c @@ -543,6 +543,9 @@ test_api_get_data(const MunitParameter params[], void *data) assert_true(sparsemap_get_data(map) == buf); + munit_free(buf); + munit_free(map); + return MUNIT_OK; } -- 2.45.2