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--; + } } }