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