split/merge #9
3 changed files with 210 additions and 168 deletions
8
Makefile
8
Makefile
|
@ -6,15 +6,15 @@ SHARED_LIB = libsparsemap.so
|
||||||
LIBS = -lm
|
LIBS = -lm
|
||||||
#CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC
|
#CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC
|
||||||
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -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 -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 -Ofast -g -std=c11 -Iinclude/ -fPIC
|
||||||
#CFLAGS = -Wall -Wextra -Wpedantic -Og -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 = -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 = -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
|
#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 = -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 -Ofast -g -std=c11 -Iinclude/ -Itests/ -fPIC
|
||||||
#TEST_FLAGS = -Wall -Wextra -Wpedantic -Og -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
|
#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
|
||||||
|
|
||||||
|
|
319
src/sparsemap.c
319
src/sparsemap.c
|
@ -264,15 +264,15 @@ __sm_chunk_increase_capacity(__sm_chunk_t *chunk, size_t capacity)
|
||||||
|
|
||||||
size_t increased = 0;
|
size_t increased = 0;
|
||||||
register uint8_t *p = (uint8_t *)chunk->m_data;
|
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) {
|
if (!*p || *p == 0xff) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int j = 0; j < SM_FLAGS_PER_INDEX_BYTE; j++) {
|
for (int j = 0; j < SM_FLAGS_PER_INDEX_BYTE; j++) {
|
||||||
size_t flags = SM_CHUNK_GET_FLAGS(*p, j);
|
size_t flags = SM_CHUNK_GET_FLAGS(*p, j);
|
||||||
if (flags == SM_PAYLOAD_NONE) {
|
if (flags == SM_PAYLOAD_NONE) {
|
||||||
p[i] &= ~((sm_bitvec_t)SM_PAYLOAD_ONES << (j * 2));
|
*p &= ~((sm_bitvec_t)SM_PAYLOAD_ONES << (j * 2));
|
||||||
p[i] |= ((sm_bitvec_t)SM_PAYLOAD_ZEROS << (j * 2));
|
*p |= ((sm_bitvec_t)SM_PAYLOAD_ZEROS << (j * 2));
|
||||||
increased += SM_BITS_PER_VECTOR;
|
increased += SM_BITS_PER_VECTOR;
|
||||||
if (increased + initial_capacity == capacity) {
|
if (increased + initial_capacity == capacity) {
|
||||||
__sm_assert(__sm_chunk_get_capacity(chunk) == 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] chunk The chunk in question.
|
||||||
* @param[in] offset The offset of the first bit in the chunk to be merged.
|
* @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
|
void
|
||||||
__sm_merge_chunk(sparsemap_t *chunk, sparsemap_idx_t offset, __sm_chunk_t src)
|
__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
|
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 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)
|
* 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));
|
__sm_append_data(map, &buf[0], sizeof(buf));
|
||||||
|
|
||||||
uint8_t *p = __sm_get_chunk_data(map, 0);
|
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);
|
__sm_set_chunk_count(map, 1);
|
||||||
|
|
||||||
|
@ -1411,35 +1410,6 @@ size_t
|
||||||
sparsemap_count(sparsemap_t *map)
|
sparsemap_count(sparsemap_t *map)
|
||||||
{
|
{
|
||||||
return sparsemap_rank(map, 0, SPARSEMAP_IDX_MAX, true);
|
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
|
void
|
||||||
|
@ -1463,75 +1433,121 @@ sparsemap_scan(sparsemap_t *map, void (*scanner)(sm_idx_t[], size_t, void *aux),
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sparsemap_merge(sparsemap_t *map, sparsemap_t *other)
|
sparsemap_merge(sparsemap_t *destination, sparsemap_t *source)
|
||||||
{
|
{
|
||||||
uint8_t *src, *dst;
|
uint8_t *src, *dst;
|
||||||
size_t src_count = __sm_get_chunk_count(other);
|
size_t src_count = __sm_get_chunk_count(source);
|
||||||
size_t dst_count = __sm_get_chunk_count(map);
|
sparsemap_idx_t src_starting_offset = sparsemap_get_starting_offset(source);
|
||||||
size_t max_chunk_count = src_count + dst_count;
|
sparsemap_idx_t src_ending_offset = sparsemap_get_ending_offset(source);
|
||||||
ssize_t difference = map->m_capacity - (other->m_data_used + src_count * (sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2));
|
sparsemap_idx_t dst_ending_offset = sparsemap_get_ending_offset(destination);
|
||||||
|
|
||||||
/* Estimate worst-case overhead required for merge. */
|
if (src_count == 0) {
|
||||||
if (difference <= 0) {
|
return 0;
|
||||||
errno = ENOSPC;
|
|
||||||
return -difference;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dst = __sm_get_chunk_data(map, 0);
|
ssize_t remaining_capacity = destination->m_capacity - destination->m_data_used -
|
||||||
src = __sm_get_chunk_data(other, 0);
|
(source->m_data_used + src_count * (sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2));
|
||||||
for (size_t i = 0; i < max_chunk_count && src_count; i++) {
|
|
||||||
|
/* 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 src_start = *(sm_idx_t *)src;
|
||||||
sm_idx_t dst_start = *(sm_idx_t *)dst;
|
__sm_chunk_t src_chunk;
|
||||||
src_start = __sm_get_chunk_aligned_offset(src_start);
|
__sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t));
|
||||||
dst_start = __sm_get_chunk_aligned_offset(dst_start);
|
size_t src_capacity = __sm_chunk_get_capacity(&src_chunk);
|
||||||
if (src_start > dst_start && dst_count > 0) {
|
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_t dst_chunk;
|
||||||
__sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
__sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
||||||
dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk);
|
size_t dst_capacity = __sm_chunk_get_capacity(&dst_chunk);
|
||||||
dst_count--;
|
|
||||||
continue;
|
/* Source chunk precedes next destination chunk. */
|
||||||
}
|
if ((src_start + src_capacity) <= dst_start) {
|
||||||
if (src_start == dst_start && dst_count > 0) {
|
size_t src_size = __sm_chunk_get_size(&src_chunk);
|
||||||
/* Chunks overlap, merge them. */
|
size_t offset = __sm_get_chunk_offset(destination, dst_start);
|
||||||
__sm_chunk_t src_chunk;
|
__sm_insert_data(destination, offset, src, sizeof(sm_idx_t) + src_size);
|
||||||
__sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t));
|
/* Update the chunk count and data_used. */
|
||||||
__sm_chunk_t dst_chunk;
|
__sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1);
|
||||||
__sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
i += src_capacity;
|
||||||
__sm_merge_chunk(map, src_start, src_chunk);
|
continue;
|
||||||
*(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the chunk count and data_used. */
|
/* Source chunk follows next destination chunk. */
|
||||||
__sm_set_chunk_count(map, __sm_get_chunk_count(map) + 1);
|
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. */
|
if (src_start == dst_start) {
|
||||||
__sm_chunk_t dst_chunk;
|
if (dst_capacity < src_capacity) {
|
||||||
__sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
__sm_chunk_increase_capacity(&dst_chunk, src_capacity);
|
||||||
src += sizeof(sm_idx_t) + __sm_chunk_get_size(&src_chunk);
|
dst_capacity = __sm_chunk_get_capacity(&dst_chunk);
|
||||||
dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk);
|
}
|
||||||
src_count--;
|
__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;
|
return 0;
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
int
|
int
|
||||||
sparsemap_merge(sparsemap_t *destination, sparsemap_t *source)
|
__sparsemap_merge(sparsemap_t *destination, sparsemap_t *source)
|
||||||
{
|
{
|
||||||
uint8_t *src, *dst;
|
uint8_t *src, *dst;
|
||||||
size_t src_count = __sm_get_chunk_count(source);
|
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++) {
|
for (size_t i = 0; i < max_chunk_count && src_count; i++) {
|
||||||
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;
|
||||||
src_start = __sm_get_chunk_aligned_offset(src_start);
|
__sm_chunk_t src_chunk;
|
||||||
dst_start = __sm_get_chunk_aligned_offset(dst_start);
|
__sm_chunk_init(&src_chunk, src + sizeof(sm_idx_t));
|
||||||
if (src_start > dst_start && dst_count > 0) {
|
__sm_chunk_t dst_chunk;
|
||||||
__sm_chunk_t dst_chunk;
|
__sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
||||||
__sm_chunk_init(&dst_chunk, dst + sizeof(sm_idx_t));
|
size_t src_capacity = __sm_chunk_get_capacity(&src_chunk);
|
||||||
dst += sizeof(sm_idx_t) + __sm_chunk_get_size(&dst_chunk);
|
size_t dst_capacity = __sm_chunk_get_capacity(&dst_chunk);
|
||||||
dst_count--;
|
/* Chunks do not overlap. */
|
||||||
continue;
|
if (dst_count == 0) {
|
||||||
}
|
/* No destination chunks, so append data. */
|
||||||
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));
|
|
||||||
size_t src_size = __sm_chunk_get_size(&src_chunk);
|
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);
|
||||||
__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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the chunk count and data_used. */
|
/* Update the chunk count and data_used. */
|
||||||
__sm_set_chunk_count(destination, __sm_get_chunk_count(destination) + 1);
|
__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_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;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
sparsemap_idx_t
|
sparsemap_idx_t
|
||||||
sparsemap_split(sparsemap_t *map, sparsemap_idx_t offset, sparsemap_t *other)
|
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;
|
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);
|
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);
|
src += sizeof(sm_idx_t);
|
||||||
__sm_chunk_t s_chunk;
|
__sm_chunk_t s_chunk;
|
||||||
__sm_chunk_init(&s_chunk, src);
|
__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)));
|
__sm_chunk_reduce_capacity(&d_chunk, __sm_get_vector_aligned_offset(capacity - (offset % capacity)));
|
||||||
|
|
||||||
/* Now copy the bits. */
|
/* Now copy the bits. */
|
||||||
sparsemap_idx_t d = offset;
|
|
||||||
sparsemap_idx_t b = __sm_get_vector_aligned_offset(offset % capacity);
|
sparsemap_idx_t b = __sm_get_vector_aligned_offset(offset % capacity);
|
||||||
for (size_t j = offset % capacity; j < capacity; j++, d++) {
|
for (size_t j = start; j < capacity + start; j++) {
|
||||||
if (__sm_chunk_is_set(&s_chunk, j)) {
|
if (j >= offset) {
|
||||||
assert(sparsemap_set(other, d, true) == d);
|
if (__sm_chunk_is_set(&s_chunk, j - start)) {
|
||||||
if (j > b && (j - b) % capacity < SM_BITS_PER_VECTOR) {
|
sparsemap_set(other, j, true);
|
||||||
sparsemap_set(map, d, false);
|
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++;
|
i++;
|
||||||
|
|
||||||
/* Reduce the capacity of the source-chunk effectively erases bits. */
|
/* 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. */
|
/* Now continue with all remaining chunks. */
|
||||||
|
|
51
tests/test.c
51
tests/test.c
|
@ -733,15 +733,15 @@ test_api_split(const MunitParameter params[], void *data)
|
||||||
|
|
||||||
sparsemap_split(map, seg + off, &portion);
|
sparsemap_split(map, seg + off, &portion);
|
||||||
|
|
||||||
for (sparsemap_idx_t i = 0; i < off; i++) {
|
for (sparsemap_idx_t i = seg; i < seg + 1024; i++) {
|
||||||
assert_true(sparsemap_is_set(map, i + seg));
|
if (i < seg + off) {
|
||||||
assert_false(sparsemap_is_set(&portion, i + seg));
|
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(map);
|
||||||
sparsemap_clear(&portion);
|
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.
|
// Merge a single set bit in the first chunk into the empty map.
|
||||||
sparsemap_set(other, 0, true);
|
sparsemap_set(other, 0, true);
|
||||||
sparsemap_merge(map, other);
|
sparsemap_merge(map, other);
|
||||||
|
|
||||||
assert_true(sparsemap_is_set(other, 0));
|
assert_true(sparsemap_is_set(other, 0));
|
||||||
assert_true(sparsemap_is_set(map, 0));
|
assert_true(sparsemap_is_set(map, 0));
|
||||||
|
|
||||||
sparsemap_clear(map);
|
sparsemap_clear(map);
|
||||||
sparsemap_clear(other);
|
sparsemap_clear(other);
|
||||||
|
|
||||||
|
@ -831,49 +829,42 @@ test_api_merge(const MunitParameter params[], void *data)
|
||||||
sparsemap_set(map, 0, true);
|
sparsemap_set(map, 0, true);
|
||||||
sparsemap_set(other, 0, true);
|
sparsemap_set(other, 0, true);
|
||||||
sparsemap_merge(map, other);
|
sparsemap_merge(map, other);
|
||||||
|
assert_true(sparsemap_is_set(map, 0));
|
||||||
sparsemap_clear(map);
|
sparsemap_clear(map);
|
||||||
sparsemap_clear(other);
|
sparsemap_clear(other);
|
||||||
|
|
||||||
// Merge an empty map with one that has the first bit set.
|
// Merge an empty map with one that has the first bit set.
|
||||||
sparsemap_set(map, 0, true);
|
sparsemap_set(map, 0, true);
|
||||||
sparsemap_merge(map, other);
|
sparsemap_merge(map, other);
|
||||||
|
|
||||||
assert_true(sparsemap_is_set(map, 0));
|
assert_true(sparsemap_is_set(map, 0));
|
||||||
|
|
||||||
sparsemap_clear(map);
|
sparsemap_clear(map);
|
||||||
sparsemap_clear(other);
|
sparsemap_clear(other);
|
||||||
|
|
||||||
sparsemap_set(other, 2049, true);
|
sparsemap_set(other, 2049, true);
|
||||||
sparsemap_merge(map, other);
|
sparsemap_merge(map, other);
|
||||||
|
|
||||||
assert_true(sparsemap_is_set(map, 2049));
|
assert_true(sparsemap_is_set(map, 2049));
|
||||||
|
|
||||||
sparsemap_clear(map);
|
sparsemap_clear(map);
|
||||||
sparsemap_clear(other);
|
sparsemap_clear(other);
|
||||||
|
|
||||||
sparsemap_set(other, 1, true);
|
sparsemap_set(other, 1, true);
|
||||||
sparsemap_set(other, 2049, true);
|
sparsemap_set(other, 2049, true);
|
||||||
sparsemap_set(map, 2050, true);
|
sparsemap_set(map, 2050, true);
|
||||||
sparsemap_set(other, 4097, true);
|
sparsemap_set(other, 4097, true);
|
||||||
sparsemap_set(map, 6113, true);
|
sparsemap_set(map, 6113, true);
|
||||||
sparsemap_set(other, 8193, 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, 1));
|
||||||
assert_true(sparsemap_is_set(map, 2049));
|
assert_true(sparsemap_is_set(map, 2049));
|
||||||
assert_true(sparsemap_is_set(map, 2050));
|
assert_true(sparsemap_is_set(map, 2050));
|
||||||
assert_true(sparsemap_is_set(map, 4097));
|
assert_true(sparsemap_is_set(map, 4097));
|
||||||
assert_true(sparsemap_is_set(map, 6113));
|
assert_true(sparsemap_is_set(map, 6113));
|
||||||
assert_true(sparsemap_is_set(map, 8193));
|
assert_true(sparsemap_is_set(map, 8193));
|
||||||
|
|
||||||
for (int i = 0; i < 10000; i++) {
|
for (int i = 0; i < 10000; i++) {
|
||||||
if (i == 2049 || i == 1 || i == 2050 || i == 4097 || i == 6113 || i == 8193)
|
if (i == 2049 || i == 1 || i == 2050 || i == 4097 || i == 6113 || i == 8193)
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
assert_false(sparsemap_is_set(map, i));
|
assert_false(sparsemap_is_set(map, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
sparsemap_clear(map);
|
sparsemap_clear(map);
|
||||||
sparsemap_clear(other);
|
sparsemap_clear(other);
|
||||||
|
|
||||||
|
@ -883,15 +874,33 @@ test_api_merge(const MunitParameter params[], void *data)
|
||||||
for (int i = 2049; i < 4096; i++) {
|
for (int i = 2049; i < 4096; i++) {
|
||||||
sparsemap_set(other, i, true);
|
sparsemap_set(other, i, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
sparsemap_merge(map, other);
|
sparsemap_merge(map, other);
|
||||||
|
|
||||||
assert(sparsemap_is_set(map, 0));
|
assert(sparsemap_is_set(map, 0));
|
||||||
assert(sparsemap_is_set(map, 2048));
|
assert(sparsemap_is_set(map, 2048));
|
||||||
assert(sparsemap_is_set(map, 8193));
|
assert(sparsemap_is_set(map, 8193));
|
||||||
for (int i = 2049; i < 4096; i++) {
|
for (int i = 2049; i < 4096; i++) {
|
||||||
assert(sparsemap_is_set(map, 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);
|
munit_free(other);
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
|
|
Loading…
Reference in a new issue