]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: ISC |
992f9967 DL |
2 | /* |
3 | * Copyright (c) 2019 David Lamparter, for NetDEF, Inc. | |
992f9967 DL |
4 | */ |
5 | ||
6 | /* C++ called, they want their templates back */ | |
7 | #define item concat(item_, TYPE) | |
8 | #define itm concat(itm_, TYPE) | |
507e0e5d | 9 | #define itmswap concat(itmswap_, TYPE) |
992f9967 DL |
10 | #define head concat(head_, TYPE) |
11 | #define list concat(TYPE, ) | |
12 | #define list_head concat(TYPE, _head) | |
13 | #define list_item concat(TYPE, _item) | |
14 | #define list_cmp concat(TYPE, _cmp) | |
15 | #define list_hash concat(TYPE, _hash) | |
16 | #define list_init concat(TYPE, _init) | |
17 | #define list_fini concat(TYPE, _fini) | |
daf3441d | 18 | #define list_const_first concat(TYPE, _const_first) |
992f9967 | 19 | #define list_first concat(TYPE, _first) |
daf3441d | 20 | #define list_const_next concat(TYPE, _const_next) |
992f9967 DL |
21 | #define list_next concat(TYPE, _next) |
22 | #define list_next_safe concat(TYPE, _next_safe) | |
643ea83b DL |
23 | #define list_const_last concat(TYPE, _const_last) |
24 | #define list_last concat(TYPE, _last) | |
25 | #define list_const_prev concat(TYPE, _const_prev) | |
26 | #define list_prev concat(TYPE, _prev) | |
27 | #define list_prev_safe concat(TYPE, _prev_safe) | |
992f9967 DL |
28 | #define list_count concat(TYPE, _count) |
29 | #define list_add concat(TYPE, _add) | |
8c3d03b3 DL |
30 | #define list_add_head concat(TYPE, _add_head) |
31 | #define list_add_tail concat(TYPE, _add_tail) | |
32 | #define list_add_after concat(TYPE, _add_after) | |
992f9967 DL |
33 | #define list_find concat(TYPE, _find) |
34 | #define list_find_lt concat(TYPE, _find_lt) | |
35 | #define list_find_gteq concat(TYPE, _find_gteq) | |
f45897e4 | 36 | #define list_member concat(TYPE, _member) |
40ee228d | 37 | #define list_anywhere concat(TYPE, _anywhere) |
992f9967 DL |
38 | #define list_del concat(TYPE, _del) |
39 | #define list_pop concat(TYPE, _pop) | |
507e0e5d | 40 | #define list_swap_all concat(TYPE, _swap_all) |
992f9967 | 41 | |
507e0e5d | 42 | #define ts_hash_head concat(ts_hash_head_, TYPE) |
8c3d03b3 | 43 | |
2214f160 DL |
44 | #ifndef REALTYPE |
45 | #define REALTYPE TYPE | |
46 | #endif | |
47 | ||
960b9a53 | 48 | PREDECL(REALTYPE, list); |
992f9967 DL |
49 | struct item { |
50 | uint64_t val; | |
51 | struct list_item itm; | |
52 | int scratchpad; | |
53 | }; | |
54 | ||
8c3d03b3 | 55 | #if IS_SORTED(REALTYPE) |
992f9967 DL |
56 | static int list_cmp(const struct item *a, const struct item *b); |
57 | ||
2214f160 | 58 | #if IS_HASH(REALTYPE) |
992f9967 | 59 | static uint32_t list_hash(const struct item *a); |
960b9a53 | 60 | DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash); |
992f9967 DL |
61 | |
62 | static uint32_t list_hash(const struct item *a) | |
63 | { | |
2214f160 | 64 | #ifdef SHITTY_HASH |
992f9967 | 65 | /* crappy hash to get some hash collisions */ |
27a6fc42 | 66 | return (a->val & 0xFF) ^ (a->val << 29) ^ 0x55AA0000U; |
2214f160 DL |
67 | #else |
68 | return jhash_1word(a->val, 0xdeadbeef); | |
69 | #endif | |
992f9967 DL |
70 | } |
71 | ||
72 | #else | |
960b9a53 | 73 | DECLARE(REALTYPE, list, struct item, itm, list_cmp); |
992f9967 DL |
74 | #endif |
75 | ||
76 | static int list_cmp(const struct item *a, const struct item *b) | |
77 | { | |
78 | if (a->val > b->val) | |
79 | return 1; | |
80 | if (a->val < b->val) | |
81 | return -1; | |
82 | return 0; | |
83 | } | |
84 | ||
8c3d03b3 | 85 | #else /* !IS_SORTED */ |
960b9a53 | 86 | DECLARE(REALTYPE, list, struct item, itm); |
8c3d03b3 DL |
87 | #endif |
88 | ||
992f9967 | 89 | #define NITEM 10000 |
507e0e5d DL |
90 | #define NITEM_SWAP 100 /* other container for swap */ |
91 | struct item itm[NITEM], itmswap[NITEM_SWAP]; | |
2214f160 | 92 | static struct list_head head = concat(INIT_, REALTYPE)(head); |
992f9967 | 93 | |
507e0e5d DL |
94 | static void ts_hash_head(struct list_head *h, const char *text, |
95 | const char *expect) | |
8c3d03b3 DL |
96 | { |
97 | int64_t us = monotime_since(&ref, NULL); | |
98 | SHA256_CTX ctx; | |
99 | struct item *item; | |
100 | unsigned i = 0; | |
101 | uint8_t hash[32]; | |
102 | char hashtext[65]; | |
1dc46d1e | 103 | uint32_t swap_count, count; |
8c3d03b3 | 104 | |
507e0e5d | 105 | count = list_count(h); |
1dc46d1e | 106 | swap_count = htonl(count); |
8c3d03b3 DL |
107 | |
108 | SHA256_Init(&ctx); | |
1dc46d1e | 109 | SHA256_Update(&ctx, &swap_count, sizeof(swap_count)); |
8c3d03b3 | 110 | |
507e0e5d | 111 | frr_each (list, h, item) { |
8c3d03b3 DL |
112 | struct { |
113 | uint32_t val_upper, val_lower, index; | |
114 | } hashitem = { | |
115 | htonl(item->val >> 32), | |
116 | htonl(item->val & 0xFFFFFFFFULL), | |
117 | htonl(i), | |
118 | }; | |
119 | SHA256_Update(&ctx, &hashitem, sizeof(hashitem)); | |
120 | i++; | |
1dc46d1e | 121 | assert(i <= count); |
8c3d03b3 DL |
122 | } |
123 | SHA256_Final(hash, &ctx); | |
124 | ||
125 | for (i = 0; i < sizeof(hash); i++) | |
126 | sprintf(hashtext + i * 2, "%02x", hash[i]); | |
127 | ||
fb84c629 | 128 | printfrr("%7"PRId64"us %-25s %s%s\n", us, text, |
8c3d03b3 DL |
129 | expect ? " " : "*", hashtext); |
130 | if (expect && strcmp(expect, hashtext)) { | |
fb84c629 | 131 | printfrr("%-21s %s\n", "EXPECTED:", expect); |
8c3d03b3 DL |
132 | assert(0); |
133 | } | |
134 | monotime(&ref); | |
135 | } | |
136 | /* hashes will have different item ordering */ | |
d0a0e597 | 137 | #if IS_HASH(REALTYPE) || IS_HEAP(REALTYPE) |
507e0e5d DL |
138 | #define ts_hash(pos, csum) ts_hash_head(&head, pos, NULL) |
139 | #define ts_hashx(pos, csum) ts_hash_head(&head, pos, NULL) | |
140 | #define ts_hash_headx(head, pos, csum) ts_hash_head(head, pos, NULL) | |
8c3d03b3 | 141 | #else |
507e0e5d DL |
142 | #define ts_hash(pos, csum) ts_hash_head(&head, pos, csum) |
143 | #define ts_hashx(pos, csum) ts_hash_head(&head, pos, csum) | |
144 | #define ts_hash_headx(head, pos, csum) ts_hash_head(head, pos, csum) | |
8c3d03b3 DL |
145 | #endif |
146 | ||
992f9967 DL |
147 | static void concat(test_, TYPE)(void) |
148 | { | |
149 | size_t i, j, k, l; | |
150 | struct prng *prng; | |
507e0e5d | 151 | struct prng *prng_swap __attribute__((unused)); |
8c3d03b3 DL |
152 | struct item *item, *prev __attribute__((unused)); |
153 | struct item dummy __attribute__((unused)); | |
992f9967 DL |
154 | |
155 | memset(itm, 0, sizeof(itm)); | |
156 | for (i = 0; i < NITEM; i++) | |
157 | itm[i].val = i; | |
158 | ||
507e0e5d DL |
159 | memset(itmswap, 0, sizeof(itmswap)); |
160 | for (i = 0; i < NITEM_SWAP; i++) | |
161 | itmswap[i].val = i; | |
162 | ||
fb84c629 | 163 | printfrr("%s start\n", str(TYPE)); |
992f9967 DL |
164 | ts_start(); |
165 | ||
166 | list_init(&head); | |
992f9967 | 167 | assert(list_first(&head) == NULL); |
643ea83b DL |
168 | #if IS_REVERSE(REALTYPE) |
169 | assert(list_last(&head) == NULL); | |
170 | #endif | |
992f9967 | 171 | |
8c3d03b3 DL |
172 | ts_hash("init", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"); |
173 | ||
174 | #if IS_SORTED(REALTYPE) | |
992f9967 DL |
175 | prng = prng_new(0); |
176 | k = 0; | |
177 | for (i = 0; i < NITEM; i++) { | |
178 | j = prng_rand(prng) % NITEM; | |
179 | if (itm[j].scratchpad == 0) { | |
180 | list_add(&head, &itm[j]); | |
181 | itm[j].scratchpad = 1; | |
182 | k++; | |
d0a0e597 DL |
183 | } |
184 | #if !IS_HEAP(REALTYPE) | |
185 | else | |
992f9967 | 186 | assert(list_add(&head, &itm[j]) == &itm[j]); |
d0a0e597 | 187 | #endif |
992f9967 DL |
188 | } |
189 | assert(list_count(&head) == k); | |
190 | assert(list_first(&head) != NULL); | |
8c3d03b3 | 191 | ts_hashx("fill", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); |
992f9967 | 192 | |
507e0e5d DL |
193 | #if !IS_ATOMIC(REALTYPE) |
194 | struct list_head other; | |
195 | ||
196 | list_init(&other); | |
197 | list_swap_all(&head, &other); | |
198 | ||
199 | assert(list_count(&head) == 0); | |
200 | assert(!list_first(&head)); | |
201 | assert(list_count(&other) == k); | |
202 | assert(list_first(&other) != NULL); | |
643ea83b DL |
203 | #if IS_REVERSE(REALTYPE) |
204 | assert(!list_last(&head)); | |
205 | assert(list_last(&other) != NULL); | |
206 | #endif | |
507e0e5d DL |
207 | ts_hash_headx( |
208 | &other, "swap1", | |
209 | "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); | |
210 | ||
211 | prng_swap = prng_new(0x1234dead); | |
212 | l = 0; | |
213 | for (i = 0; i < NITEM_SWAP; i++) { | |
214 | j = prng_rand(prng_swap) % NITEM_SWAP; | |
215 | if (itmswap[j].scratchpad == 0) { | |
216 | list_add(&head, &itmswap[j]); | |
217 | itmswap[j].scratchpad = 1; | |
218 | l++; | |
219 | } | |
220 | #if !IS_HEAP(REALTYPE) | |
221 | else { | |
222 | struct item *rv = list_add(&head, &itmswap[j]); | |
223 | assert(rv == &itmswap[j]); | |
224 | } | |
225 | #endif | |
226 | } | |
227 | assert(list_count(&head) == l); | |
228 | assert(list_first(&head) != NULL); | |
229 | ts_hash_headx( | |
230 | &head, "swap-fill", | |
231 | "26df437174051cf305d1bbb62d779ee450ca764167a1e7a94be1aece420008e6"); | |
232 | ||
233 | list_swap_all(&head, &other); | |
234 | ||
235 | assert(list_count(&other) == l); | |
236 | assert(list_first(&other)); | |
237 | ts_hash_headx( | |
238 | &other, "swap2a", | |
239 | "26df437174051cf305d1bbb62d779ee450ca764167a1e7a94be1aece420008e6"); | |
240 | assert(list_count(&head) == k); | |
241 | assert(list_first(&head) != NULL); | |
242 | ts_hash_headx( | |
243 | &head, "swap2b", | |
244 | "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); | |
9de36e51 DL |
245 | |
246 | while (list_pop(&other)) | |
247 | ; | |
248 | list_fini(&other); | |
249 | prng_free(prng_swap); | |
250 | ||
251 | ts_ref("swap-cleanup"); | |
507e0e5d DL |
252 | #endif /* !IS_ATOMIC */ |
253 | ||
992f9967 | 254 | k = 0; |
daf3441d DL |
255 | |
256 | #if IS_ATOMIC(REALTYPE) | |
257 | struct list_head *chead = &head; | |
258 | struct item *citem, *cprev = NULL; | |
259 | ||
260 | frr_each(list, chead, citem) { | |
261 | #else | |
262 | const struct list_head *chead = &head; | |
263 | const struct item *citem, *cprev = NULL; | |
264 | ||
265 | frr_each(list_const, chead, citem) { | |
266 | #endif | |
267 | ||
d0a0e597 | 268 | #if IS_HASH(REALTYPE) || IS_HEAP(REALTYPE) |
992f9967 | 269 | /* hash table doesn't give sorting */ |
daf3441d | 270 | (void)cprev; |
992f9967 | 271 | #else |
daf3441d | 272 | assert(!cprev || cprev->val < citem->val); |
643ea83b DL |
273 | #if IS_REVERSE(REALTYPE) |
274 | assert(list_const_prev(chead, citem) == cprev); | |
275 | #endif | |
992f9967 | 276 | #endif |
daf3441d | 277 | cprev = citem; |
992f9967 DL |
278 | k++; |
279 | } | |
daf3441d | 280 | assert(list_count(chead) == k); |
643ea83b DL |
281 | #if IS_REVERSE(REALTYPE) |
282 | assert(cprev == list_const_last(chead)); | |
283 | #endif | |
992f9967 DL |
284 | ts_ref("walk"); |
285 | ||
643ea83b DL |
286 | #if IS_REVERSE(REALTYPE) && !IS_HASH(REALTYPE) && !IS_HEAP(REALTYPE) |
287 | cprev = NULL; | |
288 | k = 0; | |
289 | ||
290 | frr_rev_each(list_const, chead, citem) { | |
291 | assert(!cprev || cprev->val > citem->val); | |
292 | assert(list_const_next(chead, citem) == cprev); | |
293 | ||
294 | cprev = citem; | |
295 | k++; | |
296 | } | |
297 | assert(list_count(chead) == k); | |
298 | assert(cprev == list_const_first(chead)); | |
299 | ||
300 | ts_ref("reverse-walk"); | |
301 | #endif | |
302 | ||
2214f160 | 303 | #if IS_UNIQ(REALTYPE) |
992f9967 DL |
304 | prng_free(prng); |
305 | prng = prng_new(0); | |
306 | ||
307 | for (i = 0; i < NITEM; i++) { | |
308 | j = prng_rand(prng) % NITEM; | |
309 | dummy.val = j; | |
310 | assert(list_find(&head, &dummy) == &itm[j]); | |
311 | } | |
312 | ts_ref("find"); | |
313 | ||
314 | for (i = 0; i < NITEM; i++) { | |
315 | j = prng_rand(prng) % NITEM; | |
316 | memset(&dummy, 0, sizeof(dummy)); | |
317 | dummy.val = j; | |
318 | if (itm[j].scratchpad) | |
319 | assert(list_add(&head, &dummy) == &itm[j]); | |
320 | else { | |
321 | assert(list_add(&head, &dummy) == NULL); | |
7de7c75b | 322 | assert(list_del(&head, &dummy) != NULL); |
992f9967 DL |
323 | } |
324 | } | |
8c3d03b3 | 325 | ts_hashx("add-dup", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); |
d0a0e597 DL |
326 | |
327 | #elif IS_HEAP(REALTYPE) | |
328 | /* heap - partially sorted. */ | |
329 | prev = NULL; | |
f45897e4 | 330 | l = k / 4; |
d0a0e597 DL |
331 | for (i = 0; i < l; i++) { |
332 | item = list_pop(&head); | |
333 | if (prev) | |
334 | assert(prev->val < item->val); | |
335 | item->scratchpad = 0; | |
336 | k--; | |
337 | prev = item; | |
338 | } | |
f45897e4 DL |
339 | ts_hash("pop#1", NULL); |
340 | ||
341 | for (i = 0; i < NITEM; i++) | |
342 | assertf(list_member(&head, &itm[i]) == itm[i].scratchpad, | |
343 | "%zu should:%d is:%d", i, itm[i].scratchpad, | |
344 | list_member(&head, &itm[i])); | |
345 | ts_hash("member", NULL); | |
346 | ||
347 | l = k / 2; | |
348 | for (; i < l; i++) { | |
349 | item = list_pop(&head); | |
350 | if (prev) | |
351 | assert(prev->val < item->val); | |
352 | item->scratchpad = 0; | |
353 | k--; | |
354 | prev = item; | |
355 | } | |
356 | ts_hash("pop#2", NULL); | |
d0a0e597 DL |
357 | |
358 | #else /* !IS_UNIQ(REALTYPE) && !IS_HEAP(REALTYPE) */ | |
992f9967 DL |
359 | for (i = 0; i < NITEM; i++) { |
360 | j = prng_rand(prng) % NITEM; | |
361 | memset(&dummy, 0, sizeof(dummy)); | |
362 | dummy.val = j; | |
363 | ||
364 | list_add(&head, &dummy); | |
365 | if (itm[j].scratchpad) { | |
366 | struct item *lt, *gteq, dummy2; | |
367 | ||
368 | assert(list_next(&head, &itm[j]) == &dummy || | |
369 | list_next(&head, &dummy) == &itm[j]); | |
370 | ||
371 | memset(&dummy2, 0, sizeof(dummy)); | |
372 | dummy2.val = j; | |
373 | lt = list_find_lt(&head, &dummy2); | |
374 | gteq = list_find_gteq(&head, &dummy2); | |
375 | ||
376 | assert(gteq == &itm[j] || gteq == &dummy); | |
377 | if (lt) | |
378 | assert(list_next(&head, lt) == &itm[j] || | |
379 | list_next(&head, lt) == &dummy); | |
380 | else | |
381 | assert(list_first(&head) == &itm[j] || | |
382 | list_first(&head) == &dummy); | |
383 | } else if (list_next(&head, &dummy)) | |
384 | assert(list_next(&head, &dummy)->val > j); | |
7de7c75b | 385 | assert(list_del(&head, &dummy) != NULL); |
992f9967 | 386 | } |
8c3d03b3 | 387 | ts_hash("add-dup+find_{lt,gteq}", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); |
992f9967 | 388 | #endif |
d0a0e597 | 389 | #if !IS_HASH(REALTYPE) && !IS_HEAP(REALTYPE) |
992f9967 DL |
390 | prng_free(prng); |
391 | prng = prng_new(123456); | |
392 | ||
393 | l = 0; | |
394 | for (i = 0; i < NITEM; i++) { | |
395 | struct item *lt, *gteq, *tmp; | |
396 | ||
397 | j = prng_rand(prng) % NITEM; | |
398 | dummy.val = j; | |
399 | ||
400 | lt = list_find_lt(&head, &dummy); | |
401 | gteq = list_find_gteq(&head, &dummy); | |
402 | ||
403 | if (lt) { | |
404 | assert(lt->val < j); | |
405 | tmp = list_next(&head, lt); | |
406 | assert(tmp == gteq); | |
407 | assert(!tmp || tmp->val >= j); | |
408 | } else | |
409 | assert(gteq == list_first(&head)); | |
c258527b | 410 | |
992f9967 DL |
411 | if (gteq) |
412 | assert(gteq->val >= j); | |
413 | } | |
414 | ts_ref("find_{lt,gteq}"); | |
415 | #endif /* !IS_HASH */ | |
416 | ||
417 | prng_free(prng); | |
418 | prng = prng_new(0); | |
419 | ||
420 | l = 0; | |
421 | for (i = 0; i < NITEM; i++) { | |
422 | (void)prng_rand(prng); | |
423 | j = prng_rand(prng) % NITEM; | |
424 | if (itm[j].scratchpad == 1) { | |
7de7c75b | 425 | assert(list_del(&head, &itm[j]) != NULL); |
992f9967 DL |
426 | itm[j].scratchpad = 0; |
427 | l++; | |
428 | } | |
429 | } | |
430 | assert(l + list_count(&head) == k); | |
8c3d03b3 | 431 | ts_hashx("del", "cb2e5d80f08a803ef7b56c15e981b681adcea214bebc2f55e12e0bfb242b07ca"); |
992f9967 | 432 | |
f45897e4 DL |
433 | #if !IS_ATOMIC(REALTYPE) |
434 | for (i = 0; i < NITEM; i++) | |
435 | assertf(list_member(&head, &itm[i]) == itm[i].scratchpad, | |
436 | "%zu should:%d is:%d", i, itm[i].scratchpad, | |
437 | list_member(&head, &itm[i])); | |
438 | ts_hashx("member", "cb2e5d80f08a803ef7b56c15e981b681adcea214bebc2f55e12e0bfb242b07ca"); | |
439 | #endif | |
440 | ||
81fddbe7 | 441 | frr_each_safe(list, &head, item) { |
992f9967 DL |
442 | assert(item->scratchpad != 0); |
443 | ||
444 | if (item->val & 1) { | |
7de7c75b | 445 | assert(list_del(&head, item) != NULL); |
992f9967 DL |
446 | item->scratchpad = 0; |
447 | l++; | |
448 | } | |
449 | } | |
450 | assert(l + list_count(&head) == k); | |
81fddbe7 | 451 | ts_hashx("frr_each_safe+del", "e0beb71dd963a75af05b722b8e71b61b304587d860c8accdc4349067542b86bb"); |
8c3d03b3 DL |
452 | |
453 | #else /* !IS_SORTED */ | |
454 | prng = prng_new(0); | |
455 | k = 0; | |
456 | for (i = 0; i < NITEM; i++) { | |
457 | j = prng_rand(prng) % NITEM; | |
458 | if (itm[j].scratchpad == 0) { | |
459 | list_add_tail(&head, &itm[j]); | |
460 | itm[j].scratchpad = 1; | |
461 | k++; | |
462 | } | |
463 | } | |
464 | assert(list_count(&head) == k); | |
465 | assert(list_first(&head) != NULL); | |
643ea83b DL |
466 | #if IS_REVERSE(REALTYPE) |
467 | assert(list_last(&head) != NULL); | |
468 | #endif | |
8c3d03b3 DL |
469 | ts_hash("fill / add_tail", "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19"); |
470 | ||
507e0e5d DL |
471 | #if !IS_ATOMIC(REALTYPE) |
472 | struct list_head other; | |
473 | ||
474 | list_init(&other); | |
475 | list_swap_all(&head, &other); | |
476 | ||
477 | assert(list_count(&head) == 0); | |
478 | assert(!list_first(&head)); | |
479 | assert(list_count(&other) == k); | |
480 | assert(list_first(&other) != NULL); | |
643ea83b DL |
481 | #if IS_REVERSE(REALTYPE) |
482 | assert(!list_last(&head)); | |
483 | assert(list_last(&other) != NULL); | |
484 | #endif | |
507e0e5d DL |
485 | ts_hash_head( |
486 | &other, "swap1", | |
487 | "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19"); | |
488 | ||
489 | prng_swap = prng_new(0x1234dead); | |
490 | l = 0; | |
491 | for (i = 0; i < NITEM_SWAP; i++) { | |
492 | j = prng_rand(prng_swap) % NITEM_SWAP; | |
493 | if (itmswap[j].scratchpad == 0) { | |
494 | list_add_tail(&head, &itmswap[j]); | |
495 | itmswap[j].scratchpad = 1; | |
496 | l++; | |
497 | } | |
498 | } | |
499 | assert(list_count(&head) == l); | |
500 | assert(list_first(&head) != NULL); | |
501 | ts_hash_head( | |
502 | &head, "swap-fill", | |
503 | "833e6ae437e322dfbd36eda8cfc33a61109be735b43f15d256c05e52d1b01909"); | |
504 | ||
505 | list_swap_all(&head, &other); | |
506 | ||
507 | assert(list_count(&other) == l); | |
508 | assert(list_first(&other)); | |
509 | ts_hash_head( | |
510 | &other, "swap2a", | |
511 | "833e6ae437e322dfbd36eda8cfc33a61109be735b43f15d256c05e52d1b01909"); | |
512 | assert(list_count(&head) == k); | |
513 | assert(list_first(&head) != NULL); | |
514 | ts_hash_head( | |
515 | &head, "swap2b", | |
516 | "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19"); | |
9de36e51 DL |
517 | |
518 | while (list_pop(&other)) | |
519 | ; | |
520 | list_fini(&other); | |
521 | prng_free(prng_swap); | |
522 | ||
523 | ts_ref("swap-cleanup"); | |
507e0e5d DL |
524 | #endif |
525 | ||
8c3d03b3 DL |
526 | for (i = 0; i < NITEM / 2; i++) { |
527 | j = prng_rand(prng) % NITEM; | |
528 | if (itm[j].scratchpad == 1) { | |
7de7c75b | 529 | assert(list_del(&head, &itm[j]) != NULL); |
8c3d03b3 DL |
530 | itm[j].scratchpad = 0; |
531 | k--; | |
532 | } | |
533 | } | |
534 | ts_hash("del-prng", "86d568a95eb429dab3162976c5a5f3f75aabc835932cd682aa280b6923549564"); | |
535 | ||
f45897e4 | 536 | #if !IS_ATOMIC(REALTYPE) |
40ee228d | 537 | for (i = 0; i < NITEM; i++) { |
f45897e4 DL |
538 | assertf(list_member(&head, &itm[i]) == itm[i].scratchpad, |
539 | "%zu should:%d is:%d", i, itm[i].scratchpad, | |
540 | list_member(&head, &itm[i])); | |
40ee228d DL |
541 | assertf(list_anywhere(&itm[i]) == itm[i].scratchpad, |
542 | "%zu should:%d is:%d", i, itm[i].scratchpad, | |
543 | list_anywhere(&itm[i])); | |
544 | } | |
f45897e4 DL |
545 | ts_hash("member", "86d568a95eb429dab3162976c5a5f3f75aabc835932cd682aa280b6923549564"); |
546 | #endif | |
547 | ||
8c3d03b3 | 548 | l = 0; |
f45897e4 DL |
549 | while (l < (k / 4) && (prev = list_pop(&head))) { |
550 | assert(prev->scratchpad != 0); | |
551 | ||
552 | prev->scratchpad = 0; | |
553 | l++; | |
554 | } | |
555 | ts_hash("pop#1", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d"); | |
556 | ||
557 | #if !IS_ATOMIC(REALTYPE) | |
40ee228d | 558 | for (i = 0; i < NITEM; i++) { |
f45897e4 DL |
559 | assertf(list_member(&head, &itm[i]) == itm[i].scratchpad, |
560 | "%zu should:%d is:%d", i, itm[i].scratchpad, | |
561 | list_member(&head, &itm[i])); | |
40ee228d DL |
562 | assertf(list_anywhere(&itm[i]) == itm[i].scratchpad, |
563 | "%zu should:%d is:%d", i, itm[i].scratchpad, | |
564 | list_anywhere(&itm[i])); | |
565 | } | |
f45897e4 DL |
566 | ts_hash("member", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d"); |
567 | #endif | |
643ea83b DL |
568 | #if IS_REVERSE(REALTYPE) |
569 | i = 0; | |
570 | prev = NULL; | |
571 | ||
572 | frr_rev_each (list, &head, item) { | |
573 | assert(item->scratchpad != 0); | |
574 | assert(list_next(&head, item) == prev); | |
575 | ||
576 | i++; | |
577 | prev = item; | |
578 | } | |
579 | assert(list_first(&head) == prev); | |
580 | assert(list_count(&head) == i); | |
581 | ts_hash("reverse-walk", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d"); | |
582 | #endif | |
f45897e4 | 583 | |
8c3d03b3 DL |
584 | while ((item = list_pop(&head))) { |
585 | assert(item->scratchpad != 0); | |
586 | ||
587 | item->scratchpad = 0; | |
588 | l++; | |
589 | } | |
590 | assert(l == k); | |
591 | assert(list_count(&head) == 0); | |
592 | assert(list_first(&head) == NULL); | |
f45897e4 | 593 | ts_hash("pop#2", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"); |
8c3d03b3 DL |
594 | |
595 | prng_free(prng); | |
596 | prng = prng_new(0x1e5a2d69); | |
597 | ||
598 | k = 0; | |
599 | for (i = 0; i < NITEM; i++) { | |
600 | j = prng_rand(prng) % NITEM; | |
601 | if (itm[j].scratchpad == 0) { | |
602 | list_add_head(&head, &itm[j]); | |
603 | itm[j].scratchpad = 1; | |
604 | k++; | |
605 | } | |
606 | } | |
607 | assert(list_count(&head) == k); | |
608 | assert(list_first(&head) != NULL); | |
609 | ts_hash("fill / add_head", "3084d8f8a28b8c756ccc0a92d60d86f6d776273734ddc3f9e1d89526f5ca2795"); | |
610 | ||
611 | for (i = 0; i < NITEM / 2; i++) { | |
612 | j = prng_rand(prng) % NITEM; | |
613 | if (itm[j].scratchpad == 1) { | |
7de7c75b | 614 | assert(list_del(&head, &itm[j]) != NULL); |
8c3d03b3 DL |
615 | itm[j].scratchpad = 0; |
616 | k--; | |
617 | } | |
618 | } | |
619 | ts_hash("del-prng", "dc916fa7ea4418792c7c8232d74df2887f9975ead4222f4b977be6bc0b52285e"); | |
620 | ||
621 | l = 0; | |
622 | while ((item = list_pop(&head))) { | |
623 | assert(item->scratchpad != 0); | |
624 | ||
625 | item->scratchpad = 0; | |
626 | l++; | |
627 | } | |
628 | assert(l == k); | |
629 | assert(list_count(&head) == 0); | |
630 | assert(list_first(&head) == NULL); | |
631 | ts_hash("pop", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"); | |
632 | ||
633 | prng_free(prng); | |
634 | prng = prng_new(0x692d1e5a); | |
635 | ||
636 | k = 0; | |
637 | for (i = 0; i < NITEM; i++) { | |
638 | j = prng_rand(prng) % NITEM; | |
639 | if (itm[j].scratchpad == 0) { | |
640 | if (prng_rand(prng) & 1) { | |
641 | list_add_tail(&head, &itm[j]); | |
642 | } else { | |
643 | list_add_head(&head, &itm[j]); | |
644 | } | |
645 | itm[j].scratchpad = 1; | |
646 | k++; | |
647 | } | |
648 | } | |
649 | assert(list_count(&head) == k); | |
650 | assert(list_first(&head) != NULL); | |
651 | ts_hash("fill / add_{head,tail}", "93fa180a575c96e4b6c3775c2de7843ee3254dd6ed5af699bbe155f994114b06"); | |
652 | ||
d0a0e597 DL |
653 | for (i = 0; i < NITEM * 3; i++) { |
654 | int op = prng_rand(prng); | |
655 | j = prng_rand(prng) % NITEM; | |
656 | ||
657 | if (op & 1) { | |
658 | /* delete or pop */ | |
659 | if (op & 2) { | |
660 | item = list_pop(&head); | |
661 | if (!item) | |
662 | continue; | |
663 | } else { | |
664 | item = &itm[j]; | |
665 | if (item->scratchpad == 0) | |
666 | continue; | |
7de7c75b | 667 | assert(list_del(&head, item) != NULL); |
d0a0e597 DL |
668 | } |
669 | item->scratchpad = 0; | |
670 | k--; | |
671 | } else { | |
672 | item = &itm[j]; | |
673 | if (item->scratchpad != 0) | |
674 | continue; | |
675 | ||
676 | item->scratchpad = 1; | |
677 | k++; | |
678 | ||
679 | switch ((op >> 1) & 1) { | |
680 | case 0: | |
681 | list_add_head(&head, item); | |
682 | break; | |
683 | case 1: | |
684 | list_add_tail(&head, item); | |
685 | break; | |
686 | default: | |
687 | assert(0); | |
688 | } | |
689 | } | |
690 | } | |
691 | assert(list_count(&head) == k); | |
692 | assert(list_first(&head) != NULL); | |
693 | ts_hash("prng add/del", "4909f31d06bb006efca4dfeebddb8de071733ddf502f89b6d532155208bbc6df"); | |
694 | ||
695 | #if !IS_ATOMIC(REALTYPE) | |
696 | /* variant with add_after */ | |
697 | ||
8c3d03b3 DL |
698 | for (i = 0; i < NITEM * 3; i++) { |
699 | int op = prng_rand(prng); | |
700 | j = prng_rand(prng) % NITEM; | |
701 | ||
702 | if (op & 1) { | |
703 | /* delete or pop */ | |
704 | if (op & 2) { | |
705 | item = list_pop(&head); | |
706 | if (!item) | |
707 | continue; | |
708 | } else { | |
709 | item = &itm[j]; | |
710 | if (item->scratchpad == 0) | |
711 | continue; | |
7de7c75b | 712 | assert(list_del(&head, item) != NULL); |
8c3d03b3 DL |
713 | } |
714 | item->scratchpad = 0; | |
715 | k--; | |
716 | } else { | |
717 | item = &itm[j]; | |
718 | if (item->scratchpad != 0) | |
719 | continue; | |
720 | ||
721 | item->scratchpad = 1; | |
722 | k++; | |
723 | ||
724 | switch ((op >> 1) & 3) { | |
725 | case 0: | |
726 | list_add_head(&head, item); | |
727 | break; | |
728 | case 1: | |
729 | list_add_tail(&head, item); | |
730 | break; | |
731 | case 2: | |
732 | case 3: | |
733 | prev = NULL; | |
734 | l = 0; | |
735 | do { | |
736 | j = prng_rand(prng) % NITEM; | |
737 | prev = &itm[j]; | |
738 | if (prev->scratchpad == 0 | |
739 | || prev == item) | |
740 | prev = NULL; | |
741 | l++; | |
742 | } while (!prev && l < 10); | |
743 | list_add_after(&head, prev, item); | |
744 | break; | |
745 | default: | |
746 | assert(0); | |
747 | } | |
748 | } | |
749 | } | |
750 | assert(list_count(&head) == k); | |
751 | assert(list_first(&head) != NULL); | |
d0a0e597 DL |
752 | ts_hash("prng add/after/del", "84c5fc83294eabebb9808ccbba32a303c4fca084db87ed1277d2bae1f8c5bee4"); |
753 | #endif | |
8c3d03b3 DL |
754 | |
755 | l = 0; | |
756 | #endif | |
992f9967 DL |
757 | |
758 | while ((item = list_pop(&head))) { | |
759 | assert(item->scratchpad != 0); | |
760 | ||
761 | item->scratchpad = 0; | |
762 | l++; | |
763 | } | |
764 | assert(l == k); | |
765 | assert(list_count(&head) == 0); | |
766 | assert(list_first(&head) == NULL); | |
8c3d03b3 | 767 | ts_hash("pop", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"); |
992f9967 DL |
768 | |
769 | list_fini(&head); | |
770 | ts_ref("fini"); | |
771 | ts_end(); | |
9de36e51 | 772 | prng_free(prng); |
fb84c629 | 773 | printfrr("%s end\n", str(TYPE)); |
992f9967 DL |
774 | } |
775 | ||
507e0e5d | 776 | #undef ts_hash |
8c3d03b3 | 777 | #undef ts_hashx |
507e0e5d DL |
778 | #undef ts_hash_head |
779 | #undef ts_hash_headx | |
8c3d03b3 | 780 | |
992f9967 DL |
781 | #undef item |
782 | #undef itm | |
507e0e5d | 783 | #undef itmswap |
992f9967 DL |
784 | #undef head |
785 | #undef list | |
786 | #undef list_head | |
787 | #undef list_item | |
788 | #undef list_cmp | |
789 | #undef list_hash | |
790 | #undef list_init | |
791 | #undef list_fini | |
792 | #undef list_first | |
793 | #undef list_next | |
794 | #undef list_next_safe | |
643ea83b DL |
795 | #undef list_const_first |
796 | #undef list_const_next | |
797 | #undef list_last | |
798 | #undef list_prev | |
799 | #undef list_prev_safe | |
800 | #undef list_const_last | |
801 | #undef list_const_prev | |
992f9967 DL |
802 | #undef list_count |
803 | #undef list_add | |
8c3d03b3 DL |
804 | #undef list_add_head |
805 | #undef list_add_tail | |
806 | #undef list_add_after | |
992f9967 DL |
807 | #undef list_find |
808 | #undef list_find_lt | |
809 | #undef list_find_gteq | |
f45897e4 | 810 | #undef list_member |
40ee228d | 811 | #undef list_anywhere |
992f9967 DL |
812 | #undef list_del |
813 | #undef list_pop | |
507e0e5d | 814 | #undef list_swap_all |
992f9967 | 815 | |
2214f160 | 816 | #undef REALTYPE |
992f9967 | 817 | #undef TYPE |