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