28 |
28 |
29 #include "cx/linked_list.h" |
29 #include "cx/linked_list.h" |
30 #include "test_config.h" |
30 #include "test_config.h" |
31 #include "util_allocator.h" |
31 #include "util_allocator.h" |
32 |
32 |
33 int cmp_int(int const *l, int const *r) { |
33 int cmp_int( |
|
34 int const *l, |
|
35 int const *r |
|
36 ) { |
34 int left = *l, right = *r; |
37 int left = *l, right = *r; |
35 return left == right ? 0 : (left < right ? -1 : 1); |
38 return left == right ? 0 : (left < right ? -1 : 1); |
36 } |
39 } |
37 |
40 |
|
41 struct node { |
|
42 struct node *next; |
|
43 struct node *prev; |
|
44 int data; |
|
45 }; |
|
46 |
|
47 #define nd(name) name = {0} |
|
48 |
|
49 const ptrdiff_t loc_prev = offsetof(struct node, prev); |
|
50 const ptrdiff_t loc_next = offsetof(struct node, next); |
|
51 const ptrdiff_t loc_data = offsetof(struct node, data); |
|
52 |
|
53 struct node *create_test_data( |
|
54 size_t n, |
|
55 const int data[] |
|
56 ) { |
|
57 if (n == 0) return NULL; |
|
58 struct node *begin = calloc(1, sizeof(struct node)); |
|
59 struct node *prev = begin; |
|
60 if (data) begin->data = data[0]; |
|
61 for (size_t i = 1; i < n; i++) { |
|
62 struct node *node = calloc(1, sizeof(struct node)); |
|
63 if (data) node->data = data[i]; |
|
64 cx_linked_list_link(prev, node, loc_prev, loc_next); |
|
65 prev = node; |
|
66 } |
|
67 return begin; |
|
68 } |
|
69 |
|
70 void destroy_test_data(struct node *begin) { |
|
71 struct node *node = begin; |
|
72 while (node) { |
|
73 struct node *next = node->next; |
|
74 free(node); |
|
75 node = next; |
|
76 } |
|
77 } |
|
78 |
38 void test_linked_list_link_unlink(void) { |
79 void test_linked_list_link_unlink(void) { |
39 struct node { |
80 |
40 void *next; |
81 struct node nd(a), nd(b), nd(c); |
41 void *prev; |
|
42 }; |
|
43 const ptrdiff_t loc_prev = offsetof(struct node, prev); |
|
44 const ptrdiff_t loc_next = offsetof(struct node, next); |
|
45 |
|
46 struct node a = {NULL, NULL}, b = {NULL, NULL}; |
|
47 |
82 |
48 cx_linked_list_link(&a, &b, loc_prev, loc_next); |
83 cx_linked_list_link(&a, &b, loc_prev, loc_next); |
49 CU_ASSERT_PTR_NULL(a.prev) |
84 CU_ASSERT_PTR_NULL(a.prev) |
50 CU_ASSERT_PTR_EQUAL(a.next, &b) |
85 CU_ASSERT_PTR_EQUAL(a.next, &b) |
51 CU_ASSERT_PTR_EQUAL(b.prev, &a) |
86 CU_ASSERT_PTR_EQUAL(b.prev, &a) |
101 |
123 |
102 CU_ASSERT_PTR_EQUAL(cx_linked_list_at(&d, 3, loc_prev, 0), &a) |
124 CU_ASSERT_PTR_EQUAL(cx_linked_list_at(&d, 3, loc_prev, 0), &a) |
103 CU_ASSERT_PTR_EQUAL(cx_linked_list_at(&d, 3, loc_prev, 1), &b) |
125 CU_ASSERT_PTR_EQUAL(cx_linked_list_at(&d, 3, loc_prev, 1), &b) |
104 } |
126 } |
105 |
127 |
|
128 void test_linked_list_compare(void) { |
|
129 int a[] = {2, 4, 6, 8}; |
|
130 int b[] = {2, 4, 6}; |
|
131 int c[] = {2, 4, 6, 9}; |
|
132 |
|
133 void *la = create_test_data(4, a); |
|
134 void *lb = create_test_data(3, b); |
|
135 void *lc = create_test_data(4, c); |
|
136 |
|
137 CU_ASSERT_TRUE(0 < cx_linked_list_compare(la, lb, loc_next, loc_data, |
|
138 0, (CxListComparator) cmp_int) |
|
139 ) |
|
140 CU_ASSERT_TRUE(0 > cx_linked_list_compare(lb, la, loc_next, loc_data, |
|
141 0, (CxListComparator) cmp_int) |
|
142 ) |
|
143 CU_ASSERT_TRUE(0 < cx_linked_list_compare(lc, la, loc_next, loc_data, |
|
144 0, (CxListComparator) cmp_int) |
|
145 ) |
|
146 CU_ASSERT_TRUE(0 > cx_linked_list_compare(la, lc, loc_next, loc_data, |
|
147 0, (CxListComparator) cmp_int) |
|
148 ) |
|
149 CU_ASSERT_TRUE(0 == cx_linked_list_compare(la, la, loc_next, loc_data, |
|
150 0, (CxListComparator) cmp_int) |
|
151 ) |
|
152 |
|
153 destroy_test_data(la); |
|
154 destroy_test_data(lb); |
|
155 destroy_test_data(lc); |
|
156 } |
|
157 |
106 void test_linked_list_add(void) { |
158 void test_linked_list_add(void) { |
107 struct node { |
|
108 void *prev; |
|
109 void *next; |
|
110 }; |
|
111 |
|
112 struct node nodes[4]; |
159 struct node nodes[4]; |
|
160 void *begin, *end; |
113 |
161 |
114 // test with begin, end / prev, next |
162 // test with begin, end / prev, next |
115 memset(nodes, 0, 4 * sizeof(struct node)); |
163 memset(nodes, 0, 4 * sizeof(struct node)); |
116 void *begin = NULL; |
164 begin = end = NULL; |
117 void *end = NULL; |
|
118 |
|
119 ptrdiff_t loc_prev = offsetof(struct node, prev); |
|
120 ptrdiff_t loc_next = offsetof(struct node, next); |
|
121 |
165 |
122 cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[0]); |
166 cx_linked_list_add(&begin, &end, loc_prev, loc_next, &nodes[0]); |
123 CU_ASSERT_PTR_EQUAL(begin, &nodes[0]) |
167 CU_ASSERT_PTR_EQUAL(begin, &nodes[0]) |
124 CU_ASSERT_PTR_EQUAL(end, &nodes[0]) |
168 CU_ASSERT_PTR_EQUAL(end, &nodes[0]) |
125 CU_ASSERT_PTR_NULL(nodes[0].prev) |
169 CU_ASSERT_PTR_NULL(nodes[0].prev) |
376 CU_ASSERT_PTR_NULL(nodes[3].prev) |
392 CU_ASSERT_PTR_NULL(nodes[3].prev) |
377 CU_ASSERT_PTR_EQUAL(nodes[4].next, &nodes[0]) |
393 CU_ASSERT_PTR_EQUAL(nodes[4].next, &nodes[0]) |
378 } |
394 } |
379 |
395 |
380 void test_linked_list_first(void) { |
396 void test_linked_list_first(void) { |
381 struct node { |
397 struct node *begin = create_test_data(3, NULL); |
382 int data; |
398 CU_ASSERT_PTR_EQUAL(cx_linked_list_first(begin, loc_prev), begin) |
383 void *prev; |
399 CU_ASSERT_PTR_EQUAL(cx_linked_list_first(begin->next, loc_prev), begin) |
384 }; |
400 CU_ASSERT_PTR_EQUAL(cx_linked_list_first(begin->next->next, loc_prev), begin) |
385 ptrdiff_t loc = offsetof(struct node, prev); |
401 destroy_test_data(begin); |
386 |
|
387 struct node first = {1, NULL}; |
|
388 struct node second = {2, &first}; |
|
389 struct node third = {3, &second}; |
|
390 |
|
391 CU_ASSERT_PTR_EQUAL(cx_linked_list_first(&first, loc), &first) |
|
392 CU_ASSERT_PTR_EQUAL(cx_linked_list_first(&second, loc), &first) |
|
393 CU_ASSERT_PTR_EQUAL(cx_linked_list_first(&third, loc), &first) |
|
394 } |
402 } |
395 |
403 |
396 void test_linked_list_last(void) { |
404 void test_linked_list_last(void) { |
397 struct node { |
405 struct node *begin = create_test_data(3, NULL); |
398 int data; |
406 struct node *end = begin->next->next; |
399 void *next; |
407 CU_ASSERT_PTR_EQUAL(cx_linked_list_last(begin, loc_next), end) |
400 }; |
408 CU_ASSERT_PTR_EQUAL(cx_linked_list_last(begin->next, loc_next), end) |
401 ptrdiff_t loc = offsetof(struct node, next); |
409 CU_ASSERT_PTR_EQUAL(cx_linked_list_last(begin->next->next, loc_next), end) |
402 |
410 destroy_test_data(begin); |
403 struct node third = {3, NULL}; |
|
404 struct node second = {2, &third}; |
|
405 struct node first = {1, &second}; |
|
406 |
|
407 CU_ASSERT_PTR_EQUAL(cx_linked_list_last(&first, loc), &third) |
|
408 CU_ASSERT_PTR_EQUAL(cx_linked_list_last(&second, loc), &third) |
|
409 CU_ASSERT_PTR_EQUAL(cx_linked_list_last(&third, loc), &third) |
|
410 } |
411 } |
411 |
412 |
412 void test_linked_list_prev(void) { |
413 void test_linked_list_prev(void) { |
413 struct node { |
414 struct node *begin = create_test_data(3, NULL); |
414 void *next; |
415 CU_ASSERT_PTR_NULL(cx_linked_list_prev(begin, loc_next, begin)) |
415 }; |
416 CU_ASSERT_PTR_EQUAL(cx_linked_list_prev(begin, loc_next, begin->next), begin) |
416 ptrdiff_t loc = offsetof(struct node, next); |
417 CU_ASSERT_PTR_EQUAL(cx_linked_list_prev(begin, loc_next, begin->next->next), begin->next) |
417 |
418 destroy_test_data(begin); |
418 struct node third = {NULL}; |
|
419 struct node second = {&third}; |
|
420 struct node first = {&second}; |
|
421 |
|
422 CU_ASSERT_PTR_NULL(cx_linked_list_prev(&first, loc, &first)) |
|
423 CU_ASSERT_PTR_EQUAL(cx_linked_list_prev(&first, loc, &second), &first) |
|
424 CU_ASSERT_PTR_EQUAL(cx_linked_list_prev(&first, loc, &third), &second) |
|
425 } |
419 } |
426 |
420 |
427 void test_linked_list_remove(void) { |
421 void test_linked_list_remove(void) { |
428 struct node { |
422 void *begin, *end; |
429 void *next; |
423 |
430 }; |
424 int data[] = {2, 4, 6}; |
431 struct dnode { |
425 begin = create_test_data(3, data); |
432 void *next; |
426 struct node *first = begin; |
433 void *prev; |
427 struct node *second = first->next; |
434 }; |
428 struct node *third = second->next; |
435 ptrdiff_t loc = offsetof(struct node, next); |
429 end = third; |
436 ptrdiff_t ploc = offsetof(struct dnode, prev); |
430 |
437 |
431 cx_linked_list_remove(&begin, &end, loc_prev, loc_next, second); |
438 void *begin; |
432 CU_ASSERT_PTR_EQUAL(begin, first) |
439 void *end; |
433 CU_ASSERT_PTR_EQUAL(end, third) |
440 |
434 CU_ASSERT_PTR_NULL(first->prev) |
441 // single linked list |
435 CU_ASSERT_PTR_EQUAL(first->next, third) |
442 struct node third = {NULL}; |
436 CU_ASSERT_PTR_EQUAL(third->prev, first) |
443 struct node second = {&third}; |
437 CU_ASSERT_PTR_NULL(third->next) |
444 struct node first = {&second}; |
438 |
445 begin = &first; |
439 cx_linked_list_remove(&begin, &end, loc_prev, loc_next, third); |
446 |
440 CU_ASSERT_PTR_EQUAL(begin, first) |
447 cx_linked_list_remove(&begin, NULL, -1, loc, &second); |
441 CU_ASSERT_PTR_EQUAL(end, first) |
448 CU_ASSERT_PTR_EQUAL(begin, &first) |
442 CU_ASSERT_PTR_NULL(first->prev) |
449 CU_ASSERT_PTR_EQUAL(first.next, &third) |
443 CU_ASSERT_PTR_NULL(first->next) |
450 CU_ASSERT_PTR_NULL(third.next) |
444 |
451 |
445 cx_linked_list_remove(&begin, &end, loc_prev, loc_next, first); |
452 cx_linked_list_remove(&begin, NULL, -1, loc, &first); |
|
453 CU_ASSERT_PTR_EQUAL(begin, &third) |
|
454 CU_ASSERT_PTR_NULL(third.next) |
|
455 |
|
456 cx_linked_list_remove(&begin, NULL, -1, loc, &third); |
|
457 CU_ASSERT_PTR_NULL(begin) |
|
458 |
|
459 // doubly linked list |
|
460 struct dnode dthird = {NULL , NULL}; |
|
461 struct dnode dsecond = {&dthird, NULL}; |
|
462 struct dnode dfirst = {&dsecond, NULL}; |
|
463 dthird.prev = &dsecond; |
|
464 dsecond.prev = &dfirst; |
|
465 begin = &dfirst; |
|
466 end = &dthird; |
|
467 |
|
468 cx_linked_list_remove(&begin, &end, ploc, loc, &dsecond); |
|
469 CU_ASSERT_PTR_EQUAL(begin, &dfirst) |
|
470 CU_ASSERT_PTR_EQUAL(end, &dthird) |
|
471 CU_ASSERT_PTR_NULL(dfirst.prev) |
|
472 CU_ASSERT_PTR_EQUAL(dfirst.next, &dthird) |
|
473 CU_ASSERT_PTR_EQUAL(dthird.prev, &dfirst) |
|
474 CU_ASSERT_PTR_NULL(dthird.next) |
|
475 |
|
476 cx_linked_list_remove(&begin, &end, ploc, loc, &dthird); |
|
477 CU_ASSERT_PTR_EQUAL(begin, &dfirst) |
|
478 CU_ASSERT_PTR_EQUAL(end, &dfirst) |
|
479 CU_ASSERT_PTR_NULL(dfirst.prev) |
|
480 CU_ASSERT_PTR_NULL(dfirst.next) |
|
481 |
|
482 cx_linked_list_remove(&begin, &end, ploc, loc, &dfirst); |
|
483 CU_ASSERT_PTR_NULL(begin) |
446 CU_ASSERT_PTR_NULL(begin) |
484 CU_ASSERT_PTR_NULL(end) |
447 CU_ASSERT_PTR_NULL(end) |
|
448 |
|
449 free(first); |
|
450 free(second); |
|
451 free(third); |
485 } |
452 } |
486 |
453 |
487 void test_linked_list_size(void) { |
454 void test_linked_list_size(void) { |
488 struct node { |
455 struct node *list; |
489 void *next; |
456 |
490 }; |
457 CU_ASSERT_PTR_EQUAL(cx_linked_list_size(NULL, loc_next), 0) |
491 ptrdiff_t loc = offsetof(struct node, next); |
458 |
492 |
459 list = create_test_data(5, NULL); |
493 struct node first = {NULL}; |
460 CU_ASSERT_EQUAL(cx_linked_list_size(list, loc_next), 5) |
494 struct node second = {NULL}; |
461 destroy_test_data(list); |
495 struct node third = {NULL}; |
462 |
496 |
463 list = create_test_data(13, NULL); |
497 CU_ASSERT_PTR_EQUAL(cx_linked_list_size(NULL, loc), 0) |
464 CU_ASSERT_EQUAL(cx_linked_list_size(list, loc_next), 13) |
498 CU_ASSERT_PTR_EQUAL(cx_linked_list_size(&first, loc), 1) |
465 destroy_test_data(list); |
499 first.next = &second; |
|
500 CU_ASSERT_PTR_EQUAL(cx_linked_list_size(&first, loc), 2) |
|
501 second.next = &third; |
|
502 CU_ASSERT_PTR_EQUAL(cx_linked_list_size(&first, loc), 3) |
|
503 CU_ASSERT_PTR_EQUAL(cx_linked_list_size(&second, loc), 2) |
|
504 } |
466 } |
505 |
467 |
506 void test_linked_list_sort(void) { |
468 void test_linked_list_sort(void) { |
507 struct node { |
|
508 void *prev; |
|
509 void *next; |
|
510 int data; |
|
511 }; |
|
512 |
|
513 int expected[] = { |
469 int expected[] = { |
514 14, 30, 151, 163, 227, 300, 315, 317, 363, 398, 417, 424, 438, 446, 508, 555, 605, 713, 716, 759, 761, 880, |
470 14, 30, 151, 163, 227, 300, 315, 317, 363, 398, 417, 424, 438, 446, 508, 555, 605, 713, 716, 759, 761, 880, |
515 894, 1034, 1077, 1191, 1231, 1264, 1297, 1409, 1423, 1511, 1544, 1659, 1686, 1707, 1734, 1771, 1874, 1894, |
471 894, 1034, 1077, 1191, 1231, 1264, 1297, 1409, 1423, 1511, 1544, 1659, 1686, 1707, 1734, 1771, 1874, 1894, |
516 1976, 2079, 2124, 2130, 2135, 2266, 2338, 2358, 2430, 2500, 2540, 2542, 2546, 2711, 2733, 2754, 2764, 2797, |
472 1976, 2079, 2124, 2130, 2135, 2266, 2338, 2358, 2430, 2500, 2540, 2542, 2546, 2711, 2733, 2754, 2764, 2797, |
517 2888, 2900, 3020, 3053, 3109, 3244, 3275, 3302, 3362, 3363, 3364, 3441, 3515, 3539, 3579, 3655, 3675, 3677, |
473 2888, 2900, 3020, 3053, 3109, 3244, 3275, 3302, 3362, 3363, 3364, 3441, 3515, 3539, 3579, 3655, 3675, 3677, |
525 894, 1034, 1077, 1191, 1231, 1264, 1297, 1409, 1423, 1511, 1544, 1659, 1686, 315, 317, 363, 398, 417, 424, |
481 894, 1034, 1077, 1191, 1231, 1264, 1297, 1409, 1423, 1511, 1544, 1659, 1686, 315, 317, 363, 398, 417, 424, |
526 3675, 3677, 3718, 3724, 3757, 3866, 3896, 3906, 3941, 3984, 3994, 4785, 4791, 4801, 4859, 4903, 4973, |
482 3675, 3677, 3718, 3724, 3757, 3866, 3896, 3906, 3941, 3984, 3994, 4785, 4791, 4801, 4859, 4903, 4973, |
527 4016, 4085, 4121, 4254, 4319, 4366, 4459, 4514, 4681 |
483 4016, 4085, 4121, 4254, 4319, 4366, 4459, 4514, 4681 |
528 }; |
484 }; |
529 |
485 |
530 struct node *nodes = calloc(100, sizeof(struct node)); |
486 void *begin = create_test_data(100, scrambled); |
531 for (int i = 0; i < 100; i++) { |
487 void *end = cx_linked_list_last(begin, loc_next); |
532 nodes[i].prev = i == 0 ? NULL : &nodes[i - 1]; |
488 |
533 nodes[i].next = i == 99 ? NULL : &nodes[i + 1]; |
489 cx_linked_list_sort(&begin, &end, loc_prev, loc_next, loc_data, |
534 nodes[i].data = scrambled[i]; |
|
535 } |
|
536 |
|
537 struct node *begin = &nodes[0]; |
|
538 struct node *end = &nodes[99]; |
|
539 |
|
540 cx_linked_list_sort((void **) &begin, (void **) &end, |
|
541 offsetof(struct node, prev), |
|
542 offsetof(struct node, next), |
|
543 offsetof(struct node, data), |
|
544 0, (CxListComparator) cmp_int); |
490 0, (CxListComparator) cmp_int); |
545 |
491 |
546 CU_ASSERT_PTR_NULL(begin->prev) |
|
547 CU_ASSERT_EQUAL(begin->data, expected[0]) |
|
548 struct node *check = begin; |
492 struct node *check = begin; |
549 struct node *check_last = NULL; |
493 struct node *check_last = NULL; |
|
494 CU_ASSERT_PTR_NULL(check->prev) |
|
495 CU_ASSERT_EQUAL(check->data, expected[0]) |
550 for (int i = 0; i < 100; i++) { |
496 for (int i = 0; i < 100; i++) { |
551 CU_ASSERT_EQUAL(check->data, expected[i]) |
497 CU_ASSERT_EQUAL(check->data, expected[i]) |
552 CU_ASSERT_PTR_EQUAL(check->prev, check_last) |
498 CU_ASSERT_PTR_EQUAL(check->prev, check_last) |
553 if (i < 99) { |
499 if (i < 99) { |
554 CU_ASSERT_PTR_NOT_NULL(check->next) |
500 CU_ASSERT_PTR_NOT_NULL(check->next) |
555 } |
501 } |
556 check_last = check; |
502 check_last = check; |
557 check = check->next; |
503 check = check->next; |
558 } |
504 } |
559 CU_ASSERT_PTR_NULL(check) |
505 CU_ASSERT_PTR_NULL(check) |
560 CU_ASSERT_EQUAL(end->data, expected[99]) |
506 CU_ASSERT_PTR_EQUAL(end, check_last) |
|
507 |
|
508 destroy_test_data(begin); |
561 } |
509 } |
562 |
510 |
563 void test_linked_list_reverse(void) { |
511 void test_linked_list_reverse(void) { |
564 struct node { |
512 void *begin, *end; |
565 void *next; |
513 |
566 }; |
514 int data[] = {2, 4, 6, 8}; |
567 struct dnode { |
515 int reversed[] = {8, 6, 4, 2}; |
568 void *next; |
516 |
569 void *prev; |
517 void *list = create_test_data(4, data); |
570 }; |
518 void *expected = create_test_data(4, reversed); |
571 ptrdiff_t loc = offsetof(struct node, next); |
519 |
572 ptrdiff_t ploc = offsetof(struct dnode, prev); |
520 begin = list; |
573 |
521 end = cx_linked_list_last(list, loc_next); |
574 void *begin; |
522 |
575 void *end; |
523 cx_linked_list_reverse(&begin, &end, loc_prev, loc_next); |
576 |
524 CU_ASSERT_PTR_EQUAL(end, list) |
577 // single linked list |
525 CU_ASSERT_PTR_EQUAL(begin, cx_linked_list_first(end, loc_prev)) |
578 struct node third = {NULL}; |
526 CU_ASSERT_TRUE(0 == cx_linked_list_compare(begin, expected, loc_next, loc_data, |
579 struct node second = {&third}; |
527 0, (CxListComparator) cmp_int)) |
580 struct node first = {&second}; |
528 |
581 begin = &first; |
529 destroy_test_data(begin); |
582 |
530 destroy_test_data(expected); |
583 cx_linked_list_reverse(&begin, NULL, -1, loc); |
|
584 CU_ASSERT_PTR_EQUAL(begin, &third) |
|
585 CU_ASSERT_PTR_EQUAL(third.next, &second) |
|
586 CU_ASSERT_PTR_EQUAL(second.next, &first) |
|
587 CU_ASSERT_PTR_NULL(first.next) |
|
588 |
|
589 // doubly linked list |
|
590 struct dnode dthird = {NULL , NULL}; |
|
591 struct dnode dsecond = {&dthird, NULL}; |
|
592 struct dnode dfirst = {&dsecond, NULL}; |
|
593 dthird.prev = &dsecond; |
|
594 dsecond.prev = &dfirst; |
|
595 begin = &dfirst; |
|
596 end = &dthird; |
|
597 |
|
598 cx_linked_list_reverse(&begin, &end, ploc, loc); |
|
599 CU_ASSERT_PTR_EQUAL(begin, &dthird) |
|
600 CU_ASSERT_PTR_EQUAL(end, &dfirst) |
|
601 CU_ASSERT_PTR_EQUAL(dthird.next, &dsecond) |
|
602 CU_ASSERT_PTR_EQUAL(dsecond.next, &dfirst) |
|
603 CU_ASSERT_PTR_NULL(dfirst.next) |
|
604 CU_ASSERT_PTR_NULL(dthird.prev) |
|
605 CU_ASSERT_PTR_EQUAL(dsecond.prev, &dthird) |
|
606 CU_ASSERT_PTR_EQUAL(dfirst.prev, &dsecond) |
|
607 } |
531 } |
608 |
532 |
609 void test_hl_linked_list_create(void) { |
533 void test_hl_linked_list_create(void) { |
610 cxTestingAllocatorReset(); |
534 cxTestingAllocatorReset(); |
611 |
535 |