(scm_srfi1_count): Use scm_list_copy to make arg list,
[bpt/guile.git] / srfi / srfi-1.c
1 /* srfi-1.c --- SRFI-1 procedures for Guile
2 *
3 * Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002, 2003 Free Software
4 * Foundation, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <libguile.h>
22 #include <libguile/lang.h>
23
24 #include "srfi-1.h"
25
26 /* The intent of this file is to gradually replace those Scheme
27 * procedures in srfi-1.scm which extends core primitive procedures,
28 * so that using srfi-1 won't have performance penalties.
29 *
30 * Please feel free to contribute any new replacements!
31 */
32
33 static long
34 srfi1_ilength (SCM sx)
35 {
36 long i = 0;
37 SCM tortoise = sx;
38 SCM hare = sx;
39
40 do {
41 if (SCM_NULL_OR_NIL_P(hare)) return i;
42 if (!scm_is_pair (hare)) return -2;
43 hare = SCM_CDR(hare);
44 i++;
45 if (SCM_NULL_OR_NIL_P(hare)) return i;
46 if (!scm_is_pair (hare)) return -2;
47 hare = SCM_CDR(hare);
48 i++;
49 /* For every two steps the hare takes, the tortoise takes one. */
50 tortoise = SCM_CDR(tortoise);
51 }
52 while (! scm_is_eq (hare, tortoise));
53
54 /* If the tortoise ever catches the hare, then the list must contain
55 a cycle. */
56 return -1;
57 }
58
59 static SCM
60 equal_trampoline (SCM proc, SCM arg1, SCM arg2)
61 {
62 return scm_equal_p (arg1, arg2);
63 }
64
65
66 /* scm_append and scm_append_x don't modify their list argument (only the
67 lists within that list in the case of scm_append_x), hence making them
68 suitable for direct use for concatentate. */
69
70 SCM_REGISTER_PROC (s_srfi1_concatenate, "concatenate", 1, 0, 0, scm_append);
71 SCM_REGISTER_PROC (s_srfi1_concatenate_x, "concatenate!", 1, 0, 0, scm_append_x);
72
73
74 SCM_DEFINE (scm_srfi1_count, "count", 2, 0, 1,
75 (SCM pred, SCM list1, SCM rest),
76 "Return a count of the number of times @var{pred} returns true\n"
77 "when called on elements from the given lists.\n"
78 "\n"
79 "@var{pred} is called with @var{N} parameters @code{(@var{pred}\n"
80 "@var{elem1} @dots{} @var{elemN})}, each element being from the\n"
81 "corresponding @var{list1} @dots{} @var{lstN}. The first call is\n"
82 "with the first element of each list, the second with the second\n"
83 "element from each, and so on.\n"
84 "\n"
85 "Counting stops when the end of the shortest list is reached.\n"
86 "At least one list must be non-circular.")
87 #define FUNC_NAME s_scm_srfi1_count
88 {
89 long count;
90 SCM lst;
91 int argnum;
92 SCM_VALIDATE_REST_ARGUMENT (rest);
93
94 count = 0;
95
96 if (scm_is_null (rest))
97 {
98 /* one list */
99 scm_t_trampoline_1 pred_tramp;
100 pred_tramp = scm_trampoline_1 (pred);
101 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
102
103 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
104 count += scm_is_true (pred_tramp (pred, SCM_CAR (list1)));
105
106 /* check below that list1 is a proper list, and done */
107 end_list1:
108 lst = list1;
109 argnum = 2;
110 }
111 else if (scm_is_pair (rest) && scm_is_null (SCM_CDR (rest)))
112 {
113 /* two lists */
114 scm_t_trampoline_2 pred_tramp;
115 SCM list2;
116
117 pred_tramp = scm_trampoline_2 (pred);
118 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
119
120 list2 = SCM_CAR (rest);
121 for (;;)
122 {
123 if (! scm_is_pair (list1))
124 goto end_list1;
125 if (! scm_is_pair (list2))
126 {
127 lst = list2;
128 argnum = 3;
129 break;
130 }
131 count += scm_is_true (pred_tramp
132 (pred, SCM_CAR (list1), SCM_CAR (list2)));
133 list1 = SCM_CDR (list1);
134 list2 = SCM_CDR (list2);
135 }
136 }
137 else
138 {
139 /* three or more lists */
140 SCM lstlst, args, l, a;
141
142 /* lstlst is a list of the list arguments */
143 lstlst = scm_cons (list1, rest);
144
145 /* args is the argument list to pass to pred, same length as lstlst,
146 re-used for each call */
147 args = scm_list_copy (lstlst);
148
149 for (;;)
150 {
151 /* first elem of each list in lstlst into args, and step those
152 lstlst entries onto their next element */
153 for (l = lstlst, a = args, argnum = 2;
154 scm_is_pair (l);
155 l = SCM_CDR (l), a = SCM_CDR (a), argnum++)
156 {
157 lst = SCM_CAR (l); /* list argument */
158 if (! scm_is_pair (lst))
159 goto check_lst_and_done;
160 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for pred */
161 SCM_SETCAR (l, SCM_CDR (lst)); /* keep rest of lst */
162 }
163
164 count += scm_is_true (scm_apply (pred, args, SCM_EOL));
165 }
166 }
167
168 check_lst_and_done:
169 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
170 return scm_from_long (count);
171 }
172 #undef FUNC_NAME
173
174
175 SCM_DEFINE (scm_srfi1_delete, "delete", 2, 1, 0,
176 (SCM x, SCM lst, SCM pred),
177 "Return a list containing the elements of @var{lst} but with\n"
178 "those equal to @var{x} deleted. The returned elements will be\n"
179 "in the same order as they were in @var{lst}.\n"
180 "\n"
181 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
182 "given. An equality call is made just once for each element,\n"
183 "but the order in which the calls are made on the elements is\n"
184 "unspecified.\n"
185 "\n"
186 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
187 "given @var{x} is first. This means for instance elements\n"
188 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
189 "\n"
190 "@var{lst} is not modified, but the returned list might share a\n"
191 "common tail with @var{lst}.")
192 #define FUNC_NAME s_scm_srfi1_delete
193 {
194 scm_t_trampoline_2 equal_p;
195 SCM ret, *p, keeplst;
196
197 if (SCM_UNBNDP (pred))
198 return scm_delete (x, lst);
199
200 equal_p = scm_trampoline_2 (pred);
201 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
202
203 /* ret is the return list being constructed. p is where to append to it,
204 initially &ret then SCM_CDRLOC of the last pair. lst progresses as
205 elements are considered.
206
207 Elements to be retained are not immediately copied, instead keeplst is
208 the last pair in lst which is to be retained but not yet copied. When
209 there's no more deletions, *p can be set to keeplst to share the
210 remainder of the original lst. (The entire original lst if there's no
211 deletions at all.) */
212
213 keeplst = lst;
214 ret = SCM_EOL;
215 p = &ret;
216
217 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
218 {
219 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
220 {
221 /* delete this element, so copy from keeplst (inclusive) to lst
222 (exclusive) onto ret */
223 while (! scm_is_eq (keeplst, lst))
224 {
225 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
226 *p = c;
227 p = SCM_CDRLOC (c);
228 keeplst = SCM_CDR (keeplst);
229 }
230
231 keeplst = SCM_CDR (lst);
232 }
233 }
234
235 /* final retained elements */
236 *p = keeplst;
237
238 /* demand that lst was a proper list */
239 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
240
241 return ret;
242 }
243 #undef FUNC_NAME
244
245
246 SCM_DEFINE (scm_srfi1_delete_x, "delete!", 2, 1, 0,
247 (SCM x, SCM lst, SCM pred),
248 "Return a list containing the elements of @var{lst} but with\n"
249 "those equal to @var{x} deleted. The returned elements will be\n"
250 "in the same order as they were in @var{lst}.\n"
251 "\n"
252 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
253 "given. An equality call is made just once for each element,\n"
254 "but the order in which the calls are made on the elements is\n"
255 "unspecified.\n"
256 "\n"
257 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
258 "given @var{x} is first. This means for instance elements\n"
259 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
260 "\n"
261 "@var{lst} may be modified to construct the returned list.")
262 #define FUNC_NAME s_scm_srfi1_delete_x
263 {
264 scm_t_trampoline_2 equal_p;
265 SCM walk;
266 SCM *prev;
267
268 if (SCM_UNBNDP (pred))
269 return scm_delete_x (x, lst);
270
271 equal_p = scm_trampoline_2 (pred);
272 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
273
274 for (prev = &lst, walk = lst;
275 scm_is_pair (walk);
276 walk = SCM_CDR (walk))
277 {
278 if (scm_is_true (equal_p (pred, x, SCM_CAR (walk))))
279 *prev = SCM_CDR (walk);
280 else
281 prev = SCM_CDRLOC (walk);
282 }
283
284 /* demand the input was a proper list */
285 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (walk), walk, SCM_ARG2, FUNC_NAME,"list");
286 return lst;
287 }
288 #undef FUNC_NAME
289
290
291 SCM_DEFINE (scm_srfi1_delete_duplicates, "delete-duplicates", 1, 1, 0,
292 (SCM lst, SCM pred),
293 "Return a list containing the elements of @var{lst} but without\n"
294 "duplicates.\n"
295 "\n"
296 "When elements are equal, only the first in @var{lst} is\n"
297 "retained. Equal elements can be anywhere in @var{lst}, they\n"
298 "don't have to be adjacent. The returned list will have the\n"
299 "retained elements in the same order as they were in @var{lst}.\n"
300 "\n"
301 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
302 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
303 "being before @var{y} in @var{lst}. A call is made at most once\n"
304 "for each combination, but the sequence of the calls across the\n"
305 "elements is unspecified.\n"
306 "\n"
307 "@var{lst} is not modified, but the return might share a common\n"
308 "tail with @var{lst}.\n"
309 "\n"
310 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
311 "it must check each element against all those preceding it. For\n"
312 "long lists it is more efficient to sort and then compare only\n"
313 "adjacent elements.")
314 #define FUNC_NAME s_scm_srfi1_delete_duplicates
315 {
316 scm_t_trampoline_2 equal_p;
317 SCM ret, *p, keeplst, item, l;
318
319 /* ret is the new list constructed. p is where to append, initially &ret
320 then SCM_CDRLOC of the last pair. lst is advanced as each element is
321 considered.
322
323 Elements retained are not immediately appended to ret, instead keeplst
324 is the last pair in lst which is to be kept but is not yet copied.
325 Initially this is the first pair of lst, since the first element is
326 always retained.
327
328 *p is kept set to keeplst, so ret (inclusive) to lst (exclusive) is all
329 the elements retained, making the equality search loop easy.
330
331 If an item must be deleted, elements from keeplst (inclusive) to lst
332 (exclusive) must be copied and appended to ret. When there's no more
333 deletions, *p is left set to keeplst, so ret shares structure with the
334 original lst. (ret will be the entire original lst if there are no
335 deletions.) */
336
337 /* skip to end if an empty list (or something invalid) */
338 ret = lst;
339 if (scm_is_pair (lst))
340 {
341 if (SCM_UNBNDP (pred))
342 equal_p = equal_trampoline;
343 else
344 {
345 equal_p = scm_trampoline_2 (pred);
346 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
347 }
348
349 keeplst = lst;
350 p = &ret;
351
352 /* loop over lst elements starting from second */
353 for (;;)
354 {
355 lst = SCM_CDR (lst);
356 if (! scm_is_pair (lst))
357 break;
358 item = SCM_CAR (lst);
359
360 /* loop searching ret upto lst */
361 for (l = ret; ! scm_is_eq (l, lst); l = SCM_CDR (l))
362 {
363 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
364 {
365 /* duplicate, don't want this element, so copy keeplst
366 (inclusive) to lst (exclusive) onto ret */
367 while (! scm_is_eq (keeplst, lst))
368 {
369 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
370 *p = c;
371 p = SCM_CDRLOC (c);
372 keeplst = SCM_CDR (keeplst);
373 }
374
375 keeplst = SCM_CDR (lst); /* elem after the one deleted */
376 *p = keeplst;
377 break;
378 }
379 }
380 }
381 }
382
383 /* demand that lst was a proper list */
384 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
385
386 return ret;
387 }
388 #undef FUNC_NAME
389
390
391 SCM_DEFINE (scm_srfi1_delete_duplicates_x, "delete-duplicates!", 1, 1, 0,
392 (SCM lst, SCM pred),
393 "Return a list containing the elements of @var{lst} but without\n"
394 "duplicates.\n"
395 "\n"
396 "When elements are equal, only the first in @var{lst} is\n"
397 "retained. Equal elements can be anywhere in @var{lst}, they\n"
398 "don't have to be adjacent. The returned list will have the\n"
399 "retained elements in the same order as they were in @var{lst}.\n"
400 "\n"
401 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
402 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
403 "being before @var{y} in @var{lst}. A call is made at most once\n"
404 "for each combination, but the sequence of the calls across the\n"
405 "elements is unspecified.\n"
406 "\n"
407 "@var{lst} may be modified to construct the returned list.\n"
408 "\n"
409 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
410 "it must check each element against all those preceding it. For\n"
411 "long lists it is more efficient to sort and then compare only\n"
412 "adjacent elements.")
413 #define FUNC_NAME s_scm_srfi1_delete_duplicates_x
414 {
415 scm_t_trampoline_2 equal_p;
416 SCM ret, endret, item, l;
417
418 /* ret is the return list, constructed from the pairs in lst. endret is
419 the last pair of ret, initially the first pair. lst is advanced as
420 elements are considered. */
421
422 /* skip to end if an empty list (or something invalid) */
423 ret = lst;
424 if (scm_is_pair (lst))
425 {
426 if (SCM_UNBNDP (pred))
427 equal_p = equal_trampoline;
428 else
429 {
430 equal_p = scm_trampoline_2 (pred);
431 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
432 }
433
434 endret = ret;
435
436 /* loop over lst elements starting from second */
437 for (;;)
438 {
439 lst = SCM_CDR (lst);
440 if (! scm_is_pair (lst))
441 break;
442 item = SCM_CAR (lst);
443
444 /* is item equal to any element from ret to endret (inclusive)? */
445 l = ret;
446 for (;;)
447 {
448 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
449 break; /* equal, forget this element */
450
451 if (scm_is_eq (l, endret))
452 {
453 /* not equal to any, so append this pair */
454 SCM_SETCDR (endret, lst);
455 endret = lst;
456 break;
457 }
458 l = SCM_CDR (l);
459 }
460 }
461
462 /* terminate, in case last element was deleted */
463 SCM_SETCDR (endret, SCM_EOL);
464 }
465
466 /* demand that lst was a proper list */
467 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
468
469 return ret;
470 }
471 #undef FUNC_NAME
472
473
474 SCM_DEFINE (scm_srfi1_drop_right, "drop-right", 2, 0, 0,
475 (SCM lst, SCM n),
476 "Return a new list containing all except the last @var{n}\n"
477 "elements of @var{lst}.")
478 #define FUNC_NAME s_scm_srfi1_drop_right
479 {
480 SCM tail = scm_list_tail (lst, n);
481 SCM ret = SCM_EOL;
482 SCM *rend = &ret;
483 while (scm_is_pair (tail))
484 {
485 *rend = scm_cons (SCM_CAR (lst), SCM_EOL);
486 rend = SCM_CDRLOC (*rend);
487
488 lst = SCM_CDR (lst);
489 tail = SCM_CDR (tail);
490 }
491 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
492 return ret;
493 }
494 #undef FUNC_NAME
495
496
497 SCM_DEFINE (scm_srfi1_filter_map, "filter-map", 2, 0, 1,
498 (SCM proc, SCM list1, SCM rest),
499 "Apply @var{proc} to to the elements of @var{list1} @dots{} and\n"
500 "return a list of the results as per SRFI-1 @code{map}, except\n"
501 "that any @code{#f} results are omitted from the list returned.")
502 #define FUNC_NAME s_scm_srfi1_filter_map
503 {
504 SCM ret, *loc, elem, newcell, lst;
505 int argnum;
506
507 SCM_VALIDATE_REST_ARGUMENT (rest);
508
509 ret = SCM_EOL;
510 loc = &ret;
511
512 if (SCM_NULLP (rest))
513 {
514 /* one list */
515 scm_t_trampoline_1 proc_tramp = scm_trampoline_1 (proc);
516 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
517
518 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
519 {
520 elem = proc_tramp (proc, SCM_CAR (list1));
521 if (scm_is_true (elem))
522 {
523 newcell = scm_cons (elem, SCM_EOL);
524 *loc = newcell;
525 loc = SCM_CDRLOC (newcell);
526 }
527 }
528
529 /* check below that list1 is a proper list, and done */
530 lst = list1;
531 argnum = 2;
532 }
533 else if (SCM_NULLP (SCM_CDR (rest)))
534 {
535 /* two lists */
536 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
537 SCM list2 = SCM_CAR (rest);
538 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
539
540 for (;;)
541 {
542 if (! scm_is_pair (list1))
543 {
544 lst = list1;
545 argnum = 2;
546 goto check_lst_and_done;
547 }
548 if (! scm_is_pair (list2))
549 {
550 lst = list2;
551 argnum = 3;
552 goto check_lst_and_done;
553 }
554 elem = proc_tramp (proc, SCM_CAR (list1), SCM_CAR (list2));
555 if (scm_is_true (elem))
556 {
557 newcell = scm_cons (elem, SCM_EOL);
558 *loc = newcell;
559 loc = SCM_CDRLOC (newcell);
560 }
561 list1 = SCM_CDR (list1);
562 list2 = SCM_CDR (list2);
563 }
564 }
565 else
566 {
567 /* three or more lists */
568 SCM lstlst, args, l, a;
569
570 /* lstlst is a list of the list arguments */
571 lstlst = scm_cons (list1, rest);
572
573 /* args is the argument list to pass to proc, same length as lstlst,
574 re-used for each call */
575 args = scm_list_copy (lstlst);
576
577 for (;;)
578 {
579 /* first elem of each list in lstlst into args, and step those
580 lstlst entries onto their next element */
581 for (l = lstlst, a = args, argnum = 2;
582 scm_is_pair (l);
583 l = SCM_CDR (l), a = SCM_CDR (a), argnum++)
584 {
585 lst = SCM_CAR (l); /* list argument */
586 if (! scm_is_pair (lst))
587 goto check_lst_and_done;
588 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for proc */
589 SCM_SETCAR (l, SCM_CDR (lst)); /* keep rest of lst */
590 }
591
592 elem = scm_apply (proc, args, SCM_EOL);
593 if (scm_is_true (elem))
594 {
595 newcell = scm_cons (elem, SCM_EOL);
596 *loc = newcell;
597 loc = SCM_CDRLOC (newcell);
598 }
599 }
600 }
601
602 check_lst_and_done:
603 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
604 return ret;
605 }
606 #undef FUNC_NAME
607
608
609 SCM_DEFINE (scm_srfi1_find, "find", 2, 0, 0,
610 (SCM pred, SCM lst),
611 "Return the first element of @var{lst} which satisfies the\n"
612 "predicate @var{pred}, or return @code{#f} if no such element is\n"
613 "found.")
614 #define FUNC_NAME s_scm_srfi1_find
615 {
616 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
617 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
618
619 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
620 {
621 SCM elem = SCM_CAR (lst);
622 if (scm_is_true (pred_tramp (pred, elem)))
623 return elem;
624 }
625 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
626
627 return SCM_BOOL_F;
628 }
629 #undef FUNC_NAME
630
631
632 SCM_DEFINE (scm_srfi1_find_tail, "find-tail", 2, 0, 0,
633 (SCM pred, SCM lst),
634 "Return the first pair of @var{lst} whose @sc{car} satisfies the\n"
635 "predicate @var{pred}, or return @code{#f} if no such element is\n"
636 "found.")
637 #define FUNC_NAME s_scm_srfi1_find_tail
638 {
639 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
640 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
641
642 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
643 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
644 return lst;
645 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
646
647 return SCM_BOOL_F;
648 }
649 #undef FUNC_NAME
650
651
652 SCM_DEFINE (scm_srfi1_length_plus, "length+", 1, 0, 0,
653 (SCM lst),
654 "Return the length of @var{lst}, or @code{#f} if @var{lst} is\n"
655 "circular.")
656 #define FUNC_NAME s_scm_srfi1_length_plus
657 {
658 long len = scm_ilength (lst);
659 return (len >= 0 ? SCM_I_MAKINUM (len) : SCM_BOOL_F);
660 }
661 #undef FUNC_NAME
662
663
664 /* This routine differs from the core list-copy in allowing improper lists.
665 Maybe the core could allow them similarly. */
666
667 SCM_DEFINE (scm_srfi1_list_copy, "list-copy", 1, 0, 0,
668 (SCM lst),
669 "Return a copy of the given list @var{lst}.\n"
670 "\n"
671 "@var{lst} can be a proper or improper list. And if @var{lst}\n"
672 "is not a pair then it's treated as the final tail of an\n"
673 "improper list and simply returned.")
674 #define FUNC_NAME s_scm_srfi1_list_copy
675 {
676 SCM newlst;
677 SCM * fill_here;
678 SCM from_here;
679
680 newlst = lst;
681 fill_here = &newlst;
682 from_here = lst;
683
684 while (scm_is_pair (from_here))
685 {
686 SCM c;
687 c = scm_cons (SCM_CAR (from_here), SCM_CDR (from_here));
688 *fill_here = c;
689 fill_here = SCM_CDRLOC (c);
690 from_here = SCM_CDR (from_here);
691 }
692 return newlst;
693 }
694 #undef FUNC_NAME
695
696
697 /* Typechecking for multi-argument MAP and FOR-EACH.
698
699 Verify that each element of the vector ARGV, except for the first,
700 is a list and return minimum length. Attribute errors to WHO,
701 and claim that the i'th element of ARGV is WHO's i+2'th argument. */
702 static inline int
703 check_map_args (SCM argv,
704 long len,
705 SCM gf,
706 SCM proc,
707 SCM args,
708 const char *who)
709 {
710 long i;
711
712 for (i = SCM_SIMPLE_VECTOR_LENGTH (argv) - 1; i >= 1; i--)
713 {
714 SCM elt = SCM_SIMPLE_VECTOR_REF (argv, i);
715 long elt_len;
716
717 if (!(scm_is_null (elt) || scm_is_pair (elt)))
718 {
719 check_map_error:
720 if (gf)
721 scm_apply_generic (gf, scm_cons (proc, args));
722 else
723 scm_wrong_type_arg (who, i + 2, elt);
724 }
725
726 elt_len = srfi1_ilength (elt);
727 if (elt_len < -1)
728 goto check_map_error;
729
730 if (len < 0 || (elt_len >= 0 && elt_len < len))
731 len = elt_len;
732 }
733 if (len < 0)
734 /* i == 0 */
735 goto check_map_error;
736
737 scm_remember_upto_here_1 (argv);
738 return len;
739 }
740
741
742 SCM_GPROC (s_srfi1_map, "map", 2, 0, 1, scm_srfi1_map, g_srfi1_map);
743
744 /* Note: Currently, scm_srfi1_map applies PROC to the argument list(s)
745 sequentially, starting with the first element(s). This is used in
746 the Scheme procedure `map-in-order', which guarantees sequential
747 behaviour, is implemented using scm_map. If the behaviour changes,
748 we need to update `map-in-order'.
749 */
750
751 SCM
752 scm_srfi1_map (SCM proc, SCM arg1, SCM args)
753 #define FUNC_NAME s_srfi1_map
754 {
755 long i, len;
756 SCM res = SCM_EOL;
757 SCM *pres = &res;
758
759 len = srfi1_ilength (arg1);
760 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
761 g_srfi1_map,
762 scm_cons2 (proc, arg1, args), SCM_ARG2, s_srfi1_map);
763 SCM_VALIDATE_REST_ARGUMENT (args);
764 if (scm_is_null (args))
765 {
766 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
767 SCM_GASSERT2 (call, g_srfi1_map, proc, arg1, SCM_ARG1, s_srfi1_map);
768 SCM_GASSERT2 (len >= 0, g_srfi1_map, proc, arg1, SCM_ARG2, s_srfi1_map);
769 while (SCM_NIMP (arg1))
770 {
771 *pres = scm_list_1 (call (proc, SCM_CAR (arg1)));
772 pres = SCM_CDRLOC (*pres);
773 arg1 = SCM_CDR (arg1);
774 }
775 return res;
776 }
777 if (scm_is_null (SCM_CDR (args)))
778 {
779 SCM arg2 = SCM_CAR (args);
780 int len2 = srfi1_ilength (arg2);
781 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
782 SCM_GASSERTn (call, g_srfi1_map,
783 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_map);
784 if (len < 0 || (len2 >= 0 && len2 < len))
785 len = len2;
786 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
787 && len >= 0 && len2 >= -1,
788 g_srfi1_map,
789 scm_cons2 (proc, arg1, args),
790 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
791 s_srfi1_map);
792 while (len > 0)
793 {
794 *pres = scm_list_1 (call (proc, SCM_CAR (arg1), SCM_CAR (arg2)));
795 pres = SCM_CDRLOC (*pres);
796 arg1 = SCM_CDR (arg1);
797 arg2 = SCM_CDR (arg2);
798 --len;
799 }
800 return res;
801 }
802 args = scm_vector (arg1 = scm_cons (arg1, args));
803 len = check_map_args (args, len, g_srfi1_map, proc, arg1, s_srfi1_map);
804 while (len > 0)
805 {
806 arg1 = SCM_EOL;
807 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
808 {
809 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
810 arg1 = scm_cons (SCM_CAR (elt), arg1);
811 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
812 }
813 *pres = scm_list_1 (scm_apply (proc, arg1, SCM_EOL));
814 pres = SCM_CDRLOC (*pres);
815 --len;
816 }
817 return res;
818 }
819 #undef FUNC_NAME
820
821 SCM_REGISTER_PROC (s_srfi1_map_in_order, "map-in-order", 2, 0, 1, scm_srfi1_map);
822
823 SCM_GPROC (s_srfi1_for_each, "for-each", 2, 0, 1, scm_srfi1_for_each, g_srfi1_for_each);
824
825 SCM
826 scm_srfi1_for_each (SCM proc, SCM arg1, SCM args)
827 #define FUNC_NAME s_srfi1_for_each
828 {
829 long i, len;
830 len = srfi1_ilength (arg1);
831 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
832 g_srfi1_for_each, scm_cons2 (proc, arg1, args),
833 SCM_ARG2, s_srfi1_for_each);
834 SCM_VALIDATE_REST_ARGUMENT (args);
835 if (scm_is_null (args))
836 {
837 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
838 SCM_GASSERT2 (call, g_srfi1_for_each, proc, arg1,
839 SCM_ARG1, s_srfi1_for_each);
840 SCM_GASSERT2 (len >= 0, g_srfi1_for_each, proc, arg1,
841 SCM_ARG2, s_srfi1_map);
842 while (SCM_NIMP (arg1))
843 {
844 call (proc, SCM_CAR (arg1));
845 arg1 = SCM_CDR (arg1);
846 }
847 return SCM_UNSPECIFIED;
848 }
849 if (scm_is_null (SCM_CDR (args)))
850 {
851 SCM arg2 = SCM_CAR (args);
852 int len2 = srfi1_ilength (arg2);
853 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
854 SCM_GASSERTn (call, g_srfi1_for_each,
855 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_for_each);
856 if (len < 0 || (len2 >= 0 && len2 < len))
857 len = len2;
858 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
859 && len >= 0 && len2 >= -1,
860 g_srfi1_for_each,
861 scm_cons2 (proc, arg1, args),
862 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
863 s_srfi1_for_each);
864 while (len > 0)
865 {
866 call (proc, SCM_CAR (arg1), SCM_CAR (arg2));
867 arg1 = SCM_CDR (arg1);
868 arg2 = SCM_CDR (arg2);
869 --len;
870 }
871 return SCM_UNSPECIFIED;
872 }
873 args = scm_vector (arg1 = scm_cons (arg1, args));
874 len = check_map_args (args, len, g_srfi1_for_each, proc, arg1,
875 s_srfi1_for_each);
876 while (len > 0)
877 {
878 arg1 = SCM_EOL;
879 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
880 {
881 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
882 arg1 = scm_cons (SCM_CAR (elt), arg1);
883 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
884 }
885 scm_apply (proc, arg1, SCM_EOL);
886 --len;
887 }
888 return SCM_UNSPECIFIED;
889 }
890 #undef FUNC_NAME
891
892
893 SCM_DEFINE (scm_srfi1_member, "member", 2, 1, 0,
894 (SCM x, SCM lst, SCM pred),
895 "Return the first sublist of @var{lst} whose @sc{car} is equal\n"
896 "to @var{x}. If @var{x} does not appear in @var{lst}, return\n"
897 "@code{#f}.\n"
898 "\n"
899 "Equality is determined by @code{equal?}, or by the equality\n"
900 "predicate @var{=} if given. @var{=} is called @code{(= @var{x}\n"
901 "elem)}, ie.@: with the given @var{x} first, so for example to\n"
902 "find the first element greater than 5,\n"
903 "\n"
904 "@example\n"
905 "(member 5 '(3 5 1 7 2 9) <) @result{} (7 2 9)\n"
906 "@end example\n"
907 "\n"
908 "This version of @code{member} extends the core @code{member} by\n"
909 "accepting an equality predicate.")
910 #define FUNC_NAME s_scm_srfi1_member
911 {
912 scm_t_trampoline_2 equal_p;
913 SCM_VALIDATE_LIST (2, lst);
914 if (SCM_UNBNDP (pred))
915 equal_p = equal_trampoline;
916 else
917 {
918 equal_p = scm_trampoline_2 (pred);
919 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
920 }
921 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
922 {
923 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
924 return lst;
925 }
926 return SCM_BOOL_F;
927 }
928 #undef FUNC_NAME
929
930 SCM_DEFINE (scm_srfi1_assoc, "assoc", 2, 1, 0,
931 (SCM key, SCM alist, SCM pred),
932 "Behaves like @code{assq} but uses third argument @var{pred?}\n"
933 "for key comparison. If @var{pred?} is not supplied,\n"
934 "@code{equal?} is used. (Extended from R5RS.)\n")
935 #define FUNC_NAME s_scm_srfi1_assoc
936 {
937 SCM ls = alist;
938 scm_t_trampoline_2 equal_p;
939 if (SCM_UNBNDP (pred))
940 equal_p = equal_trampoline;
941 else
942 {
943 equal_p = scm_trampoline_2 (pred);
944 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
945 }
946 for(; scm_is_pair (ls); ls = SCM_CDR (ls))
947 {
948 SCM tmp = SCM_CAR (ls);
949 SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
950 "association list");
951 if (scm_is_true (equal_p (pred, SCM_CAR (tmp), key)))
952 return tmp;
953 }
954 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
955 "association list");
956 return SCM_BOOL_F;
957 }
958 #undef FUNC_NAME
959
960 SCM_DEFINE (scm_srfi1_partition, "partition", 2, 0, 0,
961 (SCM pred, SCM list),
962 "Partition the elements of @var{list} with predicate @var{pred}.\n"
963 "Return two values: the list of elements satifying @var{pred} and\n"
964 "the list of elements @emph{not} satisfying @var{pred}. The order\n"
965 "of the output lists follows the order of @var{list}. @var{list}\n"
966 "is not mutated. One of the output lists may share memory with @var{list}.\n")
967 #define FUNC_NAME s_scm_srfi1_partition
968 {
969 /* In this implementation, the output lists don't share memory with
970 list, because it's probably not worth the effort. */
971 scm_t_trampoline_1 call = scm_trampoline_1(pred);
972 SCM kept = scm_cons(SCM_EOL, SCM_EOL);
973 SCM kept_tail = kept;
974 SCM dropped = scm_cons(SCM_EOL, SCM_EOL);
975 SCM dropped_tail = dropped;
976
977 SCM_ASSERT(call, pred, 2, FUNC_NAME);
978
979 for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR(list)) {
980 SCM elt = SCM_CAR(list);
981 SCM new_tail = scm_cons(SCM_CAR(list), SCM_EOL);
982 if (scm_is_true (call (pred, elt))) {
983 SCM_SETCDR(kept_tail, new_tail);
984 kept_tail = new_tail;
985 }
986 else {
987 SCM_SETCDR(dropped_tail, new_tail);
988 dropped_tail = new_tail;
989 }
990 }
991 /* re-use the initial conses for the values list */
992 SCM_SETCAR(kept, SCM_CDR(kept));
993 SCM_SETCDR(kept, dropped);
994 SCM_SETCAR(dropped, SCM_CDR(dropped));
995 SCM_SETCDR(dropped, SCM_EOL);
996 return scm_values(kept);
997 }
998 #undef FUNC_NAME
999
1000
1001 SCM_DEFINE (scm_srfi1_partition_x, "partition!", 2, 0, 0,
1002 (SCM pred, SCM lst),
1003 "Split @var{lst} into those elements which do and don't satisfy\n"
1004 "the predicate @var{pred}.\n"
1005 "\n"
1006 "The return is two values (@pxref{Multiple Values}), the first\n"
1007 "being a list of all elements from @var{lst} which satisfy\n"
1008 "@var{pred}, the second a list of those which do not.\n"
1009 "\n"
1010 "The elements in the result lists are in the same order as in\n"
1011 "@var{lst} but the order in which the calls @code{(@var{pred}\n"
1012 "elem)} are made on the list elements is unspecified.\n"
1013 "\n"
1014 "@var{lst} may be modified to construct the return lists.")
1015 #define FUNC_NAME s_scm_srfi1_partition_x
1016 {
1017 SCM tlst, flst, *tp, *fp;
1018 scm_t_trampoline_1 pred_tramp;
1019
1020 pred_tramp = scm_trampoline_1 (pred);
1021 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1022
1023 /* tlst and flst are the lists of true and false elements. tp and fp are
1024 where to store to append to them, initially &tlst and &flst, then
1025 SCM_CDRLOC of the last pair in the respective lists. */
1026
1027 tlst = SCM_EOL;
1028 flst = SCM_EOL;
1029 tp = &tlst;
1030 fp = &flst;
1031
1032 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1033 {
1034 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
1035 {
1036 *tp = lst;
1037 tp = SCM_CDRLOC (lst);
1038 }
1039 else
1040 {
1041 *fp = lst;
1042 fp = SCM_CDRLOC (lst);
1043 }
1044 }
1045
1046 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1047
1048 /* terminate whichever didn't get the last element(s) */
1049 *tp = SCM_EOL;
1050 *fp = SCM_EOL;
1051
1052 return scm_values (scm_list_2 (tlst, flst));
1053 }
1054 #undef FUNC_NAME
1055
1056
1057 SCM_DEFINE (scm_srfi1_remove, "remove", 2, 0, 0,
1058 (SCM pred, SCM list),
1059 "Return a list containing all elements from @var{lst} which do\n"
1060 "not satisfy the predicate @var{pred}. The elements in the\n"
1061 "result list have the same order as in @var{lst}. The order in\n"
1062 "which @var{pred} is applied to the list elements is not\n"
1063 "specified.")
1064 #define FUNC_NAME s_scm_srfi1_remove
1065 {
1066 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1067 SCM walk;
1068 SCM *prev;
1069 SCM res = SCM_EOL;
1070 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1071 SCM_VALIDATE_LIST (2, list);
1072
1073 for (prev = &res, walk = list;
1074 scm_is_pair (walk);
1075 walk = SCM_CDR (walk))
1076 {
1077 if (scm_is_false (call (pred, SCM_CAR (walk))))
1078 {
1079 *prev = scm_cons (SCM_CAR (walk), SCM_EOL);
1080 prev = SCM_CDRLOC (*prev);
1081 }
1082 }
1083
1084 return res;
1085 }
1086 #undef FUNC_NAME
1087
1088
1089 SCM_DEFINE (scm_srfi1_remove_x, "remove!", 2, 0, 0,
1090 (SCM pred, SCM list),
1091 "Return a list containing all elements from @var{list} which do\n"
1092 "not satisfy the predicate @var{pred}. The elements in the\n"
1093 "result list have the same order as in @var{list}. The order in\n"
1094 "which @var{pred} is applied to the list elements is not\n"
1095 "specified. @var{list} may be modified to build the return\n"
1096 "list.")
1097 #define FUNC_NAME s_scm_srfi1_remove_x
1098 {
1099 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1100 SCM walk;
1101 SCM *prev;
1102 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1103 SCM_VALIDATE_LIST (2, list);
1104
1105 for (prev = &list, walk = list;
1106 scm_is_pair (walk);
1107 walk = SCM_CDR (walk))
1108 {
1109 if (scm_is_false (call (pred, SCM_CAR (walk))))
1110 prev = SCM_CDRLOC (walk);
1111 else
1112 *prev = SCM_CDR (walk);
1113 }
1114
1115 return list;
1116 }
1117 #undef FUNC_NAME
1118
1119
1120 SCM_DEFINE (scm_srfi1_split_at, "split-at", 2, 0, 0,
1121 (SCM lst, SCM n),
1122 "Return two values (multiple values), being a list of the\n"
1123 "elements before index @var{n} in @var{lst}, and a list of those\n"
1124 "after.")
1125 #define FUNC_NAME s_scm_srfi1_split_at
1126 {
1127 size_t nn;
1128 /* pre is a list of elements before the i split point, loc is the CDRLOC
1129 of the last cell, ie. where to store to append to it */
1130 SCM pre = SCM_EOL;
1131 SCM *loc = &pre;
1132
1133 for (nn = scm_to_size_t (n); nn != 0; nn--)
1134 {
1135 SCM_VALIDATE_CONS (SCM_ARG1, lst);
1136
1137 *loc = scm_cons (SCM_CAR (lst), SCM_EOL);
1138 loc = SCM_CDRLOC (*loc);
1139 lst = SCM_CDR(lst);
1140 }
1141 return scm_values (scm_list_2 (pre, lst));
1142 }
1143 #undef FUNC_NAME
1144
1145
1146 SCM_DEFINE (scm_srfi1_split_at_x, "split-at!", 2, 0, 0,
1147 (SCM lst, SCM n),
1148 "Return two values (multiple values), being a list of the\n"
1149 "elements before index @var{n} in @var{lst}, and a list of those\n"
1150 "after. @var{lst} is modified to form those values.")
1151 #define FUNC_NAME s_scm_srfi1_split_at
1152 {
1153 size_t nn;
1154 SCM upto = lst;
1155 SCM *loc = &lst;
1156
1157 for (nn = scm_to_size_t (n); nn != 0; nn--)
1158 {
1159 SCM_VALIDATE_CONS (SCM_ARG1, upto);
1160
1161 loc = SCM_CDRLOC (upto);
1162 upto = SCM_CDR (upto);
1163 }
1164
1165 *loc = SCM_EOL;
1166 return scm_values (scm_list_2 (lst, upto));
1167 }
1168 #undef FUNC_NAME
1169
1170
1171 SCM_DEFINE (scm_srfi1_take_right, "take-right", 2, 0, 0,
1172 (SCM lst, SCM n),
1173 "Return the a list containing the @var{n} last elements of\n"
1174 "@var{lst}.")
1175 #define FUNC_NAME s_scm_srfi1_take_right
1176 {
1177 SCM tail = scm_list_tail (lst, n);
1178 while (scm_is_pair (tail))
1179 {
1180 lst = SCM_CDR (lst);
1181 tail = SCM_CDR (tail);
1182 }
1183 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
1184 return lst;
1185 }
1186 #undef FUNC_NAME
1187
1188
1189 void
1190 scm_init_srfi_1 (void)
1191 {
1192 SCM the_root_module = scm_lookup_closure_module (SCM_BOOL_F);
1193 #ifndef SCM_MAGIC_SNARFER
1194 #include "srfi/srfi-1.x"
1195 #endif
1196 scm_c_extend_primitive_generic
1197 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "map")),
1198 SCM_VARIABLE_REF (scm_c_lookup ("map")));
1199 scm_c_extend_primitive_generic
1200 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "for-each")),
1201 SCM_VARIABLE_REF (scm_c_lookup ("for-each")));
1202 }
1203
1204 /* End of srfi-1.c. */