sort.c 18 KB

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