* srfi-1.scm (filter, filter!): Removed. (Now implemented in the core.)
[bpt/guile.git] / libguile / list.c
CommitLineData
c614a00b 1/* Copyright (C) 1995,1996,1997,2000,2001, 2003 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84 41
1bbd0b84 42
0f2d19dd 43\f
a0599745
MD
44#include "libguile/_scm.h"
45#include "libguile/eq.h"
c96d76b8 46#include "libguile/lang.h"
20e6290e 47
a0599745
MD
48#include "libguile/validate.h"
49#include "libguile/list.h"
c614a00b 50#include "libguile/eval.h"
0f2d19dd
JB
51
52#ifdef __STDC__
53#include <stdarg.h>
54#define var_start(x, y) va_start(x, y)
55#else
56#include <varargs.h>
57#define var_start(x, y) va_start(x)
58#endif
59
60\f
df13742c 61/* creating lists */
0f2d19dd 62
34d19ef6 63#define SCM_I_CONS(cell, x, y) \
1afff620 64do { \
228a24ef 65 cell = scm_cell ((scm_t_bits)x, (scm_t_bits)y); \
1afff620
KN
66} while (0)
67
68SCM
69scm_list_1 (SCM e1)
70{
71 SCM c1;
72 SCM_I_CONS (c1, e1, SCM_EOL);
73 return c1;
74}
75
76SCM
77scm_list_2 (SCM e1, SCM e2)
78{
79 SCM c1, c2;
80 SCM_I_CONS (c2, e2, SCM_EOL);
81 SCM_I_CONS (c1, e1, c2);
82 return c1;
83}
84
85SCM
86scm_list_3 (SCM e1, SCM e2, SCM e3)
87{
88 SCM c1, c2, c3;
89 SCM_I_CONS (c3, e3, SCM_EOL);
90 SCM_I_CONS (c2, e2, c3);
91 SCM_I_CONS (c1, e1, c2);
92 return c1;
93}
94
95SCM
96scm_list_4 (SCM e1, SCM e2, SCM e3, SCM e4)
97{
98 return scm_cons2 (e1, e2, scm_list_2 (e3, e4));
99}
100
101SCM
102scm_list_5 (SCM e1, SCM e2, SCM e3, SCM e4, SCM e5)
103{
104 return scm_cons2 (e1, e2, scm_list_3 (e3, e4, e5));
105}
106
0f2d19dd 107SCM
1afff620 108scm_list_n (SCM elt, ...)
0f2d19dd
JB
109{
110 va_list foo;
2de14ecd
GB
111 SCM answer = SCM_EOL;
112 SCM *pos = &answer;
0f2d19dd
JB
113
114 var_start (foo, elt);
fbd485ba 115 while (! SCM_UNBNDP (elt))
0f2d19dd
JB
116 {
117 *pos = scm_cons (elt, SCM_EOL);
25d8012c 118 pos = SCM_CDRLOC (*pos);
0f2d19dd
JB
119 elt = va_arg (foo, SCM);
120 }
121 return answer;
122}
123
124
3b3b36dd 125SCM_DEFINE (scm_list, "list", 0, 0, 1,
1bbd0b84 126 (SCM objs),
5352393c
MG
127 "Return a list containing @var{objs}, the arguments to\n"
128 "@code{list}.")
1bbd0b84 129#define FUNC_NAME s_scm_list
0f2d19dd
JB
130{
131 return objs;
132}
1bbd0b84 133#undef FUNC_NAME
0f2d19dd
JB
134
135
26a379b2 136SCM_DEFINE (scm_cons_star, "cons*", 1, 0, 1,
1bbd0b84 137 (SCM arg, SCM rest),
5352393c
MG
138 "Like @code{list}, but the last arg provides the tail of the\n"
139 "constructed list, returning @code{(cons @var{arg1} (cons\n"
a17bb5fd 140 "@var{arg2} (cons @dots{} @var{argn})))}. Requires at least one\n"
5352393c
MG
141 "argument. If given one argument, that argument is returned as\n"
142 "result. This function is called @code{list*} in some other\n"
143 "Schemes and in Common LISP.")
26a379b2 144#define FUNC_NAME s_scm_cons_star
a610b8d9 145{
af45e3b0
DH
146 SCM_VALIDATE_REST_ARGUMENT (rest);
147 if (!SCM_NULLP (rest))
a610b8d9
MD
148 {
149 SCM prev = arg = scm_cons (arg, rest);
e1385ffc 150 while (SCM_NNULLP (SCM_CDR (rest)))
a610b8d9
MD
151 {
152 prev = rest;
153 rest = SCM_CDR (rest);
154 }
155 SCM_SETCDR (prev, SCM_CAR (rest));
156 }
157 return arg;
158}
1bbd0b84 159#undef FUNC_NAME
a610b8d9 160
0f2d19dd
JB
161
162\f
df13742c 163/* general questions about lists --- null?, list?, length, etc. */
0f2d19dd 164
3b3b36dd 165SCM_DEFINE (scm_null_p, "null?", 1, 0, 0,
1bbd0b84 166 (SCM x),
5352393c 167 "Return @code{#t} iff @var{x} is the empty list, else @code{#f}.")
1bbd0b84 168#define FUNC_NAME s_scm_null_p
0f2d19dd 169{
c96d76b8 170 return SCM_BOOL (SCM_NULL_OR_NIL_P (x));
0f2d19dd 171}
1bbd0b84 172#undef FUNC_NAME
0f2d19dd 173
2de14ecd 174
3b3b36dd 175SCM_DEFINE (scm_list_p, "list?", 1, 0, 0,
1bbd0b84 176 (SCM x),
5352393c 177 "Return @code{#t} iff @var{x} is a proper list, else @code{#f}.")
1bbd0b84 178#define FUNC_NAME s_scm_list_p
0f2d19dd 179{
2de14ecd 180 return SCM_BOOL (scm_ilength (x) >= 0);
0f2d19dd 181}
1bbd0b84 182#undef FUNC_NAME
0f2d19dd
JB
183
184
df13742c 185/* Return the length of SX, or -1 if it's not a proper list.
448a3bc2 186 This uses the "tortoise and hare" algorithm to detect "infinitely
df13742c
JB
187 long" lists (i.e. lists with cycles in their cdrs), and returns -1
188 if it does find one. */
c014a02e
ML
189long
190scm_ilength(SCM sx)
0f2d19dd 191{
c014a02e 192 long i = 0;
e1385ffc
GB
193 SCM tortoise = sx;
194 SCM hare = sx;
df13742c 195
0f2d19dd 196 do {
c96d76b8 197 if (SCM_NULL_OR_NIL_P(hare)) return i;
ff467021 198 if (SCM_NCONSP(hare)) return -1;
df13742c 199 hare = SCM_CDR(hare);
0f2d19dd 200 i++;
c96d76b8 201 if (SCM_NULL_OR_NIL_P(hare)) return i;
ff467021 202 if (SCM_NCONSP(hare)) return -1;
df13742c 203 hare = SCM_CDR(hare);
0f2d19dd 204 i++;
448a3bc2
JB
205 /* For every two steps the hare takes, the tortoise takes one. */
206 tortoise = SCM_CDR(tortoise);
0f2d19dd 207 }
fbd485ba 208 while (! SCM_EQ_P (hare, tortoise));
df13742c 209
448a3bc2 210 /* If the tortoise ever catches the hare, then the list must contain
df13742c 211 a cycle. */
0f2d19dd
JB
212 return -1;
213}
214
2de14ecd 215
3b3b36dd 216SCM_DEFINE (scm_length, "length", 1, 0, 0,
1bbd0b84 217 (SCM lst),
5352393c 218 "Return the number of elements in list @var{lst}.")
1bbd0b84 219#define FUNC_NAME s_scm_length
0f2d19dd 220{
c014a02e 221 long i;
34d19ef6 222 SCM_VALIDATE_LIST_COPYLEN (1, lst, i);
0f2d19dd
JB
223 return SCM_MAKINUM (i);
224}
1bbd0b84 225#undef FUNC_NAME
0f2d19dd
JB
226
227
228\f
df13742c 229/* appending lists */
0f2d19dd 230
a1ec6916 231SCM_DEFINE (scm_append, "append", 0, 0, 1,
1bbd0b84 232 (SCM args),
5352393c
MG
233 "Return a list consisting of the elements the lists passed as\n"
234 "arguments.\n"
1e6808ea 235 "@lisp\n"
5352393c
MG
236 "(append '(x) '(y)) @result{} (x y)\n"
237 "(append '(a) '(b c d)) @result{} (a b c d)\n"
238 "(append '(a (b)) '((c))) @result{} (a (b) (c))\n"
1e6808ea 239 "@end lisp\n"
5352393c
MG
240 "The resulting list is always newly allocated, except that it\n"
241 "shares structure with the last list argument. The last\n"
242 "argument may actually be any object; an improper list results\n"
243 "if the last argument is not a proper list.\n"
1e6808ea 244 "@lisp\n"
5352393c
MG
245 "(append '(a b) '(c . d)) @result{} (a b c . d)\n"
246 "(append '() 'a) @result{} a\n"
1e6808ea 247 "@end lisp")
1bbd0b84 248#define FUNC_NAME s_scm_append
0f2d19dd 249{
af45e3b0
DH
250 SCM_VALIDATE_REST_ARGUMENT (args);
251 if (SCM_NULLP (args)) {
252 return SCM_EOL;
253 } else {
254 SCM res = SCM_EOL;
255 SCM *lloc = &res;
256 SCM arg = SCM_CAR (args);
257 args = SCM_CDR (args);
258 while (!SCM_NULLP (args)) {
259 while (SCM_CONSP (arg)) {
260 *lloc = scm_cons (SCM_CAR (arg), SCM_EOL);
261 lloc = SCM_CDRLOC (*lloc);
262 arg = SCM_CDR (arg);
263 }
c96d76b8 264 SCM_VALIDATE_NULL_OR_NIL (SCM_ARGn, arg);
af45e3b0
DH
265 arg = SCM_CAR (args);
266 args = SCM_CDR (args);
267 };
268 *lloc = arg;
0f2d19dd
JB
269 return res;
270 }
0f2d19dd 271}
1bbd0b84 272#undef FUNC_NAME
0f2d19dd
JB
273
274
a1ec6916 275SCM_DEFINE (scm_append_x, "append!", 0, 0, 1,
1e6808ea
MG
276 (SCM lists),
277 "A destructive version of @code{append} (@pxref{Pairs and\n"
7a095584 278 "Lists,,,r5rs, The Revised^5 Report on Scheme}). The cdr field\n"
1e6808ea
MG
279 "of each list's final pair is changed to point to the head of\n"
280 "the next list, so no consing is performed. Return a pointer to\n"
281 "the mutated list.")
1bbd0b84 282#define FUNC_NAME s_scm_append_x
0f2d19dd 283{
1e6808ea 284 SCM_VALIDATE_REST_ARGUMENT (lists);
af45e3b0 285 while (1) {
1e6808ea 286 if (SCM_NULLP (lists)) {
af45e3b0
DH
287 return SCM_EOL;
288 } else {
1e6808ea
MG
289 SCM arg = SCM_CAR (lists);
290 lists = SCM_CDR (lists);
291 if (SCM_NULLP (lists)) {
af45e3b0 292 return arg;
c96d76b8 293 } else if (!SCM_NULL_OR_NIL_P (arg)) {
af45e3b0 294 SCM_VALIDATE_CONS (SCM_ARG1, arg);
1e6808ea 295 SCM_SETCDR (scm_last_pair (arg), scm_append_x (lists));
af45e3b0
DH
296 return arg;
297 }
298 }
299 }
0f2d19dd 300}
1bbd0b84 301#undef FUNC_NAME
0f2d19dd
JB
302
303
3b3b36dd 304SCM_DEFINE (scm_last_pair, "last-pair", 1, 0, 0,
e1385ffc 305 (SCM lst),
b380b885
MD
306 "Return a pointer to the last pair in @var{lst}, signalling an error if\n"
307 "@var{lst} is circular.")
1bbd0b84 308#define FUNC_NAME s_scm_last_pair
df13742c 309{
e1385ffc
GB
310 SCM tortoise = lst;
311 SCM hare = lst;
0f2d19dd 312
c96d76b8
NJ
313 if (SCM_NULL_OR_NIL_P (lst))
314 return lst;
df13742c 315
e1385ffc
GB
316 SCM_VALIDATE_CONS (SCM_ARG1, lst);
317 do {
318 SCM ahead = SCM_CDR(hare);
319 if (SCM_NCONSP(ahead)) return hare;
320 hare = ahead;
321 ahead = SCM_CDR(hare);
322 if (SCM_NCONSP(ahead)) return hare;
323 hare = ahead;
324 tortoise = SCM_CDR(tortoise);
df13742c 325 }
fbd485ba 326 while (! SCM_EQ_P (hare, tortoise));
1afff620 327 SCM_MISC_ERROR ("Circular structure in position 1: ~S", scm_list_1 (lst));
df13742c 328}
1bbd0b84 329#undef FUNC_NAME
df13742c
JB
330
331\f
332/* reversing lists */
0f2d19dd 333
a1ec6916 334SCM_DEFINE (scm_reverse, "reverse", 1, 0, 0,
e1385ffc 335 (SCM lst),
5352393c
MG
336 "Return a new list that contains the elements of @var{lst} but\n"
337 "in reverse order.")
e1385ffc
GB
338#define FUNC_NAME s_scm_reverse
339{
340 SCM result = SCM_EOL;
341 SCM tortoise = lst;
342 SCM hare = lst;
343
344 do {
c96d76b8 345 if (SCM_NULL_OR_NIL_P(hare)) return result;
e1385ffc
GB
346 SCM_ASSERT(SCM_CONSP(hare), lst, 1, FUNC_NAME);
347 result = scm_cons (SCM_CAR (hare), result);
348 hare = SCM_CDR (hare);
c96d76b8 349 if (SCM_NULL_OR_NIL_P(hare)) return result;
e1385ffc
GB
350 SCM_ASSERT(SCM_CONSP(hare), lst, 1, FUNC_NAME);
351 result = scm_cons (SCM_CAR (hare), result);
352 hare = SCM_CDR (hare);
353 tortoise = SCM_CDR (tortoise);
354 }
fbd485ba 355 while (! SCM_EQ_P (hare, tortoise));
1afff620 356 SCM_MISC_ERROR ("Circular structure in position 1: ~S", scm_list_1 (lst));
e1385ffc
GB
357}
358#undef FUNC_NAME
359
360SCM_DEFINE (scm_reverse_x, "reverse!", 1, 1, 0,
361 (SCM lst, SCM new_tail),
7a095584
NJ
362 "A destructive version of @code{reverse} (@pxref{Pairs and Lists,,,r5rs,\n"
363 "The Revised^5 Report on Scheme}). The cdr of each cell in @var{lst} is\n"
b380b885
MD
364 "modified to point to the previous list element. Return a pointer to the\n"
365 "head of the reversed list.\n\n"
366 "Caveat: because the list is modified in place, the tail of the original\n"
367 "list now becomes its head, and the head of the original list now becomes\n"
368 "the tail. Therefore, the @var{lst} symbol to which the head of the\n"
369 "original list was bound now points to the tail. To ensure that the head\n"
370 "of the modified list is not lost, it is wise to save the return value of\n"
371 "@code{reverse!}")
1bbd0b84 372#define FUNC_NAME s_scm_reverse_x
0f2d19dd 373{
e39c3de4 374 SCM_VALIDATE_LIST (1, lst);
3946f0de
MD
375 if (SCM_UNBNDP (new_tail))
376 new_tail = SCM_EOL;
377 else
e39c3de4 378 SCM_VALIDATE_LIST (2, new_tail);
0f2d19dd 379
c96d76b8 380 while (!SCM_NULL_OR_NIL_P (lst))
3946f0de 381 {
e1385ffc
GB
382 SCM old_tail = SCM_CDR (lst);
383 SCM_SETCDR (lst, new_tail);
384 new_tail = lst;
385 lst = old_tail;
3946f0de
MD
386 }
387 return new_tail;
0f2d19dd 388}
1bbd0b84 389#undef FUNC_NAME
0f2d19dd 390
0f2d19dd 391\f
685c0d71 392
df13742c 393/* indexing lists by element number */
0f2d19dd 394
3b3b36dd 395SCM_DEFINE (scm_list_ref, "list-ref", 2, 0, 0,
685c0d71 396 (SCM list, SCM k),
5352393c 397 "Return the @var{k}th element from @var{list}.")
1bbd0b84
GB
398#define FUNC_NAME s_scm_list_ref
399{
685c0d71 400 SCM lst = list;
c014a02e 401 unsigned long int i;
34d19ef6 402 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
685c0d71
DH
403 while (SCM_CONSP (lst)) {
404 if (i == 0)
405 return SCM_CAR (lst);
406 else {
407 --i;
408 lst = SCM_CDR (lst);
409 }
410 };
c96d76b8 411 if (SCM_NULL_OR_NIL_P (lst))
685c0d71
DH
412 SCM_OUT_OF_RANGE (2, k);
413 else
414 SCM_WRONG_TYPE_ARG (1, list);
0f2d19dd 415}
1bbd0b84 416#undef FUNC_NAME
0f2d19dd 417
685c0d71 418
3b3b36dd 419SCM_DEFINE (scm_list_set_x, "list-set!", 3, 0, 0,
685c0d71
DH
420 (SCM list, SCM k, SCM val),
421 "Set the @var{k}th element of @var{list} to @var{val}.")
1bbd0b84
GB
422#define FUNC_NAME s_scm_list_set_x
423{
685c0d71 424 SCM lst = list;
c014a02e 425 unsigned long int i;
34d19ef6 426 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
685c0d71
DH
427 while (SCM_CONSP (lst)) {
428 if (i == 0) {
429 SCM_SETCAR (lst, val);
430 return val;
431 } else {
432 --i;
433 lst = SCM_CDR (lst);
434 }
435 };
c96d76b8 436 if (SCM_NULL_OR_NIL_P (lst))
685c0d71
DH
437 SCM_OUT_OF_RANGE (2, k);
438 else
439 SCM_WRONG_TYPE_ARG (1, list);
0f2d19dd 440}
1bbd0b84 441#undef FUNC_NAME
0f2d19dd
JB
442
443
1bbd0b84
GB
444SCM_REGISTER_PROC(s_list_cdr_ref, "list-cdr-ref", 2, 0, 0, scm_list_tail);
445
3b3b36dd 446SCM_DEFINE (scm_list_tail, "list-tail", 2, 0, 0,
1bbd0b84 447 (SCM lst, SCM k),
8f85c0c6 448 "@deffnx {Scheme Procedure} list-cdr-ref lst k\n"
b380b885
MD
449 "Return the \"tail\" of @var{lst} beginning with its @var{k}th element.\n"
450 "The first element of the list is considered to be element 0.\n\n"
872e0c72 451 "@code{list-tail} and @code{list-cdr-ref} are identical. It may help to\n"
b380b885
MD
452 "think of @code{list-cdr-ref} as accessing the @var{k}th cdr of the list,\n"
453 "or returning the results of cdring @var{k} times down @var{lst}.")
1bbd0b84 454#define FUNC_NAME s_scm_list_tail
df13742c 455{
c014a02e 456 register long i;
34d19ef6 457 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
df13742c 458 while (i-- > 0) {
34d19ef6 459 SCM_VALIDATE_CONS (1, lst);
df13742c
JB
460 lst = SCM_CDR(lst);
461 }
462 return lst;
463}
1bbd0b84 464#undef FUNC_NAME
df13742c 465
0f2d19dd 466
3b3b36dd 467SCM_DEFINE (scm_list_cdr_set_x, "list-cdr-set!", 3, 0, 0,
685c0d71
DH
468 (SCM list, SCM k, SCM val),
469 "Set the @var{k}th cdr of @var{list} to @var{val}.")
1bbd0b84
GB
470#define FUNC_NAME s_scm_list_cdr_set_x
471{
685c0d71 472 SCM lst = list;
c014a02e 473 unsigned long int i;
34d19ef6 474 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
685c0d71
DH
475 while (SCM_CONSP (lst)) {
476 if (i == 0) {
477 SCM_SETCDR (lst, val);
478 return val;
479 } else {
480 --i;
481 lst = SCM_CDR (lst);
482 }
483 };
c96d76b8 484 if (SCM_NULL_OR_NIL_P (lst))
685c0d71
DH
485 SCM_OUT_OF_RANGE (2, k);
486 else
487 SCM_WRONG_TYPE_ARG (1, list);
0f2d19dd 488}
1bbd0b84 489#undef FUNC_NAME
0f2d19dd
JB
490
491
492\f
df13742c 493/* copying lists, perhaps partially */
0f2d19dd 494
3b3b36dd 495SCM_DEFINE (scm_list_head, "list-head", 2, 0, 0,
1bbd0b84 496 (SCM lst, SCM k),
b380b885
MD
497 "Copy the first @var{k} elements from @var{lst} into a new list, and\n"
498 "return it.")
1bbd0b84 499#define FUNC_NAME s_scm_list_head
0f2d19dd
JB
500{
501 SCM answer;
502 SCM * pos;
c014a02e 503 register long i;
0f2d19dd 504
34d19ef6 505 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
0f2d19dd
JB
506 answer = SCM_EOL;
507 pos = &answer;
0f2d19dd
JB
508 while (i-- > 0)
509 {
34d19ef6 510 SCM_VALIDATE_CONS (1, lst);
0f2d19dd 511 *pos = scm_cons (SCM_CAR (lst), SCM_EOL);
25d8012c 512 pos = SCM_CDRLOC (*pos);
0f2d19dd
JB
513 lst = SCM_CDR(lst);
514 }
515 return answer;
516}
1bbd0b84 517#undef FUNC_NAME
0f2d19dd
JB
518
519
a1ec6916 520SCM_DEFINE (scm_list_copy, "list-copy", 1, 0, 0,
1bbd0b84 521 (SCM lst),
b380b885 522 "Return a (newly-created) copy of @var{lst}.")
1bbd0b84 523#define FUNC_NAME s_scm_list_copy
df13742c
JB
524{
525 SCM newlst;
526 SCM * fill_here;
527 SCM from_here;
528
5d6bb349
KN
529 SCM_VALIDATE_LIST (1, lst);
530
df13742c
JB
531 newlst = SCM_EOL;
532 fill_here = &newlst;
533 from_here = lst;
534
0c95b57d 535 while (SCM_CONSP (from_here))
df13742c
JB
536 {
537 SCM c;
538 c = scm_cons (SCM_CAR (from_here), SCM_CDR (from_here));
539 *fill_here = c;
25d8012c 540 fill_here = SCM_CDRLOC (c);
df13742c
JB
541 from_here = SCM_CDR (from_here);
542 }
543 return newlst;
544}
1bbd0b84 545#undef FUNC_NAME
df13742c 546
0f2d19dd 547\f
df13742c
JB
548/* membership tests (memq, memv, etc.) */
549
79a3dafe
DH
550/* The function scm_c_memq returns the first sublist of list whose car is
551 * 'eq?' obj, where the sublists of list are the non-empty lists returned by
552 * (list-tail list k) for k less than the length of list. If obj does not
1e6808ea 553 * occur in list, then #f (not the empty list) is returned.
79a3dafe
DH
554 * List must be a proper list, otherwise scm_c_memq may crash or loop
555 * endlessly.
556 */
557SCM
558scm_c_memq (SCM obj, SCM list)
559{
c96d76b8 560 for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR (list))
79a3dafe
DH
561 {
562 if (SCM_EQ_P (SCM_CAR (list), obj))
563 return list;
564 }
565 return SCM_BOOL_F;
566}
567
568
3b3b36dd 569SCM_DEFINE (scm_memq, "memq", 2, 0, 0,
1bbd0b84 570 (SCM x, SCM lst),
5352393c
MG
571 "Return the first sublist of @var{lst} whose car is @code{eq?}\n"
572 "to @var{x} where the sublists of @var{lst} are the non-empty\n"
573 "lists returned by @code{(list-tail @var{lst} @var{k})} for\n"
574 "@var{k} less than the length of @var{lst}. If @var{x} does not\n"
575 "occur in @var{lst}, then @code{#f} (not the empty list) is\n"
576 "returned.")
1bbd0b84 577#define FUNC_NAME s_scm_memq
0f2d19dd 578{
daa6ba18 579 SCM_VALIDATE_LIST (2, lst);
79a3dafe 580 return scm_c_memq (x, lst);
0f2d19dd 581}
1bbd0b84 582#undef FUNC_NAME
0f2d19dd
JB
583
584
3b3b36dd 585SCM_DEFINE (scm_memv, "memv", 2, 0, 0,
1bbd0b84 586 (SCM x, SCM lst),
5352393c
MG
587 "Return the first sublist of @var{lst} whose car is @code{eqv?}\n"
588 "to @var{x} where the sublists of @var{lst} are the non-empty\n"
589 "lists returned by @code{(list-tail @var{lst} @var{k})} for\n"
590 "@var{k} less than the length of @var{lst}. If @var{x} does not\n"
591 "occur in @var{lst}, then @code{#f} (not the empty list) is\n"
592 "returned.")
1bbd0b84 593#define FUNC_NAME s_scm_memv
0f2d19dd 594{
daa6ba18 595 SCM_VALIDATE_LIST (2, lst);
c96d76b8 596 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
daa6ba18
DH
597 {
598 if (! SCM_FALSEP (scm_eqv_p (SCM_CAR (lst), x)))
599 return lst;
600 }
601 return SCM_BOOL_F;
0f2d19dd 602}
1bbd0b84 603#undef FUNC_NAME
0f2d19dd
JB
604
605
3b3b36dd 606SCM_DEFINE (scm_member, "member", 2, 0, 0,
1bbd0b84 607 (SCM x, SCM lst),
5352393c
MG
608 "Return the first sublist of @var{lst} whose car is\n"
609 "@code{equal?} to @var{x} where the sublists of @var{lst} are\n"
610 "the non-empty lists returned by @code{(list-tail @var{lst}\n"
611 "@var{k})} for @var{k} less than the length of @var{lst}. If\n"
612 "@var{x} does not occur in @var{lst}, then @code{#f} (not the\n"
613 "empty list) is returned.")
1bbd0b84 614#define FUNC_NAME s_scm_member
0f2d19dd 615{
daa6ba18 616 SCM_VALIDATE_LIST (2, lst);
c96d76b8 617 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
daa6ba18
DH
618 {
619 if (! SCM_FALSEP (scm_equal_p (SCM_CAR (lst), x)))
620 return lst;
621 }
622 return SCM_BOOL_F;
0f2d19dd 623}
1bbd0b84 624#undef FUNC_NAME
0f2d19dd 625
0f2d19dd 626\f
df13742c 627/* deleting elements from a list (delq, etc.) */
0f2d19dd 628
3b3b36dd 629SCM_DEFINE (scm_delq_x, "delq!", 2, 0, 0,
1bbd0b84 630 (SCM item, SCM lst),
8f85c0c6
NJ
631 "@deffnx {Scheme Procedure} delv! item lst\n"
632 "@deffnx {Scheme Procedure} delete! item lst\n"
b380b885
MD
633 "These procedures are destructive versions of @code{delq}, @code{delv}\n"
634 "and @code{delete}: they modify the pointers in the existing @var{lst}\n"
635 "rather than creating a new list. Caveat evaluator: Like other\n"
636 "destructive list functions, these functions cannot modify the binding of\n"
637 "@var{lst}, and so cannot be used to delete the first element of\n"
638 "@var{lst} destructively.")
1bbd0b84 639#define FUNC_NAME s_scm_delq_x
0f2d19dd 640{
164271a1
JB
641 SCM walk;
642 SCM *prev;
0f2d19dd 643
164271a1 644 for (prev = &lst, walk = lst;
0c95b57d 645 SCM_CONSP (walk);
164271a1 646 walk = SCM_CDR (walk))
0f2d19dd 647 {
fbd485ba 648 if (SCM_EQ_P (SCM_CAR (walk), item))
164271a1
JB
649 *prev = SCM_CDR (walk);
650 else
651 prev = SCM_CDRLOC (walk);
0f2d19dd 652 }
164271a1
JB
653
654 return lst;
0f2d19dd 655}
1bbd0b84 656#undef FUNC_NAME
0f2d19dd
JB
657
658
3b3b36dd 659SCM_DEFINE (scm_delv_x, "delv!", 2, 0, 0,
5352393c
MG
660 (SCM item, SCM lst),
661 "Destructively remove all elements from @var{lst} that are\n"
662 "@code{eqv?} to @var{item}.")
1bbd0b84 663#define FUNC_NAME s_scm_delv_x
0f2d19dd 664{
164271a1
JB
665 SCM walk;
666 SCM *prev;
0f2d19dd 667
164271a1 668 for (prev = &lst, walk = lst;
0c95b57d 669 SCM_CONSP (walk);
164271a1 670 walk = SCM_CDR (walk))
0f2d19dd 671 {
fbd485ba 672 if (! SCM_FALSEP (scm_eqv_p (SCM_CAR (walk), item)))
164271a1
JB
673 *prev = SCM_CDR (walk);
674 else
675 prev = SCM_CDRLOC (walk);
0f2d19dd 676 }
164271a1
JB
677
678 return lst;
0f2d19dd 679}
1bbd0b84 680#undef FUNC_NAME
0f2d19dd
JB
681
682
683
3b3b36dd 684SCM_DEFINE (scm_delete_x, "delete!", 2, 0, 0,
5352393c
MG
685 (SCM item, SCM lst),
686 "Destructively remove all elements from @var{lst} that are\n"
687 "@code{equal?} to @var{item}.")
1bbd0b84 688#define FUNC_NAME s_scm_delete_x
0f2d19dd 689{
164271a1
JB
690 SCM walk;
691 SCM *prev;
0f2d19dd 692
164271a1 693 for (prev = &lst, walk = lst;
0c95b57d 694 SCM_CONSP (walk);
164271a1 695 walk = SCM_CDR (walk))
0f2d19dd 696 {
fbd485ba 697 if (! SCM_FALSEP (scm_equal_p (SCM_CAR (walk), item)))
164271a1
JB
698 *prev = SCM_CDR (walk);
699 else
700 prev = SCM_CDRLOC (walk);
0f2d19dd 701 }
164271a1
JB
702
703 return lst;
0f2d19dd 704}
1bbd0b84 705#undef FUNC_NAME
0f2d19dd
JB
706
707
708\f
709
0f2d19dd 710
a1ec6916 711SCM_DEFINE (scm_delq, "delq", 2, 0, 0,
1bbd0b84 712 (SCM item, SCM lst),
5352393c
MG
713 "Return a newly-created copy of @var{lst} with elements\n"
714 "@code{eq?} to @var{item} removed. This procedure mirrors\n"
715 "@code{memq}: @code{delq} compares elements of @var{lst} against\n"
716 "@var{item} with @code{eq?}.")
1bbd0b84 717#define FUNC_NAME s_scm_delq
0f2d19dd 718{
1bbd0b84 719 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
720 return scm_delq_x (item, copy);
721}
1bbd0b84 722#undef FUNC_NAME
0f2d19dd 723
a1ec6916 724SCM_DEFINE (scm_delv, "delv", 2, 0, 0,
1bbd0b84 725 (SCM item, SCM lst),
5352393c
MG
726 "Return a newly-created copy of @var{lst} with elements\n"
727 "@code{eqv?} to @var{item} removed. This procedure mirrors\n"
728 "@code{memv}: @code{delv} compares elements of @var{lst} against\n"
729 "@var{item} with @code{eqv?}.")
1bbd0b84 730#define FUNC_NAME s_scm_delv
0f2d19dd 731{
1bbd0b84 732 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
733 return scm_delv_x (item, copy);
734}
1bbd0b84 735#undef FUNC_NAME
0f2d19dd 736
a1ec6916 737SCM_DEFINE (scm_delete, "delete", 2, 0, 0,
1bbd0b84 738 (SCM item, SCM lst),
5352393c
MG
739 "Return a newly-created copy of @var{lst} with elements\n"
740 "@code{equal?} to @var{item} removed. This procedure mirrors\n"
741 "@code{member}: @code{delete} compares elements of @var{lst}\n"
742 "against @var{item} with @code{equal?}.")
1bbd0b84 743#define FUNC_NAME s_scm_delete
0f2d19dd 744{
1bbd0b84 745 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
746 return scm_delete_x (item, copy);
747}
1bbd0b84 748#undef FUNC_NAME
0f2d19dd
JB
749
750
3b3b36dd 751SCM_DEFINE (scm_delq1_x, "delq1!", 2, 0, 0,
1bbd0b84 752 (SCM item, SCM lst),
5352393c
MG
753 "Like @code{delq!}, but only deletes the first occurrence of\n"
754 "@var{item} from @var{lst}. Tests for equality using\n"
755 "@code{eq?}. See also @code{delv1!} and @code{delete1!}.")
1bbd0b84 756#define FUNC_NAME s_scm_delq1_x
82dc9f57
MD
757{
758 SCM walk;
759 SCM *prev;
760
761 for (prev = &lst, walk = lst;
0c95b57d 762 SCM_CONSP (walk);
82dc9f57
MD
763 walk = SCM_CDR (walk))
764 {
fbd485ba 765 if (SCM_EQ_P (SCM_CAR (walk), item))
82dc9f57
MD
766 {
767 *prev = SCM_CDR (walk);
768 break;
769 }
770 else
771 prev = SCM_CDRLOC (walk);
772 }
773
774 return lst;
775}
1bbd0b84 776#undef FUNC_NAME
82dc9f57
MD
777
778
3b3b36dd 779SCM_DEFINE (scm_delv1_x, "delv1!", 2, 0, 0,
8507b88c 780 (SCM item, SCM lst),
5352393c
MG
781 "Like @code{delv!}, but only deletes the first occurrence of\n"
782 "@var{item} from @var{lst}. Tests for equality using\n"
783 "@code{eqv?}. See also @code{delq1!} and @code{delete1!}.")
1bbd0b84 784#define FUNC_NAME s_scm_delv1_x
82dc9f57
MD
785{
786 SCM walk;
787 SCM *prev;
788
789 for (prev = &lst, walk = lst;
0c95b57d 790 SCM_CONSP (walk);
82dc9f57
MD
791 walk = SCM_CDR (walk))
792 {
fbd485ba 793 if (! SCM_FALSEP (scm_eqv_p (SCM_CAR (walk), item)))
82dc9f57
MD
794 {
795 *prev = SCM_CDR (walk);
796 break;
797 }
798 else
799 prev = SCM_CDRLOC (walk);
800 }
801
802 return lst;
803}
1bbd0b84 804#undef FUNC_NAME
82dc9f57
MD
805
806
3b3b36dd 807SCM_DEFINE (scm_delete1_x, "delete1!", 2, 0, 0,
8507b88c 808 (SCM item, SCM lst),
5352393c
MG
809 "Like @code{delete!}, but only deletes the first occurrence of\n"
810 "@var{item} from @var{lst}. Tests for equality using\n"
811 "@code{equal?}. See also @code{delq1!} and @code{delv1!}.")
1bbd0b84 812#define FUNC_NAME s_scm_delete1_x
82dc9f57
MD
813{
814 SCM walk;
815 SCM *prev;
816
817 for (prev = &lst, walk = lst;
0c95b57d 818 SCM_CONSP (walk);
82dc9f57
MD
819 walk = SCM_CDR (walk))
820 {
fbd485ba 821 if (! SCM_FALSEP (scm_equal_p (SCM_CAR (walk), item)))
82dc9f57
MD
822 {
823 *prev = SCM_CDR (walk);
824 break;
825 }
826 else
827 prev = SCM_CDRLOC (walk);
828 }
829
830 return lst;
831}
1bbd0b84 832#undef FUNC_NAME
82dc9f57 833
c614a00b
MD
834SCM_DEFINE (scm_filter, "filter", 2, 0, 0,
835 (SCM pred, SCM list),
836 "Return all the elements of 2nd arg @var{list} that satisfy predicate @var{pred}.\n"
837 "The list is not disordered -- elements that appear in the result list occur\n"
838 "in the same order as they occur in the argument list. The returned list may\n"
839 "share a common tail with the argument list. The dynamic order in which the\n"
840 "various applications of pred are made is not specified.\n\n"
841 "@lisp\n"
842 "(filter even? '(0 7 8 8 43 -4)) => (0 8 8 -4)\n"
843 "@end lisp")
844#define FUNC_NAME s_scm_filter
845{
846 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
847 SCM walk;
848 SCM *prev;
849 SCM res = SCM_EOL;
850 SCM_ASSERT (call, pred, 1, FUNC_NAME);
851 SCM_VALIDATE_LIST (2, list);
852
853 for (prev = &res, walk = list;
854 SCM_CONSP (walk);
855 walk = SCM_CDR (walk))
856 {
857 if (!SCM_FALSEP (call (pred, SCM_CAR (walk))))
858 {
859 *prev = scm_cons (SCM_CAR (walk), SCM_EOL);
860 prev = SCM_CDRLOC (*prev);
861 }
862 }
863
864 return res;
865}
866#undef FUNC_NAME
867
868SCM_DEFINE (scm_filter_x, "filter!", 2, 0, 0,
869 (SCM pred, SCM list),
870 "Linear-update variant of @code{filter}.")
871#define FUNC_NAME s_scm_filter_x
872{
873 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
874 SCM walk;
875 SCM *prev;
876 SCM_ASSERT (call, pred, 1, FUNC_NAME);
877 SCM_VALIDATE_LIST (2, list);
878
879 for (prev = &list, walk = list;
880 SCM_CONSP (walk);
881 walk = SCM_CDR (walk))
882 {
883 if (!SCM_FALSEP (call (pred, SCM_CAR (walk))))
884 prev = SCM_CDRLOC (walk);
885 else
886 *prev = SCM_CDR (walk);
887 }
888
889 return list;
890}
891#undef FUNC_NAME
82dc9f57 892
0f2d19dd 893\f
0f2d19dd
JB
894void
895scm_init_list ()
0f2d19dd 896{
a0599745 897#include "libguile/list.x"
0f2d19dd 898}
89e00824
ML
899
900/*
901 Local Variables:
902 c-file-style: "gnu"
903 End:
904*/