torture_heap.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. /*
  2. * This file is part of the Sofia-SIP package
  3. *
  4. * Copyright (C) 2007 Nokia Corporation.
  5. *
  6. * Contact: Pekka Pessi <pekka.pessi@nokia.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  21. * 02110-1301 USA
  22. *
  23. */
  24. /**@internal
  25. * @file torture_heap.c
  26. * @brief Test heap
  27. *
  28. * @author Pekka Pessi <Pekka.Pessi@nokia.com>
  29. */
  30. #include "config.h"
  31. #include <sofia-sip/heap.h>
  32. #include <unistd.h>
  33. #include <stddef.h>
  34. #include <string.h>
  35. #include <assert.h>
  36. #include <errno.h>
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <sys/types.h>
  40. typedef struct {
  41. unsigned key, value;
  42. size_t index;
  43. } type1, *type2;
  44. static type1 const null = { 0, 0, 0 };
  45. static inline
  46. int less1(type1 a, type1 b)
  47. {
  48. return a.key < b.key;
  49. }
  50. static inline
  51. void set1(type1 *heap, size_t index, type1 e)
  52. {
  53. e.index = index;
  54. heap[index] = e;
  55. }
  56. #define alloc(a, o, size) realloc((o), (size))
  57. static inline
  58. int less2(type2 a, type2 b)
  59. {
  60. return a->key < b->key;
  61. }
  62. static inline
  63. void set2(type2 *heap, size_t index, type2 e)
  64. {
  65. e->index = index;
  66. heap[index] = e;
  67. }
  68. #define scope static
  69. /* Define heap having structs as its elements */
  70. typedef HEAP_TYPE Heap1;
  71. HEAP_DECLARE(static, Heap1, heap1_, type1);
  72. HEAP_BODIES(static, Heap1, heap1_, type1, less1, set1, alloc, null);
  73. /* Define heap having pointers as its elements */
  74. typedef HEAP_TYPE Heap2;
  75. HEAP_DECLARE(static, Heap2, heap2_, type1 *);
  76. HEAP_BODIES(static, Heap2, heap2_, type1 *, less2, set2, alloc, NULL);
  77. /* ====================================================================== */
  78. int tstflags;
  79. #define TSTFLAGS tstflags
  80. #include <sofia-sip/tstdef.h>
  81. char name[] = "torture_heap";
  82. size_t _set, _cmp;
  83. static int int_less(void *_array, size_t a, size_t b)
  84. {
  85. int *array = _array;
  86. _cmp++;
  87. return array[a] < array[b];
  88. }
  89. static void int_swap(void *_array, size_t a, size_t b)
  90. {
  91. int *array = _array;
  92. int swap = array[a];
  93. array[a] = array[b];
  94. array[b] = swap;
  95. _set++;
  96. }
  97. void test_sort(int *array, size_t r, size_t N)
  98. {
  99. su_smoothsort(array, r, N, int_less, int_swap);
  100. }
  101. int test_smooth_sort(void)
  102. {
  103. BEGIN();
  104. size_t i, n, N = 300000;
  105. int array[N];
  106. size_t v1 = 3, v2 = 1;
  107. for (n = v1; n <= N; n = v1 + v2 + 1, v2 = v1, v1 = n) {
  108. for (i = 0; i < n; i++) {
  109. array[i] = (int)(n - i - 1);
  110. }
  111. _set = 0;
  112. /* write(1, ".", 1); */
  113. test_sort(array, 0, n);
  114. TEST_1(_set > 0); _set = 0;
  115. test_sort(array, 0, n);
  116. TEST(_set, 0);
  117. for (i = 0; i < n; i++) {
  118. TEST(array[i], i);
  119. }
  120. }
  121. for (n = 4; n <= N; n *= 2) {
  122. for (i = 0; i < n; i++) {
  123. array[i] = (int)(n - i - 1);
  124. }
  125. /* write(1, "/", 1); */
  126. test_sort(array, 0, n / 2);
  127. test_sort(array, n / 2, n / 2);
  128. for (i = 0; i < n / 2; i++) {
  129. TEST(array[i], i + n / 2);
  130. }
  131. for (; i < n; i++) {
  132. TEST(array[i], i - n / 2);
  133. }
  134. }
  135. END();
  136. }
  137. int test_value(void)
  138. {
  139. BEGIN();
  140. Heap1 heap = { NULL };
  141. unsigned i, previous, n, N;
  142. unsigned char *tests;
  143. N = 3000;
  144. TEST_1(tests = calloc(sizeof (unsigned char), N + 1));
  145. TEST(heap1_resize(NULL, &heap, 0), 0);
  146. /* Add N entries in reverse order */
  147. for (i = N; i > 0; i--) {
  148. type1 e = { i / 10, i, 0 };
  149. if (heap1_is_full(heap))
  150. TEST(heap1_resize(NULL, &heap, 0), 0);
  151. TEST(heap1_is_full(heap), 0);
  152. TEST(heap1_add(heap, e), 0);
  153. tests[i] |= 1;
  154. }
  155. TEST(heap1_used(heap), N);
  156. for (i = 1; i <= N; i++) {
  157. type1 const e = heap1_get(heap, i);
  158. TEST(e.index, i);
  159. TEST(tests[e.value] & 2, 0);
  160. tests[e.value] |= 2;
  161. if (2 * i <= N) {
  162. type1 const left = heap1_get(heap, 2 * i);
  163. TEST_1(e.key <= left.key);
  164. }
  165. if (2 * i + 1 <= N) {
  166. type1 const right = heap1_get(heap, 2 * i + 1);
  167. TEST_1(e.key <= right.key);
  168. }
  169. }
  170. /* Remove N entries */
  171. previous = 0;
  172. for (n = 0; heap1_used(heap) > 0; n++) {
  173. type1 const e = heap1_get(heap, 1);
  174. TEST_1(previous <= e.key);
  175. TEST(tests[e.value] & 4, 0);
  176. tests[e.value] |= 4;
  177. previous = e.key;
  178. TEST(heap1_get(heap, 1).index, 1);
  179. TEST(heap1_remove(heap, 1).index, 0);
  180. }
  181. TEST(n, N);
  182. /* Add N entries in reverse order */
  183. for (i = N; i > 0; i--) {
  184. type1 e = { i / 10, i, 0 };
  185. if (heap1_is_full(heap))
  186. TEST(heap1_resize(NULL, &heap, 0), 0);
  187. TEST(heap1_is_full(heap), 0);
  188. TEST(heap1_add(heap, e), 0);
  189. }
  190. TEST(heap1_used(heap), N);
  191. heap1_sort(heap);
  192. for (i = 1; i <= N; i++) {
  193. type1 e = heap1_get(heap, i);
  194. TEST(e.index, i);
  195. }
  196. /* Remove 1000 entries from random places */
  197. previous = 0;
  198. for (i = 0; i < 1000 && heap1_used(heap) > 0; i++) {
  199. type1 e;
  200. n = i * 397651 % heap1_used(heap) + 1;
  201. e = heap1_get(heap, n);
  202. TEST(e.index, n);
  203. TEST(tests[e.value] & 8, 0); tests[e.value] |= 8;
  204. TEST(heap1_get(heap, n).index, n);
  205. TEST(heap1_remove(heap, n).index, 0);
  206. }
  207. for (i = 1; i <= heap1_used(heap); i++) {
  208. type1 e = heap1_get(heap, i);
  209. type1 left = heap1_get(heap, 2 * i);
  210. type1 right = heap1_get(heap, 2 * i + 1);
  211. TEST_1(left.index == 0 || e.key <= left.key);
  212. TEST_1(right.index == 0 || e.key <= right.key);
  213. }
  214. /* Remove rest */
  215. for (n = 0, previous = 0; heap1_used(heap) > 0; n++) {
  216. type1 e = heap1_get(heap, 1);
  217. TEST(e.index, 1);
  218. TEST(tests[e.value] & 8, 0);
  219. tests[e.value] |= 8;
  220. TEST_1(previous <= e.key);
  221. previous = e.key;
  222. TEST(heap1_get(heap, 1).index, 1);
  223. TEST(heap1_remove(heap, 1).index, 0);
  224. }
  225. for (i = 1; i <= N; i++) {
  226. TEST(tests[i], 8 | 4 | 2 | 1);
  227. }
  228. TEST(heap1_resize(NULL, &heap, 63), 0);
  229. TEST(heap1_size(heap), 63);
  230. TEST(heap1_free(NULL, &heap), 0);
  231. free(tests);
  232. END();
  233. }
  234. int test_ref(void)
  235. {
  236. BEGIN();
  237. Heap2 heap = { NULL };
  238. unsigned i, previous, n, N;
  239. unsigned char *tests;
  240. type1 *items;
  241. N = 300000;
  242. TEST_1(tests = calloc(sizeof (unsigned char), N + 1));
  243. TEST_1(items = calloc((sizeof *items), N + 1));
  244. TEST(heap2_resize(NULL, &heap, 0), 0);
  245. /* Add N entries in reverse order */
  246. for (i = N; i > 0; i--) {
  247. type2 e = items + i;
  248. e->key = i / 10, e->value = i;
  249. if (heap2_is_full(heap))
  250. TEST(heap2_resize(NULL, &heap, 0), 0);
  251. TEST(heap2_is_full(heap), 0);
  252. TEST(heap2_add(heap, e), 0);
  253. tests[i] |= 1;
  254. }
  255. TEST(heap2_used(heap), N);
  256. for (i = 1; i <= N; i++) {
  257. type2 const e = heap2_get(heap, i);
  258. TEST_1(e);
  259. TEST(e->index, i);
  260. TEST(tests[e->value] & 2, 0);
  261. tests[e->value] |= 2;
  262. if (2 * i <= N) {
  263. type2 const left = heap2_get(heap, 2 * i);
  264. TEST_1(e->key <= left->key);
  265. }
  266. if (2 * i + 1 <= N) {
  267. type2 const right = heap2_get(heap, 2 * i + 1);
  268. TEST_1(e->key <= right->key);
  269. }
  270. }
  271. /* Remove N entries */
  272. previous = 0;
  273. for (n = 0; heap2_used(heap) > 0; n++) {
  274. type2 const e = heap2_get(heap, 1);
  275. TEST_1(e);
  276. TEST_1(previous <= e->key);
  277. TEST(tests[e->value] & 4, 0);
  278. tests[e->value] |= 4;
  279. previous = e->key;
  280. TEST(heap2_remove(heap, 1), e);
  281. }
  282. TEST(n, N);
  283. /* Add N entries in reverse order */
  284. for (i = N; i > 0; i--) {
  285. type2 e = items + i;
  286. if (heap2_is_full(heap))
  287. TEST(heap2_resize(NULL, &heap, 0), 0);
  288. TEST(heap2_is_full(heap), 0);
  289. TEST(heap2_add(heap, e), 0);
  290. }
  291. TEST(heap2_used(heap), N);
  292. heap2_sort(heap);
  293. for (i = 1; i <= N; i++) {
  294. type2 const e = heap2_get(heap, i);
  295. TEST_1(e); TEST(e->index, i);
  296. }
  297. heap2_sort(heap);
  298. for (i = 1; i <= N; i++) {
  299. type2 const e = heap2_get(heap, i);
  300. TEST_1(e); TEST(e->index, i);
  301. }
  302. /* Remove all odd entries */
  303. for (i = heap2_used(heap), n = 0; i > 0; i--) {
  304. type2 e = heap2_get(heap, i);
  305. TEST_1(e); TEST(e->index, i);
  306. n++;
  307. tests[e->value] |= 16;
  308. if (e->value & 1) {
  309. TEST(tests[e->value] & 8, 0); tests[e->value] |= 8;
  310. heap2_remove(heap, i);
  311. }
  312. }
  313. for (i = 1; i <= N; i++) {
  314. if (i & 1)
  315. TEST(tests[i] & 8, 8);
  316. else
  317. TEST(tests[i] & 8, 0);
  318. }
  319. /* Remove 1000 entries from random places */
  320. for (i = 0; i < 1000 && heap2_used(heap) > 0; i++) {
  321. type2 e;
  322. n = i * 397651 % heap2_used(heap) + 1;
  323. e = heap2_get(heap, n);
  324. TEST_1(e); TEST(e->index, n);
  325. TEST(tests[e->value] & 8, 0); tests[e->value] |= 8;
  326. TEST(heap2_remove(heap, n), e);
  327. }
  328. for (i = 1; i <= heap2_used(heap); i++) {
  329. type2 e = heap2_get(heap, i);
  330. TEST_1(e); TEST(e->index, i);
  331. if (2 * i <= heap2_used(heap)) {
  332. type2 const left = heap2_get(heap, 2 * i);
  333. TEST_1(left);
  334. TEST_1(e->key <= left->key);
  335. }
  336. if (2 * i + 1 <= heap2_used(heap)) {
  337. type2 const right = heap2_get(heap, 2 * i + 1);
  338. TEST_1(right);
  339. TEST_1(e->key <= right->key);
  340. }
  341. }
  342. /* Remove rest */
  343. for (n = 0, previous = 0; heap2_used(heap) > 0; n++) {
  344. type2 e = heap2_remove(heap, 1);
  345. TEST_1(e); TEST(e->index, 0);
  346. TEST(tests[e->value] & 8, 0);
  347. tests[e->value] |= 8;
  348. TEST_1(previous <= e->key);
  349. previous = e->key;
  350. }
  351. for (i = 1; i <= N; i++) {
  352. TEST(tests[i], 16 | 8 | 4 | 2 | 1);
  353. }
  354. TEST(heap2_resize(NULL, &heap, 63), 0);
  355. TEST(heap2_size(heap), 63);
  356. TEST(heap2_free(NULL, &heap), 0);
  357. free(tests);
  358. free(items);
  359. END();
  360. }
  361. int test_triplet(void)
  362. {
  363. BEGIN();
  364. Heap2 heap = { NULL };
  365. unsigned i, N;
  366. type1 *items;
  367. N = 3;
  368. TEST_1(items = calloc((sizeof *items), N + 1));
  369. TEST(heap2_resize(NULL, &heap, 0), 0);
  370. for (i = 1; i <= N; i++) {
  371. type2 e = items + i;
  372. e->key = i, e->value = i;
  373. if (heap2_is_full(heap))
  374. TEST(heap2_resize(NULL, &heap, 0), 0);
  375. TEST(heap2_is_full(heap), 0);
  376. TEST(heap2_add(heap, e), 0);
  377. }
  378. for (i = 1; i <= N; i++) {
  379. type2 e = heap2_get(heap, i);
  380. TEST(e->key, i);
  381. TEST(e->value, i);
  382. }
  383. for (i = 1; i <= N; i++) {
  384. type2 e = heap2_remove(heap, 1);
  385. TEST(e->key, i);
  386. TEST(e->value, i);
  387. }
  388. TEST(heap2_free(NULL, &heap), 0);
  389. free(items);
  390. END();
  391. }
  392. void usage(int exitcode)
  393. {
  394. fprintf(stderr,
  395. "usage: %s [-v] [-a]\n",
  396. name);
  397. exit(exitcode);
  398. }
  399. int main(int argc, char *argv[])
  400. {
  401. int retval = 0;
  402. int i;
  403. for (i = 1; argv[i]; i++) {
  404. if (strcmp(argv[i], "-v") == 0)
  405. tstflags |= tst_verbatim;
  406. else if (strcmp(argv[i], "-a") == 0)
  407. tstflags |= tst_abort;
  408. else
  409. usage(1);
  410. }
  411. retval |= test_triplet(); fflush(stdout);
  412. retval |= test_smooth_sort(); fflush(stdout);
  413. retval |= test_value(); fflush(stdout);
  414. retval |= test_ref(); fflush(stdout);
  415. return retval;
  416. }