sort.c 18 KB

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