sort.c 16 KB

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