(fifth, sixth, seventh, eighth, ninth, tenth): Rewrite in C.
[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_DEFINE (scm_srfi1_alist_copy, "alist-copy", 1, 0, 0,
67 (SCM alist),
68 "Return a copy of @var{alist}, copying both the pairs comprising\n"
69 "the list and those making the associations.")
70 #define FUNC_NAME s_scm_srfi1_alist_copy
71 {
72 SCM ret, *p, elem, c;
73
74 /* ret is the list to return. p is where to append to it, initially &ret
75 then SCM_CDRLOC of the last pair. */
76 ret = SCM_EOL;
77 p = &ret;
78
79 for ( ; scm_is_pair (alist); alist = SCM_CDR (alist))
80 {
81 elem = SCM_CAR (alist);
82
83 /* each element of alist must be a pair */
84 SCM_ASSERT_TYPE (scm_is_pair (elem), alist, SCM_ARG1, FUNC_NAME,
85 "association list");
86
87 c = scm_cons (scm_cons (SCM_CAR (elem), SCM_CDR (elem)), SCM_EOL);
88 *p = c;
89 p = SCM_CDRLOC (c);
90 }
91
92 /* alist must be a proper list */
93 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (alist), alist, SCM_ARG1, FUNC_NAME,
94 "association list");
95 return ret;
96 }
97 #undef FUNC_NAME
98
99
100 SCM_DEFINE (scm_srfi1_break, "break", 2, 0, 0,
101 (SCM pred, SCM lst),
102 "Return two values, the longest initial prefix of @var{lst}\n"
103 "whose elements all fail the predicate @var{pred}, and the\n"
104 "remainder of @var{lst}.\n"
105 "\n"
106 "Note that the name @code{break} conflicts with the @code{break}\n"
107 "binding established by @code{while}. Applications wanting to\n"
108 "use @code{break} from within a @code{while} loop will need to\n"
109 "make a new define under a different name.")
110 #define FUNC_NAME s_scm_srfi1_break
111 {
112 scm_t_trampoline_1 pred_tramp;
113 SCM ret, *p;
114
115 pred_tramp = scm_trampoline_1 (pred);
116 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
117
118 ret = SCM_EOL;
119 p = &ret;
120 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
121 {
122 SCM elem = SCM_CAR (lst);
123 if (scm_is_true (pred_tramp (pred, elem)))
124 goto done;
125
126 /* want this elem, tack it onto the end of ret */
127 *p = scm_cons (elem, SCM_EOL);
128 p = SCM_CDRLOC (*p);
129 }
130 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
131
132 done:
133 return scm_values (scm_list_2 (ret, lst));
134 }
135 #undef FUNC_NAME
136
137
138 SCM_DEFINE (scm_srfi1_break_x, "break!", 2, 0, 0,
139 (SCM pred, SCM lst),
140 "Return two values, the longest initial prefix of @var{lst}\n"
141 "whose elements all fail the predicate @var{pred}, and the\n"
142 "remainder of @var{lst}. @var{lst} may be modified to form the\n"
143 "return.")
144 #define FUNC_NAME s_scm_srfi1_break_x
145 {
146 SCM upto, *p;
147 scm_t_trampoline_1 pred_tramp;
148
149 pred_tramp = scm_trampoline_1 (pred);
150 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
151
152 p = &lst;
153 for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
154 {
155 if (scm_is_true (pred_tramp (pred, SCM_CAR (upto))))
156 goto done;
157
158 /* want this element */
159 p = SCM_CDRLOC (upto);
160 }
161 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
162
163 done:
164 *p = SCM_EOL;
165 return scm_values (scm_list_2 (lst, upto));
166 }
167 #undef FUNC_NAME
168
169
170 SCM_DEFINE (scm_srfi1_concatenate, "concatenate", 1, 0, 0,
171 (SCM lstlst),
172 "Construct a list by appending all lists in @var{lstlst}.\n"
173 "\n"
174 "@code{concatenate} is the same as @code{(apply append\n"
175 "@var{lstlst})}. It exists because some Scheme implementations\n"
176 "have a limit on the number of arguments a function takes, which\n"
177 "the @code{apply} might exceed. In Guile there is no such\n"
178 "limit.")
179 #define FUNC_NAME s_scm_srfi1_concatenate
180 {
181 SCM_VALIDATE_LIST (SCM_ARG1, lstlst);
182 return scm_append (lstlst);
183 }
184 #undef FUNC_NAME
185
186
187 SCM_DEFINE (scm_srfi1_concatenate_x, "concatenate!", 1, 0, 0,
188 (SCM lstlst),
189 "Construct a list by appending all lists in @var{lstlst}. Those\n"
190 "lists may be modified to produce the result.\n"
191 "\n"
192 "@code{concatenate!} is the same as @code{(apply append!\n"
193 "@var{lstlst})}. It exists because some Scheme implementations\n"
194 "have a limit on the number of arguments a function takes, which\n"
195 "the @code{apply} might exceed. In Guile there is no such\n"
196 "limit.")
197 #define FUNC_NAME s_scm_srfi1_concatenate
198 {
199 SCM_VALIDATE_LIST (SCM_ARG1, lstlst);
200 return scm_append_x (lstlst);
201 }
202 #undef FUNC_NAME
203
204
205 SCM_DEFINE (scm_srfi1_count, "count", 2, 0, 1,
206 (SCM pred, SCM list1, SCM rest),
207 "Return a count of the number of times @var{pred} returns true\n"
208 "when called on elements from the given lists.\n"
209 "\n"
210 "@var{pred} is called with @var{N} parameters @code{(@var{pred}\n"
211 "@var{elem1} @dots{} @var{elemN})}, each element being from the\n"
212 "corresponding @var{list1} @dots{} @var{lstN}. The first call is\n"
213 "with the first element of each list, the second with the second\n"
214 "element from each, and so on.\n"
215 "\n"
216 "Counting stops when the end of the shortest list is reached.\n"
217 "At least one list must be non-circular.")
218 #define FUNC_NAME s_scm_srfi1_count
219 {
220 long count;
221 SCM lst;
222 int argnum;
223 SCM_VALIDATE_REST_ARGUMENT (rest);
224
225 count = 0;
226
227 if (scm_is_null (rest))
228 {
229 /* one list */
230 scm_t_trampoline_1 pred_tramp;
231 pred_tramp = scm_trampoline_1 (pred);
232 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
233
234 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
235 count += scm_is_true (pred_tramp (pred, SCM_CAR (list1)));
236
237 /* check below that list1 is a proper list, and done */
238 end_list1:
239 lst = list1;
240 argnum = 2;
241 }
242 else if (scm_is_pair (rest) && scm_is_null (SCM_CDR (rest)))
243 {
244 /* two lists */
245 scm_t_trampoline_2 pred_tramp;
246 SCM list2;
247
248 pred_tramp = scm_trampoline_2 (pred);
249 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
250
251 list2 = SCM_CAR (rest);
252 for (;;)
253 {
254 if (! scm_is_pair (list1))
255 goto end_list1;
256 if (! scm_is_pair (list2))
257 {
258 lst = list2;
259 argnum = 3;
260 break;
261 }
262 count += scm_is_true (pred_tramp
263 (pred, SCM_CAR (list1), SCM_CAR (list2)));
264 list1 = SCM_CDR (list1);
265 list2 = SCM_CDR (list2);
266 }
267 }
268 else
269 {
270 /* three or more lists */
271 SCM vec, args, a;
272 size_t len, i;
273
274 /* vec is the list arguments */
275 vec = scm_vector (scm_cons (list1, rest));
276 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
277
278 /* args is the argument list to pass to pred, same length as vec,
279 re-used for each call */
280 args = scm_make_list (SCM_I_MAKINUM (len), SCM_UNDEFINED);
281
282 for (;;)
283 {
284 /* first elem of each list in vec into args, and step those
285 vec entries onto their next element */
286 for (i = 0, a = args, argnum = 2;
287 i < len;
288 i++, a = SCM_CDR (a), argnum++)
289 {
290 lst = SCM_SIMPLE_VECTOR_REF (vec, i); /* list argument */
291 if (! scm_is_pair (lst))
292 goto check_lst_and_done;
293 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for pred */
294 SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst)); /* rest of lst */
295 }
296
297 count += scm_is_true (scm_apply (pred, args, SCM_EOL));
298 }
299 }
300
301 check_lst_and_done:
302 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
303 return scm_from_long (count);
304 }
305 #undef FUNC_NAME
306
307
308 SCM_DEFINE (scm_srfi1_delete, "delete", 2, 1, 0,
309 (SCM x, SCM lst, SCM pred),
310 "Return a list containing the elements of @var{lst} but with\n"
311 "those equal to @var{x} deleted. The returned elements will be\n"
312 "in the same order as they were in @var{lst}.\n"
313 "\n"
314 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
315 "given. An equality call is made just once for each element,\n"
316 "but the order in which the calls are made on the elements is\n"
317 "unspecified.\n"
318 "\n"
319 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
320 "given @var{x} is first. This means for instance elements\n"
321 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
322 "\n"
323 "@var{lst} is not modified, but the returned list might share a\n"
324 "common tail with @var{lst}.")
325 #define FUNC_NAME s_scm_srfi1_delete
326 {
327 scm_t_trampoline_2 equal_p;
328 SCM ret, *p, keeplst;
329
330 if (SCM_UNBNDP (pred))
331 return scm_delete (x, lst);
332
333 equal_p = scm_trampoline_2 (pred);
334 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
335
336 /* ret is the return list being constructed. p is where to append to it,
337 initially &ret then SCM_CDRLOC of the last pair. lst progresses as
338 elements are considered.
339
340 Elements to be retained are not immediately copied, instead keeplst is
341 the last pair in lst which is to be retained but not yet copied. When
342 there's no more deletions, *p can be set to keeplst to share the
343 remainder of the original lst. (The entire original lst if there's no
344 deletions at all.) */
345
346 keeplst = lst;
347 ret = SCM_EOL;
348 p = &ret;
349
350 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
351 {
352 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
353 {
354 /* delete this element, so copy from keeplst (inclusive) to lst
355 (exclusive) onto ret */
356 while (! scm_is_eq (keeplst, lst))
357 {
358 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
359 *p = c;
360 p = SCM_CDRLOC (c);
361 keeplst = SCM_CDR (keeplst);
362 }
363
364 keeplst = SCM_CDR (lst);
365 }
366 }
367
368 /* final retained elements */
369 *p = keeplst;
370
371 /* demand that lst was a proper list */
372 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
373
374 return ret;
375 }
376 #undef FUNC_NAME
377
378
379 SCM_DEFINE (scm_srfi1_delete_x, "delete!", 2, 1, 0,
380 (SCM x, SCM lst, SCM pred),
381 "Return a list containing the elements of @var{lst} but with\n"
382 "those equal to @var{x} deleted. The returned elements will be\n"
383 "in the same order as they were in @var{lst}.\n"
384 "\n"
385 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
386 "given. An equality call is made just once for each element,\n"
387 "but the order in which the calls are made on the elements is\n"
388 "unspecified.\n"
389 "\n"
390 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
391 "given @var{x} is first. This means for instance elements\n"
392 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
393 "\n"
394 "@var{lst} may be modified to construct the returned list.")
395 #define FUNC_NAME s_scm_srfi1_delete_x
396 {
397 scm_t_trampoline_2 equal_p;
398 SCM walk;
399 SCM *prev;
400
401 if (SCM_UNBNDP (pred))
402 return scm_delete_x (x, lst);
403
404 equal_p = scm_trampoline_2 (pred);
405 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
406
407 for (prev = &lst, walk = lst;
408 scm_is_pair (walk);
409 walk = SCM_CDR (walk))
410 {
411 if (scm_is_true (equal_p (pred, x, SCM_CAR (walk))))
412 *prev = SCM_CDR (walk);
413 else
414 prev = SCM_CDRLOC (walk);
415 }
416
417 /* demand the input was a proper list */
418 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (walk), walk, SCM_ARG2, FUNC_NAME,"list");
419 return lst;
420 }
421 #undef FUNC_NAME
422
423
424 SCM_DEFINE (scm_srfi1_delete_duplicates, "delete-duplicates", 1, 1, 0,
425 (SCM lst, SCM pred),
426 "Return a list containing the elements of @var{lst} but without\n"
427 "duplicates.\n"
428 "\n"
429 "When elements are equal, only the first in @var{lst} is\n"
430 "retained. Equal elements can be anywhere in @var{lst}, they\n"
431 "don't have to be adjacent. The returned list will have the\n"
432 "retained elements in the same order as they were in @var{lst}.\n"
433 "\n"
434 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
435 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
436 "being before @var{y} in @var{lst}. A call is made at most once\n"
437 "for each combination, but the sequence of the calls across the\n"
438 "elements is unspecified.\n"
439 "\n"
440 "@var{lst} is not modified, but the return might share a common\n"
441 "tail with @var{lst}.\n"
442 "\n"
443 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
444 "it must check each element against all those preceding it. For\n"
445 "long lists it is more efficient to sort and then compare only\n"
446 "adjacent elements.")
447 #define FUNC_NAME s_scm_srfi1_delete_duplicates
448 {
449 scm_t_trampoline_2 equal_p;
450 SCM ret, *p, keeplst, item, l;
451
452 /* ret is the new list constructed. p is where to append, initially &ret
453 then SCM_CDRLOC of the last pair. lst is advanced as each element is
454 considered.
455
456 Elements retained are not immediately appended to ret, instead keeplst
457 is the last pair in lst which is to be kept but is not yet copied.
458 Initially this is the first pair of lst, since the first element is
459 always retained.
460
461 *p is kept set to keeplst, so ret (inclusive) to lst (exclusive) is all
462 the elements retained, making the equality search loop easy.
463
464 If an item must be deleted, elements from keeplst (inclusive) to lst
465 (exclusive) must be copied and appended to ret. When there's no more
466 deletions, *p is left set to keeplst, so ret shares structure with the
467 original lst. (ret will be the entire original lst if there are no
468 deletions.) */
469
470 /* skip to end if an empty list (or something invalid) */
471 ret = lst;
472 if (scm_is_pair (lst))
473 {
474 if (SCM_UNBNDP (pred))
475 equal_p = equal_trampoline;
476 else
477 {
478 equal_p = scm_trampoline_2 (pred);
479 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
480 }
481
482 keeplst = lst;
483 p = &ret;
484
485 /* loop over lst elements starting from second */
486 for (;;)
487 {
488 lst = SCM_CDR (lst);
489 if (! scm_is_pair (lst))
490 break;
491 item = SCM_CAR (lst);
492
493 /* loop searching ret upto lst */
494 for (l = ret; ! scm_is_eq (l, lst); l = SCM_CDR (l))
495 {
496 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
497 {
498 /* duplicate, don't want this element, so copy keeplst
499 (inclusive) to lst (exclusive) onto ret */
500 while (! scm_is_eq (keeplst, lst))
501 {
502 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
503 *p = c;
504 p = SCM_CDRLOC (c);
505 keeplst = SCM_CDR (keeplst);
506 }
507
508 keeplst = SCM_CDR (lst); /* elem after the one deleted */
509 *p = keeplst;
510 break;
511 }
512 }
513 }
514 }
515
516 /* demand that lst was a proper list */
517 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
518
519 return ret;
520 }
521 #undef FUNC_NAME
522
523
524 SCM_DEFINE (scm_srfi1_delete_duplicates_x, "delete-duplicates!", 1, 1, 0,
525 (SCM lst, SCM pred),
526 "Return a list containing the elements of @var{lst} but without\n"
527 "duplicates.\n"
528 "\n"
529 "When elements are equal, only the first in @var{lst} is\n"
530 "retained. Equal elements can be anywhere in @var{lst}, they\n"
531 "don't have to be adjacent. The returned list will have the\n"
532 "retained elements in the same order as they were in @var{lst}.\n"
533 "\n"
534 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
535 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
536 "being before @var{y} in @var{lst}. A call is made at most once\n"
537 "for each combination, but the sequence of the calls across the\n"
538 "elements is unspecified.\n"
539 "\n"
540 "@var{lst} may be modified to construct the returned list.\n"
541 "\n"
542 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
543 "it must check each element against all those preceding it. For\n"
544 "long lists it is more efficient to sort and then compare only\n"
545 "adjacent elements.")
546 #define FUNC_NAME s_scm_srfi1_delete_duplicates_x
547 {
548 scm_t_trampoline_2 equal_p;
549 SCM ret, endret, item, l;
550
551 /* ret is the return list, constructed from the pairs in lst. endret is
552 the last pair of ret, initially the first pair. lst is advanced as
553 elements are considered. */
554
555 /* skip to end if an empty list (or something invalid) */
556 ret = lst;
557 if (scm_is_pair (lst))
558 {
559 if (SCM_UNBNDP (pred))
560 equal_p = equal_trampoline;
561 else
562 {
563 equal_p = scm_trampoline_2 (pred);
564 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
565 }
566
567 endret = ret;
568
569 /* loop over lst elements starting from second */
570 for (;;)
571 {
572 lst = SCM_CDR (lst);
573 if (! scm_is_pair (lst))
574 break;
575 item = SCM_CAR (lst);
576
577 /* is item equal to any element from ret to endret (inclusive)? */
578 l = ret;
579 for (;;)
580 {
581 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
582 break; /* equal, forget this element */
583
584 if (scm_is_eq (l, endret))
585 {
586 /* not equal to any, so append this pair */
587 SCM_SETCDR (endret, lst);
588 endret = lst;
589 break;
590 }
591 l = SCM_CDR (l);
592 }
593 }
594
595 /* terminate, in case last element was deleted */
596 SCM_SETCDR (endret, SCM_EOL);
597 }
598
599 /* demand that lst was a proper list */
600 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
601
602 return ret;
603 }
604 #undef FUNC_NAME
605
606
607 SCM_DEFINE (scm_srfi1_drop_right, "drop-right", 2, 0, 0,
608 (SCM lst, SCM n),
609 "Return a new list containing all except the last @var{n}\n"
610 "elements of @var{lst}.")
611 #define FUNC_NAME s_scm_srfi1_drop_right
612 {
613 SCM tail = scm_list_tail (lst, n);
614 SCM ret = SCM_EOL;
615 SCM *rend = &ret;
616 while (scm_is_pair (tail))
617 {
618 *rend = scm_cons (SCM_CAR (lst), SCM_EOL);
619 rend = SCM_CDRLOC (*rend);
620
621 lst = SCM_CDR (lst);
622 tail = SCM_CDR (tail);
623 }
624 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
625 return ret;
626 }
627 #undef FUNC_NAME
628
629
630 SCM_DEFINE (scm_srfi1_drop_right_x, "drop-right!", 2, 0, 0,
631 (SCM lst, SCM n),
632 "Return the a list containing the @var{n} last elements of\n"
633 "@var{lst}. @var{lst} may be modified to build the return.")
634 #define FUNC_NAME s_scm_srfi1_drop_right_x
635 {
636 SCM tail, *p;
637
638 if (scm_is_eq (n, SCM_INUM0))
639 return lst;
640
641 tail = scm_list_tail (lst, n);
642 p = &lst;
643
644 /* p and tail work along the list, p being the cdrloc of the cell n steps
645 behind tail */
646 for ( ; scm_is_pair (tail); tail = SCM_CDR (tail))
647 p = SCM_CDRLOC (*p);
648
649 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
650
651 *p = SCM_EOL;
652 return lst;
653 }
654 #undef FUNC_NAME
655
656
657 SCM_DEFINE (scm_srfi1_drop_while, "drop-while", 2, 0, 0,
658 (SCM pred, SCM lst),
659 "Drop the longest initial prefix of @var{lst} whose elements all\n"
660 "satisfy the predicate @var{pred}.")
661 #define FUNC_NAME s_scm_srfi1_drop_while
662 {
663 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
664 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
665
666 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
667 if (scm_is_false (pred_tramp (pred, SCM_CAR (lst))))
668 goto done;
669
670 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
671 done:
672 return lst;
673 }
674 #undef FUNC_NAME
675
676
677 SCM_DEFINE (scm_srfi1_eighth, "eighth", 1, 0, 0,
678 (SCM lst),
679 "Return the eighth element of @var{lst}.")
680 #define FUNC_NAME s_scm_srfi1_eighth
681 {
682 return scm_list_ref (lst, SCM_I_MAKINUM (7));
683 }
684 #undef FUNC_NAME
685
686
687 SCM_DEFINE (scm_srfi1_fifth, "fifth", 1, 0, 0,
688 (SCM lst),
689 "Return the fifth element of @var{lst}.")
690 #define FUNC_NAME s_scm_srfi1_fifth
691 {
692 return scm_list_ref (lst, SCM_I_MAKINUM (4));
693 }
694 #undef FUNC_NAME
695
696
697 SCM_DEFINE (scm_srfi1_filter_map, "filter-map", 2, 0, 1,
698 (SCM proc, SCM list1, SCM rest),
699 "Apply @var{proc} to to the elements of @var{list1} @dots{} and\n"
700 "return a list of the results as per SRFI-1 @code{map}, except\n"
701 "that any @code{#f} results are omitted from the list returned.")
702 #define FUNC_NAME s_scm_srfi1_filter_map
703 {
704 SCM ret, *loc, elem, newcell, lst;
705 int argnum;
706
707 SCM_VALIDATE_REST_ARGUMENT (rest);
708
709 ret = SCM_EOL;
710 loc = &ret;
711
712 if (SCM_NULLP (rest))
713 {
714 /* one list */
715 scm_t_trampoline_1 proc_tramp = scm_trampoline_1 (proc);
716 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
717
718 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
719 {
720 elem = proc_tramp (proc, SCM_CAR (list1));
721 if (scm_is_true (elem))
722 {
723 newcell = scm_cons (elem, SCM_EOL);
724 *loc = newcell;
725 loc = SCM_CDRLOC (newcell);
726 }
727 }
728
729 /* check below that list1 is a proper list, and done */
730 end_list1:
731 lst = list1;
732 argnum = 2;
733 }
734 else if (SCM_NULLP (SCM_CDR (rest)))
735 {
736 /* two lists */
737 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
738 SCM list2 = SCM_CAR (rest);
739 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
740
741 for (;;)
742 {
743 if (! scm_is_pair (list1))
744 goto end_list1;
745 if (! scm_is_pair (list2))
746 {
747 lst = list2;
748 argnum = 3;
749 goto check_lst_and_done;
750 }
751 elem = proc_tramp (proc, SCM_CAR (list1), SCM_CAR (list2));
752 if (scm_is_true (elem))
753 {
754 newcell = scm_cons (elem, SCM_EOL);
755 *loc = newcell;
756 loc = SCM_CDRLOC (newcell);
757 }
758 list1 = SCM_CDR (list1);
759 list2 = SCM_CDR (list2);
760 }
761 }
762 else
763 {
764 /* three or more lists */
765 SCM vec, args, a;
766 size_t len, i;
767
768 /* vec is the list arguments */
769 vec = scm_vector (scm_cons (list1, rest));
770 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
771
772 /* args is the argument list to pass to proc, same length as vec,
773 re-used for each call */
774 args = scm_make_list (SCM_I_MAKINUM (len), SCM_UNDEFINED);
775
776 for (;;)
777 {
778 /* first elem of each list in vec into args, and step those
779 vec entries onto their next element */
780 for (i = 0, a = args, argnum = 2;
781 i < len;
782 i++, a = SCM_CDR (a), argnum++)
783 {
784 lst = SCM_SIMPLE_VECTOR_REF (vec, i); /* list argument */
785 if (! scm_is_pair (lst))
786 goto check_lst_and_done;
787 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for proc */
788 SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst)); /* rest of lst */
789 }
790
791 elem = scm_apply (proc, args, SCM_EOL);
792 if (scm_is_true (elem))
793 {
794 newcell = scm_cons (elem, SCM_EOL);
795 *loc = newcell;
796 loc = SCM_CDRLOC (newcell);
797 }
798 }
799 }
800
801 check_lst_and_done:
802 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
803 return ret;
804 }
805 #undef FUNC_NAME
806
807
808 SCM_DEFINE (scm_srfi1_find, "find", 2, 0, 0,
809 (SCM pred, SCM lst),
810 "Return the first element of @var{lst} which satisfies the\n"
811 "predicate @var{pred}, or return @code{#f} if no such element is\n"
812 "found.")
813 #define FUNC_NAME s_scm_srfi1_find
814 {
815 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
816 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
817
818 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
819 {
820 SCM elem = SCM_CAR (lst);
821 if (scm_is_true (pred_tramp (pred, elem)))
822 return elem;
823 }
824 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
825
826 return SCM_BOOL_F;
827 }
828 #undef FUNC_NAME
829
830
831 SCM_DEFINE (scm_srfi1_find_tail, "find-tail", 2, 0, 0,
832 (SCM pred, SCM lst),
833 "Return the first pair of @var{lst} whose @sc{car} satisfies the\n"
834 "predicate @var{pred}, or return @code{#f} if no such element is\n"
835 "found.")
836 #define FUNC_NAME s_scm_srfi1_find_tail
837 {
838 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
839 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
840
841 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
842 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
843 return lst;
844 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
845
846 return SCM_BOOL_F;
847 }
848 #undef FUNC_NAME
849
850
851 SCM_DEFINE (scm_srfi1_length_plus, "length+", 1, 0, 0,
852 (SCM lst),
853 "Return the length of @var{lst}, or @code{#f} if @var{lst} is\n"
854 "circular.")
855 #define FUNC_NAME s_scm_srfi1_length_plus
856 {
857 long len = scm_ilength (lst);
858 return (len >= 0 ? SCM_I_MAKINUM (len) : SCM_BOOL_F);
859 }
860 #undef FUNC_NAME
861
862
863 /* This routine differs from the core list-copy in allowing improper lists.
864 Maybe the core could allow them similarly. */
865
866 SCM_DEFINE (scm_srfi1_list_copy, "list-copy", 1, 0, 0,
867 (SCM lst),
868 "Return a copy of the given list @var{lst}.\n"
869 "\n"
870 "@var{lst} can be a proper or improper list. And if @var{lst}\n"
871 "is not a pair then it's treated as the final tail of an\n"
872 "improper list and simply returned.")
873 #define FUNC_NAME s_scm_srfi1_list_copy
874 {
875 SCM newlst;
876 SCM * fill_here;
877 SCM from_here;
878
879 newlst = lst;
880 fill_here = &newlst;
881 from_here = lst;
882
883 while (scm_is_pair (from_here))
884 {
885 SCM c;
886 c = scm_cons (SCM_CAR (from_here), SCM_CDR (from_here));
887 *fill_here = c;
888 fill_here = SCM_CDRLOC (c);
889 from_here = SCM_CDR (from_here);
890 }
891 return newlst;
892 }
893 #undef FUNC_NAME
894
895
896 SCM_DEFINE (scm_srfi1_lset_adjoin, "lset-adjoin", 2, 0, 1,
897 (SCM equal, SCM lst, SCM rest),
898 "Add to @var{list} any of the given @var{elem}s not already in\n"
899 "the list. @var{elem}s are @code{cons}ed onto the start of\n"
900 "@var{list} (so the return shares a common tail with\n"
901 "@var{list}), but the order they're added is unspecified.\n"
902 "\n"
903 "The given @var{=} procedure is used for comparing elements,\n"
904 "called as @code{(@var{=} listelem elem)}, ie.@: the second\n"
905 "argument is one of the given @var{elem} parameters.\n"
906 "\n"
907 "@example\n"
908 "(lset-adjoin eqv? '(1 2 3) 4 1 5) @result{} (5 4 1 2 3)\n"
909 "@end example")
910 #define FUNC_NAME s_scm_srfi1_lset_adjoin
911 {
912 scm_t_trampoline_2 equal_tramp;
913 SCM l, elem;
914
915 equal_tramp = scm_trampoline_2 (equal);
916 SCM_ASSERT (equal_tramp, equal, SCM_ARG1, FUNC_NAME);
917 SCM_VALIDATE_REST_ARGUMENT (rest);
918
919 /* It's not clear if duplicates among the `rest' elements are meant to be
920 cast out. The spec says `=' is called as (= list-elem rest-elem),
921 suggesting perhaps not, but the reference implementation shows the
922 "list" at each stage as including those "rest" elements already added.
923 The latter corresponds to what's described for lset-union, so that's
924 what's done here. */
925
926 for ( ; scm_is_pair (rest); rest = SCM_CDR (rest))
927 {
928 elem = SCM_CAR (rest);
929
930 for (l = lst; scm_is_pair (l); l = SCM_CDR (l))
931 if (scm_is_true (equal_tramp (equal, SCM_CAR (l), elem)))
932 goto next_elem; /* elem already in lst, don't add */
933
934 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(l), lst, SCM_ARG2, FUNC_NAME, "list");
935
936 /* elem is not equal to anything already in lst, add it */
937 lst = scm_cons (elem, lst);
938
939 next_elem:
940 ;
941 }
942
943 return lst;
944 }
945 #undef FUNC_NAME
946
947
948 /* Typechecking for multi-argument MAP and FOR-EACH.
949
950 Verify that each element of the vector ARGV, except for the first,
951 is a list and return minimum length. Attribute errors to WHO,
952 and claim that the i'th element of ARGV is WHO's i+2'th argument. */
953 static inline int
954 check_map_args (SCM argv,
955 long len,
956 SCM gf,
957 SCM proc,
958 SCM args,
959 const char *who)
960 {
961 long i;
962
963 for (i = SCM_SIMPLE_VECTOR_LENGTH (argv) - 1; i >= 1; i--)
964 {
965 SCM elt = SCM_SIMPLE_VECTOR_REF (argv, i);
966 long elt_len;
967
968 if (!(scm_is_null (elt) || scm_is_pair (elt)))
969 {
970 check_map_error:
971 if (gf)
972 scm_apply_generic (gf, scm_cons (proc, args));
973 else
974 scm_wrong_type_arg (who, i + 2, elt);
975 }
976
977 elt_len = srfi1_ilength (elt);
978 if (elt_len < -1)
979 goto check_map_error;
980
981 if (len < 0 || (elt_len >= 0 && elt_len < len))
982 len = elt_len;
983 }
984 if (len < 0)
985 /* i == 0 */
986 goto check_map_error;
987
988 scm_remember_upto_here_1 (argv);
989 return len;
990 }
991
992
993 SCM_GPROC (s_srfi1_map, "map", 2, 0, 1, scm_srfi1_map, g_srfi1_map);
994
995 /* Note: Currently, scm_srfi1_map applies PROC to the argument list(s)
996 sequentially, starting with the first element(s). This is used in
997 the Scheme procedure `map-in-order', which guarantees sequential
998 behaviour, is implemented using scm_map. If the behaviour changes,
999 we need to update `map-in-order'.
1000 */
1001
1002 SCM
1003 scm_srfi1_map (SCM proc, SCM arg1, SCM args)
1004 #define FUNC_NAME s_srfi1_map
1005 {
1006 long i, len;
1007 SCM res = SCM_EOL;
1008 SCM *pres = &res;
1009
1010 len = srfi1_ilength (arg1);
1011 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
1012 g_srfi1_map,
1013 scm_cons2 (proc, arg1, args), SCM_ARG2, s_srfi1_map);
1014 SCM_VALIDATE_REST_ARGUMENT (args);
1015 if (scm_is_null (args))
1016 {
1017 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
1018 SCM_GASSERT2 (call, g_srfi1_map, proc, arg1, SCM_ARG1, s_srfi1_map);
1019 SCM_GASSERT2 (len >= 0, g_srfi1_map, proc, arg1, SCM_ARG2, s_srfi1_map);
1020 while (SCM_NIMP (arg1))
1021 {
1022 *pres = scm_list_1 (call (proc, SCM_CAR (arg1)));
1023 pres = SCM_CDRLOC (*pres);
1024 arg1 = SCM_CDR (arg1);
1025 }
1026 return res;
1027 }
1028 if (scm_is_null (SCM_CDR (args)))
1029 {
1030 SCM arg2 = SCM_CAR (args);
1031 int len2 = srfi1_ilength (arg2);
1032 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
1033 SCM_GASSERTn (call, g_srfi1_map,
1034 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_map);
1035 if (len < 0 || (len2 >= 0 && len2 < len))
1036 len = len2;
1037 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
1038 && len >= 0 && len2 >= -1,
1039 g_srfi1_map,
1040 scm_cons2 (proc, arg1, args),
1041 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
1042 s_srfi1_map);
1043 while (len > 0)
1044 {
1045 *pres = scm_list_1 (call (proc, SCM_CAR (arg1), SCM_CAR (arg2)));
1046 pres = SCM_CDRLOC (*pres);
1047 arg1 = SCM_CDR (arg1);
1048 arg2 = SCM_CDR (arg2);
1049 --len;
1050 }
1051 return res;
1052 }
1053 args = scm_vector (arg1 = scm_cons (arg1, args));
1054 len = check_map_args (args, len, g_srfi1_map, proc, arg1, s_srfi1_map);
1055 while (len > 0)
1056 {
1057 arg1 = SCM_EOL;
1058 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
1059 {
1060 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
1061 arg1 = scm_cons (SCM_CAR (elt), arg1);
1062 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
1063 }
1064 *pres = scm_list_1 (scm_apply (proc, arg1, SCM_EOL));
1065 pres = SCM_CDRLOC (*pres);
1066 --len;
1067 }
1068 return res;
1069 }
1070 #undef FUNC_NAME
1071
1072 SCM_REGISTER_PROC (s_srfi1_map_in_order, "map-in-order", 2, 0, 1, scm_srfi1_map);
1073
1074 SCM_GPROC (s_srfi1_for_each, "for-each", 2, 0, 1, scm_srfi1_for_each, g_srfi1_for_each);
1075
1076 SCM
1077 scm_srfi1_for_each (SCM proc, SCM arg1, SCM args)
1078 #define FUNC_NAME s_srfi1_for_each
1079 {
1080 long i, len;
1081 len = srfi1_ilength (arg1);
1082 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
1083 g_srfi1_for_each, scm_cons2 (proc, arg1, args),
1084 SCM_ARG2, s_srfi1_for_each);
1085 SCM_VALIDATE_REST_ARGUMENT (args);
1086 if (scm_is_null (args))
1087 {
1088 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
1089 SCM_GASSERT2 (call, g_srfi1_for_each, proc, arg1,
1090 SCM_ARG1, s_srfi1_for_each);
1091 SCM_GASSERT2 (len >= 0, g_srfi1_for_each, proc, arg1,
1092 SCM_ARG2, s_srfi1_map);
1093 while (SCM_NIMP (arg1))
1094 {
1095 call (proc, SCM_CAR (arg1));
1096 arg1 = SCM_CDR (arg1);
1097 }
1098 return SCM_UNSPECIFIED;
1099 }
1100 if (scm_is_null (SCM_CDR (args)))
1101 {
1102 SCM arg2 = SCM_CAR (args);
1103 int len2 = srfi1_ilength (arg2);
1104 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
1105 SCM_GASSERTn (call, g_srfi1_for_each,
1106 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_for_each);
1107 if (len < 0 || (len2 >= 0 && len2 < len))
1108 len = len2;
1109 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
1110 && len >= 0 && len2 >= -1,
1111 g_srfi1_for_each,
1112 scm_cons2 (proc, arg1, args),
1113 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
1114 s_srfi1_for_each);
1115 while (len > 0)
1116 {
1117 call (proc, SCM_CAR (arg1), SCM_CAR (arg2));
1118 arg1 = SCM_CDR (arg1);
1119 arg2 = SCM_CDR (arg2);
1120 --len;
1121 }
1122 return SCM_UNSPECIFIED;
1123 }
1124 args = scm_vector (arg1 = scm_cons (arg1, args));
1125 len = check_map_args (args, len, g_srfi1_for_each, proc, arg1,
1126 s_srfi1_for_each);
1127 while (len > 0)
1128 {
1129 arg1 = SCM_EOL;
1130 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
1131 {
1132 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
1133 arg1 = scm_cons (SCM_CAR (elt), arg1);
1134 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
1135 }
1136 scm_apply (proc, arg1, SCM_EOL);
1137 --len;
1138 }
1139 return SCM_UNSPECIFIED;
1140 }
1141 #undef FUNC_NAME
1142
1143
1144 SCM_DEFINE (scm_srfi1_member, "member", 2, 1, 0,
1145 (SCM x, SCM lst, SCM pred),
1146 "Return the first sublist of @var{lst} whose @sc{car} is equal\n"
1147 "to @var{x}. If @var{x} does not appear in @var{lst}, return\n"
1148 "@code{#f}.\n"
1149 "\n"
1150 "Equality is determined by @code{equal?}, or by the equality\n"
1151 "predicate @var{=} if given. @var{=} is called @code{(= @var{x}\n"
1152 "elem)}, ie.@: with the given @var{x} first, so for example to\n"
1153 "find the first element greater than 5,\n"
1154 "\n"
1155 "@example\n"
1156 "(member 5 '(3 5 1 7 2 9) <) @result{} (7 2 9)\n"
1157 "@end example\n"
1158 "\n"
1159 "This version of @code{member} extends the core @code{member} by\n"
1160 "accepting an equality predicate.")
1161 #define FUNC_NAME s_scm_srfi1_member
1162 {
1163 scm_t_trampoline_2 equal_p;
1164 SCM_VALIDATE_LIST (2, lst);
1165 if (SCM_UNBNDP (pred))
1166 equal_p = equal_trampoline;
1167 else
1168 {
1169 equal_p = scm_trampoline_2 (pred);
1170 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
1171 }
1172 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
1173 {
1174 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
1175 return lst;
1176 }
1177 return SCM_BOOL_F;
1178 }
1179 #undef FUNC_NAME
1180
1181 SCM_DEFINE (scm_srfi1_assoc, "assoc", 2, 1, 0,
1182 (SCM key, SCM alist, SCM pred),
1183 "Behaves like @code{assq} but uses third argument @var{pred?}\n"
1184 "for key comparison. If @var{pred?} is not supplied,\n"
1185 "@code{equal?} is used. (Extended from R5RS.)\n")
1186 #define FUNC_NAME s_scm_srfi1_assoc
1187 {
1188 SCM ls = alist;
1189 scm_t_trampoline_2 equal_p;
1190 if (SCM_UNBNDP (pred))
1191 equal_p = equal_trampoline;
1192 else
1193 {
1194 equal_p = scm_trampoline_2 (pred);
1195 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
1196 }
1197 for(; scm_is_pair (ls); ls = SCM_CDR (ls))
1198 {
1199 SCM tmp = SCM_CAR (ls);
1200 SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
1201 "association list");
1202 if (scm_is_true (equal_p (pred, SCM_CAR (tmp), key)))
1203 return tmp;
1204 }
1205 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
1206 "association list");
1207 return SCM_BOOL_F;
1208 }
1209 #undef FUNC_NAME
1210
1211
1212 SCM_DEFINE (scm_srfi1_ninth, "ninth", 1, 0, 0,
1213 (SCM lst),
1214 "Return the ninth element of @var{lst}.")
1215 #define FUNC_NAME s_scm_srfi1_ninth
1216 {
1217 return scm_list_ref (lst, SCM_I_MAKINUM (8));
1218 }
1219 #undef FUNC_NAME
1220
1221
1222 SCM_DEFINE (scm_srfi1_partition, "partition", 2, 0, 0,
1223 (SCM pred, SCM list),
1224 "Partition the elements of @var{list} with predicate @var{pred}.\n"
1225 "Return two values: the list of elements satifying @var{pred} and\n"
1226 "the list of elements @emph{not} satisfying @var{pred}. The order\n"
1227 "of the output lists follows the order of @var{list}. @var{list}\n"
1228 "is not mutated. One of the output lists may share memory with @var{list}.\n")
1229 #define FUNC_NAME s_scm_srfi1_partition
1230 {
1231 /* In this implementation, the output lists don't share memory with
1232 list, because it's probably not worth the effort. */
1233 scm_t_trampoline_1 call = scm_trampoline_1(pred);
1234 SCM kept = scm_cons(SCM_EOL, SCM_EOL);
1235 SCM kept_tail = kept;
1236 SCM dropped = scm_cons(SCM_EOL, SCM_EOL);
1237 SCM dropped_tail = dropped;
1238
1239 SCM_ASSERT(call, pred, 2, FUNC_NAME);
1240
1241 for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR(list)) {
1242 SCM elt = SCM_CAR(list);
1243 SCM new_tail = scm_cons(SCM_CAR(list), SCM_EOL);
1244 if (scm_is_true (call (pred, elt))) {
1245 SCM_SETCDR(kept_tail, new_tail);
1246 kept_tail = new_tail;
1247 }
1248 else {
1249 SCM_SETCDR(dropped_tail, new_tail);
1250 dropped_tail = new_tail;
1251 }
1252 }
1253 /* re-use the initial conses for the values list */
1254 SCM_SETCAR(kept, SCM_CDR(kept));
1255 SCM_SETCDR(kept, dropped);
1256 SCM_SETCAR(dropped, SCM_CDR(dropped));
1257 SCM_SETCDR(dropped, SCM_EOL);
1258 return scm_values(kept);
1259 }
1260 #undef FUNC_NAME
1261
1262
1263 SCM_DEFINE (scm_srfi1_partition_x, "partition!", 2, 0, 0,
1264 (SCM pred, SCM lst),
1265 "Split @var{lst} into those elements which do and don't satisfy\n"
1266 "the predicate @var{pred}.\n"
1267 "\n"
1268 "The return is two values (@pxref{Multiple Values}), the first\n"
1269 "being a list of all elements from @var{lst} which satisfy\n"
1270 "@var{pred}, the second a list of those which do not.\n"
1271 "\n"
1272 "The elements in the result lists are in the same order as in\n"
1273 "@var{lst} but the order in which the calls @code{(@var{pred}\n"
1274 "elem)} are made on the list elements is unspecified.\n"
1275 "\n"
1276 "@var{lst} may be modified to construct the return lists.")
1277 #define FUNC_NAME s_scm_srfi1_partition_x
1278 {
1279 SCM tlst, flst, *tp, *fp;
1280 scm_t_trampoline_1 pred_tramp;
1281
1282 pred_tramp = scm_trampoline_1 (pred);
1283 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1284
1285 /* tlst and flst are the lists of true and false elements. tp and fp are
1286 where to store to append to them, initially &tlst and &flst, then
1287 SCM_CDRLOC of the last pair in the respective lists. */
1288
1289 tlst = SCM_EOL;
1290 flst = SCM_EOL;
1291 tp = &tlst;
1292 fp = &flst;
1293
1294 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1295 {
1296 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
1297 {
1298 *tp = lst;
1299 tp = SCM_CDRLOC (lst);
1300 }
1301 else
1302 {
1303 *fp = lst;
1304 fp = SCM_CDRLOC (lst);
1305 }
1306 }
1307
1308 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1309
1310 /* terminate whichever didn't get the last element(s) */
1311 *tp = SCM_EOL;
1312 *fp = SCM_EOL;
1313
1314 return scm_values (scm_list_2 (tlst, flst));
1315 }
1316 #undef FUNC_NAME
1317
1318
1319 SCM_DEFINE (scm_srfi1_reduce, "reduce", 3, 0, 0,
1320 (SCM proc, SCM def, SCM lst),
1321 "@code{reduce} is a variant of @code{fold}, where the first call\n"
1322 "to @var{proc} is on two elements from @var{lst}, rather than\n"
1323 "one element and a given initial value.\n"
1324 "\n"
1325 "If @var{lst} is empty, @code{reduce} returns @var{def} (this is\n"
1326 "the only use for @var{def}). If @var{lst} has just one element\n"
1327 "then that's the return value. Otherwise @var{proc} is called\n"
1328 "on the elements of @var{lst}.\n"
1329 "\n"
1330 "Each @var{proc} call is @code{(@var{proc} @var{elem}\n"
1331 "@var{previous})}, where @var{elem} is from @var{lst} (the\n"
1332 "second and subsequent elements of @var{lst}), and\n"
1333 "@var{previous} is the return from the previous call to\n"
1334 "@var{proc}. The first element of @var{lst} is the\n"
1335 "@var{previous} for the first call to @var{proc}.\n"
1336 "\n"
1337 "For example, the following adds a list of numbers, the calls\n"
1338 "made to @code{+} are shown. (Of course @code{+} accepts\n"
1339 "multiple arguments and can add a list directly, with\n"
1340 "@code{apply}.)\n"
1341 "\n"
1342 "@example\n"
1343 "(reduce + 0 '(5 6 7)) @result{} 18\n"
1344 "\n"
1345 "(+ 6 5) @result{} 11\n"
1346 "(+ 7 11) @result{} 18\n"
1347 "@end example\n"
1348 "\n"
1349 "@code{reduce} can be used instead of @code{fold} where the\n"
1350 "@var{init} value is an ``identity'', meaning a value which\n"
1351 "under @var{proc} doesn't change the result, in this case 0 is\n"
1352 "an identity since @code{(+ 5 0)} is just 5. @code{reduce}\n"
1353 "avoids that unnecessary call.")
1354 #define FUNC_NAME s_scm_srfi1_reduce
1355 {
1356 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
1357 SCM ret;
1358
1359 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
1360
1361 ret = def; /* if lst is empty */
1362 if (scm_is_pair (lst))
1363 {
1364 ret = SCM_CAR (lst); /* if lst has one element */
1365
1366 for (lst = SCM_CDR (lst); scm_is_pair (lst); lst = SCM_CDR (lst))
1367 ret = proc_tramp (proc, SCM_CAR (lst), ret);
1368 }
1369
1370 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG3, FUNC_NAME, "list");
1371 return ret;
1372 }
1373 #undef FUNC_NAME
1374
1375
1376 SCM_DEFINE (scm_srfi1_reduce_right, "reduce-right", 3, 0, 0,
1377 (SCM proc, SCM def, SCM lst),
1378 "@code{reduce-right} is a variant of @code{fold-right}, where\n"
1379 "the first call to @var{proc} is on two elements from @var{lst},\n"
1380 "rather than one element and a given initial value.\n"
1381 "\n"
1382 "If @var{lst} is empty, @code{reduce-right} returns @var{def}\n"
1383 "(this is the only use for @var{def}). If @var{lst} has just\n"
1384 "one element then that's the return value. Otherwise @var{proc}\n"
1385 "is called on the elements of @var{lst}.\n"
1386 "\n"
1387 "Each @var{proc} call is @code{(@var{proc} @var{elem}\n"
1388 "@var{previous})}, where @var{elem} is from @var{lst} (the\n"
1389 "second last and then working back to the first element of\n"
1390 "@var{lst}), and @var{previous} is the return from the previous\n"
1391 "call to @var{proc}. The last element of @var{lst} is the\n"
1392 "@var{previous} for the first call to @var{proc}.\n"
1393 "\n"
1394 "For example, the following adds a list of numbers, the calls\n"
1395 "made to @code{+} are shown. (Of course @code{+} accepts\n"
1396 "multiple arguments and can add a list directly, with\n"
1397 "@code{apply}.)\n"
1398 "\n"
1399 "@example\n"
1400 "(reduce-right + 0 '(5 6 7)) @result{} 18\n"
1401 "\n"
1402 "(+ 6 7) @result{} 13\n"
1403 "(+ 5 13) @result{} 18\n"
1404 "@end example\n"
1405 "\n"
1406 "@code{reduce-right} can be used instead of @code{fold-right}\n"
1407 "where the @var{init} value is an ``identity'', meaning a value\n"
1408 "which under @var{proc} doesn't change the result, in this case\n"
1409 "0 is an identity since @code{(+ 7 0)} is just 5.\n"
1410 "@code{reduce-right} avoids that unnecessary call.\n"
1411 "\n"
1412 "@code{reduce} should be preferred over @code{reduce-right} if\n"
1413 "the order of processing doesn't matter, or can be arranged\n"
1414 "either way, since @code{reduce} is a little more efficient.")
1415 #define FUNC_NAME s_scm_srfi1_reduce_right
1416 {
1417 /* To work backwards across a list requires either repeatedly traversing
1418 to get each previous element, or using some memory for a reversed or
1419 random-access form. Repeated traversal might not be too terrible, but
1420 is of course quadratic complexity and hence to be avoided in case LST
1421 is long. A vector is preferred over a reversed list since it's more
1422 compact and is less work for the gc to collect. */
1423
1424 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
1425 SCM ret, vec;
1426 long len, i;
1427
1428 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
1429
1430 if (SCM_NULL_OR_NIL_P (lst))
1431 return def;
1432
1433 vec = scm_vector (lst);
1434 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
1435
1436 ret = SCM_SIMPLE_VECTOR_REF (vec, len-1);
1437 for (i = len-2; i >= 0; i--)
1438 ret = proc_tramp (proc, SCM_SIMPLE_VECTOR_REF (vec, i), ret);
1439
1440 return ret;
1441 }
1442 #undef FUNC_NAME
1443
1444
1445 SCM_DEFINE (scm_srfi1_remove, "remove", 2, 0, 0,
1446 (SCM pred, SCM list),
1447 "Return a list containing all elements from @var{lst} which do\n"
1448 "not satisfy the predicate @var{pred}. The elements in the\n"
1449 "result list have the same order as in @var{lst}. The order in\n"
1450 "which @var{pred} is applied to the list elements is not\n"
1451 "specified.")
1452 #define FUNC_NAME s_scm_srfi1_remove
1453 {
1454 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1455 SCM walk;
1456 SCM *prev;
1457 SCM res = SCM_EOL;
1458 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1459 SCM_VALIDATE_LIST (2, list);
1460
1461 for (prev = &res, walk = list;
1462 scm_is_pair (walk);
1463 walk = SCM_CDR (walk))
1464 {
1465 if (scm_is_false (call (pred, SCM_CAR (walk))))
1466 {
1467 *prev = scm_cons (SCM_CAR (walk), SCM_EOL);
1468 prev = SCM_CDRLOC (*prev);
1469 }
1470 }
1471
1472 return res;
1473 }
1474 #undef FUNC_NAME
1475
1476
1477 SCM_DEFINE (scm_srfi1_remove_x, "remove!", 2, 0, 0,
1478 (SCM pred, SCM list),
1479 "Return a list containing all elements from @var{list} which do\n"
1480 "not satisfy the predicate @var{pred}. The elements in the\n"
1481 "result list have the same order as in @var{list}. The order in\n"
1482 "which @var{pred} is applied to the list elements is not\n"
1483 "specified. @var{list} may be modified to build the return\n"
1484 "list.")
1485 #define FUNC_NAME s_scm_srfi1_remove_x
1486 {
1487 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1488 SCM walk;
1489 SCM *prev;
1490 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1491 SCM_VALIDATE_LIST (2, list);
1492
1493 for (prev = &list, walk = list;
1494 scm_is_pair (walk);
1495 walk = SCM_CDR (walk))
1496 {
1497 if (scm_is_false (call (pred, SCM_CAR (walk))))
1498 prev = SCM_CDRLOC (walk);
1499 else
1500 *prev = SCM_CDR (walk);
1501 }
1502
1503 return list;
1504 }
1505 #undef FUNC_NAME
1506
1507
1508 SCM_DEFINE (scm_srfi1_seventh, "seventh", 1, 0, 0,
1509 (SCM lst),
1510 "Return the seventh element of @var{lst}.")
1511 #define FUNC_NAME s_scm_srfi1_seventh
1512 {
1513 return scm_list_ref (lst, SCM_I_MAKINUM (6));
1514 }
1515 #undef FUNC_NAME
1516
1517
1518 SCM_DEFINE (scm_srfi1_sixth, "sixth", 1, 0, 0,
1519 (SCM lst),
1520 "Return the sixth element of @var{lst}.")
1521 #define FUNC_NAME s_scm_srfi1_sixth
1522 {
1523 return scm_list_ref (lst, SCM_I_MAKINUM (5));
1524 }
1525 #undef FUNC_NAME
1526
1527
1528 SCM_DEFINE (scm_srfi1_span, "span", 2, 0, 0,
1529 (SCM pred, SCM lst),
1530 "Return two values, the longest initial prefix of @var{lst}\n"
1531 "whose elements all satisfy the predicate @var{pred}, and the\n"
1532 "remainder of @var{lst}.")
1533 #define FUNC_NAME s_scm_srfi1_span
1534 {
1535 scm_t_trampoline_1 pred_tramp;
1536 SCM ret, *p;
1537
1538 pred_tramp = scm_trampoline_1 (pred);
1539 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1540
1541 ret = SCM_EOL;
1542 p = &ret;
1543 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1544 {
1545 SCM elem = SCM_CAR (lst);
1546 if (scm_is_false (pred_tramp (pred, elem)))
1547 goto done;
1548
1549 /* want this elem, tack it onto the end of ret */
1550 *p = scm_cons (elem, SCM_EOL);
1551 p = SCM_CDRLOC (*p);
1552 }
1553 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1554
1555 done:
1556 return scm_values (scm_list_2 (ret, lst));
1557 }
1558 #undef FUNC_NAME
1559
1560
1561 SCM_DEFINE (scm_srfi1_span_x, "span!", 2, 0, 0,
1562 (SCM pred, SCM lst),
1563 "Return two values, the longest initial prefix of @var{lst}\n"
1564 "whose elements all satisfy the predicate @var{pred}, and the\n"
1565 "remainder of @var{lst}. @var{lst} may be modified to form the\n"
1566 "return.")
1567 #define FUNC_NAME s_scm_srfi1_span_x
1568 {
1569 SCM upto, *p;
1570 scm_t_trampoline_1 pred_tramp;
1571
1572 pred_tramp = scm_trampoline_1 (pred);
1573 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1574
1575 p = &lst;
1576 for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
1577 {
1578 if (scm_is_false (pred_tramp (pred, SCM_CAR (upto))))
1579 goto done;
1580
1581 /* want this element */
1582 p = SCM_CDRLOC (upto);
1583 }
1584 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
1585
1586 done:
1587 *p = SCM_EOL;
1588 return scm_values (scm_list_2 (lst, upto));
1589 }
1590 #undef FUNC_NAME
1591
1592
1593 SCM_DEFINE (scm_srfi1_split_at, "split-at", 2, 0, 0,
1594 (SCM lst, SCM n),
1595 "Return two values (multiple values), being a list of the\n"
1596 "elements before index @var{n} in @var{lst}, and a list of those\n"
1597 "after.")
1598 #define FUNC_NAME s_scm_srfi1_split_at
1599 {
1600 size_t nn;
1601 /* pre is a list of elements before the i split point, loc is the CDRLOC
1602 of the last cell, ie. where to store to append to it */
1603 SCM pre = SCM_EOL;
1604 SCM *loc = &pre;
1605
1606 for (nn = scm_to_size_t (n); nn != 0; nn--)
1607 {
1608 SCM_VALIDATE_CONS (SCM_ARG1, lst);
1609
1610 *loc = scm_cons (SCM_CAR (lst), SCM_EOL);
1611 loc = SCM_CDRLOC (*loc);
1612 lst = SCM_CDR(lst);
1613 }
1614 return scm_values (scm_list_2 (pre, lst));
1615 }
1616 #undef FUNC_NAME
1617
1618
1619 SCM_DEFINE (scm_srfi1_split_at_x, "split-at!", 2, 0, 0,
1620 (SCM lst, SCM n),
1621 "Return two values (multiple values), being a list of the\n"
1622 "elements before index @var{n} in @var{lst}, and a list of those\n"
1623 "after. @var{lst} is modified to form those values.")
1624 #define FUNC_NAME s_scm_srfi1_split_at
1625 {
1626 size_t nn;
1627 SCM upto = lst;
1628 SCM *loc = &lst;
1629
1630 for (nn = scm_to_size_t (n); nn != 0; nn--)
1631 {
1632 SCM_VALIDATE_CONS (SCM_ARG1, upto);
1633
1634 loc = SCM_CDRLOC (upto);
1635 upto = SCM_CDR (upto);
1636 }
1637
1638 *loc = SCM_EOL;
1639 return scm_values (scm_list_2 (lst, upto));
1640 }
1641 #undef FUNC_NAME
1642
1643
1644 SCM_DEFINE (scm_srfi1_take_x, "take!", 2, 0, 0,
1645 (SCM lst, SCM n),
1646 "Return a list containing the first @var{n} elements of\n"
1647 "@var{lst}.")
1648 #define FUNC_NAME s_scm_srfi1_take_x
1649 {
1650 long nn;
1651 SCM pos;
1652
1653 SCM_VALIDATE_INUM_MIN_COPY (SCM_ARG2, n, 0, nn);
1654
1655 if (nn == 0)
1656 return SCM_EOL;
1657
1658 pos = scm_list_tail (lst, SCM_I_MAKINUM (nn - 1));
1659
1660 /* Must have at least one cell left, mustn't have reached the end of an
1661 n-1 element list. SCM_VALIDATE_CONS here gives the same error as
1662 scm_list_tail does on say an n-2 element list, though perhaps a range
1663 error would make more sense (for both). */
1664 SCM_VALIDATE_CONS (SCM_ARG1, pos);
1665
1666 SCM_SETCDR (pos, SCM_EOL);
1667 return lst;
1668 }
1669 #undef FUNC_NAME
1670
1671
1672 SCM_DEFINE (scm_srfi1_take_right, "take-right", 2, 0, 0,
1673 (SCM lst, SCM n),
1674 "Return the a list containing the @var{n} last elements of\n"
1675 "@var{lst}.")
1676 #define FUNC_NAME s_scm_srfi1_take_right
1677 {
1678 SCM tail = scm_list_tail (lst, n);
1679 while (scm_is_pair (tail))
1680 {
1681 lst = SCM_CDR (lst);
1682 tail = SCM_CDR (tail);
1683 }
1684 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
1685 return lst;
1686 }
1687 #undef FUNC_NAME
1688
1689
1690 SCM_DEFINE (scm_srfi1_take_while, "take-while", 2, 0, 0,
1691 (SCM pred, SCM lst),
1692 "Return a new list which is the longest initial prefix of\n"
1693 "@var{lst} whose elements all satisfy the predicate @var{pred}.")
1694 #define FUNC_NAME s_scm_srfi1_take_while
1695 {
1696 scm_t_trampoline_1 pred_tramp;
1697 SCM ret, *p;
1698
1699 pred_tramp = scm_trampoline_1 (pred);
1700 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1701
1702 ret = SCM_EOL;
1703 p = &ret;
1704 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1705 {
1706 SCM elem = SCM_CAR (lst);
1707 if (scm_is_false (pred_tramp (pred, elem)))
1708 goto done;
1709
1710 /* want this elem, tack it onto the end of ret */
1711 *p = scm_cons (elem, SCM_EOL);
1712 p = SCM_CDRLOC (*p);
1713 }
1714 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1715
1716 done:
1717 return ret;
1718 }
1719 #undef FUNC_NAME
1720
1721
1722 SCM_DEFINE (scm_srfi1_take_while_x, "take-while!", 2, 0, 0,
1723 (SCM pred, SCM lst),
1724 "Return the longest initial prefix of @var{lst} whose elements\n"
1725 "all satisfy the predicate @var{pred}. @var{lst} may be\n"
1726 "modified to form the return.")
1727 #define FUNC_NAME s_scm_srfi1_take_while_x
1728 {
1729 SCM upto, *p;
1730 scm_t_trampoline_1 pred_tramp;
1731
1732 pred_tramp = scm_trampoline_1 (pred);
1733 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1734
1735 p = &lst;
1736 for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
1737 {
1738 if (scm_is_false (pred_tramp (pred, SCM_CAR (upto))))
1739 goto done;
1740
1741 /* want this element */
1742 p = SCM_CDRLOC (upto);
1743 }
1744 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
1745
1746 done:
1747 *p = SCM_EOL;
1748 return lst;
1749 }
1750 #undef FUNC_NAME
1751
1752
1753 SCM_DEFINE (scm_srfi1_tenth, "tenth", 1, 0, 0,
1754 (SCM lst),
1755 "Return the tenth element of @var{lst}.")
1756 #define FUNC_NAME s_scm_srfi1_tenth
1757 {
1758 return scm_list_ref (lst, SCM_I_MAKINUM (9));
1759 }
1760 #undef FUNC_NAME
1761
1762
1763 void
1764 scm_init_srfi_1 (void)
1765 {
1766 SCM the_root_module = scm_lookup_closure_module (SCM_BOOL_F);
1767 #ifndef SCM_MAGIC_SNARFER
1768 #include "srfi/srfi-1.x"
1769 #endif
1770 scm_c_extend_primitive_generic
1771 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "map")),
1772 SCM_VARIABLE_REF (scm_c_lookup ("map")));
1773 scm_c_extend_primitive_generic
1774 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "for-each")),
1775 SCM_VARIABLE_REF (scm_c_lookup ("for-each")));
1776 }
1777
1778 /* End of srfi-1.c. */