sort.c 19 KB

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