sort.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. /* Copyright (C) 1999,2000,2001,2002, 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
  2. * This library is free software; you can redistribute it and/or
  3. * modify it under the terms of the GNU Lesser General Public
  4. * License as published by the Free Software Foundation; either
  5. * version 2.1 of the License, or (at your option) any later version.
  6. *
  7. * This library 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 GNU
  10. * Lesser General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU Lesser General Public
  13. * License along with this library; if not, write to the Free Software
  14. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  15. */
  16. /* Written in December 1998 by Roland Orre <orre@nada.kth.se>
  17. * This implements the same sort interface as slib/sort.scm
  18. * for lists and vectors where slib defines:
  19. * sorted?, merge, merge!, sort, sort!
  20. * For scsh compatibility sort-list and sort-list! are also defined.
  21. * In cases where a stable-sort is required use stable-sort or
  22. * stable-sort!. An additional feature is
  23. * (restricted-vector-sort! vector less? startpos endpos)
  24. * which allows you to sort part of a vector.
  25. * Thanks to Aubrey Jaffer for the slib/sort.scm library.
  26. * Thanks to Richard A. O'Keefe (based on Prolog code by D.H.D.Warren)
  27. * for the merge sort inspiration.
  28. * Thanks to Douglas C. Schmidt (schmidt@ics.uci.edu) for the
  29. * quicksort code.
  30. */
  31. #ifdef HAVE_CONFIG_H
  32. # include <config.h>
  33. #endif
  34. #include "libguile/_scm.h"
  35. #include "libguile/eval.h"
  36. #include "libguile/unif.h"
  37. #include "libguile/ramap.h"
  38. #include "libguile/feature.h"
  39. #include "libguile/vectors.h"
  40. #include "libguile/lang.h"
  41. #include "libguile/async.h"
  42. #include "libguile/dynwind.h"
  43. #include "libguile/validate.h"
  44. #include "libguile/sort.h"
  45. /* We have two quicksort variants: one for contigous vectors and one
  46. for vectors with arbitrary increments between elements. Note that
  47. increments can be negative.
  48. */
  49. #define NAME quicksort1
  50. #define INC_PARAM /* empty */
  51. #define INC 1
  52. #include "libguile/quicksort.i.c"
  53. #define NAME quicksort
  54. #define INC_PARAM ssize_t inc,
  55. #define INC inc
  56. #include "libguile/quicksort.i.c"
  57. static scm_t_trampoline_2
  58. compare_function (SCM less, unsigned int arg_nr, const char* fname)
  59. {
  60. const scm_t_trampoline_2 cmp = scm_trampoline_2 (less);
  61. SCM_ASSERT_TYPE (cmp != NULL, less, arg_nr, fname, "less predicate");
  62. return cmp;
  63. }
  64. SCM_DEFINE (scm_restricted_vector_sort_x, "restricted-vector-sort!", 4, 0, 0,
  65. (SCM vec, SCM less, SCM startpos, SCM endpos),
  66. "Sort the vector @var{vec}, using @var{less} for comparing\n"
  67. "the vector elements. @var{startpos} (inclusively) and\n"
  68. "@var{endpos} (exclusively) delimit\n"
  69. "the range of the vector which gets sorted. The return value\n"
  70. "is not specified.")
  71. #define FUNC_NAME s_scm_restricted_vector_sort_x
  72. {
  73. const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
  74. size_t vlen, spos, len;
  75. ssize_t vinc;
  76. scm_t_array_handle handle;
  77. SCM *velts;
  78. velts = scm_vector_writable_elements (vec, &handle, &vlen, &vinc);
  79. spos = scm_to_unsigned_integer (startpos, 0, vlen);
  80. len = scm_to_unsigned_integer (endpos, spos, vlen) - spos;
  81. if (vinc == 1)
  82. quicksort1 (velts + spos*vinc, len, cmp, less);
  83. else
  84. quicksort (velts + spos*vinc, len, vinc, cmp, less);
  85. scm_array_handle_release (&handle);
  86. return SCM_UNSPECIFIED;
  87. }
  88. #undef FUNC_NAME
  89. /* (sorted? sequence less?)
  90. * is true when sequence is a list (x0 x1 ... xm) or a vector #(x0 ... xm)
  91. * such that for all 1 <= i <= m,
  92. * (not (less? (list-ref list i) (list-ref list (- i 1)))). */
  93. SCM_DEFINE (scm_sorted_p, "sorted?", 2, 0, 0,
  94. (SCM items, SCM less),
  95. "Return @code{#t} iff @var{items} is a list or a vector such that\n"
  96. "for all 1 <= i <= m, the predicate @var{less} returns true when\n"
  97. "applied to all elements i - 1 and i")
  98. #define FUNC_NAME s_scm_sorted_p
  99. {
  100. const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
  101. long len, j; /* list/vector length, temp j */
  102. SCM item, rest; /* rest of items loop variable */
  103. if (SCM_NULL_OR_NIL_P (items))
  104. return SCM_BOOL_T;
  105. if (scm_is_pair (items))
  106. {
  107. len = scm_ilength (items); /* also checks that it's a pure list */
  108. SCM_ASSERT_RANGE (1, items, len >= 0);
  109. if (len <= 1)
  110. return SCM_BOOL_T;
  111. item = SCM_CAR (items);
  112. rest = SCM_CDR (items);
  113. j = len - 1;
  114. while (j > 0)
  115. {
  116. if (scm_is_true ((*cmp) (less, SCM_CAR (rest), item)))
  117. return SCM_BOOL_F;
  118. else
  119. {
  120. item = SCM_CAR (rest);
  121. rest = SCM_CDR (rest);
  122. j--;
  123. }
  124. }
  125. return SCM_BOOL_T;
  126. }
  127. else
  128. {
  129. scm_t_array_handle handle;
  130. size_t i, len;
  131. ssize_t inc;
  132. const SCM *elts;
  133. SCM result = SCM_BOOL_T;
  134. elts = scm_vector_elements (items, &handle, &len, &inc);
  135. for (i = 1; i < len; i++, elts += inc)
  136. {
  137. if (scm_is_true ((*cmp) (less, elts[inc], elts[0])))
  138. {
  139. result = SCM_BOOL_F;
  140. break;
  141. }
  142. }
  143. scm_array_handle_release (&handle);
  144. return result;
  145. }
  146. return SCM_BOOL_F;
  147. }
  148. #undef FUNC_NAME
  149. /* (merge a b less?)
  150. takes two lists a and b such that (sorted? a less?) and (sorted? b less?)
  151. and returns a new list in which the elements of a and b have been stably
  152. interleaved so that (sorted? (merge a b less?) less?).
  153. Note: this does _not_ accept vectors. */
  154. SCM_DEFINE (scm_merge, "merge", 3, 0, 0,
  155. (SCM alist, SCM blist, SCM less),
  156. "Merge two already sorted lists into one.\n"
  157. "Given two lists @var{alist} and @var{blist}, such that\n"
  158. "@code{(sorted? alist less?)} and @code{(sorted? blist less?)},\n"
  159. "return a new list in which the elements of @var{alist} and\n"
  160. "@var{blist} have been stably interleaved so that\n"
  161. "@code{(sorted? (merge alist blist less?) less?)}.\n"
  162. "Note: this does _not_ accept vectors.")
  163. #define FUNC_NAME s_scm_merge
  164. {
  165. SCM build;
  166. if (SCM_NULL_OR_NIL_P (alist))
  167. return blist;
  168. else if (SCM_NULL_OR_NIL_P (blist))
  169. return alist;
  170. else
  171. {
  172. const scm_t_trampoline_2 cmp = compare_function (less, 3, FUNC_NAME);
  173. long alen, blen; /* list lengths */
  174. SCM last;
  175. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (1, alist, alen);
  176. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (2, blist, blen);
  177. if (scm_is_true ((*cmp) (less, SCM_CAR (blist), SCM_CAR (alist))))
  178. {
  179. build = scm_cons (SCM_CAR (blist), SCM_EOL);
  180. blist = SCM_CDR (blist);
  181. blen--;
  182. }
  183. else
  184. {
  185. build = scm_cons (SCM_CAR (alist), SCM_EOL);
  186. alist = SCM_CDR (alist);
  187. alen--;
  188. }
  189. last = build;
  190. while ((alen > 0) && (blen > 0))
  191. {
  192. SCM_TICK;
  193. if (scm_is_true ((*cmp) (less, SCM_CAR (blist), SCM_CAR (alist))))
  194. {
  195. SCM_SETCDR (last, scm_cons (SCM_CAR (blist), SCM_EOL));
  196. blist = SCM_CDR (blist);
  197. blen--;
  198. }
  199. else
  200. {
  201. SCM_SETCDR (last, scm_cons (SCM_CAR (alist), SCM_EOL));
  202. alist = SCM_CDR (alist);
  203. alen--;
  204. }
  205. last = SCM_CDR (last);
  206. }
  207. if ((alen > 0) && (blen == 0))
  208. SCM_SETCDR (last, alist);
  209. else if ((alen == 0) && (blen > 0))
  210. SCM_SETCDR (last, blist);
  211. }
  212. return build;
  213. }
  214. #undef FUNC_NAME
  215. static SCM
  216. scm_merge_list_x (SCM alist, SCM blist,
  217. long alen, long blen,
  218. scm_t_trampoline_2 cmp, SCM less)
  219. {
  220. SCM build, last;
  221. if (SCM_NULL_OR_NIL_P (alist))
  222. return blist;
  223. else if (SCM_NULL_OR_NIL_P (blist))
  224. return alist;
  225. else
  226. {
  227. if (scm_is_true ((*cmp) (less, SCM_CAR (blist), SCM_CAR (alist))))
  228. {
  229. build = blist;
  230. blist = SCM_CDR (blist);
  231. blen--;
  232. }
  233. else
  234. {
  235. build = alist;
  236. alist = SCM_CDR (alist);
  237. alen--;
  238. }
  239. last = build;
  240. while ((alen > 0) && (blen > 0))
  241. {
  242. SCM_TICK;
  243. if (scm_is_true ((*cmp) (less, SCM_CAR (blist), SCM_CAR (alist))))
  244. {
  245. SCM_SETCDR (last, blist);
  246. blist = SCM_CDR (blist);
  247. blen--;
  248. }
  249. else
  250. {
  251. SCM_SETCDR (last, alist);
  252. alist = SCM_CDR (alist);
  253. alen--;
  254. }
  255. last = SCM_CDR (last);
  256. }
  257. if ((alen > 0) && (blen == 0))
  258. SCM_SETCDR (last, alist);
  259. else if ((alen == 0) && (blen > 0))
  260. SCM_SETCDR (last, blist);
  261. }
  262. return build;
  263. } /* scm_merge_list_x */
  264. SCM_DEFINE (scm_merge_x, "merge!", 3, 0, 0,
  265. (SCM alist, SCM blist, SCM less),
  266. "Takes two lists @var{alist} and @var{blist} such that\n"
  267. "@code{(sorted? alist less?)} and @code{(sorted? blist less?)} and\n"
  268. "returns a new list in which the elements of @var{alist} and\n"
  269. "@var{blist} have been stably interleaved so that\n"
  270. " @code{(sorted? (merge alist blist less?) less?)}.\n"
  271. "This is the destructive variant of @code{merge}\n"
  272. "Note: this does _not_ accept vectors.")
  273. #define FUNC_NAME s_scm_merge_x
  274. {
  275. if (SCM_NULL_OR_NIL_P (alist))
  276. return blist;
  277. else if (SCM_NULL_OR_NIL_P (blist))
  278. return alist;
  279. else
  280. {
  281. const scm_t_trampoline_2 cmp = compare_function (less, 3, FUNC_NAME);
  282. long alen, blen; /* list lengths */
  283. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (1, alist, alen);
  284. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (2, blist, blen);
  285. return scm_merge_list_x (alist, blist, alen, blen, cmp, less);
  286. }
  287. }
  288. #undef FUNC_NAME
  289. /* This merge sort algorithm is same as slib's by Richard A. O'Keefe.
  290. The algorithm is stable. We also tried to use the algorithm used by
  291. scsh's merge-sort but that algorithm showed to not be stable, even
  292. though it claimed to be.
  293. */
  294. static SCM
  295. scm_merge_list_step (SCM * seq, scm_t_trampoline_2 cmp, SCM less, long n)
  296. {
  297. SCM a, b;
  298. if (n > 2)
  299. {
  300. long mid = n / 2;
  301. SCM_TICK;
  302. a = scm_merge_list_step (seq, cmp, less, mid);
  303. b = scm_merge_list_step (seq, cmp, less, n - mid);
  304. return scm_merge_list_x (a, b, mid, n - mid, cmp, less);
  305. }
  306. else if (n == 2)
  307. {
  308. SCM p = *seq;
  309. SCM rest = SCM_CDR (*seq);
  310. SCM x = SCM_CAR (*seq);
  311. SCM y = SCM_CAR (SCM_CDR (*seq));
  312. *seq = SCM_CDR (rest);
  313. SCM_SETCDR (rest, SCM_EOL);
  314. if (scm_is_true ((*cmp) (less, y, x)))
  315. {
  316. SCM_SETCAR (p, y);
  317. SCM_SETCAR (rest, x);
  318. }
  319. return p;
  320. }
  321. else if (n == 1)
  322. {
  323. SCM p = *seq;
  324. *seq = SCM_CDR (p);
  325. SCM_SETCDR (p, SCM_EOL);
  326. return p;
  327. }
  328. else
  329. return SCM_EOL;
  330. } /* scm_merge_list_step */
  331. SCM_DEFINE (scm_sort_x, "sort!", 2, 0, 0,
  332. (SCM items, SCM less),
  333. "Sort the sequence @var{items}, which may be a list or a\n"
  334. "vector. @var{less} is used for comparing the sequence\n"
  335. "elements. The sorting is destructive, that means that the\n"
  336. "input sequence is modified to produce the sorted result.\n"
  337. "This is not a stable sort.")
  338. #define FUNC_NAME s_scm_sort_x
  339. {
  340. long len; /* list/vector length */
  341. if (SCM_NULL_OR_NIL_P (items))
  342. return items;
  343. if (scm_is_pair (items))
  344. {
  345. const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
  346. SCM_VALIDATE_LIST_COPYLEN (1, items, len);
  347. return scm_merge_list_step (&items, cmp, less, len);
  348. }
  349. else if (scm_is_vector (items))
  350. {
  351. scm_restricted_vector_sort_x (items,
  352. less,
  353. scm_from_int (0),
  354. scm_vector_length (items));
  355. return items;
  356. }
  357. else
  358. SCM_WRONG_TYPE_ARG (1, items);
  359. }
  360. #undef FUNC_NAME
  361. SCM_DEFINE (scm_sort, "sort", 2, 0, 0,
  362. (SCM items, SCM less),
  363. "Sort the sequence @var{items}, which may be a list or a\n"
  364. "vector. @var{less} is used for comparing the sequence\n"
  365. "elements. This is not a stable sort.")
  366. #define FUNC_NAME s_scm_sort
  367. {
  368. if (SCM_NULL_OR_NIL_P (items))
  369. return items;
  370. if (scm_is_pair (items))
  371. return scm_sort_x (scm_list_copy (items), less);
  372. else if (scm_is_vector (items))
  373. return scm_sort_x (scm_vector_copy (items), less);
  374. else
  375. SCM_WRONG_TYPE_ARG (1, items);
  376. }
  377. #undef FUNC_NAME
  378. static void
  379. scm_merge_vector_x (SCM *vec,
  380. SCM *temp,
  381. scm_t_trampoline_2 cmp,
  382. SCM less,
  383. size_t low,
  384. size_t mid,
  385. size_t high,
  386. ssize_t inc)
  387. {
  388. size_t it; /* Index for temp vector */
  389. size_t i1 = low; /* Index for lower vector segment */
  390. size_t i2 = mid + 1; /* Index for upper vector segment */
  391. #define VEC(i) vec[(i)*inc]
  392. /* Copy while both segments contain more characters */
  393. for (it = low; (i1 <= mid) && (i2 <= high); ++it)
  394. {
  395. if (scm_is_true ((*cmp) (less, VEC(i2), VEC(i1))))
  396. temp[it] = VEC(i2++);
  397. else
  398. temp[it] = VEC(i1++);
  399. }
  400. {
  401. /* Copy while first segment contains more characters */
  402. while (i1 <= mid)
  403. temp[it++] = VEC(i1++);
  404. /* Copy while second segment contains more characters */
  405. while (i2 <= high)
  406. temp[it++] = VEC(i2++);
  407. /* Copy back from temp to vp */
  408. for (it = low; it <= high; it++)
  409. VEC(it) = temp[it];
  410. }
  411. } /* scm_merge_vector_x */
  412. static void
  413. scm_merge_vector_step (SCM *vec,
  414. SCM *temp,
  415. scm_t_trampoline_2 cmp,
  416. SCM less,
  417. size_t low,
  418. size_t high,
  419. ssize_t inc)
  420. {
  421. if (high > low)
  422. {
  423. size_t mid = (low + high) / 2;
  424. SCM_TICK;
  425. scm_merge_vector_step (vec, temp, cmp, less, low, mid, inc);
  426. scm_merge_vector_step (vec, temp, cmp, less, mid+1, high, inc);
  427. scm_merge_vector_x (vec, temp, cmp, less, low, mid, high, inc);
  428. }
  429. } /* scm_merge_vector_step */
  430. SCM_DEFINE (scm_stable_sort_x, "stable-sort!", 2, 0, 0,
  431. (SCM items, SCM less),
  432. "Sort the sequence @var{items}, which may be a list or a\n"
  433. "vector. @var{less} is used for comparing the sequence elements.\n"
  434. "The sorting is destructive, that means that the input sequence\n"
  435. "is modified to produce the sorted result.\n"
  436. "This is a stable sort.")
  437. #define FUNC_NAME s_scm_stable_sort_x
  438. {
  439. const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
  440. long len; /* list/vector length */
  441. if (SCM_NULL_OR_NIL_P (items))
  442. return items;
  443. if (scm_is_pair (items))
  444. {
  445. SCM_VALIDATE_LIST_COPYLEN (1, items, len);
  446. return scm_merge_list_step (&items, cmp, less, len);
  447. }
  448. else if (scm_is_vector (items))
  449. {
  450. scm_t_array_handle temp_handle, vec_handle;
  451. SCM temp, *temp_elts, *vec_elts;
  452. size_t len;
  453. ssize_t inc;
  454. vec_elts = scm_vector_writable_elements (items, &vec_handle,
  455. &len, &inc);
  456. temp = scm_c_make_vector (len, SCM_UNDEFINED);
  457. temp_elts = scm_vector_writable_elements (temp, &temp_handle,
  458. NULL, NULL);
  459. scm_merge_vector_step (vec_elts, temp_elts, cmp, less, 0, len-1, inc);
  460. scm_array_handle_release (&temp_handle);
  461. scm_array_handle_release (&vec_handle);
  462. return items;
  463. }
  464. else
  465. SCM_WRONG_TYPE_ARG (1, items);
  466. }
  467. #undef FUNC_NAME
  468. SCM_DEFINE (scm_stable_sort, "stable-sort", 2, 0, 0,
  469. (SCM items, SCM less),
  470. "Sort the sequence @var{items}, which may be a list or a\n"
  471. "vector. @var{less} is used for comparing the sequence elements.\n"
  472. "This is a stable sort.")
  473. #define FUNC_NAME s_scm_stable_sort
  474. {
  475. if (SCM_NULL_OR_NIL_P (items))
  476. return SCM_EOL;
  477. if (scm_is_pair (items))
  478. return scm_stable_sort_x (scm_list_copy (items), less);
  479. else if (scm_is_vector (items))
  480. return scm_stable_sort_x (scm_vector_copy (items), less);
  481. else
  482. SCM_WRONG_TYPE_ARG (1, items);
  483. }
  484. #undef FUNC_NAME
  485. SCM_DEFINE (scm_sort_list_x, "sort-list!", 2, 0, 0,
  486. (SCM items, SCM less),
  487. "Sort the list @var{items}, using @var{less} for comparing the\n"
  488. "list elements. The sorting is destructive, that means that the\n"
  489. "input list is modified to produce the sorted result.\n"
  490. "This is a stable sort.")
  491. #define FUNC_NAME s_scm_sort_list_x
  492. {
  493. const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
  494. long len;
  495. SCM_VALIDATE_LIST_COPYLEN (1, items, len);
  496. return scm_merge_list_step (&items, cmp, less, len);
  497. }
  498. #undef FUNC_NAME
  499. SCM_DEFINE (scm_sort_list, "sort-list", 2, 0, 0,
  500. (SCM items, SCM less),
  501. "Sort the list @var{items}, using @var{less} for comparing the\n"
  502. "list elements. This is a stable sort.")
  503. #define FUNC_NAME s_scm_sort_list
  504. {
  505. const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
  506. long len;
  507. SCM_VALIDATE_LIST_COPYLEN (1, items, len);
  508. items = scm_list_copy (items);
  509. return scm_merge_list_step (&items, cmp, less, len);
  510. }
  511. #undef FUNC_NAME
  512. void
  513. scm_init_sort ()
  514. {
  515. #include "libguile/sort.x"
  516. scm_add_feature ("sort");
  517. }
  518. /*
  519. Local Variables:
  520. c-file-style: "gnu"
  521. End:
  522. */