Include <config.h> in all C files; use `#ifdef HAVE_CONFIG_H' rather than `#if'.
[bpt/guile.git] / libguile / sort.c
CommitLineData
dbb605f5 1/* Copyright (C) 1999,2000,2001,2002, 2004, 2006, 2007, 2008 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
dbb605f5
LC
35#ifdef HAVE_CONFIG_H
36# include <config.h>
37#endif
38
a0599745 39#include "libguile/_scm.h"
a0599745
MD
40#include "libguile/eval.h"
41#include "libguile/unif.h"
42#include "libguile/ramap.h"
a0599745
MD
43#include "libguile/feature.h"
44#include "libguile/vectors.h"
c96d76b8 45#include "libguile/lang.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
d339981a
DH
67static scm_t_trampoline_2
68compare_function (SCM less, unsigned int arg_nr, const char* fname)
54e09076 69{
d339981a
DH
70 const scm_t_trampoline_2 cmp = scm_trampoline_2 (less);
71 SCM_ASSERT_TYPE (cmp != NULL, less, arg_nr, fname, "less predicate");
72 return cmp;
73}
54e09076 74
54e09076 75
a1ec6916 76SCM_DEFINE (scm_restricted_vector_sort_x, "restricted-vector-sort!", 4, 0, 0,
1bbd0b84 77 (SCM vec, SCM less, SCM startpos, SCM endpos),
e3239868 78 "Sort the vector @var{vec}, using @var{less} for comparing\n"
3bdf7962
MV
79 "the vector elements. @var{startpos} (inclusively) and\n"
80 "@var{endpos} (exclusively) delimit\n"
e3239868
DH
81 "the range of the vector which gets sorted. The return value\n"
82 "is not specified.")
1bbd0b84 83#define FUNC_NAME s_scm_restricted_vector_sort_x
54e09076 84{
d339981a 85 const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
cb26f569
MV
86 size_t vlen, spos, len;
87 ssize_t vinc;
88 scm_t_array_handle handle;
89 SCM *velts;
54e09076 90
cb26f569 91 velts = scm_vector_writable_elements (vec, &handle, &vlen, &vinc);
a55c2b68 92 spos = scm_to_unsigned_integer (startpos, 0, vlen);
3bdf7962 93 len = scm_to_unsigned_integer (endpos, spos, vlen) - spos;
54e09076 94
cb26f569
MV
95 if (vinc == 1)
96 quicksort1 (velts + spos*vinc, len, cmp, less);
97 else
98 quicksort (velts + spos*vinc, len, vinc, cmp, less);
99
c8857a4d
MV
100 scm_array_handle_release (&handle);
101
d339981a 102 return SCM_UNSPECIFIED;
1bbd0b84
GB
103}
104#undef FUNC_NAME
54e09076 105
d339981a 106
54e09076
MD
107/* (sorted? sequence less?)
108 * is true when sequence is a list (x0 x1 ... xm) or a vector #(x0 ... xm)
109 * such that for all 1 <= i <= m,
110 * (not (less? (list-ref list i) (list-ref list (- i 1)))). */
a1ec6916 111SCM_DEFINE (scm_sorted_p, "sorted?", 2, 0, 0,
1bbd0b84 112 (SCM items, SCM less),
e3239868
DH
113 "Return @code{#t} iff @var{items} is a list or a vector such that\n"
114 "for all 1 <= i <= m, the predicate @var{less} returns true when\n"
115 "applied to all elements i - 1 and i")
1bbd0b84 116#define FUNC_NAME s_scm_sorted_p
54e09076 117{
d339981a 118 const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
c014a02e 119 long len, j; /* list/vector length, temp j */
54e09076 120 SCM item, rest; /* rest of items loop variable */
54e09076 121
c96d76b8 122 if (SCM_NULL_OR_NIL_P (items))
54e09076 123 return SCM_BOOL_T;
1bbd0b84 124
d2e53ed6 125 if (scm_is_pair (items))
54e09076
MD
126 {
127 len = scm_ilength (items); /* also checks that it's a pure list */
34d19ef6 128 SCM_ASSERT_RANGE (1, items, len >= 0);
54e09076
MD
129 if (len <= 1)
130 return SCM_BOOL_T;
131
132 item = SCM_CAR (items);
133 rest = SCM_CDR (items);
134 j = len - 1;
135 while (j > 0)
136 {
7888309b 137 if (scm_is_true ((*cmp) (less, SCM_CAR (rest), item)))
54e09076
MD
138 return SCM_BOOL_F;
139 else
140 {
141 item = SCM_CAR (rest);
142 rest = SCM_CDR (rest);
143 j--;
144 }
145 }
146 return SCM_BOOL_T;
147 }
148 else
149 {
cb26f569
MV
150 scm_t_array_handle handle;
151 size_t i, len;
152 ssize_t inc;
153 const SCM *elts;
154 SCM result = SCM_BOOL_T;
b5c2579a 155
cb26f569
MV
156 elts = scm_vector_elements (items, &handle, &len, &inc);
157
158 for (i = 1; i < len; i++, elts += inc)
54e09076 159 {
cb26f569 160 if (scm_is_true ((*cmp) (less, elts[inc], elts[0])))
b5c2579a 161 {
cb26f569
MV
162 result = SCM_BOOL_F;
163 break;
b5c2579a 164 }
54e09076 165 }
cb26f569 166
c8857a4d
MV
167 scm_array_handle_release (&handle);
168
cb26f569 169 return result;
54e09076 170 }
b5c2579a 171
54e09076 172 return SCM_BOOL_F;
1bbd0b84
GB
173}
174#undef FUNC_NAME
54e09076 175
d339981a 176
54e09076
MD
177/* (merge a b less?)
178 takes two lists a and b such that (sorted? a less?) and (sorted? b less?)
179 and returns a new list in which the elements of a and b have been stably
180 interleaved so that (sorted? (merge a b less?) less?).
181 Note: this does _not_ accept vectors. */
a1ec6916 182SCM_DEFINE (scm_merge, "merge", 3, 0, 0,
1bbd0b84 183 (SCM alist, SCM blist, SCM less),
8f85c0c6
NJ
184 "Merge two already sorted lists into one.\n"
185 "Given two lists @var{alist} and @var{blist}, such that\n"
186 "@code{(sorted? alist less?)} and @code{(sorted? blist less?)},\n"
187 "return a new list in which the elements of @var{alist} and\n"
e3239868
DH
188 "@var{blist} have been stably interleaved so that\n"
189 "@code{(sorted? (merge alist blist less?) less?)}.\n"
190 "Note: this does _not_ accept vectors.")
1bbd0b84 191#define FUNC_NAME s_scm_merge
54e09076 192{
d339981a 193 SCM build;
54e09076 194
c96d76b8 195 if (SCM_NULL_OR_NIL_P (alist))
54e09076 196 return blist;
c96d76b8 197 else if (SCM_NULL_OR_NIL_P (blist))
54e09076
MD
198 return alist;
199 else
200 {
d339981a
DH
201 const scm_t_trampoline_2 cmp = compare_function (less, 3, FUNC_NAME);
202 long alen, blen; /* list lengths */
203 SCM last;
204
34d19ef6
HWN
205 SCM_VALIDATE_NONEMPTYLIST_COPYLEN (1, alist, alen);
206 SCM_VALIDATE_NONEMPTYLIST_COPYLEN (2, blist, blen);
7888309b 207 if (scm_is_true ((*cmp) (less, SCM_CAR (blist), SCM_CAR (alist))))
54e09076
MD
208 {
209 build = scm_cons (SCM_CAR (blist), SCM_EOL);
210 blist = SCM_CDR (blist);
211 blen--;
212 }
c56cc3c8
MD
213 else
214 {
215 build = scm_cons (SCM_CAR (alist), SCM_EOL);
216 alist = SCM_CDR (alist);
217 alen--;
218 }
54e09076
MD
219 last = build;
220 while ((alen > 0) && (blen > 0))
221 {
ee1ac75b 222 SCM_TICK;
7888309b 223 if (scm_is_true ((*cmp) (less, SCM_CAR (blist), SCM_CAR (alist))))
54e09076
MD
224 {
225 SCM_SETCDR (last, scm_cons (SCM_CAR (blist), SCM_EOL));
226 blist = SCM_CDR (blist);
227 blen--;
228 }
c56cc3c8
MD
229 else
230 {
231 SCM_SETCDR (last, scm_cons (SCM_CAR (alist), SCM_EOL));
232 alist = SCM_CDR (alist);
233 alen--;
234 }
54e09076
MD
235 last = SCM_CDR (last);
236 }
237 if ((alen > 0) && (blen == 0))
238 SCM_SETCDR (last, alist);
239 else if ((alen == 0) && (blen > 0))
240 SCM_SETCDR (last, blist);
241 }
242 return build;
1bbd0b84
GB
243}
244#undef FUNC_NAME
245
54e09076
MD
246
247static SCM
248scm_merge_list_x (SCM alist, SCM blist,
249 long alen, long blen,
d339981a 250 scm_t_trampoline_2 cmp, SCM less)
54e09076
MD
251{
252 SCM build, last;
253
c96d76b8 254 if (SCM_NULL_OR_NIL_P (alist))
54e09076 255 return blist;
c96d76b8 256 else if (SCM_NULL_OR_NIL_P (blist))
54e09076
MD
257 return alist;
258 else
259 {
7888309b 260 if (scm_is_true ((*cmp) (less, SCM_CAR (blist), SCM_CAR (alist))))
54e09076
MD
261 {
262 build = blist;
263 blist = SCM_CDR (blist);
264 blen--;
265 }
c56cc3c8
MD
266 else
267 {
268 build = alist;
269 alist = SCM_CDR (alist);
270 alen--;
271 }
54e09076
MD
272 last = build;
273 while ((alen > 0) && (blen > 0))
274 {
ee1ac75b 275 SCM_TICK;
7888309b 276 if (scm_is_true ((*cmp) (less, SCM_CAR (blist), SCM_CAR (alist))))
54e09076
MD
277 {
278 SCM_SETCDR (last, blist);
279 blist = SCM_CDR (blist);
280 blen--;
281 }
c56cc3c8
MD
282 else
283 {
284 SCM_SETCDR (last, alist);
285 alist = SCM_CDR (alist);
286 alen--;
287 }
54e09076
MD
288 last = SCM_CDR (last);
289 }
290 if ((alen > 0) && (blen == 0))
291 SCM_SETCDR (last, alist);
292 else if ((alen == 0) && (blen > 0))
293 SCM_SETCDR (last, blist);
294 }
295 return build;
296} /* scm_merge_list_x */
297
d339981a 298
a1ec6916 299SCM_DEFINE (scm_merge_x, "merge!", 3, 0, 0,
1bbd0b84 300 (SCM alist, SCM blist, SCM less),
e3239868
DH
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.")
1bbd0b84 308#define FUNC_NAME s_scm_merge_x
54e09076 309{
c96d76b8 310 if (SCM_NULL_OR_NIL_P (alist))
54e09076 311 return blist;
c96d76b8 312 else if (SCM_NULL_OR_NIL_P (blist))
54e09076
MD
313 return alist;
314 else
315 {
d339981a
DH
316 const scm_t_trampoline_2 cmp = compare_function (less, 3, FUNC_NAME);
317 long alen, blen; /* list lengths */
34d19ef6
HWN
318 SCM_VALIDATE_NONEMPTYLIST_COPYLEN (1, alist, alen);
319 SCM_VALIDATE_NONEMPTYLIST_COPYLEN (2, blist, blen);
d339981a 320 return scm_merge_list_x (alist, blist, alen, blen, cmp, less);
54e09076 321 }
1bbd0b84
GB
322}
323#undef FUNC_NAME
54e09076 324
d339981a 325
54e09076
MD
326/* This merge sort algorithm is same as slib's by Richard A. O'Keefe.
327 The algorithm is stable. We also tried to use the algorithm used by
328 scsh's merge-sort but that algorithm showed to not be stable, even
329 though it claimed to be.
330*/
331static SCM
d339981a 332scm_merge_list_step (SCM * seq, scm_t_trampoline_2 cmp, SCM less, long n)
54e09076 333{
c56cc3c8
MD
334 SCM a, b;
335
54e09076
MD
336 if (n > 2)
337 {
c014a02e 338 long mid = n / 2;
ee1ac75b 339 SCM_TICK;
c56cc3c8
MD
340 a = scm_merge_list_step (seq, cmp, less, mid);
341 b = scm_merge_list_step (seq, cmp, less, n - mid);
342 return scm_merge_list_x (a, b, mid, n - mid, cmp, less);
54e09076
MD
343 }
344 else if (n == 2)
345 {
346 SCM p = *seq;
347 SCM rest = SCM_CDR (*seq);
348 SCM x = SCM_CAR (*seq);
349 SCM y = SCM_CAR (SCM_CDR (*seq));
350 *seq = SCM_CDR (rest);
351 SCM_SETCDR (rest, SCM_EOL);
7888309b 352 if (scm_is_true ((*cmp) (less, y, x)))
54e09076 353 {
4b479d98
DH
354 SCM_SETCAR (p, y);
355 SCM_SETCAR (rest, x);
54e09076
MD
356 }
357 return p;
358 }
359 else if (n == 1)
360 {
361 SCM p = *seq;
362 *seq = SCM_CDR (p);
363 SCM_SETCDR (p, SCM_EOL);
364 return p;
365 }
366 else
367 return SCM_EOL;
368} /* scm_merge_list_step */
369
370
a1ec6916 371SCM_DEFINE (scm_sort_x, "sort!", 2, 0, 0,
1bbd0b84 372 (SCM items, SCM less),
e3239868
DH
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.")
1bbd0b84 378#define FUNC_NAME s_scm_sort_x
54e09076 379{
c014a02e 380 long len; /* list/vector length */
c96d76b8
NJ
381 if (SCM_NULL_OR_NIL_P (items))
382 return items;
b5c2579a 383
d2e53ed6 384 if (scm_is_pair (items))
54e09076 385 {
d339981a 386 const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
34d19ef6 387 SCM_VALIDATE_LIST_COPYLEN (1, items, len);
d339981a 388 return scm_merge_list_step (&items, cmp, less, len);
54e09076 389 }
cb26f569 390 else if (scm_is_vector (items))
54e09076 391 {
54e09076
MD
392 scm_restricted_vector_sort_x (items,
393 less,
e11e83f3 394 scm_from_int (0),
cb26f569 395 scm_vector_length (items));
54e09076
MD
396 return items;
397 }
398 else
276dd677 399 SCM_WRONG_TYPE_ARG (1, items);
1bbd0b84 400}
0f981281 401#undef FUNC_NAME
54e09076 402
1bbd0b84 403
a1ec6916 404SCM_DEFINE (scm_sort, "sort", 2, 0, 0,
1bbd0b84 405 (SCM items, SCM less),
e3239868
DH
406 "Sort the sequence @var{items}, which may be a list or a\n"
407 "vector. @var{less} is used for comparing the sequence\n"
408 "elements. This is not a stable sort.")
1bbd0b84 409#define FUNC_NAME s_scm_sort
54e09076 410{
c96d76b8
NJ
411 if (SCM_NULL_OR_NIL_P (items))
412 return items;
b5c2579a 413
d2e53ed6 414 if (scm_is_pair (items))
cb26f569
MV
415 return scm_sort_x (scm_list_copy (items), less);
416 else if (scm_is_vector (items))
417 return scm_sort_x (scm_vector_copy (items), less);
54e09076 418 else
276dd677 419 SCM_WRONG_TYPE_ARG (1, items);
1bbd0b84 420}
0f981281 421#undef FUNC_NAME
54e09076 422
d339981a 423
54e09076 424static void
cb26f569
MV
425scm_merge_vector_x (SCM *vec,
426 SCM *temp,
d339981a 427 scm_t_trampoline_2 cmp,
54e09076 428 SCM less,
cb26f569
MV
429 size_t low,
430 size_t mid,
431 size_t high,
432 ssize_t inc)
54e09076 433{
cb26f569
MV
434 size_t it; /* Index for temp vector */
435 size_t i1 = low; /* Index for lower vector segment */
436 size_t i2 = mid + 1; /* Index for upper vector segment */
437
438#define VEC(i) vec[(i)*inc]
54e09076
MD
439
440 /* Copy while both segments contain more characters */
441 for (it = low; (i1 <= mid) && (i2 <= high); ++it)
1d1559ce 442 {
cb26f569
MV
443 if (scm_is_true ((*cmp) (less, VEC(i2), VEC(i1))))
444 temp[it] = VEC(i2++);
1d1559ce 445 else
cb26f569 446 temp[it] = VEC(i1++);
1d1559ce 447 }
54e09076 448
1d1559ce 449 {
1d1559ce
HWN
450 /* Copy while first segment contains more characters */
451 while (i1 <= mid)
cb26f569 452 temp[it++] = VEC(i1++);
1d1559ce
HWN
453
454 /* Copy while second segment contains more characters */
455 while (i2 <= high)
cb26f569 456 temp[it++] = VEC(i2++);
1d1559ce
HWN
457
458 /* Copy back from temp to vp */
cb26f569
MV
459 for (it = low; it <= high; it++)
460 VEC(it) = temp[it];
1d1559ce
HWN
461 }
462} /* scm_merge_vector_x */
54e09076 463
d339981a 464
54e09076 465static void
cb26f569
MV
466scm_merge_vector_step (SCM *vec,
467 SCM *temp,
d339981a 468 scm_t_trampoline_2 cmp,
54e09076 469 SCM less,
cb26f569
MV
470 size_t low,
471 size_t high,
472 ssize_t inc)
54e09076
MD
473{
474 if (high > low)
475 {
cb26f569 476 size_t mid = (low + high) / 2;
ee1ac75b 477 SCM_TICK;
cb26f569
MV
478 scm_merge_vector_step (vec, temp, cmp, less, low, mid, inc);
479 scm_merge_vector_step (vec, temp, cmp, less, mid+1, high, inc);
480 scm_merge_vector_x (vec, temp, cmp, less, low, mid, high, inc);
54e09076
MD
481 }
482} /* scm_merge_vector_step */
483
484
a1ec6916 485SCM_DEFINE (scm_stable_sort_x, "stable-sort!", 2, 0, 0,
1bbd0b84 486 (SCM items, SCM less),
e3239868
DH
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.")
1bbd0b84 492#define FUNC_NAME s_scm_stable_sort_x
54e09076 493{
d339981a 494 const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
c014a02e 495 long len; /* list/vector length */
54e09076 496
c96d76b8
NJ
497 if (SCM_NULL_OR_NIL_P (items))
498 return items;
b5c2579a 499
d2e53ed6 500 if (scm_is_pair (items))
54e09076 501 {
34d19ef6 502 SCM_VALIDATE_LIST_COPYLEN (1, items, len);
d339981a 503 return scm_merge_list_step (&items, cmp, less, len);
54e09076 504 }
cb26f569 505 else if (scm_is_vector (items))
54e09076 506 {
cb26f569
MV
507 scm_t_array_handle temp_handle, vec_handle;
508 SCM temp, *temp_elts, *vec_elts;
509 size_t len;
510 ssize_t inc;
511
512 vec_elts = scm_vector_writable_elements (items, &vec_handle,
513 &len, &inc);
514 temp = scm_c_make_vector (len, SCM_UNDEFINED);
515 temp_elts = scm_vector_writable_elements (temp, &temp_handle,
516 NULL, NULL);
34d19ef6 517
cb26f569 518 scm_merge_vector_step (vec_elts, temp_elts, cmp, less, 0, len-1, inc);
34d19ef6 519
c8857a4d
MV
520 scm_array_handle_release (&temp_handle);
521 scm_array_handle_release (&vec_handle);
522
54e09076
MD
523 return items;
524 }
525 else
276dd677 526 SCM_WRONG_TYPE_ARG (1, items);
1bbd0b84 527}
0f981281 528#undef FUNC_NAME
54e09076 529
d339981a 530
a1ec6916 531SCM_DEFINE (scm_stable_sort, "stable-sort", 2, 0, 0,
1bbd0b84 532 (SCM items, SCM less),
e3239868
DH
533 "Sort the sequence @var{items}, which may be a list or a\n"
534 "vector. @var{less} is used for comparing the sequence elements.\n"
535 "This is a stable sort.")
1bbd0b84 536#define FUNC_NAME s_scm_stable_sort
54e09076 537{
651f2cd2
KR
538 if (SCM_NULL_OR_NIL_P (items))
539 return SCM_EOL;
540
d2e53ed6 541 if (scm_is_pair (items))
cb26f569
MV
542 return scm_stable_sort_x (scm_list_copy (items), less);
543 else if (scm_is_vector (items))
544 return scm_stable_sort_x (scm_vector_copy (items), less);
54e09076 545 else
276dd677 546 SCM_WRONG_TYPE_ARG (1, items);
1bbd0b84 547}
0f981281 548#undef FUNC_NAME
54e09076 549
d339981a 550
a1ec6916 551SCM_DEFINE (scm_sort_list_x, "sort-list!", 2, 0, 0,
1bbd0b84 552 (SCM items, SCM less),
e3239868
DH
553 "Sort the list @var{items}, using @var{less} for comparing the\n"
554 "list elements. The sorting is destructive, that means that the\n"
555 "input list is modified to produce the sorted result.\n"
556 "This is a stable sort.")
1bbd0b84 557#define FUNC_NAME s_scm_sort_list_x
54e09076 558{
d339981a 559 const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
c014a02e 560 long len;
d339981a 561
34d19ef6 562 SCM_VALIDATE_LIST_COPYLEN (1, items, len);
d339981a 563 return scm_merge_list_step (&items, cmp, less, len);
1bbd0b84 564}
0f981281 565#undef FUNC_NAME
54e09076 566
d339981a 567
a1ec6916 568SCM_DEFINE (scm_sort_list, "sort-list", 2, 0, 0,
e3239868
DH
569 (SCM items, SCM less),
570 "Sort the list @var{items}, using @var{less} for comparing the\n"
571 "list elements. This is a stable sort.")
1bbd0b84 572#define FUNC_NAME s_scm_sort_list
54e09076 573{
d339981a 574 const scm_t_trampoline_2 cmp = compare_function (less, 2, FUNC_NAME);
c014a02e 575 long len;
d339981a 576
34d19ef6 577 SCM_VALIDATE_LIST_COPYLEN (1, items, len);
54e09076 578 items = scm_list_copy (items);
d339981a 579 return scm_merge_list_step (&items, cmp, less, len);
1bbd0b84 580}
0f981281 581#undef FUNC_NAME
54e09076 582
d339981a 583
54e09076
MD
584void
585scm_init_sort ()
586{
a0599745 587#include "libguile/sort.x"
54e09076
MD
588
589 scm_add_feature ("sort");
590}
89e00824
ML
591
592/*
593 Local Variables:
594 c-file-style: "gnu"
595 End:
596*/