* validate.h, deprecated.h (SCM_VALIDATE_INUM, SCM_VALIDATE_INUM_COPY,
[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{
7888309b 146 return scm_from_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{
7888309b 156 return scm_from_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);
93ccaef0 199 return SCM_I_MAKINUM (i);
0f2d19dd 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;
a55c2b68 386 i = scm_to_ulong (k);
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;
a55c2b68 409 unsigned long int i = scm_to_ulong (k);
685c0d71
DH
410 while (SCM_CONSP (lst)) {
411 if (i == 0) {
412 SCM_SETCAR (lst, val);
413 return val;
414 } else {
415 --i;
416 lst = SCM_CDR (lst);
417 }
418 };
c96d76b8 419 if (SCM_NULL_OR_NIL_P (lst))
685c0d71
DH
420 SCM_OUT_OF_RANGE (2, k);
421 else
422 SCM_WRONG_TYPE_ARG (1, list);
0f2d19dd 423}
1bbd0b84 424#undef FUNC_NAME
0f2d19dd
JB
425
426
1bbd0b84
GB
427SCM_REGISTER_PROC(s_list_cdr_ref, "list-cdr-ref", 2, 0, 0, scm_list_tail);
428
3b3b36dd 429SCM_DEFINE (scm_list_tail, "list-tail", 2, 0, 0,
1bbd0b84 430 (SCM lst, SCM k),
8f85c0c6 431 "@deffnx {Scheme Procedure} list-cdr-ref lst k\n"
b380b885
MD
432 "Return the \"tail\" of @var{lst} beginning with its @var{k}th element.\n"
433 "The first element of the list is considered to be element 0.\n\n"
872e0c72 434 "@code{list-tail} and @code{list-cdr-ref} are identical. It may help to\n"
b380b885
MD
435 "think of @code{list-cdr-ref} as accessing the @var{k}th cdr of the list,\n"
436 "or returning the results of cdring @var{k} times down @var{lst}.")
1bbd0b84 437#define FUNC_NAME s_scm_list_tail
df13742c 438{
a55c2b68 439 size_t i = scm_to_size_t (k);
df13742c 440 while (i-- > 0) {
34d19ef6 441 SCM_VALIDATE_CONS (1, lst);
df13742c
JB
442 lst = SCM_CDR(lst);
443 }
444 return lst;
445}
1bbd0b84 446#undef FUNC_NAME
df13742c 447
0f2d19dd 448
3b3b36dd 449SCM_DEFINE (scm_list_cdr_set_x, "list-cdr-set!", 3, 0, 0,
685c0d71
DH
450 (SCM list, SCM k, SCM val),
451 "Set the @var{k}th cdr of @var{list} to @var{val}.")
1bbd0b84
GB
452#define FUNC_NAME s_scm_list_cdr_set_x
453{
685c0d71 454 SCM lst = list;
a55c2b68 455 size_t i = scm_to_size_t (k);
685c0d71
DH
456 while (SCM_CONSP (lst)) {
457 if (i == 0) {
458 SCM_SETCDR (lst, val);
459 return val;
460 } else {
461 --i;
462 lst = SCM_CDR (lst);
463 }
464 };
c96d76b8 465 if (SCM_NULL_OR_NIL_P (lst))
685c0d71
DH
466 SCM_OUT_OF_RANGE (2, k);
467 else
468 SCM_WRONG_TYPE_ARG (1, list);
0f2d19dd 469}
1bbd0b84 470#undef FUNC_NAME
0f2d19dd
JB
471
472
473\f
df13742c 474/* copying lists, perhaps partially */
0f2d19dd 475
3b3b36dd 476SCM_DEFINE (scm_list_head, "list-head", 2, 0, 0,
1bbd0b84 477 (SCM lst, SCM k),
b380b885
MD
478 "Copy the first @var{k} elements from @var{lst} into a new list, and\n"
479 "return it.")
1bbd0b84 480#define FUNC_NAME s_scm_list_head
0f2d19dd
JB
481{
482 SCM answer;
483 SCM * pos;
a55c2b68 484 size_t i = scm_to_size_t (k);
0f2d19dd 485
0f2d19dd
JB
486 answer = SCM_EOL;
487 pos = &answer;
0f2d19dd
JB
488 while (i-- > 0)
489 {
34d19ef6 490 SCM_VALIDATE_CONS (1, lst);
0f2d19dd 491 *pos = scm_cons (SCM_CAR (lst), SCM_EOL);
25d8012c 492 pos = SCM_CDRLOC (*pos);
0f2d19dd
JB
493 lst = SCM_CDR(lst);
494 }
495 return answer;
496}
1bbd0b84 497#undef FUNC_NAME
0f2d19dd
JB
498
499
212e58ed
DH
500/* Copy a list which is known to be finite. The last pair may or may not have
501 * a '() in its cdr. That is, improper lists are accepted. */
502SCM
503scm_i_finite_list_copy (SCM list)
504{
505 if (!SCM_CONSP (list))
506 {
507 return list;
508 }
509 else
510 {
511 SCM tail;
512 const SCM result = tail = scm_list_1 (SCM_CAR (list));
513 list = SCM_CDR (list);
514 while (SCM_CONSP (list))
515 {
516 const SCM new_tail = scm_list_1 (SCM_CAR (list));
517 SCM_SETCDR (tail, new_tail);
518 tail = new_tail;
519 list = SCM_CDR (list);
520 }
521 SCM_SETCDR (tail, list);
522
523 return result;
524 }
525}
526
527
a1ec6916 528SCM_DEFINE (scm_list_copy, "list-copy", 1, 0, 0,
1bbd0b84 529 (SCM lst),
b380b885 530 "Return a (newly-created) copy of @var{lst}.")
1bbd0b84 531#define FUNC_NAME s_scm_list_copy
df13742c
JB
532{
533 SCM newlst;
534 SCM * fill_here;
535 SCM from_here;
536
5d6bb349
KN
537 SCM_VALIDATE_LIST (1, lst);
538
df13742c
JB
539 newlst = SCM_EOL;
540 fill_here = &newlst;
541 from_here = lst;
542
0c95b57d 543 while (SCM_CONSP (from_here))
df13742c
JB
544 {
545 SCM c;
546 c = scm_cons (SCM_CAR (from_here), SCM_CDR (from_here));
547 *fill_here = c;
25d8012c 548 fill_here = SCM_CDRLOC (c);
df13742c
JB
549 from_here = SCM_CDR (from_here);
550 }
551 return newlst;
552}
1bbd0b84 553#undef FUNC_NAME
df13742c 554
0f2d19dd 555\f
df13742c
JB
556/* membership tests (memq, memv, etc.) */
557
79a3dafe
DH
558/* The function scm_c_memq returns the first sublist of list whose car is
559 * 'eq?' obj, where the sublists of list are the non-empty lists returned by
560 * (list-tail list k) for k less than the length of list. If obj does not
1e6808ea 561 * occur in list, then #f (not the empty list) is returned.
79a3dafe
DH
562 * List must be a proper list, otherwise scm_c_memq may crash or loop
563 * endlessly.
564 */
565SCM
566scm_c_memq (SCM obj, SCM list)
567{
c96d76b8 568 for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR (list))
79a3dafe
DH
569 {
570 if (SCM_EQ_P (SCM_CAR (list), obj))
571 return list;
572 }
573 return SCM_BOOL_F;
574}
575
576
3b3b36dd 577SCM_DEFINE (scm_memq, "memq", 2, 0, 0,
1bbd0b84 578 (SCM x, SCM lst),
5352393c
MG
579 "Return the first sublist of @var{lst} whose car is @code{eq?}\n"
580 "to @var{x} where the sublists of @var{lst} are the non-empty\n"
581 "lists returned by @code{(list-tail @var{lst} @var{k})} for\n"
582 "@var{k} less than the length of @var{lst}. If @var{x} does not\n"
583 "occur in @var{lst}, then @code{#f} (not the empty list) is\n"
584 "returned.")
1bbd0b84 585#define FUNC_NAME s_scm_memq
0f2d19dd 586{
daa6ba18 587 SCM_VALIDATE_LIST (2, lst);
79a3dafe 588 return scm_c_memq (x, lst);
0f2d19dd 589}
1bbd0b84 590#undef FUNC_NAME
0f2d19dd
JB
591
592
3b3b36dd 593SCM_DEFINE (scm_memv, "memv", 2, 0, 0,
1bbd0b84 594 (SCM x, SCM lst),
5352393c
MG
595 "Return the first sublist of @var{lst} whose car is @code{eqv?}\n"
596 "to @var{x} where the sublists of @var{lst} are the non-empty\n"
597 "lists returned by @code{(list-tail @var{lst} @var{k})} for\n"
598 "@var{k} less than the length of @var{lst}. If @var{x} does not\n"
599 "occur in @var{lst}, then @code{#f} (not the empty list) is\n"
600 "returned.")
1bbd0b84 601#define FUNC_NAME s_scm_memv
0f2d19dd 602{
daa6ba18 603 SCM_VALIDATE_LIST (2, lst);
c96d76b8 604 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
daa6ba18 605 {
7888309b 606 if (! scm_is_false (scm_eqv_p (SCM_CAR (lst), x)))
daa6ba18
DH
607 return lst;
608 }
609 return SCM_BOOL_F;
0f2d19dd 610}
1bbd0b84 611#undef FUNC_NAME
0f2d19dd
JB
612
613
3b3b36dd 614SCM_DEFINE (scm_member, "member", 2, 0, 0,
1bbd0b84 615 (SCM x, SCM lst),
5352393c
MG
616 "Return the first sublist of @var{lst} whose car is\n"
617 "@code{equal?} to @var{x} where the sublists of @var{lst} are\n"
618 "the non-empty lists returned by @code{(list-tail @var{lst}\n"
619 "@var{k})} for @var{k} less than the length of @var{lst}. If\n"
620 "@var{x} does not occur in @var{lst}, then @code{#f} (not the\n"
621 "empty list) is returned.")
1bbd0b84 622#define FUNC_NAME s_scm_member
0f2d19dd 623{
daa6ba18 624 SCM_VALIDATE_LIST (2, lst);
c96d76b8 625 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
daa6ba18 626 {
7888309b 627 if (! scm_is_false (scm_equal_p (SCM_CAR (lst), x)))
daa6ba18
DH
628 return lst;
629 }
630 return SCM_BOOL_F;
0f2d19dd 631}
1bbd0b84 632#undef FUNC_NAME
0f2d19dd 633
0f2d19dd 634\f
df13742c 635/* deleting elements from a list (delq, etc.) */
0f2d19dd 636
3b3b36dd 637SCM_DEFINE (scm_delq_x, "delq!", 2, 0, 0,
1bbd0b84 638 (SCM item, SCM lst),
8f85c0c6
NJ
639 "@deffnx {Scheme Procedure} delv! item lst\n"
640 "@deffnx {Scheme Procedure} delete! item lst\n"
b380b885 641 "These procedures are destructive versions of @code{delq}, @code{delv}\n"
bfefbf18 642 "and @code{delete}: they modify the existing @var{lst}\n"
b380b885
MD
643 "rather than creating a new list. Caveat evaluator: Like other\n"
644 "destructive list functions, these functions cannot modify the binding of\n"
645 "@var{lst}, and so cannot be used to delete the first element of\n"
646 "@var{lst} destructively.")
1bbd0b84 647#define FUNC_NAME s_scm_delq_x
0f2d19dd 648{
164271a1
JB
649 SCM walk;
650 SCM *prev;
0f2d19dd 651
164271a1 652 for (prev = &lst, walk = lst;
0c95b57d 653 SCM_CONSP (walk);
164271a1 654 walk = SCM_CDR (walk))
0f2d19dd 655 {
fbd485ba 656 if (SCM_EQ_P (SCM_CAR (walk), item))
164271a1
JB
657 *prev = SCM_CDR (walk);
658 else
659 prev = SCM_CDRLOC (walk);
0f2d19dd 660 }
164271a1
JB
661
662 return lst;
0f2d19dd 663}
1bbd0b84 664#undef FUNC_NAME
0f2d19dd
JB
665
666
3b3b36dd 667SCM_DEFINE (scm_delv_x, "delv!", 2, 0, 0,
5352393c
MG
668 (SCM item, SCM lst),
669 "Destructively remove all elements from @var{lst} that are\n"
670 "@code{eqv?} to @var{item}.")
1bbd0b84 671#define FUNC_NAME s_scm_delv_x
0f2d19dd 672{
164271a1
JB
673 SCM walk;
674 SCM *prev;
0f2d19dd 675
164271a1 676 for (prev = &lst, walk = lst;
0c95b57d 677 SCM_CONSP (walk);
164271a1 678 walk = SCM_CDR (walk))
0f2d19dd 679 {
7888309b 680 if (! scm_is_false (scm_eqv_p (SCM_CAR (walk), item)))
164271a1
JB
681 *prev = SCM_CDR (walk);
682 else
683 prev = SCM_CDRLOC (walk);
0f2d19dd 684 }
164271a1
JB
685
686 return lst;
0f2d19dd 687}
1bbd0b84 688#undef FUNC_NAME
0f2d19dd
JB
689
690
691
3b3b36dd 692SCM_DEFINE (scm_delete_x, "delete!", 2, 0, 0,
5352393c
MG
693 (SCM item, SCM lst),
694 "Destructively remove all elements from @var{lst} that are\n"
695 "@code{equal?} to @var{item}.")
1bbd0b84 696#define FUNC_NAME s_scm_delete_x
0f2d19dd 697{
164271a1
JB
698 SCM walk;
699 SCM *prev;
0f2d19dd 700
164271a1 701 for (prev = &lst, walk = lst;
0c95b57d 702 SCM_CONSP (walk);
164271a1 703 walk = SCM_CDR (walk))
0f2d19dd 704 {
7888309b 705 if (! scm_is_false (scm_equal_p (SCM_CAR (walk), item)))
164271a1
JB
706 *prev = SCM_CDR (walk);
707 else
708 prev = SCM_CDRLOC (walk);
0f2d19dd 709 }
164271a1
JB
710
711 return lst;
0f2d19dd 712}
1bbd0b84 713#undef FUNC_NAME
0f2d19dd
JB
714
715
716\f
717
0f2d19dd 718
a1ec6916 719SCM_DEFINE (scm_delq, "delq", 2, 0, 0,
1bbd0b84 720 (SCM item, SCM lst),
5352393c
MG
721 "Return a newly-created copy of @var{lst} with elements\n"
722 "@code{eq?} to @var{item} removed. This procedure mirrors\n"
723 "@code{memq}: @code{delq} compares elements of @var{lst} against\n"
724 "@var{item} with @code{eq?}.")
1bbd0b84 725#define FUNC_NAME s_scm_delq
0f2d19dd 726{
1bbd0b84 727 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
728 return scm_delq_x (item, copy);
729}
1bbd0b84 730#undef FUNC_NAME
0f2d19dd 731
a1ec6916 732SCM_DEFINE (scm_delv, "delv", 2, 0, 0,
1bbd0b84 733 (SCM item, SCM lst),
5352393c
MG
734 "Return a newly-created copy of @var{lst} with elements\n"
735 "@code{eqv?} to @var{item} removed. This procedure mirrors\n"
736 "@code{memv}: @code{delv} compares elements of @var{lst} against\n"
737 "@var{item} with @code{eqv?}.")
1bbd0b84 738#define FUNC_NAME s_scm_delv
0f2d19dd 739{
1bbd0b84 740 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
741 return scm_delv_x (item, copy);
742}
1bbd0b84 743#undef FUNC_NAME
0f2d19dd 744
a1ec6916 745SCM_DEFINE (scm_delete, "delete", 2, 0, 0,
1bbd0b84 746 (SCM item, SCM lst),
5352393c
MG
747 "Return a newly-created copy of @var{lst} with elements\n"
748 "@code{equal?} to @var{item} removed. This procedure mirrors\n"
749 "@code{member}: @code{delete} compares elements of @var{lst}\n"
750 "against @var{item} with @code{equal?}.")
1bbd0b84 751#define FUNC_NAME s_scm_delete
0f2d19dd 752{
1bbd0b84 753 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
754 return scm_delete_x (item, copy);
755}
1bbd0b84 756#undef FUNC_NAME
0f2d19dd
JB
757
758
3b3b36dd 759SCM_DEFINE (scm_delq1_x, "delq1!", 2, 0, 0,
1bbd0b84 760 (SCM item, SCM lst),
5352393c
MG
761 "Like @code{delq!}, but only deletes the first occurrence of\n"
762 "@var{item} from @var{lst}. Tests for equality using\n"
763 "@code{eq?}. See also @code{delv1!} and @code{delete1!}.")
1bbd0b84 764#define FUNC_NAME s_scm_delq1_x
82dc9f57
MD
765{
766 SCM walk;
767 SCM *prev;
768
769 for (prev = &lst, walk = lst;
0c95b57d 770 SCM_CONSP (walk);
82dc9f57
MD
771 walk = SCM_CDR (walk))
772 {
fbd485ba 773 if (SCM_EQ_P (SCM_CAR (walk), item))
82dc9f57
MD
774 {
775 *prev = SCM_CDR (walk);
776 break;
777 }
778 else
779 prev = SCM_CDRLOC (walk);
780 }
781
782 return lst;
783}
1bbd0b84 784#undef FUNC_NAME
82dc9f57
MD
785
786
3b3b36dd 787SCM_DEFINE (scm_delv1_x, "delv1!", 2, 0, 0,
8507b88c 788 (SCM item, SCM lst),
5352393c
MG
789 "Like @code{delv!}, but only deletes the first occurrence of\n"
790 "@var{item} from @var{lst}. Tests for equality using\n"
791 "@code{eqv?}. See also @code{delq1!} and @code{delete1!}.")
1bbd0b84 792#define FUNC_NAME s_scm_delv1_x
82dc9f57
MD
793{
794 SCM walk;
795 SCM *prev;
796
797 for (prev = &lst, walk = lst;
0c95b57d 798 SCM_CONSP (walk);
82dc9f57
MD
799 walk = SCM_CDR (walk))
800 {
7888309b 801 if (! scm_is_false (scm_eqv_p (SCM_CAR (walk), item)))
82dc9f57
MD
802 {
803 *prev = SCM_CDR (walk);
804 break;
805 }
806 else
807 prev = SCM_CDRLOC (walk);
808 }
809
810 return lst;
811}
1bbd0b84 812#undef FUNC_NAME
82dc9f57
MD
813
814
3b3b36dd 815SCM_DEFINE (scm_delete1_x, "delete1!", 2, 0, 0,
8507b88c 816 (SCM item, SCM lst),
5352393c
MG
817 "Like @code{delete!}, but only deletes the first occurrence of\n"
818 "@var{item} from @var{lst}. Tests for equality using\n"
819 "@code{equal?}. See also @code{delq1!} and @code{delv1!}.")
1bbd0b84 820#define FUNC_NAME s_scm_delete1_x
82dc9f57
MD
821{
822 SCM walk;
823 SCM *prev;
824
825 for (prev = &lst, walk = lst;
0c95b57d 826 SCM_CONSP (walk);
82dc9f57
MD
827 walk = SCM_CDR (walk))
828 {
7888309b 829 if (! scm_is_false (scm_equal_p (SCM_CAR (walk), item)))
82dc9f57
MD
830 {
831 *prev = SCM_CDR (walk);
832 break;
833 }
834 else
835 prev = SCM_CDRLOC (walk);
836 }
837
838 return lst;
839}
1bbd0b84 840#undef FUNC_NAME
82dc9f57 841
c614a00b
MD
842SCM_DEFINE (scm_filter, "filter", 2, 0, 0,
843 (SCM pred, SCM list),
844 "Return all the elements of 2nd arg @var{list} that satisfy predicate @var{pred}.\n"
845 "The list is not disordered -- elements that appear in the result list occur\n"
846 "in the same order as they occur in the argument list. The returned list may\n"
847 "share a common tail with the argument list. The dynamic order in which the\n"
848 "various applications of pred are made is not specified.\n\n"
849 "@lisp\n"
850 "(filter even? '(0 7 8 8 43 -4)) => (0 8 8 -4)\n"
851 "@end lisp")
852#define FUNC_NAME s_scm_filter
853{
854 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
855 SCM walk;
856 SCM *prev;
857 SCM res = SCM_EOL;
858 SCM_ASSERT (call, pred, 1, FUNC_NAME);
859 SCM_VALIDATE_LIST (2, list);
860
861 for (prev = &res, walk = list;
862 SCM_CONSP (walk);
863 walk = SCM_CDR (walk))
864 {
7888309b 865 if (scm_is_true (call (pred, SCM_CAR (walk))))
c614a00b
MD
866 {
867 *prev = scm_cons (SCM_CAR (walk), SCM_EOL);
868 prev = SCM_CDRLOC (*prev);
869 }
870 }
871
872 return res;
873}
874#undef FUNC_NAME
875
876SCM_DEFINE (scm_filter_x, "filter!", 2, 0, 0,
877 (SCM pred, SCM list),
878 "Linear-update variant of @code{filter}.")
879#define FUNC_NAME s_scm_filter_x
880{
881 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
882 SCM walk;
883 SCM *prev;
884 SCM_ASSERT (call, pred, 1, FUNC_NAME);
885 SCM_VALIDATE_LIST (2, list);
886
887 for (prev = &list, walk = list;
888 SCM_CONSP (walk);
889 walk = SCM_CDR (walk))
890 {
7888309b 891 if (scm_is_true (call (pred, SCM_CAR (walk))))
c614a00b
MD
892 prev = SCM_CDRLOC (walk);
893 else
894 *prev = SCM_CDR (walk);
895 }
896
897 return list;
898}
899#undef FUNC_NAME
82dc9f57 900
0f2d19dd 901\f
0f2d19dd
JB
902void
903scm_init_list ()
0f2d19dd 904{
a0599745 905#include "libguile/list.x"
0f2d19dd 906}
89e00824
ML
907
908/*
909 Local Variables:
910 c-file-style: "gnu"
911 End:
912*/