BLI_array_store_test.cc 24 KB

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