ql.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. #include "test/jemalloc_test.h"
  2. #include "jemalloc/internal/ql.h"
  3. /* Number of ring entries, in [2..26]. */
  4. #define NENTRIES 9
  5. typedef struct list_s list_t;
  6. typedef ql_head(list_t) list_head_t;
  7. struct list_s {
  8. ql_elm(list_t) link;
  9. char id;
  10. };
  11. static void
  12. test_empty_list(list_head_t *head) {
  13. list_t *t;
  14. unsigned i;
  15. expect_true(ql_empty(head), "Unexpected element for empty list");
  16. expect_ptr_null(ql_first(head), "Unexpected element for empty list");
  17. expect_ptr_null(ql_last(head, link),
  18. "Unexpected element for empty list");
  19. i = 0;
  20. ql_foreach(t, head, link) {
  21. i++;
  22. }
  23. expect_u_eq(i, 0, "Unexpected element for empty list");
  24. i = 0;
  25. ql_reverse_foreach(t, head, link) {
  26. i++;
  27. }
  28. expect_u_eq(i, 0, "Unexpected element for empty list");
  29. }
  30. TEST_BEGIN(test_ql_empty) {
  31. list_head_t head;
  32. ql_new(&head);
  33. test_empty_list(&head);
  34. }
  35. TEST_END
  36. static void
  37. init_entries(list_t *entries, unsigned nentries) {
  38. unsigned i;
  39. for (i = 0; i < nentries; i++) {
  40. entries[i].id = 'a' + i;
  41. ql_elm_new(&entries[i], link);
  42. }
  43. }
  44. static void
  45. test_entries_list(list_head_t *head, list_t *entries, unsigned nentries) {
  46. list_t *t;
  47. unsigned i;
  48. expect_false(ql_empty(head), "List should not be empty");
  49. expect_c_eq(ql_first(head)->id, entries[0].id, "Element id mismatch");
  50. expect_c_eq(ql_last(head, link)->id, entries[nentries-1].id,
  51. "Element id mismatch");
  52. i = 0;
  53. ql_foreach(t, head, link) {
  54. expect_c_eq(t->id, entries[i].id, "Element id mismatch");
  55. i++;
  56. }
  57. i = 0;
  58. ql_reverse_foreach(t, head, link) {
  59. expect_c_eq(t->id, entries[nentries-i-1].id,
  60. "Element id mismatch");
  61. i++;
  62. }
  63. for (i = 0; i < nentries-1; i++) {
  64. t = ql_next(head, &entries[i], link);
  65. expect_c_eq(t->id, entries[i+1].id, "Element id mismatch");
  66. }
  67. expect_ptr_null(ql_next(head, &entries[nentries-1], link),
  68. "Unexpected element");
  69. expect_ptr_null(ql_prev(head, &entries[0], link), "Unexpected element");
  70. for (i = 1; i < nentries; i++) {
  71. t = ql_prev(head, &entries[i], link);
  72. expect_c_eq(t->id, entries[i-1].id, "Element id mismatch");
  73. }
  74. }
  75. TEST_BEGIN(test_ql_tail_insert) {
  76. list_head_t head;
  77. list_t entries[NENTRIES];
  78. unsigned i;
  79. ql_new(&head);
  80. init_entries(entries, sizeof(entries)/sizeof(list_t));
  81. for (i = 0; i < NENTRIES; i++) {
  82. ql_tail_insert(&head, &entries[i], link);
  83. }
  84. test_entries_list(&head, entries, NENTRIES);
  85. }
  86. TEST_END
  87. TEST_BEGIN(test_ql_tail_remove) {
  88. list_head_t head;
  89. list_t entries[NENTRIES];
  90. unsigned i;
  91. ql_new(&head);
  92. init_entries(entries, sizeof(entries)/sizeof(list_t));
  93. for (i = 0; i < NENTRIES; i++) {
  94. ql_tail_insert(&head, &entries[i], link);
  95. }
  96. for (i = 0; i < NENTRIES; i++) {
  97. test_entries_list(&head, entries, NENTRIES-i);
  98. ql_tail_remove(&head, list_t, link);
  99. }
  100. test_empty_list(&head);
  101. }
  102. TEST_END
  103. TEST_BEGIN(test_ql_head_insert) {
  104. list_head_t head;
  105. list_t entries[NENTRIES];
  106. unsigned i;
  107. ql_new(&head);
  108. init_entries(entries, sizeof(entries)/sizeof(list_t));
  109. for (i = 0; i < NENTRIES; i++) {
  110. ql_head_insert(&head, &entries[NENTRIES-i-1], link);
  111. }
  112. test_entries_list(&head, entries, NENTRIES);
  113. }
  114. TEST_END
  115. TEST_BEGIN(test_ql_head_remove) {
  116. list_head_t head;
  117. list_t entries[NENTRIES];
  118. unsigned i;
  119. ql_new(&head);
  120. init_entries(entries, sizeof(entries)/sizeof(list_t));
  121. for (i = 0; i < NENTRIES; i++) {
  122. ql_head_insert(&head, &entries[NENTRIES-i-1], link);
  123. }
  124. for (i = 0; i < NENTRIES; i++) {
  125. test_entries_list(&head, &entries[i], NENTRIES-i);
  126. ql_head_remove(&head, list_t, link);
  127. }
  128. test_empty_list(&head);
  129. }
  130. TEST_END
  131. TEST_BEGIN(test_ql_insert) {
  132. list_head_t head;
  133. list_t entries[8];
  134. list_t *a, *b, *c, *d, *e, *f, *g, *h;
  135. ql_new(&head);
  136. init_entries(entries, sizeof(entries)/sizeof(list_t));
  137. a = &entries[0];
  138. b = &entries[1];
  139. c = &entries[2];
  140. d = &entries[3];
  141. e = &entries[4];
  142. f = &entries[5];
  143. g = &entries[6];
  144. h = &entries[7];
  145. /*
  146. * ql_remove(), ql_before_insert(), and ql_after_insert() are used
  147. * internally by other macros that are already tested, so there's no
  148. * need to test them completely. However, insertion/deletion from the
  149. * middle of lists is not otherwise tested; do so here.
  150. */
  151. ql_tail_insert(&head, f, link);
  152. ql_before_insert(&head, f, b, link);
  153. ql_before_insert(&head, f, c, link);
  154. ql_after_insert(f, h, link);
  155. ql_after_insert(f, g, link);
  156. ql_before_insert(&head, b, a, link);
  157. ql_after_insert(c, d, link);
  158. ql_before_insert(&head, f, e, link);
  159. test_entries_list(&head, entries, sizeof(entries)/sizeof(list_t));
  160. }
  161. TEST_END
  162. static void
  163. test_concat_split_entries(list_t *entries, unsigned nentries_a,
  164. unsigned nentries_b) {
  165. init_entries(entries, nentries_a + nentries_b);
  166. list_head_t head_a;
  167. ql_new(&head_a);
  168. for (unsigned i = 0; i < nentries_a; i++) {
  169. ql_tail_insert(&head_a, &entries[i], link);
  170. }
  171. if (nentries_a == 0) {
  172. test_empty_list(&head_a);
  173. } else {
  174. test_entries_list(&head_a, entries, nentries_a);
  175. }
  176. list_head_t head_b;
  177. ql_new(&head_b);
  178. for (unsigned i = 0; i < nentries_b; i++) {
  179. ql_tail_insert(&head_b, &entries[nentries_a + i], link);
  180. }
  181. if (nentries_b == 0) {
  182. test_empty_list(&head_b);
  183. } else {
  184. test_entries_list(&head_b, entries + nentries_a, nentries_b);
  185. }
  186. ql_concat(&head_a, &head_b, link);
  187. if (nentries_a + nentries_b == 0) {
  188. test_empty_list(&head_a);
  189. } else {
  190. test_entries_list(&head_a, entries, nentries_a + nentries_b);
  191. }
  192. test_empty_list(&head_b);
  193. if (nentries_b == 0) {
  194. return;
  195. }
  196. list_head_t head_c;
  197. ql_split(&head_a, &entries[nentries_a], &head_c, link);
  198. if (nentries_a == 0) {
  199. test_empty_list(&head_a);
  200. } else {
  201. test_entries_list(&head_a, entries, nentries_a);
  202. }
  203. test_entries_list(&head_c, entries + nentries_a, nentries_b);
  204. }
  205. TEST_BEGIN(test_ql_concat_split) {
  206. list_t entries[NENTRIES];
  207. test_concat_split_entries(entries, 0, 0);
  208. test_concat_split_entries(entries, 0, 1);
  209. test_concat_split_entries(entries, 1, 0);
  210. test_concat_split_entries(entries, 0, NENTRIES);
  211. test_concat_split_entries(entries, 1, NENTRIES - 1);
  212. test_concat_split_entries(entries, NENTRIES / 2,
  213. NENTRIES - NENTRIES / 2);
  214. test_concat_split_entries(entries, NENTRIES - 1, 1);
  215. test_concat_split_entries(entries, NENTRIES, 0);
  216. }
  217. TEST_END
  218. TEST_BEGIN(test_ql_rotate) {
  219. list_head_t head;
  220. list_t entries[NENTRIES];
  221. unsigned i;
  222. ql_new(&head);
  223. init_entries(entries, sizeof(entries)/sizeof(list_t));
  224. for (i = 0; i < NENTRIES; i++) {
  225. ql_tail_insert(&head, &entries[i], link);
  226. }
  227. char head_id = ql_first(&head)->id;
  228. for (i = 0; i < NENTRIES; i++) {
  229. assert_c_eq(ql_first(&head)->id, head_id, "");
  230. ql_rotate(&head, link);
  231. assert_c_eq(ql_last(&head, link)->id, head_id, "");
  232. head_id++;
  233. }
  234. test_entries_list(&head, entries, NENTRIES);
  235. }
  236. TEST_END
  237. TEST_BEGIN(test_ql_move) {
  238. list_head_t head_dest, head_src;
  239. list_t entries[NENTRIES];
  240. unsigned i;
  241. ql_new(&head_src);
  242. ql_move(&head_dest, &head_src);
  243. test_empty_list(&head_src);
  244. test_empty_list(&head_dest);
  245. init_entries(entries, sizeof(entries)/sizeof(list_t));
  246. for (i = 0; i < NENTRIES; i++) {
  247. ql_tail_insert(&head_src, &entries[i], link);
  248. }
  249. ql_move(&head_dest, &head_src);
  250. test_empty_list(&head_src);
  251. test_entries_list(&head_dest, entries, NENTRIES);
  252. }
  253. TEST_END
  254. int
  255. main(void) {
  256. return test(
  257. test_ql_empty,
  258. test_ql_tail_insert,
  259. test_ql_tail_remove,
  260. test_ql_head_insert,
  261. test_ql_head_remove,
  262. test_ql_insert,
  263. test_ql_concat_split,
  264. test_ql_rotate,
  265. test_ql_move);
  266. }