PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/darray.c

#
C | 668 lines | 465 code | 75 blank | 128 comment | 102 complexity | facf2b80695deedf06a9c4d3fb78c062 MD5 | raw file
  1. /* darray.c -- dynamic arrays handling
  2. Copyright (c) 1996-99 Akim Demaille, Miguel Santana
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  14. /* Author: Akim Demaille <demaille@inf.enst.fr> */
  15. #include <system.h>
  16. #include "darray.h"
  17. int da_exit_error = 1; /* exit value when encounters *
  18. * an error */
  19. #define QSORT_INSERT_SORT_LIMIT 37 /* Bellow, insert sort is used */
  20. #define QSORT_STACK 100
  21. #define DA_SWAP(a,i,j) \
  22. do { \
  23. tmp = a->content [i]; \
  24. a->content [i] = a->content [j]; \
  25. a->content [j] = tmp ; \
  26. } while (0)
  27. /*
  28. * Create a dynamic array
  29. */
  30. struct darray *
  31. da_new (const char * name, size_t size,
  32. enum da_growth growth, size_t increment,
  33. da_print_func_t self_print,
  34. da_cmp_func_t cmp)
  35. {
  36. struct darray * res;
  37. /* No longer relevant: size_t cannot be null */
  38. if (size == 0)
  39. error (da_exit_error, 0, "invalid size for dynamic array `%s': %d",
  40. name, size);
  41. if (increment == 0 && growth != da_steady)
  42. error (da_exit_error, 0, "invalid increment for dynamic array `%s': %d",
  43. name, increment);
  44. res = XMALLOC (struct darray, 1);
  45. res->name = name;
  46. res->original_size = size;
  47. res->size = size;
  48. res->content = XCALLOC (void *, res->size);
  49. res->growth = growth;
  50. res->increment = increment;
  51. res->len = 0;
  52. /* Routines */
  53. res->self_print = self_print;
  54. res->cmp = cmp;
  55. return res;
  56. }
  57. static inline void
  58. _da_erase (struct darray * arr)
  59. {
  60. if (arr) {
  61. XFREE (arr->content);
  62. free (arr);
  63. }
  64. }
  65. void
  66. da_erase (struct darray * arr)
  67. {
  68. _da_erase (arr);
  69. }
  70. /*
  71. * Set length of ARR to 0, and free with FREE_FUNC if non NULL
  72. */
  73. static inline void
  74. _da_free_content (struct darray * arr, da_map_func_t free_func)
  75. {
  76. size_t i;
  77. if (free_func)
  78. for (i = 0 ; i < arr->len ; i++)
  79. (*free_func) (arr->content [i]);
  80. arr->len = 0;
  81. }
  82. void
  83. da_free_content (struct darray * arr, da_map_func_t free_func)
  84. {
  85. _da_free_content (arr, free_func);
  86. }
  87. /*
  88. * Set length of ARR to 0, and free with FREE_FUNC if non NULL
  89. * and free the structure
  90. */
  91. void
  92. da_free (struct darray * arr, da_map_func_t free_func)
  93. {
  94. _da_free_content (arr, free_func);
  95. _da_erase (arr);
  96. }
  97. /*
  98. * Report the status of the array
  99. */
  100. void
  101. da_print_stats (struct darray * arr, FILE * stream)
  102. {
  103. const char * cp = NULL;
  104. fprintf (stream, _("Dynamic array `%s':\n"), arr->name);
  105. fprintf (stream, _("\tload: %d/%d (%2.1f%%)\n"),
  106. arr->len, arr->size, 100.0 * arr->len / arr->size);
  107. switch (arr->growth) {
  108. case da_steady:
  109. /* growth is steady, i.e., it cannot grow, it is constant */
  110. cp = "[const]";
  111. break;
  112. case da_linear:
  113. /* growth is linear. eg. 2, 4, 6, 8 */
  114. cp = "+=";
  115. break;
  116. case da_geometrical:
  117. /* growth is exponential. eg. 2, 4, 8, 16 */
  118. cp = "*=";
  119. break;
  120. default:
  121. abort ();
  122. }
  123. fprintf (stream, _("\toriginal size: %d, growth: %s %d\n"),
  124. arr->original_size, cp, arr->increment);
  125. }
  126. /*
  127. * Resize, unless too small to fit
  128. */
  129. void
  130. da_resize (struct darray * arr, size_t size)
  131. {
  132. if (arr->len + 1 < size)
  133. {
  134. arr->size = size;
  135. arr->content = XREALLOC (arr->content, void *, arr->size);
  136. }
  137. }
  138. /*
  139. * Make a dyn. array bigger
  140. */
  141. void
  142. da_grow (struct darray * arr)
  143. {
  144. switch (arr->growth) {
  145. case da_steady:
  146. return;
  147. case da_linear:
  148. arr->size += arr->increment;
  149. break;
  150. case da_geometrical:
  151. arr->size *= arr->increment;
  152. break;
  153. default:
  154. abort ();
  155. }
  156. arr->content = XREALLOC (arr->content, void *, arr->size);
  157. }
  158. /*
  159. * Make a clone
  160. */
  161. struct darray *
  162. da_clone (struct darray * array)
  163. {
  164. struct darray * res;
  165. res = CLONE (array);
  166. res->content = CCLONE (array->content, array->len);
  167. return res;
  168. }
  169. /*
  170. * Is it sorted?
  171. */
  172. int
  173. da_is_sorted (struct darray * arr)
  174. {
  175. size_t i;
  176. for (i = 1 ; i < arr->len ; i++)
  177. if (arr->cmp (arr->content [i], arr->content [i - 1]) < 0)
  178. return 0;
  179. return 1;
  180. }
  181. /*
  182. * Are two darray equal (pointer-wise)?
  183. */
  184. int
  185. da_equal (struct darray * ar1, struct darray * ar2)
  186. {
  187. size_t i;
  188. if (ar1->len != ar2->len)
  189. return 0;
  190. for (i = 0 ; i< ar1->len ; i++)
  191. if (ar1->content [i] != ar2->content [i])
  192. return 0;
  193. return 1;
  194. }
  195. /*
  196. * Do two arrays have same semantics (wrt cmp) content?
  197. * (ar1->cmp is used for the comparison)
  198. */
  199. int
  200. da_cmp_equal (struct darray * ar1, struct darray * ar2)
  201. {
  202. size_t i;
  203. if (ar1->len != ar2->len)
  204. return 0;
  205. for (i = 0 ; i< ar1->len ; i++)
  206. if (ar1->cmp (ar1->content [i], ar2->content [i]))
  207. return 0;
  208. return 1;
  209. }
  210. /*
  211. * Where is STUFF in ARR (equal in the sense of self_cmp)
  212. * -1 if is not in.
  213. */
  214. int
  215. da_where (struct darray * arr, const void * stuff)
  216. {
  217. size_t i;
  218. for (i = 0 ; i < arr->len ; i++)
  219. if (!arr->cmp (arr->content[i], stuff))
  220. return (int) i;
  221. return -1;
  222. }
  223. /*
  224. * Does this stuff is selfcmp equal to an item of the darray?
  225. */
  226. int
  227. da_includes (struct darray * arr, const void * stuff)
  228. {
  229. return (da_where (arr, stuff) != -1);
  230. }
  231. /*
  232. * Append an element
  233. */
  234. void
  235. da_append (struct darray * arr, void * elem)
  236. {
  237. if (da_is_full (arr))
  238. da_grow (arr);
  239. arr->content [arr->len++] = elem;
  240. }
  241. /*
  242. * Insert an element at a given place.
  243. */
  244. void
  245. da_insert_at (struct darray * arr, void * elem, size_t where)
  246. {
  247. size_t i;
  248. if (where > arr->len)
  249. error (da_exit_error, 0, "can't insert at %d in darray %s [0,%d]\n",
  250. where, arr->name, arr->len - 1);
  251. if (da_is_full (arr))
  252. da_grow (arr);
  253. for (i = arr->len ; where < i ; i--)
  254. arr->content [i] = arr->content [i - 1];
  255. arr->content [ where ] = elem;
  256. arr->len ++;
  257. }
  258. /*
  259. * Remove an element at a given place.
  260. */
  261. void
  262. da_remove_at (struct darray * arr, size_t where, da_map_func_t free_func)
  263. {
  264. size_t i;
  265. if (where >= arr->len)
  266. error (da_exit_error, 0, "can't remove at %d in darray %s [0,%d]\n",
  267. where, arr->name, arr->len - 1);
  268. if (free_func)
  269. (*free_func) (arr->content [where]);
  270. for (i = where + 1 ; i < arr->len ; i++)
  271. arr->content [i - 1] = arr->content [i];
  272. arr->len --;
  273. }
  274. /*
  275. * Concat the second in the first
  276. */
  277. void
  278. da_concat (struct darray * arr, struct darray * arr2)
  279. {
  280. size_t i;
  281. size_t len = arr->len + arr2->len;
  282. if (len > arr->size) {
  283. arr->size = len + 1;
  284. arr->content = XREALLOC (arr->content, void *, arr->size);
  285. }
  286. for (i = 0 ; i < arr2->len ; i++)
  287. arr->content [arr->len++] = arr2->content[i];
  288. }
  289. /*
  290. * Prefix the content of ARR by that of ARR2
  291. */
  292. void
  293. da_prefix (struct darray * arr, struct darray * arr2)
  294. {
  295. int i;
  296. size_t len = arr->len + arr2->len;
  297. if (len > arr->size) {
  298. arr->size = len + 1;
  299. arr->content = XREALLOC (arr->content, void *, arr->size);
  300. }
  301. /* Move the content of ARR */
  302. for (i = (int) arr->len - 1 ; i >= 0 ; i--)
  303. arr->content [ i + arr2->len ] = arr->content [ i ];
  304. /* Copy the content of ARR2 */
  305. for (i = 0 ; i < (int) arr2->len ; i++)
  306. arr->content [ i ] = arr2->content[ i ];
  307. arr->len += arr2->len;
  308. }
  309. /*
  310. * Implementation of QSORT as given by Sedgewick
  311. */
  312. void
  313. da_qsort (struct darray * arr)
  314. {
  315. int ir, j, k, l, i;
  316. int jstack, *istack;
  317. void * a, * tmp;
  318. /* Do not sort an empty array */
  319. if (arr->len <= 1)
  320. return;
  321. istack = XMALLOC (int, QSORT_STACK);
  322. ir = arr->len - 1;
  323. l = 0;
  324. jstack = 0;
  325. for (;;) {
  326. if (ir - l < QSORT_INSERT_SORT_LIMIT)
  327. { /* Insertion sort is then prefered */
  328. for (j = l + 1 ; j <= ir ; j++) {
  329. a = arr->content [j];
  330. for (i = j - 1 ; i >= l ; i--) {
  331. if (arr->cmp (arr->content [i], a) <= 0)
  332. break;
  333. arr->content [i + 1] = arr->content [i];
  334. }
  335. arr->content [i + 1] = a;
  336. }
  337. if (jstack == 0)
  338. break;
  339. ir = istack [jstack--];
  340. l = istack [jstack--];
  341. }
  342. else
  343. {
  344. k = (l + ir) / 2;
  345. DA_SWAP (arr, k, l + 1);
  346. if (arr->cmp (arr->content [l], arr->content [ir]) > 0)
  347. DA_SWAP (arr, l, ir);
  348. if (arr->cmp (arr->content [l + 1], arr->content [ir]) > 0)
  349. DA_SWAP (arr, l + 1, ir);
  350. if (arr->cmp (arr->content [l], arr->content [l + 1]) > 0)
  351. DA_SWAP (arr, l, l + 1);
  352. i = l + 1;
  353. j = ir;
  354. a = arr->content [l + 1];
  355. for (;;) {
  356. do i++; while (arr->cmp (arr->content [i], a) < 0);
  357. do j--; while (arr->cmp (arr->content [j], a) > 0);
  358. if (j < i)
  359. break; /* Partion is completed */
  360. DA_SWAP (arr, i, j);
  361. }
  362. arr->content [l + 1] = arr->content [j];
  363. arr->content [j] = a;
  364. jstack += 2;
  365. /* Push pointers to larger subarry on stack.
  366. * Process smaller subarrays now */
  367. if (jstack > QSORT_STACK)
  368. error (da_exit_error, 0, "da_qsort: QSORT_STACK too small (%d)",
  369. QSORT_STACK);
  370. if (ir - i + 1 >= j - l) {
  371. istack [jstack] = ir;
  372. istack [jstack - 1] = i;
  373. ir = j - 1;
  374. } else {
  375. istack [jstack] = j - 1;
  376. istack [jstack - 1] = l;
  377. l = i;
  378. }
  379. }
  380. }
  381. free (istack);
  382. }
  383. /*
  384. * Implementation of QSORT as given by Sedgewick
  385. */
  386. void
  387. da_qsort_with_arg (struct darray * arr, da_cmp_arg_func_t cmp,
  388. const void * arg)
  389. {
  390. int ir, j, k, l, i;
  391. int jstack, *istack;
  392. void * a, * tmp;
  393. /* Do not sort an empty array */
  394. if (arr->len <= 1)
  395. return;
  396. istack = XMALLOC (int, QSORT_STACK);
  397. ir = arr->len - 1;
  398. l = 0;
  399. jstack = 0;
  400. for (;;) {
  401. if (ir - l < QSORT_INSERT_SORT_LIMIT)
  402. { /* Insertion sort is then prefered */
  403. for (j = l + 1 ; j <= ir ; j++) {
  404. a = arr->content [j];
  405. for (i = j - 1 ; i >= l ; i--) {
  406. if (cmp (arr->content [i], a, arg) <= 0)
  407. break;
  408. arr->content [i + 1] = arr->content [i];
  409. }
  410. arr->content [i + 1] = a;
  411. }
  412. if (jstack == 0)
  413. break;
  414. ir = istack [jstack--];
  415. l = istack [jstack--];
  416. }
  417. else
  418. {
  419. k = (l + ir) / 2;
  420. DA_SWAP (arr, k, l + 1);
  421. if (cmp (arr->content [l], arr->content [ir], arg) > 0)
  422. DA_SWAP (arr, l, ir);
  423. if (cmp (arr->content [l + 1], arr->content [ir], arg) > 0)
  424. DA_SWAP (arr, l + 1, ir);
  425. if (cmp (arr->content [l], arr->content [l + 1], arg) > 0)
  426. DA_SWAP (arr, l, l + 1);
  427. i = l + 1;
  428. j = ir;
  429. a = arr->content [l + 1];
  430. for (;;) {
  431. do i++; while (cmp (arr->content [i], a, arg) < 0);
  432. do j--; while (cmp (arr->content [j], a, arg) > 0);
  433. if (j < i)
  434. break; /* Partion is completed */
  435. DA_SWAP (arr, i, j);
  436. }
  437. arr->content [l + 1] = arr->content [j];
  438. arr->content [j] = a;
  439. jstack += 2;
  440. /* Push pointers to larger subarry on stack.
  441. * Process smaller subarrays now */
  442. if (jstack > QSORT_STACK)
  443. error (da_exit_error, 0, "da_qsort: QSORT_STACK too small (%d)",
  444. QSORT_STACK);
  445. if (ir - i + 1 >= j - l) {
  446. istack [jstack] = ir;
  447. istack [jstack - 1] = i;
  448. ir = j - 1;
  449. } else {
  450. istack [jstack] = j - 1;
  451. istack [jstack - 1] = l;
  452. l = i;
  453. }
  454. }
  455. }
  456. free (istack);
  457. }
  458. /*
  459. * Leave the first of each doubles
  460. */
  461. void
  462. da_unique (struct darray * arr, da_map_func_t free_func)
  463. {
  464. size_t c;
  465. c = 1;
  466. while (c < arr->len) {
  467. if (arr->cmp (arr->content [c - 1], arr->content[c]) == 0)
  468. da_remove_at (arr, c, free_func);
  469. else
  470. c++;
  471. }
  472. }
  473. /*
  474. * Merge A2 into A1. Both *are sorted*.
  475. * In the result there are never two equal entries
  476. * (in the sense of self_cmp).
  477. *
  478. * In case of conflict (equal entries from the point of view
  479. * of a1->cmp),
  480. * - if POLICY == da_1_wins, keep that of A1
  481. * - if POLICY == da_2_wins, keep that of A2
  482. *
  483. * If there are doubles in a1 and/or in a2, they still will be doubles
  484. * in the returned result.
  485. */
  486. void
  487. da_merge (struct darray * a1, struct darray * a2,
  488. da_map_func_t free_func, enum da_include_policy policy)
  489. {
  490. size_t c1, c2; /* Counters on a1, and a2 */
  491. c1 = c2 = 0;
  492. while ((c1 != a1->len) || (c2 != a2->len))
  493. {
  494. /* Leave what is in a1 as long as it is strictly smaller than the
  495. * next item of a2 */
  496. while ((c1 < a1->len)
  497. && ((c2 == a2->len)
  498. || (a1->cmp (a1->content [c1], a2->content [c2]) < 0)))
  499. c1 ++;
  500. /* Skip whatever appears in a1, but is in a2 too */
  501. while ((c1 < a1->len) && (c2 < a2->len)
  502. && (a1->cmp (a1->content [c1], a2->content [c2]) == 0))
  503. if (policy == da_1_wins)
  504. {
  505. if (free_func)
  506. da_remove_at (a2, c2, free_func);
  507. else
  508. c2++;
  509. }
  510. else
  511. {
  512. if (free_func)
  513. da_remove_at (a1, c1, free_func);
  514. else
  515. c1++;
  516. }
  517. /* Take what is is a2 as long as it is smaller or equal to
  518. * what appeared last in a1 */
  519. while ((c2 < a2->len)
  520. && ((c1 == a1->len)
  521. || (a1->cmp (a1->content [c1], a2->content [c2]) >= 0)))
  522. da_insert_at (a1, a2->content [c2++], c1);
  523. }
  524. }
  525. /*
  526. * Dump on stderr the content
  527. */
  528. void
  529. da_self_print (struct darray * arr, FILE * stream)
  530. {
  531. size_t i;
  532. fprintf (stream, _("Dynamic array `%s':\n"), arr->name);
  533. if (!arr->self_print)
  534. abort ();
  535. for (i = 0 ; i < arr->len ; i++) {
  536. fprintf (stream, "[%2d] = ", i);
  537. arr->self_print (arr->content [i], stream);
  538. fprintf (stream, "\n");
  539. }
  540. }
  541. /*
  542. * For each item of ARR, call FN (ITEM)
  543. */
  544. void
  545. da_map (struct darray * arr, da_map_func_t fn)
  546. {
  547. size_t i;
  548. for (i = 0 ; i < arr->len ; i++)
  549. (*fn) (arr->content [i]);
  550. }
  551. /*
  552. * Idem, but with an argument
  553. */
  554. void
  555. da_maparg (struct darray * arr, da_maparg_func_t func, void * arg)
  556. {
  557. size_t i;
  558. for (i = 0 ; i < arr->len ; i++)
  559. (*func) (arr->content [i], arg);
  560. }
  561. /*
  562. * Some helping routines for special darray cases
  563. */
  564. /*
  565. * darray of strings
  566. */
  567. int
  568. da_str_cmp (const char * s1, const char * s2)
  569. {
  570. return strcmp (s1, s2);
  571. }
  572. void
  573. da_str_print (const char * s1, FILE * stream)
  574. {
  575. fputs ((const char *) s1, stream);
  576. }
  577. void
  578. da_str_printnl (const char * s1, FILE * stream)
  579. {
  580. fputs ((const char *) s1, stream);
  581. putc ('\n', stream);
  582. }