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