Blender  V2.93
BLI_listbase_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_utils.h"
8 #include "BLI_listbase.h"
9 #include "BLI_path_util.h"
10 #include "BLI_ressource_strings.h"
11 #include "BLI_string.h"
12 
13 /* local validation function */
14 static bool listbase_is_valid(const ListBase *listbase)
15 {
16 #define TESTFAIL(test) \
17  if (!(test)) { \
18  goto fail; \
19  } \
20  ((void)0)
21 
22  if (listbase->first) {
23  const Link *prev, *link;
24  link = (Link *)listbase->first;
25  TESTFAIL(link->prev == nullptr);
26 
27  link = (Link *)listbase->last;
28  TESTFAIL(link->next == nullptr);
29 
30  prev = nullptr;
31  link = (Link *)listbase->first;
32  do {
33  TESTFAIL(link->prev == prev);
34  } while ((void)(prev = link), (link = link->next));
35  TESTFAIL(prev == listbase->last);
36 
37  prev = nullptr;
38  link = (Link *)listbase->last;
39  do {
40  TESTFAIL(link->next == prev);
41  } while ((void)(prev = link), (link = link->prev));
42  TESTFAIL(prev == listbase->first);
43  }
44  else {
45  TESTFAIL(listbase->last == nullptr);
46  }
47 #undef TESTFAIL
48 
49  return true;
50 
51 fail:
52  return false;
53 }
54 
55 static int char_switch(char *string, char ch_src, char ch_dst)
56 {
57  int tot = 0;
58  while (*string != 0) {
59  if (*string == ch_src) {
60  *string = ch_dst;
61  tot++;
62  }
63  string++;
64  }
65  return tot;
66 }
67 
68 TEST(listbase, FindLinkOrIndex)
69 {
70  ListBase lb;
71  void *link1 = MEM_callocN(sizeof(Link), "link1");
72  void *link2 = MEM_callocN(sizeof(Link), "link2");
73 
74  /* Empty list */
75  BLI_listbase_clear(&lb);
76  EXPECT_EQ(BLI_findlink(&lb, -1), (void *)nullptr);
77  EXPECT_EQ(BLI_findlink(&lb, 0), (void *)nullptr);
78  EXPECT_EQ(BLI_findlink(&lb, 1), (void *)nullptr);
79  EXPECT_EQ(BLI_rfindlink(&lb, -1), (void *)nullptr);
80  EXPECT_EQ(BLI_rfindlink(&lb, 0), (void *)nullptr);
81  EXPECT_EQ(BLI_rfindlink(&lb, 1), (void *)nullptr);
82  EXPECT_EQ(BLI_findindex(&lb, link1), -1);
83 
84  /* One link */
85  BLI_addtail(&lb, link1);
86  EXPECT_EQ(BLI_findlink(&lb, 0), link1);
87  EXPECT_EQ(BLI_rfindlink(&lb, 0), link1);
88  EXPECT_EQ(BLI_findindex(&lb, link1), 0);
89 
90  /* Two links */
91  BLI_addtail(&lb, link2);
92  EXPECT_EQ(BLI_findlink(&lb, 1), link2);
93  EXPECT_EQ(BLI_rfindlink(&lb, 0), link2);
94  EXPECT_EQ(BLI_findindex(&lb, link2), 1);
95 
96  BLI_freelistN(&lb);
97 }
98 
99 /* -------------------------------------------------------------------- */
100 /* Sort utilities & test */
101 
102 static int testsort_array_str_cmp(const void *a, const void *b)
103 {
104  int i = strcmp(*(const char **)a, *(const char **)b);
105  return (i > 0) ? 1 : (i < 0) ? -1 : 0;
106 }
107 
108 static int testsort_listbase_str_cmp(const void *a, const void *b)
109 {
110  const LinkData *link_a = (LinkData *)a;
111  const LinkData *link_b = (LinkData *)b;
112  int i = strcmp((const char *)link_a->data, (const char *)link_b->data);
113  return (i > 0) ? 1 : (i < 0) ? -1 : 0;
114 }
115 
116 static int testsort_array_str_cmp_reverse(const void *a, const void *b)
117 {
118  return -testsort_array_str_cmp(a, b);
119 }
120 
121 static int testsort_listbase_str_cmp_reverse(const void *a, const void *b)
122 {
123  return -testsort_listbase_str_cmp(a, b);
124 }
125 
126 /* check array and listbase compare */
127 static bool testsort_listbase_array_str_cmp(ListBase *lb, char **arr, int arr_tot)
128 {
129  LinkData *link_step;
130  int i;
131 
132  link_step = (LinkData *)lb->first;
133  for (i = 0; i < arr_tot; i++) {
134  if (strcmp(arr[i], (char *)link_step->data) != 0) {
135  return false;
136  }
137  link_step = link_step->next;
138  }
139  if (link_step) {
140  return false;
141  }
142 
143  return true;
144 }
145 
146 /* assumes nodes are allocated in-order */
147 static bool testsort_listbase_sort_is_stable(ListBase *lb, bool forward)
148 {
149  LinkData *link_step;
150 
151  link_step = (LinkData *)lb->first;
152  while (link_step && link_step->next) {
153  if (strcmp((const char *)link_step->data, (const char *)link_step->next->data) == 0) {
154  if ((link_step < link_step->next) != forward) {
155  return false;
156  }
157  }
158  link_step = link_step->next;
159  }
160  return true;
161 }
162 
163 TEST(listbase, Sort)
164 {
165  const int words_len = sizeof(words10k) - 1;
166  char *words = BLI_strdupn(words10k, words_len);
167  int words_tot;
168  char **words_arr; /* qsort for comparison */
169  int i;
170  char *w_step;
171  ListBase words_lb;
172  LinkData *words_linkdata_arr;
173 
174  /* delimit words */
175  words_tot = 1 + char_switch(words, ' ', '\0');
176 
177  words_arr = (char **)MEM_mallocN(sizeof(*words_arr) * words_tot, __func__);
178 
179  words_linkdata_arr = (LinkData *)MEM_mallocN(sizeof(*words_linkdata_arr) * words_tot, __func__);
180 
181  /* create array */
182  w_step = words;
183  for (i = 0; i < words_tot; i++) {
184  words_arr[i] = w_step;
185  w_step += strlen(w_step) + 1;
186  }
187 
188  /* sort empty list */
189  {
190  BLI_listbase_clear(&words_lb);
192  EXPECT_TRUE(listbase_is_valid(&words_lb));
193  }
194 
195  /* sort single single */
196  {
197  LinkData link;
198  link.data = words;
199  BLI_addtail(&words_lb, &link);
201  EXPECT_TRUE(listbase_is_valid(&words_lb));
202  BLI_listbase_clear(&words_lb);
203  }
204 
205  /* create listbase */
206  BLI_listbase_clear(&words_lb);
207  w_step = words;
208  for (i = 0; i < words_tot; i++) {
209  LinkData *link = &words_linkdata_arr[i];
210  link->data = w_step;
211  BLI_addtail(&words_lb, link);
212  w_step += strlen(w_step) + 1;
213  }
214  EXPECT_TRUE(listbase_is_valid(&words_lb));
215 
216  /* sort (forward) */
217  {
218  qsort(words_arr, words_tot, sizeof(*words_arr), testsort_array_str_cmp);
219 
221  EXPECT_TRUE(listbase_is_valid(&words_lb));
222  EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
223  EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, true));
224  }
225 
226  /* sort (reverse) */
227  {
228  qsort(words_arr, words_tot, sizeof(*words_arr), testsort_array_str_cmp_reverse);
229 
231  EXPECT_TRUE(listbase_is_valid(&words_lb));
232  EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
233  EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, true));
234  }
235 
236  /* sort (forward but after reversing, test stability in alternate direction) */
237  {
238  BLI_array_reverse(words_arr, words_tot);
239  BLI_listbase_reverse(&words_lb);
240 
241  EXPECT_TRUE(listbase_is_valid(&words_lb));
242  EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
243  EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, false));
244 
245  /* and again */
246  BLI_array_reverse(words_arr, words_tot);
248  EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
249  EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, false));
250  }
251 
252  MEM_freeN(words);
253  MEM_freeN(words_arr);
254  MEM_freeN(words_linkdata_arr);
255 }
Generic array manipulation API.
#define BLI_array_reverse(arr, arr_len)
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 void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void * BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void void void void void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1)
Definition: listbase.c:871
static int testsort_listbase_str_cmp(const void *a, const void *b)
static int testsort_array_str_cmp(const void *a, const void *b)
static bool listbase_is_valid(const ListBase *listbase)
static bool testsort_listbase_array_str_cmp(ListBase *lb, char **arr, int arr_tot)
static int testsort_array_str_cmp_reverse(const void *a, const void *b)
TEST(listbase, FindLinkOrIndex)
static int char_switch(char *string, char ch_src, char ch_dst)
static int testsort_listbase_str_cmp_reverse(const void *a, const void *b)
static bool testsort_listbase_sort_is_stable(ListBase *lb, bool forward)
#define TESTFAIL(test)
const char words10k[]
char * BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:54
Read Guarded memory(de)allocation.
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong * next
static unsigned a[3]
Definition: RandGen.cpp:92
void * data
Definition: DNA_listBase.h:42
struct LinkData * next
Definition: DNA_listBase.h:41
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47