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