127 #define USE_FASTPATH_CHUNKS_FIRST
136 #ifdef USE_FASTPATH_CHUNKS_FIRST
137 # define USE_FASTPATH_CHUNKS_LAST
145 #define USE_ALIGN_CHUNKS_TEST
150 #define USE_HASH_TABLE_ACCUMULATE
152 #ifdef USE_HASH_TABLE_ACCUMULATE
157 # define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS 4
161 # define BCHUNK_HASH_LEN 4
166 #define USE_HASH_TABLE_KEY_CACHE
167 #ifdef USE_HASH_TABLE_KEY_CACHE
168 # define HASH_TABLE_KEY_UNSET ((uint64_t)-1)
169 # define HASH_TABLE_KEY_FALLBACK ((uint64_t)-2)
174 #define BCHUNK_HASH_TABLE_MUL 3
186 #define USE_MERGE_CHUNKS
188 #ifdef USE_MERGE_CHUNKS
191 # define BCHUNK_SIZE_MIN_DIV 8
198 # define BCHUNK_SIZE_MAX_MUL 2
227 #ifdef USE_HASH_TABLE_ACCUMULATE
288 #ifdef USE_HASH_TABLE_KEY_CACHE
328 #ifdef USE_HASH_TABLE_KEY_CACHE
337 memcpy(data_copy,
data, data_len);
338 return bchunk_new(bs_mem, data_copy, data_len);
344 if (chunk->
users == 1) {
354 const uchar *data_base,
355 const size_t data_base_len,
358 if (offset + (
size_t)chunk->
data_len <= data_base_len) {
359 return (memcmp(&data_base[offset], chunk->
data, chunk->
data_len) == 0);
377 chunk_list->
users = 0;
384 if (chunk_list->
users == 1) {
394 chunk_list->
users -= 1;
398 #ifdef USE_VALIDATE_LIST_SIZE
400 # define ASSERT_CHUNKLIST_SIZE(chunk_list, n) BLI_assert(bchunk_list_size(chunk_list) == n)
403 #ifndef ASSERT_CHUNKLIST_SIZE
404 # define ASSERT_CHUNKLIST_SIZE(chunk_list, n) (EXPR_NOP(chunk_list), EXPR_NOP(n))
407 #ifdef USE_VALIDATE_LIST_DATA_PARTIAL
419 # define ASSERT_CHUNKLIST_DATA(chunk_list, data) \
420 BLI_assert(bchunk_list_data_check(chunk_list, data))
422 # define ASSERT_CHUNKLIST_DATA(chunk_list, data) (EXPR_NOP(chunk_list), EXPR_NOP(data))
425 #ifdef USE_MERGE_CHUNKS
439 if (data_merge_len <= info->chunk_byte_size_max) {
449 memcpy(data_merge, chunk_prev->
data, chunk_prev->
data_len);
468 const size_t data_prev_len =
split;
469 const size_t data_curr_len = data_merge_len -
split;
473 if (data_prev_len <= chunk_prev->data_len) {
474 const size_t data_curr_shrink_len = chunk_prev->
data_len - data_prev_len;
477 memcpy(data_prev, chunk_prev->
data, data_prev_len);
480 memcpy(data_curr, &chunk_prev->
data[data_prev_len], data_curr_shrink_len);
481 memcpy(&data_curr[data_curr_shrink_len], chunk_curr->
data, chunk_curr->
data_len);
484 BLI_assert(data_curr_len <= chunk_curr->data_len);
487 const size_t data_prev_grow_len = data_prev_len - chunk_prev->
data_len;
490 memcpy(data_prev, chunk_prev->
data, chunk_prev->
data_len);
491 memcpy(&data_prev[chunk_prev->
data_len], chunk_curr->
data, data_prev_grow_len);
494 memcpy(data_curr, &chunk_curr->
data[data_prev_grow_len], data_curr_len);
521 const size_t data_len,
522 size_t *r_data_trim_len,
523 size_t *r_data_last_chunk_len)
525 size_t data_last_chunk_len = 0;
526 size_t data_trim_len = data_len;
528 #ifdef USE_MERGE_CHUNKS
533 data_trim_len = data_trim_len - data_last_chunk_len;
534 if (data_last_chunk_len) {
535 if (data_last_chunk_len < info->chunk_byte_size_min) {
544 data_last_chunk_len = data_len;
550 data_trim_len = data_trim_len - data_last_chunk_len;
553 BLI_assert(data_trim_len + data_last_chunk_len == data_len);
555 *r_data_trim_len = data_trim_len;
556 *r_data_last_chunk_len = data_last_chunk_len;
579 const size_t data_len)
583 #ifdef USE_MERGE_CHUNKS
584 BLI_assert(data_len <= info->chunk_byte_size_max);
591 const size_t data_merge_len = chunk_prev->
data_len + data_len;
595 memcpy(&data_merge[chunk_prev->
data_len],
data, data_len);
601 memcpy(data_merge, chunk_prev->
data, chunk_prev->
data_len);
602 memcpy(&data_merge[chunk_prev->
data_len],
data, data_len);
619 # ifdef USE_MERGE_CHUNKS
638 size_t data_trim_len, data_last_chunk_len;
641 if (data_trim_len != 0) {
650 while (i_prev != data_trim_len) {
657 if (data_last_chunk_len) {
666 if (data_last_chunk_len) {
672 #ifdef USE_MERGE_CHUNKS
687 #ifdef USE_MERGE_CHUNKS
698 const size_t data_len)
702 size_t data_trim_len, data_last_chunk_len;
706 while (i_prev != data_trim_len) {
713 if (data_last_chunk_len) {
719 #ifdef USE_MERGE_CHUNKS
728 # ifdef USE_MERGE_CHUNKS
749 #define HASH_INIT (5381)
759 const signed char *p;
762 for (p = (
const signed char *)key; n--; p++) {
763 h = ((h << 5) + h) + (
unsigned int)*p;
771 #ifdef USE_HASH_TABLE_ACCUMULATE
773 const uchar *data_slice,
774 const size_t data_slice_len,
778 for (
size_t i = 0, i_step = 0; i_step < data_slice_len; i++, i_step += info->
chunk_stride) {
784 for (
size_t i = 0; i < data_slice_len; i++) {
796 const size_t data_len,
799 const size_t hash_array_len = data_len / info->
chunk_stride;
802 size_t i_next = hash_array_len - i;
808 BLI_assert(data_trim_len <= cref->link->data_len);
812 }
while ((i < hash_array_len) && (
cref !=
NULL));
822 if (
UNLIKELY((iter_steps > hash_array_len))) {
823 iter_steps = hash_array_len;
826 const size_t hash_array_search_len = hash_array_len - iter_steps;
827 while (iter_steps != 0) {
828 const size_t hash_offset = iter_steps;
829 for (
uint i = 0; i < hash_array_search_len; i++) {
830 hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1);
843 if (
UNLIKELY(!(iter_steps <= hash_array_len))) {
845 iter_steps = hash_array_len;
849 size_t iter_steps_sub = iter_steps;
851 while (iter_steps != 0) {
852 const size_t hash_array_search_len = hash_array_len - iter_steps_sub;
853 const size_t hash_offset = iter_steps;
854 for (
uint i = 0; i < hash_array_search_len; i++) {
855 hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1);
858 iter_steps_sub += iter_steps;
866 const size_t hash_store_len)
875 # ifdef USE_HASH_TABLE_KEY_CACHE
905 # ifdef USE_HASH_TABLE_KEY_CACHE
915 const size_t table_len,
916 const size_t i_table_start,
918 const size_t data_len,
922 size_t size_left = data_len - offset;
924 size_t key_index = (size_t)(key % (
hash_key)table_len);
925 for (
const BTableRef *tref = table[key_index]; tref; tref = tref->
next) {
927 # ifdef USE_HASH_TABLE_KEY_CACHE
932 if (chunk_test->
data_len <= size_left) {
949 const size_t data_hash_len = BCHUNK_HASH_LEN * info->
chunk_stride;
953 # ifdef USE_HASH_TABLE_KEY_CACHE
976 const size_t table_len,
979 const size_t data_len,
983 const size_t data_hash_len = BCHUNK_HASH_LEN * info->
chunk_stride;
985 size_t size_left = data_len - offset;
987 size_t key_index = (size_t)(key % (
hash_key)table_len);
988 for (
BTableRef *tref = table[key_index]; tref; tref = tref->
next) {
990 # ifdef USE_HASH_TABLE_KEY_CACHE
995 if (chunk_test->
data_len <= size_left) {
1038 uint chunk_list_reference_skip_len = 0;
1039 size_t chunk_list_reference_skip_bytes = 0;
1042 #ifdef USE_FASTPATH_CHUNKS_FIRST
1044 bool full_match =
true;
1049 cref_match_first =
cref;
1050 chunk_list_reference_skip_len += 1;
1075 if (cref_match_first !=
NULL) {
1076 size_t chunk_size_step = 0;
1080 chunk_size_step += chunk->
data_len;
1084 if (
cref == cref_match_first) {
1094 i_prev = chunk_size_step;
1112 #define data_len_original invalid_usage
1113 #ifdef data_len_original
1118 #ifdef USE_FASTPATH_CHUNKS_LAST
1124 size_t offset = data_len - chunk_test->
data_len;
1127 chunk_list_reference_last =
cref;
1128 chunk_list_reference_skip_len += 1;
1149 bool use_aligned =
false;
1151 #ifdef USE_ALIGN_CHUNKS_TEST
1154 if (data_len - i_prev <= chunk_list->total_size / 4) {
1170 while (i_prev != data_len) {
1174 if ((
cref != chunk_list_reference_last) &&
1192 (chunk_list_reference->
chunk_refs_len >= chunk_list_reference_skip_len) &&
1203 #ifdef USE_HASH_TABLE_ACCUMULATE
1204 size_t i_table_start = i_prev;
1205 const size_t table_hash_array_len = (data_len - i_prev) / info->
chunk_stride;
1206 hash_key *table_hash_array =
MEM_mallocN(
sizeof(*table_hash_array) * table_hash_array_len,
1213 uint i_table_start = 0;
1217 const uint chunk_list_reference_remaining_len = (chunk_list_reference->
chunk_refs_len -
1218 chunk_list_reference_skip_len) +
1221 chunk_list_reference_remaining_len *
sizeof(
BTableRef), __func__);
1222 uint table_ref_stack_n = 0;
1230 #ifdef USE_HASH_TABLE_ACCUMULATE
1236 size_t chunk_list_reference_bytes_remaining = chunk_list_reference->
total_size -
1237 chunk_list_reference_skip_bytes;
1239 if (cref_match_first) {
1240 cref = cref_match_first;
1247 #ifdef USE_PARANOID_CHECKS
1249 size_t test_bytes_len = 0;
1251 while (cr != chunk_list_reference_last) {
1255 BLI_assert(test_bytes_len == chunk_list_reference_bytes_remaining);
1259 while ((
cref != chunk_list_reference_last) &&
1270 size_t key_index = (size_t)(key % (
hash_key)table_len);
1271 BTableRef *tref_prev = table[key_index];
1272 BLI_assert(table_ref_stack_n < chunk_list_reference_remaining_len);
1273 BTableRef *tref = &table_ref_stack[table_ref_stack_n++];
1275 tref->
next = tref_prev;
1276 table[key_index] = tref;
1282 BLI_assert(table_ref_stack_n <= chunk_list_reference_remaining_len);
1284 #ifdef USE_HASH_TABLE_ACCUMULATE
1291 for (
size_t i = i_prev; i < data_len;) {
1295 info, table, table_len, i_table_start,
data, data_len, i, table_hash_array);
1296 if (cref_found !=
NULL) {
1315 while (!
ELEM(cref_found->
next,
NULL, chunk_list_reference_last)) {
1316 cref_found = cref_found->
next;
1340 #ifdef USE_HASH_TABLE_ACCUMULATE
1358 if (i_prev != data_len) {
1365 #ifdef USE_FASTPATH_CHUNKS_LAST
1366 if (chunk_list_reference_last !=
NULL) {
1382 #undef data_len_original
1430 #ifdef USE_MERGE_CHUNKS
1435 #ifdef USE_HASH_TABLE_ACCUMULATE
1470 state_next =
state->next;
1514 size_t size_accum = 0;
1516 size_accum +=
state->chunk_list->total_size;
1527 size_t size_total = 0;
1533 size_total += (size_t)chunk->
data_len;
1558 const size_t data_len,
1564 #ifdef USE_PARANOID_CHECKS
1565 if (state_reference) {
1571 if (state_reference) {
1584 chunk_list->
users += 1;
1587 state->chunk_list = chunk_list;
1591 #ifdef USE_PARANOID_CHECKS
1593 size_t data_test_len;
1611 #ifdef USE_PARANOID_CHECKS
1627 return state->chunk_list->total_size;
1635 #ifdef USE_PARANOID_CHECKS
1636 size_t data_test_len = 0;
1658 *r_data_len =
state->chunk_list->total_size;
1671 size_t total_size = 0;
1695 #ifdef USE_MERGE_CHUNKS
1723 #define GHASH_PTR_ADD_USER(gh, pt) \
1726 if (BLI_ghash_ensure_p((gh), (pt), &val)) { \
1727 *((int *)val) += 1; \
1730 *((int *)val) = 1; \
1782 #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_)
unsigned int BLI_ghash_len(GHash *gh) ATTR_WARN_UNUSED_RESULT
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT 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 totelem, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1)
int BLI_mempool_len(BLI_mempool *pool) ATTR_NONNULL(1)
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
#define POINTER_AS_INT(i)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei stride
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 BChunk * bchunk_new_copydata(BArrayMemory *bs_mem, const uchar *data, const size_t data_len)
static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref, hash_key *hash_store, const size_t hash_store_len)
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 array_store_free_data(BArrayStore *bs)
#define USE_HASH_TABLE_ACCUMULATE
struct BArrayMemory BArrayMemory
struct BChunkRef BChunkRef
BArrayStore * BLI_array_store_create(uint stride, uint chunk_count)
static BChunkList * bchunk_list_new(BArrayMemory *bs_mem, size_t total_size)
struct BArrayInfo BArrayInfo
static void hash_array_from_cref(const BArrayInfo *info, const BChunkRef *cref, const size_t data_len, hash_key *hash_array)
BLI_INLINE uint hash_data_single(const uchar p)
void * BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len)
#define GHASH_PTR_ADD_USER(gh, pt)
static bool bchunk_data_compare(const BChunk *chunk, const uchar *data_base, const size_t data_base_len, const size_t offset)
static void bchunk_list_fill_from_array(const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, const uchar *data, const size_t data_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)
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)
static uint hash_data(const uchar *key, size_t n)
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(BArrayState *state, void *data)
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)
BArrayState * BLI_array_store_state_add(BArrayStore *bs, const void *data, const size_t data_len, const BArrayState *state_reference)
#define HASH_TABLE_KEY_FALLBACK
size_t BLI_array_store_state_size_get(BArrayState *state)
#define data_len_original
struct BChunkList BChunkList
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)
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)
void BLI_array_store_destroy(BArrayStore *bs)
static BChunk * bchunk_new(BArrayMemory *bs_mem, const uchar *data, const size_t data_len)
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
#define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS
static void bchunk_list_append(const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, BChunk *chunk)
static void bchunk_list_append_data(const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, const uchar *data, const size_t data_len)
#define BCHUNK_SIZE_MIN_DIV
struct BTableRef BTableRef
void(* MEM_freeN)(void *vmemh)
size_t(* MEM_allocN_len)(const void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
void *(* MEM_mallocN)(size_t len, const char *str)
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
unsigned __int64 uint64_t
size_t chunk_byte_size_max
size_t chunk_byte_size_min
size_t accum_read_ahead_bytes
size_t accum_read_ahead_len
struct BArrayState * next
struct BChunkList * chunk_list
struct BArrayState * prev