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