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