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