Blender V4.3
BLI_array_store_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
7#include "MEM_guardedalloc.h"
8
9#include "BLI_array_store.h"
10#include "BLI_array_utils.h"
11#include "BLI_listbase.h"
12#include "BLI_rand.h"
14#include "BLI_string.h"
15#include "BLI_sys_types.h"
16#include "BLI_utildefines.h"
17
18/* print memory savings */
19// #define DEBUG_PRINT
20
21/* -------------------------------------------------------------------- */
22/* Helper functions */
23
24#ifdef DEBUG_PRINT
25static void print_mem_saved(const char *id, const BArrayStore *bs)
26{
27 const double size_real = BLI_array_store_calc_size_compacted_get(bs);
28 const double size_expand = BLI_array_store_calc_size_expanded_get(bs);
29 const double percent = size_expand ? ((size_real / size_expand) * 100.0) : -1.0;
30 printf("%s: %.8f%%\n", id, percent);
31}
32#endif
33
34/* -------------------------------------------------------------------- */
35/* Test Chunks (building data from list of chunks) */
36
37struct TestChunk {
39 const void *data;
40 size_t data_len;
41};
42
43static TestChunk *testchunk_list_add(ListBase *lb, const void *data, size_t data_len)
44{
45 TestChunk *tc = (TestChunk *)MEM_mallocN(sizeof(*tc), __func__);
46 tc->data = data;
47 tc->data_len = data_len;
48 BLI_addtail(lb, tc);
49
50 return tc;
51}
52
53#if 0
54static TestChunk *testchunk_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
55{
56 void *data_copy = MEM_mallocN(data_len, __func__);
57 memcpy(data_copy, data, data_len);
58 return testchunk_list_add(lb, data_copy, data_len);
59}
60#endif
61
63{
64 for (TestChunk *tc = (TestChunk *)lb->first, *tb_next; tc; tc = tb_next) {
65 tb_next = tc->next;
66 MEM_freeN((void *)tc->data);
67 MEM_freeN(tc);
68 }
70}
71
72#if 0
73static char *testchunk_as_data(ListBase *lb, size_t *r_data_len)
74{
75 size_t data_len = 0;
76 for (TestChunk *tc = (TestChunk *)lb->first; tc; tc = tc->next) {
77 data_len += tc->data_len;
78 }
79 char *data = (char *)MEM_mallocN(data_len, __func__);
80 size_t i = 0;
81 for (TestChunk *tc = (TestChunk *)lb->first; tc; tc = tc->next) {
82 memcpy(&data[i], tc->data, tc->data_len);
83 data_len += tc->data_len;
84 i += tc->data_len;
85 }
86 if (r_data_len) {
87 *r_data_len = i;
88 }
89 return data;
90}
91#endif
92
93static char *testchunk_as_data_array(TestChunk **tc_array, int tc_array_len, size_t *r_data_len)
94{
95 size_t data_len = 0;
96 for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
97 data_len += tc_array[tc_index]->data_len;
98 }
99 char *data = (char *)MEM_mallocN(data_len, __func__);
100 size_t i = 0;
101 for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
102 TestChunk *tc = tc_array[tc_index];
103 memcpy(&data[i], tc->data, tc->data_len);
104 i += tc->data_len;
105 }
106 if (r_data_len) {
107 *r_data_len = i;
108 }
109 return data;
110}
111
112/* -------------------------------------------------------------------- */
113/* Test Buffer */
114
115/* API to handle local allocation of data so we can compare it with the data in the array_store */
118 const void *data;
119 size_t data_len;
120
121 /* for reference */
123};
124
125static TestBuffer *testbuffer_list_add(ListBase *lb, const void *data, size_t data_len)
126{
127 TestBuffer *tb = (TestBuffer *)MEM_mallocN(sizeof(*tb), __func__);
128 tb->data = data;
129 tb->data_len = data_len;
130 tb->state = nullptr;
131 BLI_addtail(lb, tb);
132 return tb;
133}
134
135static TestBuffer *testbuffer_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
136{
137 void *data_copy = MEM_mallocN(data_len, __func__);
138 memcpy(data_copy, data, data_len);
139 return testbuffer_list_add(lb, data_copy, data_len);
140}
141
142static void testbuffer_list_state_from_data(ListBase *lb, const char *data, const size_t data_len)
143{
144 testbuffer_list_add_copydata(lb, (const void *)data, data_len);
145}
146
152 const char *data,
153 const size_t data_len,
154 const size_t stride)
155{
156 if (stride == 1) {
157 testbuffer_list_state_from_data(lb, data, data_len);
158 }
159 else {
160 const size_t data_stride_len = data_len * stride;
161 char *data_stride = (char *)MEM_mallocN(data_stride_len, __func__);
162
163 for (size_t i = 0, i_stride = 0; i < data_len; i += 1, i_stride += stride) {
164 memset(&data_stride[i_stride], data[i], stride);
165 }
166
167 testbuffer_list_add(lb, (const void *)data_stride, data_stride_len);
168 }
169}
170
171#define testbuffer_list_state_from_string_array(lb, data_array) \
172 { \
173 uint i_ = 0; \
174 const char *data; \
175 while ((data = data_array[i_++])) { \
176 testbuffer_list_state_from_data(lb, data, strlen(data)); \
177 } \
178 } \
179 ((void)0)
180
181//
182
183#define TESTBUFFER_STRINGS_CREATE(lb, ...) \
184 { \
185 BLI_listbase_clear(lb); \
186 const char *data_array[] = {__VA_ARGS__ nullptr}; \
187 testbuffer_list_state_from_string_array((lb), data_array); \
188 } \
189 ((void)0)
190
191/* test in both directions */
192#define TESTBUFFER_STRINGS(stride, chunk_count, ...) \
193 { \
194 ListBase lb; \
195 TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
196\
197 testbuffer_run_tests_simple(&lb, stride, chunk_count); \
198\
199 testbuffer_list_free(&lb); \
200 } \
201 ((void)0)
202
204{
205 size_t data_state_len;
206 bool ok = true;
207 void *data_state = BLI_array_store_state_data_get_alloc(tb->state, &data_state_len);
208 if (tb->data_len != data_state_len) {
209 ok = false;
210 }
211 else if (memcmp(data_state, tb->data, data_state_len) != 0) {
212 ok = false;
213 }
214 MEM_freeN(data_state);
215 return ok;
216}
217
218static bool testbuffer_list_validate(const ListBase *lb)
219{
220 LISTBASE_FOREACH (TestBuffer *, tb, lb) {
221 if (!testbuffer_item_validate(tb)) {
222 return false;
223 }
224 }
225
226 return true;
227}
228
229static void testbuffer_list_data_randomize(ListBase *lb, uint random_seed)
230{
231 LISTBASE_FOREACH (TestBuffer *, tb, lb) {
232 BLI_array_randomize((void *)tb->data, 1, tb->data_len, random_seed++);
233 }
234}
235
237{
238 for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_prev = nullptr; tb;
239 tb_prev = tb, tb = tb->next)
240 {
241 tb->state = BLI_array_store_state_add(
242 bs, tb->data, tb->data_len, (tb_prev ? tb_prev->state : nullptr));
243 }
244}
245
247{
248 LISTBASE_FOREACH (TestBuffer *, tb, lb) {
249 BLI_array_store_state_remove(bs, tb->state);
250 tb->state = nullptr;
251 }
252}
253
255{
256 for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_next; tb; tb = tb_next) {
257 tb_next = tb->next;
258 MEM_freeN((void *)tb->data);
259 MEM_freeN(tb);
260 }
262}
263
265{
267 EXPECT_TRUE(testbuffer_list_validate(lb));
268 EXPECT_TRUE(BLI_array_store_is_valid(bs));
269#ifdef DEBUG_PRINT
270 print_mem_saved("data", bs);
271#endif
272}
273
274/* avoid copy-paste code to run tests */
276{
277 /* forwards */
280
282
283 /* backwards */
286}
287
288static void testbuffer_run_tests_simple(ListBase *lb, const int stride, const int chunk_count)
289{
290 BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
291 testbuffer_run_tests(bs, lb);
293}
294
295/* -------------------------------------------------------------------- */
296/* Basic Tests */
297
298TEST(array_store, Nop)
299{
302}
303
304TEST(array_store, NopState)
305{
307 const uchar data[] = "test";
308 BArrayState *state = BLI_array_store_state_add(bs, data, sizeof(data) - 1, nullptr);
312}
313
314TEST(array_store, Single)
315{
317 const char data_src[] = "test";
318 const char *data_dst;
319 BArrayState *state = BLI_array_store_state_add(bs, data_src, sizeof(data_src), nullptr);
320 size_t data_dst_len;
321 data_dst = (char *)BLI_array_store_state_data_get_alloc(state, &data_dst_len);
322 EXPECT_STREQ(data_src, data_dst);
323 EXPECT_EQ(data_dst_len, sizeof(data_src));
325 MEM_freeN((void *)data_dst);
326}
327
328TEST(array_store, DoubleNop)
329{
331 const char data_src[] = "test";
332 const char *data_dst;
333
334 BArrayState *state_a = BLI_array_store_state_add(bs, data_src, sizeof(data_src), nullptr);
335 BArrayState *state_b = BLI_array_store_state_add(bs, data_src, sizeof(data_src), state_a);
336
338 EXPECT_EQ(BLI_array_store_calc_size_expanded_get(bs), sizeof(data_src) * 2);
339
340 size_t data_dst_len;
341
342 data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
343 EXPECT_STREQ(data_src, data_dst);
344 MEM_freeN((void *)data_dst);
345
346 data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
347 EXPECT_STREQ(data_src, data_dst);
348 MEM_freeN((void *)data_dst);
349
350 EXPECT_EQ(data_dst_len, sizeof(data_src));
352}
353
354TEST(array_store, DoubleDiff)
355{
357 const char data_src_a[] = "test";
358 const char data_src_b[] = "####";
359 const char *data_dst;
360
361 BArrayState *state_a = BLI_array_store_state_add(bs, data_src_a, sizeof(data_src_a), nullptr);
362 BArrayState *state_b = BLI_array_store_state_add(bs, data_src_b, sizeof(data_src_b), state_a);
363 size_t data_dst_len;
364
365 EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), sizeof(data_src_a) * 2);
366 EXPECT_EQ(BLI_array_store_calc_size_expanded_get(bs), sizeof(data_src_a) * 2);
367
368 data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
369 EXPECT_STREQ(data_src_a, data_dst);
370 MEM_freeN((void *)data_dst);
371
372 data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
373 EXPECT_STREQ(data_src_b, data_dst);
374 MEM_freeN((void *)data_dst);
375
377}
378
379TEST(array_store, TextMixed)
380{
381 TESTBUFFER_STRINGS(1, 4, "", );
382 TESTBUFFER_STRINGS(1, 4, "test", );
383 TESTBUFFER_STRINGS(1, 4, "", "test", );
384 TESTBUFFER_STRINGS(1, 4, "test", "", );
385 TESTBUFFER_STRINGS(1, 4, "test", "", "test", );
386 TESTBUFFER_STRINGS(1, 4, "", "test", "", );
387}
388
389TEST(array_store, TextDupeIncreaseDecrease)
390{
391 ListBase lb;
392
393#define D "#1#2#3#4"
394 TESTBUFFER_STRINGS_CREATE(&lb, D, D D, D D D, D D D D, );
395
397
398 /* forward */
400 EXPECT_TRUE(testbuffer_list_validate(&lb));
401 EXPECT_TRUE(BLI_array_store_is_valid(bs));
403
406
407 /* backwards */
409 EXPECT_TRUE(testbuffer_list_validate(&lb));
410 EXPECT_TRUE(BLI_array_store_is_valid(bs));
411 /* larger since first block doesn't de-duplicate */
413
414#undef D
416
418}
419
420/* -------------------------------------------------------------------- */
421/* Plain Text Tests */
422
427static void plain_text_helper(const char *words,
428 int words_len,
429 const char word_delim,
430 const int stride,
431 const int chunk_count,
432 const int random_seed)
433{
434
435 ListBase lb;
437
438 for (int i = 0, i_prev = 0; i < words_len; i++) {
439 if (ELEM(words[i], word_delim, '\0')) {
440 if (i != i_prev) {
441 testbuffer_list_state_from_data__stride_expand(&lb, &words[i_prev], i - i_prev, stride);
442 }
443 i_prev = i;
444 }
445 }
446
447 if (random_seed) {
448 testbuffer_list_data_randomize(&lb, random_seed);
449 }
450
451 testbuffer_run_tests_simple(&lb, stride, chunk_count);
452
454}
455
456/* split by '.' (multiple words) */
457#define WORDS words10k, sizeof(words10k)
458TEST(array_store, TextSentences_Chunk1)
459{
460 plain_text_helper(WORDS, '.', 1, 1, 0);
461}
462TEST(array_store, TextSentences_Chunk2)
463{
464 plain_text_helper(WORDS, '.', 1, 2, 0);
465}
466TEST(array_store, TextSentences_Chunk8)
467{
468 plain_text_helper(WORDS, '.', 1, 8, 0);
469}
470TEST(array_store, TextSentences_Chunk32)
471{
472 plain_text_helper(WORDS, '.', 1, 32, 0);
473}
474TEST(array_store, TextSentences_Chunk128)
475{
476 plain_text_helper(WORDS, '.', 1, 128, 0);
477}
478TEST(array_store, TextSentences_Chunk1024)
479{
480 plain_text_helper(WORDS, '.', 1, 1024, 0);
481}
482/* odd numbers */
483TEST(array_store, TextSentences_Chunk3)
484{
485 plain_text_helper(WORDS, '.', 1, 3, 0);
486}
487TEST(array_store, TextSentences_Chunk13)
488{
489 plain_text_helper(WORDS, '.', 1, 13, 0);
490}
491TEST(array_store, TextSentences_Chunk131)
492{
493 plain_text_helper(WORDS, '.', 1, 131, 0);
494}
495
496/* split by ' ', individual words */
497TEST(array_store, TextWords_Chunk1)
498{
499 plain_text_helper(WORDS, ' ', 1, 1, 0);
500}
501TEST(array_store, TextWords_Chunk2)
502{
503 plain_text_helper(WORDS, ' ', 1, 2, 0);
504}
505TEST(array_store, TextWords_Chunk8)
506{
507 plain_text_helper(WORDS, ' ', 1, 8, 0);
508}
509TEST(array_store, TextWords_Chunk32)
510{
511 plain_text_helper(WORDS, ' ', 1, 32, 0);
512}
513TEST(array_store, TextWords_Chunk128)
514{
515 plain_text_helper(WORDS, ' ', 1, 128, 0);
516}
517TEST(array_store, TextWords_Chunk1024)
518{
519 plain_text_helper(WORDS, ' ', 1, 1024, 0);
520}
521/* odd numbers */
522TEST(array_store, TextWords_Chunk3)
523{
524 plain_text_helper(WORDS, ' ', 1, 3, 0);
525}
526TEST(array_store, TextWords_Chunk13)
527{
528 plain_text_helper(WORDS, ' ', 1, 13, 0);
529}
530TEST(array_store, TextWords_Chunk131)
531{
532 plain_text_helper(WORDS, ' ', 1, 131, 0);
533}
534
535/* various tests with different strides & randomizing */
536TEST(array_store, TextSentencesRandom_Stride3_Chunk3)
537{
538 plain_text_helper(WORDS, 'q', 3, 3, 7337);
539}
540TEST(array_store, TextSentencesRandom_Stride8_Chunk8)
541{
542 plain_text_helper(WORDS, 'n', 8, 8, 5667);
543}
544TEST(array_store, TextSentencesRandom_Stride32_Chunk1)
545{
546 plain_text_helper(WORDS, 'a', 1, 32, 1212);
547}
548TEST(array_store, TextSentencesRandom_Stride12_Chunk512)
549{
550 plain_text_helper(WORDS, 'g', 12, 512, 9999);
551}
552TEST(array_store, TextSentencesRandom_Stride128_Chunk6)
553{
554 plain_text_helper(WORDS, 'b', 20, 6, 1000);
555}
556
557#undef WORDS
558
559/* -------------------------------------------------------------------- */
560/* Random Data Tests */
561
563{
564 if (min_i == max_i) {
565 return min_i;
566 }
568 BLI_assert(((min_i % step) == 0) && ((max_i % step) == 0));
569 uint range = (max_i - min_i);
570 uint value = BLI_rng_get_uint(rng) % range;
571 value = (value / step) * step;
572 return min_i + value;
573}
574
576 const size_t stride,
577 const size_t data_min_len,
578 const size_t data_max_len,
579
580 const uint mutate,
581 RNG *rng)
582{
583 size_t data_len = rand_range_i(rng, data_min_len, data_max_len + stride, stride);
584 char *data = (char *)MEM_mallocN(data_len, __func__);
585
586 if (lb->last == nullptr) {
587 BLI_rng_get_char_n(rng, data, data_len);
588 }
589 else {
590 TestBuffer *tb_last = (TestBuffer *)lb->last;
591 if (tb_last->data_len >= data_len) {
592 memcpy(data, tb_last->data, data_len);
593 }
594 else {
595 memcpy(data, tb_last->data, tb_last->data_len);
596 BLI_rng_get_char_n(rng, &data[tb_last->data_len], data_len - tb_last->data_len);
597 }
598
599 /* perform multiple small mutations to the array. */
600 for (int i = 0; i < mutate; i++) {
601 enum {
602 MUTATE_NOP = 0,
603 MUTATE_ADD,
604 MUTATE_REMOVE,
605 MUTATE_ROTATE,
606 MUTATE_RANDOMIZE,
607 MUTATE_TOTAL,
608 };
609
610 switch (BLI_rng_get_uint(rng) % MUTATE_TOTAL) {
611 case MUTATE_NOP: {
612 break;
613 }
614 case MUTATE_ADD: {
615 const uint offset = rand_range_i(rng, 0, data_len, stride);
616 if (data_len < data_max_len) {
617 data_len += stride;
618 data = (char *)MEM_reallocN((void *)data, data_len);
619 memmove(&data[offset + stride], &data[offset], data_len - (offset + stride));
620 BLI_rng_get_char_n(rng, &data[offset], stride);
621 }
622 break;
623 }
624 case MUTATE_REMOVE: {
625 const uint offset = rand_range_i(rng, 0, data_len, stride);
626 if (data_len > data_min_len) {
627 memmove(&data[offset], &data[offset + stride], data_len - (offset + stride));
628 data_len -= stride;
629 }
630 break;
631 }
632 case MUTATE_ROTATE: {
633 int items = data_len / stride;
634 if (items > 1) {
635 _bli_array_wrap(data, items, stride, (BLI_rng_get_uint(rng) % 2) ? -1 : 1);
636 }
637 break;
638 }
639 case MUTATE_RANDOMIZE: {
640 if (data_len > 0) {
641 const uint offset = rand_range_i(rng, 0, data_len - stride, stride);
642 BLI_rng_get_char_n(rng, &data[offset], stride);
643 }
644 break;
645 }
646 default:
648 }
649 }
650 }
651
652 testbuffer_list_add(lb, (const void *)data, data_len);
653}
654
655static void random_data_mutate_helper(const int items_size_min,
656 const int items_size_max,
657 const int items_total,
658 const int stride,
659 const int chunk_count,
660 const int random_seed,
661 const int mutate)
662{
663
664 ListBase lb;
666
667 const size_t data_min_len = items_size_min * stride;
668 const size_t data_max_len = items_size_max * stride;
669
670 {
671 RNG *rng = BLI_rng_new(random_seed);
672 for (int i = 0; i < items_total; i++) {
673 testbuffer_list_state_random_data(&lb, stride, data_min_len, data_max_len, mutate, rng);
674 }
675 BLI_rng_free(rng);
676 }
677
678 testbuffer_run_tests_simple(&lb, stride, chunk_count);
679
681}
682
683TEST(array_store, TestData_Stride1_Chunk32_Mutate2)
684{
685 random_data_mutate_helper(0, 100, 400, 1, 32, 9779, 2);
686}
687TEST(array_store, TestData_Stride8_Chunk512_Mutate2)
688{
689 random_data_mutate_helper(0, 128, 400, 8, 512, 1001, 2);
690}
691TEST(array_store, TestData_Stride12_Chunk48_Mutate2)
692{
693 random_data_mutate_helper(200, 256, 400, 12, 48, 1331, 2);
694}
695TEST(array_store, TestData_Stride32_Chunk64_Mutate1)
696{
697 random_data_mutate_helper(0, 256, 200, 32, 64, 3112, 1);
698}
699TEST(array_store, TestData_Stride32_Chunk64_Mutate8)
700{
701 random_data_mutate_helper(0, 256, 200, 32, 64, 7117, 8);
702}
703
704/* -------------------------------------------------------------------- */
705/* Randomized Chunks Test */
706
708 const int chunks_per_buffer,
709 const int stride,
710 const int chunk_count,
711 const int random_seed)
712{
713 RNG *rng = BLI_rng_new(random_seed);
714 const size_t chunk_size_bytes = stride * chunk_count;
715 for (int i = 0; i < chunks_per_buffer; i++) {
716 char *data_chunk = (char *)MEM_mallocN(chunk_size_bytes, __func__);
717 BLI_rng_get_char_n(rng, data_chunk, chunk_size_bytes);
718 testchunk_list_add(lb, data_chunk, chunk_size_bytes);
719 }
720 BLI_rng_free(rng);
721}
722
726static void random_chunk_mutate_helper(const int chunks_per_buffer,
727 const int items_total,
728 const int stride,
729 const int chunk_count,
730 const int random_seed)
731{
732 /* generate random chunks */
733
734 ListBase random_chunks;
735 BLI_listbase_clear(&random_chunks);
736 random_chunk_generate(&random_chunks, chunks_per_buffer, stride, chunk_count, random_seed);
737 TestChunk **chunks_array = (TestChunk **)MEM_mallocN(chunks_per_buffer * sizeof(TestChunk *),
738 __func__);
739 {
740 TestChunk *tc = (TestChunk *)random_chunks.first;
741 for (int i = 0; i < chunks_per_buffer; i++, tc = tc->next) {
742 chunks_array[i] = tc;
743 }
744 }
745
746 /* add and re-order each time */
747 ListBase lb;
749
750 {
751 RNG *rng = BLI_rng_new(random_seed);
752 for (int i = 0; i < items_total; i++) {
753 BLI_rng_shuffle_array(rng, chunks_array, sizeof(TestChunk *), chunks_per_buffer);
754 size_t data_len;
755 char *data = testchunk_as_data_array(chunks_array, chunks_per_buffer, &data_len);
756 BLI_assert(data_len == chunks_per_buffer * chunk_count * stride);
757 testbuffer_list_add(&lb, (const void *)data, data_len);
758 }
759 BLI_rng_free(rng);
760 }
761
762 testchunk_list_free(&random_chunks);
763 MEM_freeN(chunks_array);
764
765 BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
767
768 size_t expected_size = chunks_per_buffer * chunk_count * stride;
770
772
774}
775
776TEST(array_store, TestChunk_Rand8_Stride1_Chunk64)
777{
778 random_chunk_mutate_helper(8, 100, 1, 64, 9779);
779}
780TEST(array_store, TestChunk_Rand32_Stride1_Chunk64)
781{
782 random_chunk_mutate_helper(32, 100, 1, 64, 1331);
783}
784TEST(array_store, TestChunk_Rand64_Stride8_Chunk32)
785{
786 random_chunk_mutate_helper(64, 100, 8, 32, 2772);
787}
788TEST(array_store, TestChunk_Rand31_Stride11_Chunk21)
789{
790 random_chunk_mutate_helper(31, 100, 11, 21, 7117);
791}
792
793#if 0
794/* -------------------------------------------------------------------- */
795
796/* Test From Files (disabled, keep for local tests.) */
797
798static void *file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
799{
800 FILE *fp = fopen(filepath, "rb");
801 void *mem = nullptr;
802
803 if (fp) {
804 long int filelen_read;
805 fseek(fp, 0L, SEEK_END);
806 const long int filelen = ftell(fp);
807 if (filelen == -1) {
808 goto finally;
809 }
810 fseek(fp, 0L, SEEK_SET);
811
812 mem = MEM_mallocN(filelen + pad_bytes, __func__);
813 if (mem == nullptr) {
814 goto finally;
815 }
816
817 filelen_read = fread(mem, 1, filelen, fp);
818 if ((filelen_read != filelen) || ferror(fp)) {
819 MEM_freeN(mem);
820 mem = nullptr;
821 goto finally;
822 }
823
824 *r_size = filelen_read;
825
826 finally:
827 fclose(fp);
828 }
829
830 return mem;
831}
832
833TEST(array_store, PlainTextFiles)
834{
835 ListBase lb;
838
839 for (int i = 0; i < 629; i++) {
840 char str[512];
841 BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/xz_data/%04d.c.xz", i);
842 // BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/c_code/%04d.c", i);
843 // printf("%s\n", str);
844 size_t data_len;
845 void *data;
846 data = file_read_binary_as_mem(str, 0, &data_len);
847
848 testbuffer_list_add(&lb, (const void *)data, data_len);
849 }
850
851 /* forwards */
853 EXPECT_TRUE(testbuffer_list_validate(&lb));
854 EXPECT_TRUE(BLI_array_store_is_valid(bs));
855# ifdef DEBUG_PRINT
856 print_mem_saved("source code forward", bs);
857# endif
858
861
862 /* backwards */
864 EXPECT_TRUE(testbuffer_list_validate(&lb));
865 EXPECT_TRUE(BLI_array_store_is_valid(bs));
866# ifdef DEBUG_PRINT
867 print_mem_saved("source code backwards", bs);
868# endif
869
872}
873#endif
Efficient in-memory storage of multiple similar arrays.
BArrayState * BLI_array_store_state_add(BArrayStore *bs, const void *data, size_t data_len, const BArrayState *state_reference)
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
bool BLI_array_store_is_valid(BArrayStore *bs)
size_t BLI_array_store_state_size_get(BArrayState *state)
void * BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len)
void BLI_array_store_destroy(BArrayStore *bs)
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
BArrayStore * BLI_array_store_create(unsigned int stride, unsigned int chunk_count)
static void random_data_mutate_helper(const int items_size_min, const int items_size_max, const int items_total, const int stride, const int chunk_count, const int random_seed, const int mutate)
#define TESTBUFFER_STRINGS(stride, chunk_count,...)
static void testbuffer_list_state_from_data__stride_expand(ListBase *lb, const char *data, const size_t data_len, const size_t stride)
TEST(array_store, Nop)
#define TESTBUFFER_STRINGS_CREATE(lb,...)
static TestChunk * testchunk_list_add(ListBase *lb, const void *data, size_t data_len)
static void testbuffer_list_state_random_data(ListBase *lb, const size_t stride, const size_t data_min_len, const size_t data_max_len, const uint mutate, RNG *rng)
static void testbuffer_list_store_populate(BArrayStore *bs, ListBase *lb)
static void testbuffer_list_store_clear(BArrayStore *bs, ListBase *lb)
static bool testbuffer_item_validate(TestBuffer *tb)
static void testbuffer_list_data_randomize(ListBase *lb, uint random_seed)
static TestBuffer * testbuffer_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
static void random_chunk_mutate_helper(const int chunks_per_buffer, const int items_total, const int stride, const int chunk_count, const int random_seed)
static void testbuffer_run_tests(BArrayStore *bs, ListBase *lb)
static void testchunk_list_free(ListBase *lb)
static void testbuffer_run_tests_single(BArrayStore *bs, ListBase *lb)
static bool testbuffer_list_validate(const ListBase *lb)
static void random_chunk_generate(ListBase *lb, const int chunks_per_buffer, const int stride, const int chunk_count, const int random_seed)
static TestBuffer * testbuffer_list_add(ListBase *lb, const void *data, size_t data_len)
static char * testchunk_as_data_array(TestChunk **tc_array, int tc_array_len, size_t *r_data_len)
static void testbuffer_list_state_from_data(ListBase *lb, const char *data, const size_t data_len)
static void plain_text_helper(const char *words, int words_len, const char word_delim, const int stride, const int chunk_count, const int random_seed)
#define WORDS
static void testbuffer_run_tests_simple(ListBase *lb, const int stride, const int chunk_count)
static void testbuffer_list_free(ListBase *lb)
static uint rand_range_i(RNG *rng, uint min_i, uint max_i, uint step)
Generic array manipulation API.
void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
Definition array_utils.c:44
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
#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)
Definition listbase.cc:110
void void void void void void void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1)
Definition listbase.cc:823
Random number functions.
void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_num) ATTR_NONNULL(1
struct RNG * BLI_rng_new(unsigned int seed)
Definition rand.cc:39
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:58
unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:83
void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1
void BLI_array_randomize(void *data, unsigned int elem_size, unsigned int elem_num, unsigned int seed)
Definition rand.cc:188
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
#define ELEM(...)
int max_i(int a, int b)
Definition Basic.c:11
int min_i(int a, int b)
Definition Basic.c:7
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
#define printf
#define str(s)
IndexRange range
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static ulong state[N]
#define L
void * last
void * first
Definition rand.cc:33
BArrayState * state
const void * data