121#define USE_FASTPATH_CHUNKS_FIRST
131#ifdef USE_FASTPATH_CHUNKS_FIRST
132# define USE_FASTPATH_CHUNKS_LAST
141#define USE_ALIGN_CHUNKS_TEST
147#define USE_HASH_TABLE_ACCUMULATE
149#ifdef USE_HASH_TABLE_ACCUMULATE
158# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_DEFAULT 3
159# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_32BITS 4
160# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_16BITS 5
169# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_8BITS 6
175# define BCHUNK_HASH_LEN 16
181#define USE_HASH_TABLE_KEY_CACHE
182#ifdef USE_HASH_TABLE_KEY_CACHE
183# define HASH_TABLE_KEY_UNSET ((hash_key) - 1)
184# define HASH_TABLE_KEY_FALLBACK ((hash_key) - 2)
195#define USE_HASH_TABLE_DEDUPLICATE
200#define BCHUNK_HASH_TABLE_MUL 3
213#define USE_MERGE_CHUNKS
215#ifdef USE_MERGE_CHUNKS
217# define BCHUNK_SIZE_MIN_DIV 8
226# define BCHUNK_SIZE_MAX_MUL 2
258#ifdef USE_HASH_TABLE_ACCUMULATE
322#ifdef USE_HASH_TABLE_KEY_CACHE
362#ifdef USE_HASH_TABLE_KEY_CACHE
371 memcpy(data_copy,
data, data_len);
372 return bchunk_new(bs_mem, data_copy, data_len);
378 if (chunk->
users == 1) {
388 const uchar *data_base,
389 const size_t data_base_len,
394 return (memcmp(&data_base[offset], chunk->
data, chunk->
data_len) == 0);
398 const uchar *data_base,
399 const size_t data_base_len,
402 if (offset +
size_t(chunk->
data_len) <= data_base_len) {
421 chunk_list->
users = 0;
428 if (chunk_list->
users == 1) {
433 cref_next = cref->next;
441 chunk_list->
users -= 1;
445#ifdef USE_VALIDATE_LIST_SIZE
447# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) BLI_assert(bchunk_list_size(chunk_list) == n)
450#ifndef ASSERT_CHUNKLIST_SIZE
451# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) (EXPR_NOP(chunk_list), EXPR_NOP(n))
454#ifdef USE_VALIDATE_LIST_DATA_PARTIAL
459 if (memcmp(&
data[offset], cref->link->data, cref->link->data_len) != 0) {
462 offset += cref->link->data_len;
466# define ASSERT_CHUNKLIST_DATA(chunk_list, data) \
467 BLI_assert(bchunk_list_data_check(chunk_list, data))
469# define ASSERT_CHUNKLIST_DATA(chunk_list, data) (EXPR_NOP(chunk_list), EXPR_NOP(data))
472#ifdef USE_MERGE_CHUNKS
478 if (cref && cref->
prev) {
486 if (data_merge_len <= info->chunk_byte_size_max) {
496 memcpy(data_merge, chunk_prev->
data, chunk_prev->
data_len);
515 const size_t data_prev_len =
split;
516 const size_t data_curr_len = data_merge_len -
split;
520 if (data_prev_len <= chunk_prev->data_len) {
521 const size_t data_curr_shrink_len = chunk_prev->
data_len - data_prev_len;
524 memcpy(data_prev, chunk_prev->
data, data_prev_len);
527 memcpy(data_curr, &chunk_prev->
data[data_prev_len], data_curr_shrink_len);
528 memcpy(&data_curr[data_curr_shrink_len], chunk_curr->
data, chunk_curr->
data_len);
531 BLI_assert(data_curr_len <= chunk_curr->data_len);
534 const size_t data_prev_grow_len = data_prev_len - chunk_prev->
data_len;
537 memcpy(data_prev, chunk_prev->
data, chunk_prev->
data_len);
538 memcpy(&data_prev[chunk_prev->
data_len], chunk_curr->
data, data_prev_grow_len);
541 memcpy(data_curr, &chunk_curr->
data[data_prev_grow_len], data_curr_len);
568 const size_t data_len,
569 size_t *r_data_trim_len,
570 size_t *r_data_last_chunk_len)
572 size_t data_last_chunk_len = 0;
573 size_t data_trim_len = data_len;
575#ifdef USE_MERGE_CHUNKS
579 data_trim_len = data_trim_len - data_last_chunk_len;
580 if (data_last_chunk_len) {
581 if (data_last_chunk_len < info->chunk_byte_size_min) {
590 data_last_chunk_len = data_len;
596 data_trim_len = data_trim_len - data_last_chunk_len;
599 BLI_assert(data_trim_len + data_last_chunk_len == data_len);
601 *r_data_trim_len = data_trim_len;
602 *r_data_last_chunk_len = data_last_chunk_len;
625 const size_t data_len)
629#ifdef USE_MERGE_CHUNKS
630 BLI_assert(data_len <= info->chunk_byte_size_max);
637 const size_t data_merge_len = chunk_prev->
data_len + data_len;
642 memcpy(&data_merge[chunk_prev->
data_len],
data, data_len);
648 memcpy(data_merge, chunk_prev->
data, chunk_prev->
data_len);
649 memcpy(&data_merge[chunk_prev->
data_len],
data, data_len);
666# ifdef USE_MERGE_CHUNKS
685 size_t data_trim_len, data_last_chunk_len;
688 if (data_trim_len != 0) {
697 while (i_prev != data_trim_len) {
704 if (data_last_chunk_len) {
712 if (data_last_chunk_len) {
718#ifdef USE_MERGE_CHUNKS
733#ifdef USE_MERGE_CHUNKS
744 const size_t data_len)
748 size_t data_trim_len, data_last_chunk_len;
752 while (i_prev != data_trim_len) {
759 if (data_last_chunk_len) {
765#ifdef USE_MERGE_CHUNKS
774# ifdef USE_MERGE_CHUNKS
795#define HASH_INIT (5381)
805 const signed char *p;
808 for (p = (
const signed char *)key; n--; p++) {
817#ifdef USE_HASH_TABLE_ACCUMULATE
819 const uchar *data_slice,
820 const size_t data_slice_len,
824 for (
size_t i = 0, i_step = 0; i_step < data_slice_len;
i++, i_step += info->
chunk_stride) {
830 for (
size_t i = 0;
i < data_slice_len;
i++) {
842 const size_t data_len,
845 const size_t hash_array_len = data_len / info->
chunk_stride;
848 size_t i_next = hash_array_len -
i;
854 BLI_assert(data_trim_len <= cref->link->data_len);
858 }
while ((
i < hash_array_len) && (cref !=
nullptr));
870 hash_array[i_dst] += ((hash_array[i_ahead] << 3) ^ (hash_array[i_dst] >> 1));
876 if (
UNLIKELY(iter_steps > hash_array_len)) {
877 iter_steps = hash_array_len;
880 const size_t hash_array_search_len = hash_array_len - iter_steps;
881 while (iter_steps != 0) {
882 const size_t hash_offset = iter_steps;
883 for (
size_t i = 0;
i < hash_array_search_len;
i++) {
897 if (
UNLIKELY(!(iter_steps <= hash_array_len))) {
899 iter_steps = hash_array_len;
903 size_t iter_steps_sub = iter_steps;
905 while (iter_steps != 0) {
906 const size_t hash_array_search_len = hash_array_len - iter_steps_sub;
907 const size_t hash_offset = iter_steps;
908 for (
uint i = 0;
i < hash_array_search_len;
i++) {
912 iter_steps_sub += iter_steps;
920 const size_t hash_store_len)
929# ifdef USE_HASH_TABLE_KEY_CACHE
959# ifdef USE_HASH_TABLE_KEY_CACHE
969 const size_t table_len,
970 const size_t i_table_start,
972 const size_t data_len,
978 const BTableRef *tref = table[key_index];
979 if (tref !=
nullptr) {
980 const size_t size_left = data_len - offset;
983# ifdef USE_HASH_TABLE_KEY_CACHE
988 if (chunk_test->
data_len <= size_left) {
995 }
while ((tref = tref->
next));
1010# ifdef USE_HASH_TABLE_KEY_CACHE
1033 const size_t table_len,
1036 const size_t data_len,
1037 const size_t offset,
1040 const size_t data_hash_len = BCHUNK_HASH_LEN * info->
chunk_stride;
1042 const size_t size_left = data_len - offset;
1045 for (
BTableRef *tref = table[key_index]; tref; tref = tref->
next) {
1047# ifdef USE_HASH_TABLE_KEY_CACHE
1052 if (chunk_test->
data_len <= size_left) {
1093 const BChunkRef *cref_match_first =
nullptr;
1095 uint chunk_list_reference_skip_len = 0;
1096 size_t chunk_list_reference_skip_bytes = 0;
1099#ifdef USE_FASTPATH_CHUNKS_FIRST
1101 bool full_match =
true;
1106 cref_match_first = cref;
1107 chunk_list_reference_skip_len += 1;
1108 chunk_list_reference_skip_bytes += cref->
link->
data_len;
1132 if (cref_match_first !=
nullptr) {
1133 size_t chunk_size_step = 0;
1137 chunk_size_step += chunk->
data_len;
1141 if (cref == cref_match_first) {
1151 i_prev = chunk_size_step;
1168#define data_len_original invalid_usage
1169#ifdef data_len_original
1173 const BChunkRef *chunk_list_reference_last =
nullptr;
1175#ifdef USE_FASTPATH_CHUNKS_LAST
1178 while ((cref->
prev !=
nullptr) && (cref != cref_match_first) &&
1182 size_t offset = data_len - chunk_test->
data_len;
1185 chunk_list_reference_last = cref;
1186 chunk_list_reference_skip_len += 1;
1187 chunk_list_reference_skip_bytes += cref->
link->
data_len;
1207 bool use_aligned =
false;
1209#ifdef USE_ALIGN_CHUNKS_TEST
1212 if (data_len - i_prev <= chunk_list->total_expanded_size / 4) {
1226 const BChunkRef *cref = cref_match_first ? cref_match_first->
next :
1229 while (i_prev != data_len) {
1233 if ((cref != chunk_list_reference_last) &&
1252 (chunk_list_reference->
chunk_refs_len >= chunk_list_reference_skip_len) &&
1264#ifdef USE_HASH_TABLE_ACCUMULATE
1265 size_t i_table_start = i_prev;
1266 const size_t table_hash_array_len = (data_len - i_prev) / info->
chunk_stride;
1273 uint i_table_start = 0;
1274 hash_key *table_hash_array =
nullptr;
1277 const uint chunk_list_reference_remaining_len = (chunk_list_reference->
chunk_refs_len -
1278 chunk_list_reference_skip_len) +
1282 uint table_ref_stack_n = 0;
1290#ifdef USE_HASH_TABLE_ACCUMULATE
1297 chunk_list_reference_skip_bytes;
1299 if (cref_match_first) {
1300 cref = cref_match_first;
1301 chunk_list_reference_bytes_remaining += cref->
link->
data_len;
1307#ifdef USE_PARANOID_CHECKS
1309 size_t test_bytes_len = 0;
1311 while (cr != chunk_list_reference_last) {
1315 BLI_assert(test_bytes_len == chunk_list_reference_bytes_remaining);
1319 while ((cref != chunk_list_reference_last) &&
1332 BTableRef *tref_prev = table[key_index];
1333 BLI_assert(table_ref_stack_n < chunk_list_reference_remaining_len);
1334#ifdef USE_HASH_TABLE_DEDUPLICATE
1335 bool is_duplicate =
false;
1343# ifdef USE_HASH_TABLE_KEY_CACHE
1344 if (key == chunk_b->
key)
1347 if (chunk_a != chunk_b) {
1350 is_duplicate =
true;
1356 }
while ((tref = tref->
next));
1362 BTableRef *tref = &table_ref_stack[table_ref_stack_n++];
1364 tref->
next = tref_prev;
1365 table[key_index] = tref;
1368 chunk_list_reference_bytes_remaining -= cref->
link->
data_len;
1372 BLI_assert(table_ref_stack_n <= chunk_list_reference_remaining_len);
1374#ifdef USE_HASH_TABLE_ACCUMULATE
1381 for (
size_t i = i_prev;
i < data_len;) {
1385 info, table, table_len, i_table_start,
data, data_len,
i, table_hash_array);
1386 if (cref_found !=
nullptr) {
1405 while (!
ELEM(cref_found->
next,
nullptr, chunk_list_reference_last)) {
1406 cref_found = cref_found->
next;
1430#ifdef USE_HASH_TABLE_ACCUMULATE
1448 if (i_prev != data_len) {
1456#ifdef USE_FASTPATH_CHUNKS_LAST
1457 if (chunk_list_reference_last !=
nullptr) {
1459 const BChunkRef *cref = chunk_list_reference_last;
1460 while (cref !=
nullptr) {
1472#undef data_len_original
1503#ifdef USE_MERGE_CHUNKS
1508#ifdef USE_HASH_TABLE_ACCUMULATE
1511 if (stride <=
sizeof(int8_t)) {
1514 else if (stride <=
sizeof(int16_t)) {
1517 else if (stride <=
sizeof(
int32_t)) {
1565 state_next =
state->next;
1600 size_t size_accum = 0;
1602 size_accum +=
state->chunk_list->total_expanded_size;
1609 size_t size_total = 0;
1615 size_total += size_t(chunk->
data_len);
1628 const size_t data_len,
1634#ifdef USE_PARANOID_CHECKS
1635 if (state_reference) {
1641 if (state_reference) {
1654 chunk_list->
users += 1;
1657 state->chunk_list = chunk_list;
1661#ifdef USE_PARANOID_CHECKS
1663 size_t data_test_len;
1676#ifdef USE_PARANOID_CHECKS
1688 return state->chunk_list->total_expanded_size;
1693#ifdef USE_PARANOID_CHECKS
1694 size_t data_test_len = 0;
1713 *r_data_len =
state->chunk_list->total_expanded_size;
1726 size_t total_expanded_size = 0;
1730 return total_expanded_size;
1750#ifdef USE_MERGE_CHUNKS
1778#define GHASH_PTR_ADD_USER(gh, pt) \
1781 if (BLI_ghash_ensure_p((gh), (pt), &val)) { \
1782 *((int *)val) += 1; \
1785 *((int *)val) = 1; \
1839#undef GHASH_PTR_ADD_USER
Efficient in-memory storage of multiple similar arrays.
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
#define GHASH_ITER(gh_iter_, ghash_)
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1)
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1)
#define UNUSED_VARS_NDEBUG(...)
#define POINTER_AS_INT(i)
static void split(const char *text, const char *seps, char ***str, int *count)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
static void bchunk_list_calc_trim_len(const BArrayInfo *info, const size_t data_len, size_t *r_data_trim_len, size_t *r_data_last_chunk_len)
#define BCHUNK_HASH_TABLE_MUL
static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref, hash_key *hash_store, const size_t hash_store_len)
static const BChunkRef * table_lookup(const BArrayInfo *info, BTableRef **table, const size_t table_len, const size_t i_table_start, const uchar *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array)
static void array_store_free_data(BArrayStore *bs)
#define USE_HASH_TABLE_ACCUMULATE
static void hash_array_from_cref(const BArrayInfo *info, const BChunkRef *cref, const size_t data_len, hash_key *hash_array)
#define GHASH_PTR_ADD_USER(gh, pt)
BLI_INLINE void hash_accum_impl(hash_key *hash_array, const size_t i_dst, const size_t i_ahead)
#define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_DEFAULT
static bool bchunk_data_compare(const BChunk *chunk, const uchar *data_base, const size_t data_base_len, const size_t offset)
static hash_key hash_data(const uchar *key, size_t n)
static void bchunk_list_fill_from_array(const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, const uchar *data, const size_t data_len)
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
#define ASSERT_CHUNKLIST_DATA(chunk_list, data)
static void bchunk_decref(BArrayMemory *bs_mem, BChunk *chunk)
static void hash_accum_single(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps)
#define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_8BITS
BLI_INLINE hash_key hash_data_single(const uchar p)
static BChunkList * bchunk_list_from_data_merge(const BArrayInfo *info, BArrayMemory *bs_mem, const uchar *data, const size_t data_len_original, const BChunkList *chunk_list_reference)
static void bchunk_list_append_data_n(const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, const uchar *data, size_t data_len)
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
#define HASH_TABLE_KEY_UNSET
void * BLI_array_store_state_data_get_alloc(const BArrayState *state, size_t *r_data_len)
BArrayStore * BLI_array_store_create(uint stride, uint chunk_count)
void BLI_array_store_clear(BArrayStore *bs)
static void bchunk_list_decref(BArrayMemory *bs_mem, BChunkList *chunk_list)
static size_t bchunk_list_size(const BChunkList *chunk_list)
#define BCHUNK_SIZE_MAX_MUL
bool BLI_array_store_is_valid(BArrayStore *bs)
#define HASH_TABLE_KEY_FALLBACK
#define data_len_original
static void bchunk_list_ensure_min_size_last(const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list)
static void hash_accum(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps)
#define ASSERT_CHUNKLIST_SIZE(chunk_list, n)
#define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_32BITS
static BChunk * bchunk_new(BArrayMemory *bs_mem, const uchar *data, const size_t data_len)
static void hash_array_from_data(const BArrayInfo *info, const uchar *data_slice, const size_t data_slice_len, hash_key *hash_array)
static void bchunk_list_append_only(BArrayMemory *bs_mem, BChunkList *chunk_list, BChunk *chunk)
size_t BLI_array_store_state_size_get(const BArrayState *state)
void BLI_array_store_state_data_get(const BArrayState *state, void *data)
void BLI_array_store_destroy(BArrayStore *bs)
BArrayState * BLI_array_store_state_add(BArrayStore *bs, const void *data, const size_t data_len, const BArrayState *state_reference)
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
static void bchunk_list_append(const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, BChunk *chunk)
static BChunk * bchunk_new_copydata(BArrayMemory *bs_mem, const uchar *data, const size_t data_len)
static void bchunk_list_append_data(const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, const uchar *data, const size_t data_len)
BLI_INLINE bool bchunk_data_compare_unchecked(const BChunk *chunk, const uchar *data_base, const size_t data_base_len, const size_t offset)
#define BCHUNK_SIZE_MIN_DIV
#define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_16BITS
static BChunkList * bchunk_list_new(BArrayMemory *bs_mem, size_t total_expanded_size)
BMesh const char void * data
void * MEM_mallocN(size_t len, const char *str)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
size_t(* MEM_allocN_len)(const void *vmemh)
void MEM_freeN(void *vmemh)
size_t chunk_byte_size_max
size_t chunk_byte_size_min
size_t accum_read_ahead_bytes
size_t accum_read_ahead_len
size_t total_expanded_size