comparison src/sequence.c @ 5607:1a507c4c6c42

Refactor out sequence-oriented builtins from fns.c to the new sequence.c. src/ChangeLog addition: 2011-12-04 Aidan Kehoe <kehoea@parhasard.net> * Makefile.in.in (objs): * depend: Add sequence.o to the list of objects and dependencies. * alloc.c: * alloc.c (mark_bit_vector): * alloc.c (print_bit_vector): * alloc.c (bit_vector_equal): * alloc.c (internal_bit_vector_equalp_hash): * alloc.c (bit_vector_hash): * alloc.c (init_alloc_once_early): Move the implementation of the bit vector type here from fns.c. * emacs.c (main_1): Call syms_of_sequence() here, now sequence.c is included. * fns.c (Fold_rassq): Move this together with the rest of the Fold_* functions. * fns.c: * fns.c (syms_of_fns): Move most functions dealing with sequences generally, and especially those taking key arguments, to a separate file, sequence.c. * general-slots.h: Qyes_or_no_p belong here, not fns.c. * lisp.h: Make Flist_length available here, it's used by sequence.c * sequence.c: * sequence.c (check_sequence_range): * sequence.c (Flength): * sequence.c (check_other_nokey): * sequence.c (check_other_key): * sequence.c (check_if_key): * sequence.c (check_match_eq_key): * sequence.c (check_match_eql_key): * sequence.c (check_match_equal_key): * sequence.c (check_match_equalp_key): * sequence.c (check_match_other_key): * sequence.c (check_lss_key): * sequence.c (check_lss_key_car): * sequence.c (check_string_lessp_key): * sequence.c (check_string_lessp_key_car): * sequence.c (get_check_match_function_1): * sequence.c (get_merge_predicate): * sequence.c (count_with_tail): * sequence.c (list_count_from_end): * sequence.c (string_count_from_end): * sequence.c (Fcount): * sequence.c (Fsubseq): * sequence.c (list_position_cons_before): * sequence.c (FmemberX): * sequence.c (Fadjoin): * sequence.c (FassocX): * sequence.c (FrassocX): * sequence.c (position): * sequence.c (Fposition): * sequence.c (Ffind): * sequence.c (delq_no_quit_and_free_cons): * sequence.c (FdeleteX): * sequence.c (FremoveX): * sequence.c (list_delete_duplicates_from_end): * sequence.c (Fdelete_duplicates): * sequence.c (Fremove_duplicates): * sequence.c (Fnreverse): * sequence.c (Freverse): * sequence.c (list_merge): * sequence.c (array_merge): * sequence.c (list_array_merge_into_list): * sequence.c (list_list_merge_into_array): * sequence.c (list_array_merge_into_array): * sequence.c (Fmerge): * sequence.c (list_sort): * sequence.c (array_sort): * sequence.c (FsortX): * sequence.c (Ffill): * sequence.c (mapcarX): * sequence.c (shortest_length_among_sequences): * sequence.c (Fmapconcat): * sequence.c (FmapcarX): * sequence.c (Fmapvector): * sequence.c (Fmapcan): * sequence.c (Fmap): * sequence.c (Fmap_into): * sequence.c (Fsome): * sequence.c (Fevery): * sequence.c (Freduce): * sequence.c (replace_string_range_1): * sequence.c (Freplace): * sequence.c (Fnsubstitute): * sequence.c (Fsubstitute): * sequence.c (subst): * sequence.c (sublis): * sequence.c (Fsublis): * sequence.c (nsublis): * sequence.c (Fnsublis): * sequence.c (Fsubst): * sequence.c (Fnsubst): * sequence.c (tree_equal): * sequence.c (Ftree_equal): * sequence.c (mismatch_from_end): * sequence.c (mismatch_list_list): * sequence.c (mismatch_list_string): * sequence.c (mismatch_list_array): * sequence.c (mismatch_string_array): * sequence.c (mismatch_string_string): * sequence.c (mismatch_array_array): * sequence.c (get_mismatch_func): * sequence.c (Fmismatch): * sequence.c (Fsearch): * sequence.c (venn): * sequence.c (nvenn): * sequence.c (Funion): * sequence.c (Fset_exclusive_or): * sequence.c (Fnset_exclusive_or): * sequence.c (syms_of_sequence): Add this file, containing those general functions that dealt with sequences that were in fns.c. * symsinit.h: Make syms_of_sequence() available here. man/ChangeLog addition: 2011-12-04 Aidan Kehoe <kehoea@parhasard.net> * internals/internals.texi (Basic Lisp Modules): Document sequence.c here too.
author Aidan Kehoe <kehoea@parhasard.net>
date Sun, 04 Dec 2011 18:42:50 +0000
parents
children 37479d841681
comparison
equal deleted inserted replaced
5606:7c383c5784ed 5607:1a507c4c6c42
1 /* Various functions that operate on sequences, split out from fns.c
2 Copyright (C) 1985, 86, 87, 93, 94, 95 Free Software Foundation, Inc.
3 Copyright (C) 1995, 1996, 2000, 2001, 2002, 2003, 2010 Ben Wing.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation, either version 3 of the License, or (at your
10 option) any later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include <config.h>
21 #include "lisp.h"
22 #include "extents.h"
23
24 Lisp_Object Qadjoin, Qarray, QassocX, Qbit_vector, Qcar_less_than_car;
25 Lisp_Object QdeleteX, Qdelete_duplicates, Qevery, Qfill, Qfind, Qidentity;
26 Lisp_Object Qintersection, Qmap, Qmap_into, Qmapc, Qmapcan, QmapcarX;
27 Lisp_Object Qmapconcat, Qmapvector, Qmerge, Qmismatch, Qnintersection;
28 Lisp_Object Qnset_difference, Qnsubstitute, Qnunion, Qposition, QrassocX;
29 Lisp_Object Qreduce, QremoveX, Qreplace, Qset_difference, Qsome, QsortX;
30 Lisp_Object Qstring_lessp, Qsubsetp, Qsubstitute, Qvector;
31
32 Lisp_Object Q_count, Q_descend_structures, Q_end1, Q_end2, Q_from_end;
33 Lisp_Object Q_if_, Q_if_not, Q_initial_value, Q_stable, Q_start1, Q_start2;
34 Lisp_Object Q_test_not;
35
36 extern Fixnum max_lisp_eval_depth;
37 extern int lisp_eval_depth;
38
39 Lisp_Object safe_copy_tree (Lisp_Object arg, Lisp_Object vecp, int depth);
40
41 static DOESNT_RETURN
42 mapping_interaction_error (Lisp_Object func, Lisp_Object object)
43 {
44 invalid_state_2 ("object modified while traversing it", func, object);
45 }
46
47 static void
48 check_sequence_range (Lisp_Object sequence, Lisp_Object start,
49 Lisp_Object end, Lisp_Object length)
50 {
51 Lisp_Object args[] = { Qzero, start, NILP (end) ? length : end, length };
52
53 if (NILP (Fleq (countof (args), args)))
54 {
55 args_out_of_range_3 (sequence, start, end);
56 }
57 }
58
59 DEFUN ("length", Flength, 1, 1, 0, /*
60 Return the length of vector, bit vector, list or string SEQUENCE.
61 */
62 (sequence))
63 {
64 retry:
65 if (STRINGP (sequence))
66 return make_fixnum (string_char_length (sequence));
67 else if (CONSP (sequence))
68 {
69 Elemcount len;
70 GET_EXTERNAL_LIST_LENGTH (sequence, len);
71 return make_fixnum (len);
72 }
73 else if (VECTORP (sequence))
74 return make_fixnum (XVECTOR_LENGTH (sequence));
75 else if (NILP (sequence))
76 return Qzero;
77 else if (BIT_VECTORP (sequence))
78 return make_fixnum (bit_vector_length (XBIT_VECTOR (sequence)));
79 else
80 {
81 check_losing_bytecode ("length", sequence);
82 sequence = wrong_type_argument (Qsequencep, sequence);
83 goto retry;
84 }
85 }
86
87 /* Various test functions for #'member*, #'assoc* and the other functions
88 that take both TEST and KEY arguments. */
89
90 Boolint
91 check_eq_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key),
92 Lisp_Object item, Lisp_Object elt)
93 {
94 return EQ (item, elt);
95 }
96
97 static Boolint
98 check_eq_key (Lisp_Object UNUSED (test), Lisp_Object key, Lisp_Object item,
99 Lisp_Object elt)
100 {
101 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt));
102 return EQ (item, elt);
103 }
104
105 /* The next two are not used by #'member* and #'assoc*, since we can decide
106 on #'eq vs. #'equal when we have the type of ITEM. */
107 static Boolint
108 check_eql_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key),
109 Lisp_Object elt1, Lisp_Object elt2)
110 {
111 return EQ (elt1, elt2)
112 || (NON_FIXNUM_NUMBER_P (elt1) && internal_equal (elt1, elt2, 0));
113 }
114
115 static Boolint
116 check_eql_key (Lisp_Object UNUSED (test), Lisp_Object key, Lisp_Object item,
117 Lisp_Object elt)
118 {
119 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt));
120 return EQ (item, elt)
121 || (NON_FIXNUM_NUMBER_P (item) && internal_equal (item, elt, 0));
122 }
123
124 static Boolint
125 check_equal_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key),
126 Lisp_Object item, Lisp_Object elt)
127 {
128 return internal_equal (item, elt, 0);
129 }
130
131 static Boolint
132 check_equal_key (Lisp_Object UNUSED (test), Lisp_Object key, Lisp_Object item,
133 Lisp_Object elt)
134 {
135 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt));
136 return internal_equal (item, elt, 0);
137 }
138
139 static Boolint
140 check_equalp_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key),
141 Lisp_Object item, Lisp_Object elt)
142 {
143 return internal_equalp (item, elt, 0);
144 }
145
146 static Boolint
147 check_equalp_key (Lisp_Object UNUSED (test), Lisp_Object key,
148 Lisp_Object item, Lisp_Object elt)
149 {
150 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt));
151 return internal_equalp (item, elt, 0);
152 }
153
154 static Boolint
155 check_string_match_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key),
156 Lisp_Object item, Lisp_Object elt)
157 {
158 return !NILP (Fstring_match (item, elt, Qnil, Qnil));
159 }
160
161 static Boolint
162 check_string_match_key (Lisp_Object UNUSED (test), Lisp_Object key,
163 Lisp_Object item, Lisp_Object elt)
164 {
165 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt));
166 return !NILP (Fstring_match (item, elt, Qnil, Qnil));
167 }
168
169 static Boolint
170 check_other_nokey (Lisp_Object test, Lisp_Object UNUSED (key),
171 Lisp_Object item, Lisp_Object elt)
172 {
173 Lisp_Object args[] = { test, item, elt };
174 struct gcpro gcpro1;
175
176 GCPRO1 (args[0]);
177 gcpro1.nvars = countof (args);
178 item = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args));
179 UNGCPRO;
180
181 return !NILP (item);
182 }
183
184 static Boolint
185 check_other_key (Lisp_Object test, Lisp_Object key,
186 Lisp_Object item, Lisp_Object elt)
187 {
188 Lisp_Object args[] = { item, key, elt };
189 struct gcpro gcpro1;
190
191 GCPRO1 (args[0]);
192 gcpro1.nvars = countof (args);
193 args[2] = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args) - 1, args + 1));
194 args[1] = item;
195 args[0] = test;
196 item = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args));
197 UNGCPRO;
198
199 return !NILP (item);
200 }
201
202 static Boolint
203 check_if_nokey (Lisp_Object test, Lisp_Object UNUSED (key),
204 Lisp_Object UNUSED (item), Lisp_Object elt)
205 {
206 elt = IGNORE_MULTIPLE_VALUES (call1 (test, elt));
207 return !NILP (elt);
208 }
209
210 static Boolint
211 check_if_key (Lisp_Object test, Lisp_Object key,
212 Lisp_Object UNUSED (item), Lisp_Object elt)
213 {
214 Lisp_Object args[] = { key, elt };
215 struct gcpro gcpro1;
216
217 GCPRO1 (args[0]);
218 gcpro1.nvars = countof (args);
219 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args));
220 args[0] = test;
221 elt = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args));
222 UNGCPRO;
223
224 return !NILP (elt);
225 }
226
227 static Boolint
228 check_match_eq_key (Lisp_Object UNUSED (test), Lisp_Object key,
229 Lisp_Object elt1, Lisp_Object elt2)
230 {
231 Lisp_Object args[] = { key, elt1, elt2 };
232 struct gcpro gcpro1;
233
234 GCPRO1 (args[0]);
235 gcpro1.nvars = countof (args);
236 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args));
237 args[1] = key;
238 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1));
239 UNGCPRO;
240
241 return EQ (args[0], args[1]);
242 }
243
244 static Boolint
245 check_match_eql_key (Lisp_Object UNUSED (test), Lisp_Object key,
246 Lisp_Object elt1, Lisp_Object elt2)
247 {
248 Lisp_Object args[] = { key, elt1, elt2 };
249 struct gcpro gcpro1;
250
251 GCPRO1 (args[0]);
252 gcpro1.nvars = countof (args);
253 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args));
254 args[1] = key;
255 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1));
256 UNGCPRO;
257
258 return EQ (args[0], args[1]) ||
259 (NON_FIXNUM_NUMBER_P (args[0]) && internal_equal (args[0], args[1], 0));
260 }
261
262 static Boolint
263 check_match_equal_key (Lisp_Object UNUSED (test), Lisp_Object key,
264 Lisp_Object elt1, Lisp_Object elt2)
265 {
266 Lisp_Object args[] = { key, elt1, elt2 };
267 struct gcpro gcpro1;
268
269 GCPRO1 (args[0]);
270 gcpro1.nvars = countof (args);
271 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args));
272 args[1] = key;
273 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1));
274 UNGCPRO;
275
276 return internal_equal (args[0], args[1], 0);
277 }
278
279 static Boolint
280 check_match_equalp_key (Lisp_Object UNUSED (test), Lisp_Object key,
281 Lisp_Object elt1, Lisp_Object elt2)
282 {
283 Lisp_Object args[] = { key, elt1, elt2 };
284 struct gcpro gcpro1;
285
286 GCPRO1 (args[0]);
287 gcpro1.nvars = countof (args);
288 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args));
289 args[1] = key;
290 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1));
291 UNGCPRO;
292
293 return internal_equalp (args[0], args[1], 0);
294 }
295
296 static Boolint
297 check_match_other_key (Lisp_Object test, Lisp_Object key,
298 Lisp_Object elt1, Lisp_Object elt2)
299 {
300 Lisp_Object args[] = { key, elt1, elt2 };
301 struct gcpro gcpro1;
302
303 GCPRO1 (args[0]);
304 gcpro1.nvars = countof (args);
305 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args));
306 args[1] = key;
307 args[2] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1));
308 args[1] = args[0];
309 args[0] = test;
310
311 elt1 = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args));
312 UNGCPRO;
313
314 return !NILP (elt1);
315 }
316
317 static Boolint
318 check_lss_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key),
319 Lisp_Object elt1, Lisp_Object elt2)
320 {
321 return bytecode_arithcompare (elt1, elt2) < 0;
322 }
323
324 static Boolint
325 check_lss_key (Lisp_Object UNUSED (test), Lisp_Object key,
326 Lisp_Object elt1, Lisp_Object elt2)
327 {
328 Lisp_Object args[] = { key, elt1, elt2 };
329 struct gcpro gcpro1;
330
331 GCPRO1 (args[0]);
332 gcpro1.nvars = countof (args);
333 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args));
334 args[1] = key;
335 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1));
336 UNGCPRO;
337
338 return bytecode_arithcompare (args[0], args[1]) < 0;
339 }
340
341 Boolint
342 check_lss_key_car (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key),
343 Lisp_Object elt1, Lisp_Object elt2)
344 {
345 struct gcpro gcpro1, gcpro2;
346
347 GCPRO2 (elt1, elt2);
348 elt1 = CONSP (elt1) ? XCAR (elt1) : Fcar (elt1);
349 elt2 = CONSP (elt2) ? XCAR (elt2) : Fcar (elt2);
350 UNGCPRO;
351
352 return bytecode_arithcompare (elt1, elt2) < 0;
353 }
354
355 Boolint
356 check_string_lessp_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key),
357 Lisp_Object elt1, Lisp_Object elt2)
358 {
359 return !NILP (Fstring_lessp (elt1, elt2));
360 }
361
362 static Boolint
363 check_string_lessp_key (Lisp_Object UNUSED (test), Lisp_Object key,
364 Lisp_Object elt1, Lisp_Object elt2)
365 {
366 Lisp_Object args[] = { key, elt1, elt2 };
367 struct gcpro gcpro1;
368
369 GCPRO1 (args[0]);
370 gcpro1.nvars = countof (args);
371 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args));
372 args[1] = key;
373 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1));
374 UNGCPRO;
375
376 return !NILP (Fstring_lessp (args[0], args[1]));
377 }
378
379 static Boolint
380 check_string_lessp_key_car (Lisp_Object UNUSED (test),
381 Lisp_Object UNUSED (key),
382 Lisp_Object elt1, Lisp_Object elt2)
383 {
384 struct gcpro gcpro1, gcpro2;
385
386 GCPRO2 (elt1, elt2);
387 elt1 = CONSP (elt1) ? XCAR (elt1) : Fcar (elt1);
388 elt2 = CONSP (elt2) ? XCAR (elt2) : Fcar (elt2);
389 UNGCPRO;
390
391 return !NILP (Fstring_lessp (elt1, elt2));
392 }
393
394 static check_test_func_t
395 get_check_match_function_1 (Lisp_Object item,
396 Lisp_Object *test_inout, Lisp_Object test_not,
397 Lisp_Object if_, Lisp_Object if_not,
398 Lisp_Object key, Boolint *test_not_unboundp_out,
399 check_test_func_t *test_func_out)
400 {
401 Lisp_Object test = *test_inout;
402 check_test_func_t result = NULL, test_func = NULL;
403 Boolint force_if = 0;
404
405 if (!NILP (if_))
406 {
407 if (!(NILP (test) && NILP (test_not) && NILP (if_not)))
408 {
409 invalid_argument ("only one keyword among :test :test-not "
410 ":if :if-not allowed", if_);
411 }
412
413 test = *test_inout = if_;
414 force_if = 1;
415 }
416 else if (!NILP (if_not))
417 {
418 if (!(NILP (test) && NILP (test_not)))
419 {
420 invalid_argument ("only one keyword among :test :test-not "
421 ":if :if-not allowed", if_not);
422 }
423
424 test_not = if_not;
425 force_if = 1;
426 }
427
428 if (NILP (test))
429 {
430 if (!NILP (test_not))
431 {
432 test = *test_inout = test_not;
433 if (NULL != test_not_unboundp_out)
434 {
435 *test_not_unboundp_out = 0;
436 }
437 }
438 else
439 {
440 test = Qeql;
441 if (NULL != test_not_unboundp_out)
442 {
443 *test_not_unboundp_out = 1;
444 }
445 }
446 }
447 else if (!NILP (test_not))
448 {
449 invalid_argument_2 ("conflicting :test and :test-not keyword arguments",
450 test, test_not);
451 }
452
453 test = indirect_function (test, 1);
454
455 if (NILP (key) ||
456 EQ (indirect_function (key, 1), XSYMBOL_FUNCTION (Qidentity)))
457 {
458 key = Qidentity;
459 }
460
461 if (force_if)
462 {
463 result = EQ (key, Qidentity) ? check_if_nokey : check_if_key;
464
465 if (NULL != test_func_out)
466 {
467 *test_func_out = result;
468 }
469
470 return result;
471 }
472
473 if (!UNBOUNDP (item) && EQ (test, XSYMBOL_FUNCTION (Qeql)))
474 {
475 test = XSYMBOL_FUNCTION (NON_FIXNUM_NUMBER_P (item) ? Qequal : Qeq);
476 }
477
478 #define FROB(known_test, eq_condition) \
479 if (EQ (test, XSYMBOL_FUNCTION (Q##known_test))) do \
480 { \
481 if (eq_condition) \
482 { \
483 test = XSYMBOL_FUNCTION (Qeq); \
484 goto force_eq_check; \
485 } \
486 \
487 if (!EQ (Qidentity, key)) \
488 { \
489 test_func = check_##known_test##_key; \
490 result = check_match_##known_test##_key; \
491 } \
492 else \
493 { \
494 result = test_func = check_##known_test##_nokey; \
495 } \
496 } while (0)
497
498 FROB (eql, 0);
499 else if (SUBRP (test))
500 {
501 force_eq_check:
502 FROB (eq, 0);
503 else FROB (equal, (SYMBOLP (item) || FIXNUMP (item) || CHARP (item)));
504 else FROB (equalp, (SYMBOLP (item)));
505 else if (EQ (test, XSYMBOL_FUNCTION (Qstring_match)))
506 {
507 if (EQ (Qidentity, key))
508 {
509 test_func = result = check_string_match_nokey;
510 }
511 else
512 {
513 test_func = check_string_match_key;
514 result = check_other_key;
515 }
516 }
517 }
518
519 if (NULL == result)
520 {
521 if (EQ (Qidentity, key))
522 {
523 test_func = result = check_other_nokey;
524 }
525 else
526 {
527 test_func = check_other_key;
528 result = check_match_other_key;
529 }
530 }
531
532 if (NULL != test_func_out)
533 {
534 *test_func_out = test_func;
535 }
536
537 return result;
538 }
539 #undef FROB
540
541 /* Given TEST, TEST_NOT, IF, IF_NOT, KEY, and ITEM, return a C function
542 pointer appropriate for use in deciding whether a given element of a
543 sequence satisfies TEST.
544
545 Set *test_not_unboundp_out to 1 if TEST_NOT was not bound; set it to zero
546 if it was bound, and set *test_inout to the value it was bound to. If
547 TEST was not bound, leave *test_inout alone; the value is not used by
548 check_eq_*key() or check_equal_*key(), which are the defaults, depending
549 on the type of ITEM.
550
551 The returned function takes arguments (TEST, KEY, ITEM, ELT), where ITEM
552 is the item being searched for and ELT is the element of the sequence
553 being examined.
554
555 Error if both TEST and TEST_NOT were specified, which Common Lisp says is
556 undefined behaviour. */
557
558 static check_test_func_t
559 get_check_test_function (Lisp_Object item,
560 Lisp_Object *test_inout, Lisp_Object test_not,
561 Lisp_Object if_, Lisp_Object if_not,
562 Lisp_Object key, Boolint *test_not_unboundp_out)
563 {
564 check_test_func_t result = NULL;
565 get_check_match_function_1 (item, test_inout, test_not, if_, if_not,
566 key, test_not_unboundp_out, &result);
567 return result;
568 }
569
570 /* Given TEST, TEST_NOT, IF, IF_NOT and KEY, return a C function pointer
571 appropriate for use in deciding whether two given elements of a sequence
572 satisfy TEST.
573
574 Set *test_not_unboundp_out to 1 if TEST_NOT was not bound; set it to zero
575 if it was bound, and set *test_inout to the value it was bound to. If
576 TEST was not bound, leave *test_inout alone; the value is not used by
577 check_eql_*key().
578
579 The returned function takes arguments (TEST, KEY, ELT1, ELT2), where ELT1
580 and ELT2 are elements of the sequence being examined.
581
582 The value that would be given by get_check_test_function() is returned in
583 *TEST_FUNC_OUT, which allows calling functions to do their own key checks
584 if they're processing one element at a time.
585
586 Error if both TEST and TEST_NOT were specified, which Common Lisp says is
587 undefined behaviour. */
588
589 static check_test_func_t
590 get_check_match_function (Lisp_Object *test_inout, Lisp_Object test_not,
591 Lisp_Object if_, Lisp_Object if_not,
592 Lisp_Object key, Boolint *test_not_unboundp_out,
593 check_test_func_t *test_func_out)
594 {
595 return get_check_match_function_1 (Qunbound, test_inout, test_not,
596 if_, if_not, key,
597 test_not_unboundp_out, test_func_out);
598 }
599
600 /* Given PREDICATE and KEY, return a C function pointer appropriate for use
601 in deciding whether one given element of a sequence is less than
602 another. */
603
604 static check_test_func_t
605 get_merge_predicate (Lisp_Object predicate, Lisp_Object key)
606 {
607 predicate = indirect_function (predicate, 1);
608
609 if (NILP (key))
610 {
611 key = Qidentity;
612 }
613 else
614 {
615 key = indirect_function (key, 1);
616 if (EQ (key, XSYMBOL_FUNCTION (Qidentity)))
617 {
618 key = Qidentity;
619 }
620 }
621
622 if (EQ (key, Qidentity) && EQ (predicate,
623 XSYMBOL_FUNCTION (Qcar_less_than_car)))
624 {
625 key = XSYMBOL_FUNCTION (Qcar);
626 predicate = XSYMBOL_FUNCTION (Qlss);
627 }
628
629 if (EQ (predicate, XSYMBOL_FUNCTION (Qlss)))
630 {
631 if (EQ (key, Qidentity))
632 {
633 return check_lss_nokey;
634 }
635
636 if (EQ (key, XSYMBOL_FUNCTION (Qcar)))
637 {
638 return check_lss_key_car;
639 }
640
641 return check_lss_key;
642 }
643
644 if (EQ (predicate, XSYMBOL_FUNCTION (Qstring_lessp)))
645 {
646 if (EQ (key, Qidentity))
647 {
648 return check_string_lessp_nokey;
649 }
650
651 if (EQ (key, XSYMBOL_FUNCTION (Qcar)))
652 {
653 return check_string_lessp_key_car;
654 }
655
656 return check_string_lessp_key;
657 }
658
659 if (EQ (key, Qidentity))
660 {
661 return check_other_nokey;
662 }
663
664 return check_match_other_key;
665 }
666
667
668 static Lisp_Object string_count_from_end (Lisp_Object, Lisp_Object ,
669 check_test_func_t, Boolint,
670 Lisp_Object, Lisp_Object,
671 Lisp_Object, Lisp_Object);
672
673 static Lisp_Object list_count_from_end (Lisp_Object, Lisp_Object,
674 check_test_func_t, Boolint,
675 Lisp_Object, Lisp_Object,
676 Lisp_Object, Lisp_Object);
677
678 /* Count the number of occurrences of ITEM in SEQUENCE; if SEQUENCE is a
679 list, store the cons cell of which the car is the last ITEM in SEQUENCE,
680 at the address given by tail_out. */
681
682 static Lisp_Object
683 count_with_tail (Lisp_Object *tail_out, int nargs, Lisp_Object *args,
684 Lisp_Object caller)
685 {
686 Lisp_Object item = args[0], sequence = args[1];
687 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, encountered = 0;
688 Elemcount len, ii = 0, counting = MOST_POSITIVE_FIXNUM;
689 Boolint test_not_unboundp = 1;
690 check_test_func_t check_test = NULL;
691
692 PARSE_KEYWORDS_8 (caller, nargs, args, 9,
693 (test, key, start, end, from_end, test_not, count,
694 if_, if_not), (start = Qzero), 2, 0);
695
696 CHECK_SEQUENCE (sequence);
697 CHECK_NATNUM (start);
698 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start);
699
700 if (!NILP (end))
701 {
702 CHECK_NATNUM (end);
703 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end);
704 }
705
706 if (!NILP (count))
707 {
708 CHECK_INTEGER (count);
709 counting = BIGNUMP (count) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (count);
710
711 /* Our callers should have filtered out non-positive COUNT. */
712 assert (counting >= 0);
713 /* And we're not prepared to handle COUNT from any other caller at the
714 moment. */
715 assert (EQ (caller, QremoveX)|| EQ (caller, QdeleteX));
716 }
717
718 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
719 key, &test_not_unboundp);
720
721 *tail_out = Qnil;
722
723 if (CONSP (sequence))
724 {
725 if (EQ (caller, Qcount) && !NILP (from_end)
726 && (!EQ (key, Qnil) ||
727 check_test == check_other_nokey || check_test == check_if_nokey))
728 {
729 /* #'count, #'count-if, and #'count-if-not are documented to have
730 a given traversal order if :from-end t is passed in, even
731 though forward traversal of the sequence has the same result
732 and is algorithmically less expensive for lists and strings.
733 This order isn't necessary for other callers, though. */
734 return list_count_from_end (item, sequence, check_test,
735 test_not_unboundp, test, key,
736 start, end);
737 }
738
739 /* If COUNT is non-nil and FROM-END is t, we can give the tail
740 containing the last match, since that's what #'remove* is
741 interested in (a zero or negative COUNT won't ever reach
742 count_with_tail(), our callers will return immediately on seeing
743 it). */
744 if (!NILP (count) && !NILP (from_end))
745 {
746 counting = MOST_POSITIVE_FIXNUM;
747 }
748
749 {
750 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail)
751 {
752 if (!(ii < ending))
753 {
754 break;
755 }
756
757 if (starting <= ii &&
758 check_test (test, key, item, elt) == test_not_unboundp)
759 {
760 encountered++;
761 *tail_out = tail;
762
763 if (encountered == counting)
764 {
765 break;
766 }
767 }
768
769 ii++;
770 }
771 END_GC_EXTERNAL_LIST_LOOP (elt);
772 }
773
774 if ((ii < starting || (ii < ending && !NILP (end))) &&
775 encountered != counting)
776 {
777 check_sequence_range (args[1], start, end, Flength (args[1]));
778 }
779 }
780 else if (STRINGP (sequence))
781 {
782 Ibyte *startp = XSTRING_DATA (sequence), *cursor = startp;
783 Bytecount byte_len = XSTRING_LENGTH (sequence), cursor_offset = 0;
784 Lisp_Object character = Qnil;
785
786 if (EQ (caller, Qcount) && !NILP (from_end)
787 && (!EQ (key, Qnil) ||
788 check_test == check_other_nokey || check_test == check_if_nokey))
789 {
790 /* See comment above in the list code. */
791 return string_count_from_end (item, sequence,
792 check_test, test_not_unboundp,
793 test, key, start, end);
794 }
795
796 while (cursor_offset < byte_len && ii < ending && encountered < counting)
797 {
798 if (ii >= starting)
799 {
800 character = make_char (itext_ichar (cursor));
801
802 if (check_test (test, key, item, character)
803 == test_not_unboundp)
804 {
805 encountered++;
806 }
807
808 startp = XSTRING_DATA (sequence);
809 cursor = startp + cursor_offset;
810 if (byte_len != XSTRING_LENGTH (sequence)
811 || !valid_ibyteptr_p (cursor))
812 {
813 mapping_interaction_error (caller, sequence);
814 }
815 }
816
817 INC_IBYTEPTR (cursor);
818 cursor_offset = cursor - startp;
819 ii++;
820 }
821
822 if (ii < starting || (ii < ending && !NILP (end)))
823 {
824 check_sequence_range (sequence, start, end, Flength (sequence));
825 }
826 }
827 else
828 {
829 Lisp_Object object = Qnil;
830
831 len = XFIXNUM (Flength (sequence));
832 check_sequence_range (sequence, start, end, make_fixnum (len));
833
834 ending = min (ending, len);
835 if (0 == len)
836 {
837 /* Catches the case where we have nil. */
838 return make_integer (encountered);
839 }
840
841 if (NILP (from_end))
842 {
843 for (ii = starting; ii < ending && encountered < counting; ii++)
844 {
845 object = Faref (sequence, make_fixnum (ii));
846 if (check_test (test, key, item, object) == test_not_unboundp)
847 {
848 encountered++;
849 }
850 }
851 }
852 else
853 {
854 for (ii = ending - 1; ii >= starting && encountered < counting; ii--)
855 {
856 object = Faref (sequence, make_fixnum (ii));
857 if (check_test (test, key, item, object) == test_not_unboundp)
858 {
859 encountered++;
860 }
861 }
862 }
863 }
864
865 return make_integer (encountered);
866 }
867
868 static Lisp_Object
869 list_count_from_end (Lisp_Object item, Lisp_Object sequence,
870 check_test_func_t check_test, Boolint test_not_unboundp,
871 Lisp_Object test, Lisp_Object key,
872 Lisp_Object start, Lisp_Object end)
873 {
874 Elemcount length = XFIXNUM (Flength (sequence)), ii = 0, starting = XFIXNUM (start);
875 Elemcount ending = NILP (end) ? length : XFIXNUM (end), encountered = 0;
876 Lisp_Object *storage;
877 struct gcpro gcpro1;
878
879 check_sequence_range (sequence, start, end, make_integer (length));
880
881 storage = alloca_array (Lisp_Object, ending - starting);
882
883 {
884 EXTERNAL_LIST_LOOP_2 (elt, sequence)
885 {
886 if (starting <= ii && ii < ending)
887 {
888 storage[ii - starting] = elt;
889 }
890 ii++;
891 }
892 }
893
894 GCPRO1 (storage[0]);
895 gcpro1.nvars = ending - starting;
896
897 for (ii = ending - 1; ii >= starting; ii--)
898 {
899 if (check_test (test, key, item, storage[ii - starting])
900 == test_not_unboundp)
901 {
902 encountered++;
903 }
904 }
905
906 UNGCPRO;
907
908 return make_integer (encountered);
909 }
910
911 static Lisp_Object
912 string_count_from_end (Lisp_Object item, Lisp_Object sequence,
913 check_test_func_t check_test, Boolint test_not_unboundp,
914 Lisp_Object test, Lisp_Object key,
915 Lisp_Object start, Lisp_Object end)
916 {
917 Elemcount length = string_char_length (sequence), ii = 0;
918 Elemcount starting = XFIXNUM (start), ending = NILP (end) ? length : XFIXNUM (end);
919 Elemcount encountered = 0;
920 Ibyte *cursor = XSTRING_DATA (sequence);
921 Ibyte *endp = cursor + XSTRING_LENGTH (sequence);
922 Ichar *storage;
923
924 check_sequence_range (sequence, start, end, make_integer (length));
925
926 storage = alloca_array (Ichar, ending - starting);
927
928 while (cursor < endp && ii < ending)
929 {
930 if (starting <= ii && ii < ending)
931 {
932 storage [ii - starting] = itext_ichar (cursor);
933 }
934
935 ii++;
936 INC_IBYTEPTR (cursor);
937 }
938
939 for (ii = ending - 1; ii >= starting; ii--)
940 {
941 if (check_test (test, key, item, make_char (storage [ii - starting]))
942 == test_not_unboundp)
943 {
944 encountered++;
945 }
946 }
947
948 return make_integer (encountered);
949 }
950
951 DEFUN ("count", Fcount, 2, MANY, 0, /*
952 Count the number of occurrences of ITEM in SEQUENCE.
953
954 See `remove*' for the meaning of the keywords.
955
956 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) END FROM-END TEST-NOT)
957 */
958 (int nargs, Lisp_Object *args))
959 {
960 Lisp_Object tail = Qnil;
961
962 /* count_with_tail() accepts more keywords than we do, check those we've
963 been given. */
964 PARSE_KEYWORDS (Fcount, nargs, args, 8,
965 (test, test_not, if_, if_not, key, start, end, from_end),
966 NULL);
967
968 return count_with_tail (&tail, nargs, args, Qcount);
969 }
970
971 DEFUN ("subseq", Fsubseq, 2, 3, 0, /*
972 Return the subsequence of SEQUENCE starting at START and ending before END.
973 END may be omitted; then the subsequence runs to the end of SEQUENCE.
974
975 If START or END is negative, it counts from the end, in contravention of
976 Common Lisp.
977 The returned subsequence is always of the same type as SEQUENCE.
978 If SEQUENCE is a string, relevant parts of the string-extent-data
979 are copied to the new string.
980
981 See also `substring-no-properties', which only operates on strings, and does
982 not copy extent data.
983 */
984 (sequence, start, end))
985 {
986 Elemcount len, ss, ee = MOST_POSITIVE_FIXNUM, ii;
987 Lisp_Object result = Qnil;
988
989 CHECK_SEQUENCE (sequence);
990 CHECK_FIXNUM (start);
991 ss = XFIXNUM (start);
992
993 if (!NILP (end))
994 {
995 CHECK_FIXNUM (end);
996 ee = XFIXNUM (end);
997 }
998
999 if (STRINGP (sequence))
1000 {
1001 Bytecount bstart, blen;
1002
1003 get_string_range_char (sequence, start, end, &ss, &ee,
1004 GB_HISTORICAL_STRING_BEHAVIOR);
1005 bstart = string_index_char_to_byte (sequence, ss);
1006 blen = string_offset_char_to_byte_len (sequence, bstart, ee - ss);
1007
1008 result = make_string (XSTRING_DATA (sequence) + bstart, blen);
1009 /* Copy any applicable extent information into the new string. */
1010 copy_string_extents (result, sequence, 0, bstart, blen);
1011 }
1012 else if (CONSP (sequence))
1013 {
1014 Lisp_Object result_tail, saved = sequence;
1015
1016 if (ss < 0 || ee < 0)
1017 {
1018 len = XFIXNUM (Flength (sequence));
1019 if (ss < 0)
1020 {
1021 ss = len + ss;
1022 start = make_integer (ss);
1023 }
1024
1025 if (ee < 0)
1026 {
1027 ee = len + ee;
1028 end = make_integer (ee);
1029 }
1030 else
1031 {
1032 ee = min (ee, len);
1033 }
1034 }
1035
1036 if (0 != ss)
1037 {
1038 sequence = Fnthcdr (make_fixnum (ss), sequence);
1039 }
1040
1041 ii = ss + 1;
1042
1043 if (ss < ee && !NILP (sequence))
1044 {
1045 result = result_tail = Fcons (Fcar (sequence), Qnil);
1046 sequence = Fcdr (sequence);
1047
1048 {
1049 EXTERNAL_LIST_LOOP_2 (elt, sequence)
1050 {
1051 if (!(ii < ee))
1052 {
1053 break;
1054 }
1055
1056 XSETCDR (result_tail, Fcons (elt, Qnil));
1057 result_tail = XCDR (result_tail);
1058 ii++;
1059 }
1060 }
1061 }
1062
1063 if (NILP (result) || (ii < ee && !NILP (end)))
1064 {
1065 /* We were handed a cons, which definitely has elements. nil
1066 result means either ss >= ee or SEQUENCE was nil after the
1067 nthcdr; in both cases that means START and END were incorrectly
1068 specified for this sequence. ii < ee with a non-nil end means
1069 the user handed us a bogus end value. */
1070 check_sequence_range (saved, start, end, Flength (saved));
1071 }
1072 }
1073 else
1074 {
1075 len = XFIXNUM (Flength (sequence));
1076 if (ss < 0)
1077 {
1078 ss = len + ss;
1079 start = make_integer (ss);
1080 }
1081
1082 if (ee < 0)
1083 {
1084 ee = len + ee;
1085 end = make_integer (ee);
1086 }
1087 else
1088 {
1089 ee = min (len, ee);
1090 }
1091
1092 check_sequence_range (sequence, start, end, make_fixnum (len));
1093
1094 if (VECTORP (sequence))
1095 {
1096 result = Fvector (ee - ss, XVECTOR_DATA (sequence) + ss);
1097 }
1098 else if (BIT_VECTORP (sequence))
1099 {
1100 result = make_bit_vector (ee - ss, Qzero);
1101
1102 for (ii = ss; ii < ee; ii++)
1103 {
1104 set_bit_vector_bit (XBIT_VECTOR (result), ii - ss,
1105 bit_vector_bit (XBIT_VECTOR (sequence), ii));
1106 }
1107 }
1108 else if (NILP (sequence))
1109 {
1110 DO_NOTHING;
1111 }
1112 else
1113 {
1114 /* Won't happen, since CHECK_SEQUENCE didn't error. */
1115 ABORT ();
1116 }
1117 }
1118
1119 return result;
1120 }
1121
1122 DEFUN ("elt", Felt, 2, 2, 0, /*
1123 Return element of SEQUENCE at index N.
1124 */
1125 (sequence, n))
1126 {
1127 /* This function can GC */
1128 retry:
1129 CHECK_FIXNUM_COERCE_CHAR (n); /* yuck! */
1130 if (LISTP (sequence))
1131 {
1132 Lisp_Object tem = Fnthcdr (n, sequence);
1133 /* #### Utterly, completely, fucking disgusting.
1134 * #### The whole point of "elt" is that it operates on
1135 * #### sequences, and does error- (bounds-) checking.
1136 */
1137 if (CONSP (tem))
1138 return XCAR (tem);
1139 else
1140 #if 1
1141 /* This is The Way It Has Always Been. */
1142 return Qnil;
1143 #else
1144 /* This is The Way Mly and Cltl2 say It Should Be. */
1145 args_out_of_range (sequence, n);
1146 #endif
1147 }
1148 else if (STRINGP (sequence) ||
1149 VECTORP (sequence) ||
1150 BIT_VECTORP (sequence))
1151 return Faref (sequence, n);
1152 else
1153 {
1154 check_losing_bytecode ("elt", sequence);
1155 sequence = wrong_type_argument (Qsequencep, sequence);
1156 goto retry;
1157 }
1158 }
1159
1160 DEFUN ("copy-tree", Fcopy_tree, 1, 2, 0, /*
1161 Return a copy of a list and substructures.
1162 The argument is copied, and any lists contained within it are copied
1163 recursively. Circularities and shared substructures are not preserved.
1164 Second arg VECP causes vectors to be copied, too. Strings and bit vectors
1165 are not copied.
1166 */
1167 (arg, vecp))
1168 {
1169 return safe_copy_tree (arg, vecp, 0);
1170 }
1171
1172 Lisp_Object
1173 safe_copy_tree (Lisp_Object arg, Lisp_Object vecp, int depth)
1174 {
1175 if (depth + lisp_eval_depth > max_lisp_eval_depth)
1176 stack_overflow ("Stack overflow in copy-tree", arg);
1177
1178 if (CONSP (arg))
1179 {
1180 Lisp_Object rest;
1181 rest = arg = Fcopy_sequence (arg);
1182 while (CONSP (rest))
1183 {
1184 Lisp_Object elt = XCAR (rest);
1185 QUIT;
1186 if (CONSP (elt) || VECTORP (elt))
1187 XCAR (rest) = safe_copy_tree (elt, vecp, depth + 1);
1188 if (VECTORP (XCDR (rest))) /* hack for (a b . [c d]) */
1189 XCDR (rest) = safe_copy_tree (XCDR (rest), vecp, depth +1);
1190 rest = XCDR (rest);
1191 }
1192 }
1193 else if (VECTORP (arg) && ! NILP (vecp))
1194 {
1195 int i = XVECTOR_LENGTH (arg);
1196 int j;
1197 arg = Fcopy_sequence (arg);
1198 for (j = 0; j < i; j++)
1199 {
1200 Lisp_Object elt = XVECTOR_DATA (arg) [j];
1201 QUIT;
1202 if (CONSP (elt) || VECTORP (elt))
1203 XVECTOR_DATA (arg) [j] = safe_copy_tree (elt, vecp, depth + 1);
1204 }
1205 }
1206 return arg;
1207 }
1208
1209 DEFUN ("member", Fmember, 2, 2, 0, /*
1210 Return non-nil if ELT is an element of LIST. Comparison done with `equal'.
1211 The value is actually the tail of LIST whose car is ELT.
1212 */
1213 (elt, list))
1214 {
1215 EXTERNAL_LIST_LOOP_3 (list_elt, list, tail)
1216 {
1217 if (internal_equal (elt, list_elt, 0))
1218 return tail;
1219 }
1220 return Qnil;
1221 }
1222
1223 DEFUN ("memq", Fmemq, 2, 2, 0, /*
1224 Return non-nil if ELT is an element of LIST. Comparison done with `eq'.
1225 The value is actually the tail of LIST whose car is ELT.
1226 */
1227 (elt, list))
1228 {
1229 EXTERNAL_LIST_LOOP_3 (list_elt, list, tail)
1230 {
1231 if (EQ_WITH_EBOLA_NOTICE (elt, list_elt))
1232 return tail;
1233 }
1234 return Qnil;
1235 }
1236
1237 Lisp_Object
1238 memq_no_quit (Lisp_Object elt, Lisp_Object list)
1239 {
1240 LIST_LOOP_3 (list_elt, list, tail)
1241 {
1242 if (EQ_WITH_EBOLA_NOTICE (elt, list_elt))
1243 return tail;
1244 }
1245 return Qnil;
1246 }
1247
1248 /* Return the first index of ITEM in LIST. In CONS_OUT, return the cons cell
1249 before that containing the element. If the element is in the first cons
1250 cell, return Qnil in CONS_OUT. TEST, KEY, START, END are as in
1251 #'remove*; CHECK_TEST and TEST_NOT_UNBOUNDP should have been initialized
1252 with get_check_match_function() or get_check_test_function(). A non-zero
1253 REVERSE_TEST_ORDER means call TEST with the element from LIST as its
1254 first argument and ITEM as its second. Error if LIST is ill-formed, or
1255 circular. */
1256 static Lisp_Object
1257 list_position_cons_before (Lisp_Object *cons_out,
1258 Lisp_Object item, Lisp_Object list,
1259 check_test_func_t check_test,
1260 Boolint test_not_unboundp,
1261 Lisp_Object test, Lisp_Object key,
1262 Boolint reverse_test_order,
1263 Lisp_Object start, Lisp_Object end)
1264 {
1265 struct gcpro gcpro1;
1266 Lisp_Object tail_before = Qnil;
1267 Elemcount ii = 0, starting = XFIXNUM (start);
1268 Elemcount ending = NILP (end) ? MOST_POSITIVE_FIXNUM : XFIXNUM (end);
1269
1270 GCPRO1 (tail_before);
1271
1272 if (check_test == check_eq_nokey)
1273 {
1274 /* TEST is #'eq, no need to call any C functions, and the test order
1275 won't be visible. */
1276 EXTERNAL_LIST_LOOP_3 (elt, list, tail)
1277 {
1278 if (starting <= ii && ii < ending &&
1279 EQ (item, elt) == test_not_unboundp)
1280 {
1281 *cons_out = tail_before;
1282 RETURN_UNGCPRO (make_integer (ii));
1283 }
1284 else
1285 {
1286 if (ii >= ending)
1287 {
1288 break;
1289 }
1290 }
1291 ii++;
1292 tail_before = tail;
1293 }
1294 }
1295 else
1296 {
1297 GC_EXTERNAL_LIST_LOOP_3 (elt, list, tail)
1298 {
1299 if (starting <= ii && ii < ending &&
1300 (reverse_test_order ?
1301 check_test (test, key, elt, item) :
1302 check_test (test, key, item, elt)) == test_not_unboundp)
1303 {
1304 *cons_out = tail_before;
1305 XUNGCPRO (elt);
1306 UNGCPRO;
1307 return make_integer (ii);
1308 }
1309 else
1310 {
1311 if (ii >= ending)
1312 {
1313 break;
1314 }
1315 }
1316 ii++;
1317 tail_before = tail;
1318 }
1319 END_GC_EXTERNAL_LIST_LOOP (elt);
1320 }
1321
1322 RETURN_UNGCPRO (Qnil);
1323 }
1324
1325 DEFUN ("member*", FmemberX, 2, MANY, 0, /*
1326 Return the first sublist of LIST with car ITEM, or nil if no such sublist.
1327
1328 The keyword :test specifies a two-argument function that is used to compare
1329 ITEM with elements in LIST; if omitted, it defaults to `eql'.
1330
1331 The keyword :test-not is similar, but specifies a negated function. That
1332 is, ITEM is considered equal to an element in LIST if the given function
1333 returns nil. Common Lisp deprecates :test-not, and if both are specified,
1334 XEmacs signals an error.
1335
1336 :key specifies a one-argument function that transforms elements of LIST into
1337 \"comparison keys\" before the test predicate is applied. For example,
1338 if :key is #'car, then ITEM is compared with the car of elements from LIST.
1339 The :key function, however, is not applied to ITEM, and does not affect the
1340 elements in the returned list, which are taken directly from the elements in
1341 LIST.
1342
1343 arguments: (ITEM LIST &key (TEST #'eql) TEST-NOT (KEY #'identity))
1344 */
1345 (int nargs, Lisp_Object *args))
1346 {
1347 Lisp_Object item = args[0], list = args[1], result = Qnil, position0;
1348 Boolint test_not_unboundp = 1;
1349 check_test_func_t check_test = NULL;
1350
1351 PARSE_KEYWORDS (FmemberX, nargs, args, 5, (test, if_not, if_, test_not, key),
1352 NULL);
1353 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
1354 key, &test_not_unboundp);
1355 position0
1356 = list_position_cons_before (&result, item, list, check_test,
1357 test_not_unboundp, test, key, 0, Qzero, Qnil);
1358
1359 return CONSP (result) ? XCDR (result) : ZEROP (position0) ? list : Qnil;
1360 }
1361
1362 /* This macro might eventually find a better home than here. */
1363
1364 #define CHECK_KEY_ARGUMENT(key) \
1365 do { \
1366 if (NILP (key)) \
1367 { \
1368 key = Qidentity; \
1369 } \
1370 \
1371 if (!EQ (key, Qidentity)) \
1372 { \
1373 key = indirect_function (key, 1); \
1374 if (EQ (key, XSYMBOL_FUNCTION (Qidentity))) \
1375 { \
1376 key = Qidentity; \
1377 } \
1378 } \
1379 } while (0)
1380
1381 #define KEY(key, item) (EQ (Qidentity, key) ? item : \
1382 IGNORE_MULTIPLE_VALUES (call1 (key, item)))
1383
1384 DEFUN ("adjoin", Fadjoin, 2, MANY, 0, /*
1385 Return ITEM consed onto the front of LIST, if not already in LIST.
1386
1387 Otherwise, return LIST unmodified.
1388
1389 See `member*' for the meaning of the keywords.
1390
1391 arguments: (ITEM LIST &key (TEST #'eql) (KEY #'identity) TEST-NOT)
1392 */
1393 (int nargs, Lisp_Object *args))
1394 {
1395 Lisp_Object item = args[0], list = args[1], keyed = Qnil, ignore = Qnil;
1396 struct gcpro gcpro1;
1397 Boolint test_not_unboundp = 1;
1398 check_test_func_t check_test = NULL;
1399
1400 PARSE_KEYWORDS (Fadjoin, nargs, args, 3, (test, key, test_not),
1401 NULL);
1402
1403 CHECK_KEY_ARGUMENT (key);
1404
1405 keyed = KEY (key, item);
1406
1407 GCPRO1 (keyed);
1408 check_test = get_check_test_function (keyed, &test, test_not, Qnil, Qnil,
1409 key, &test_not_unboundp);
1410 if (NILP (list_position_cons_before (&ignore, keyed, list, check_test,
1411 test_not_unboundp, test, key, 0, Qzero,
1412 Qnil)))
1413 {
1414 RETURN_UNGCPRO (Fcons (item, list));
1415 }
1416
1417 RETURN_UNGCPRO (list);
1418 }
1419
1420 DEFUN ("assoc", Fassoc, 2, 2, 0, /*
1421 Return non-nil if KEY is `equal' to the car of an element of ALIST.
1422 The value is actually the element of ALIST whose car equals KEY.
1423 */
1424 (key, alist))
1425 {
1426 /* This function can GC. */
1427 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
1428 {
1429 if (internal_equal (key, elt_car, 0))
1430 return elt;
1431 }
1432 return Qnil;
1433 }
1434
1435 Lisp_Object
1436 assoc_no_quit (Lisp_Object key, Lisp_Object alist)
1437 {
1438 int speccount = specpdl_depth ();
1439 specbind (Qinhibit_quit, Qt);
1440 return unbind_to_1 (speccount, Fassoc (key, alist));
1441 }
1442
1443 DEFUN ("assq", Fassq, 2, 2, 0, /*
1444 Return non-nil if KEY is `eq' to the car of an element of ALIST.
1445 The value is actually the element of ALIST whose car is KEY.
1446 Elements of ALIST that are not conses are ignored.
1447 */
1448 (key, alist))
1449 {
1450 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
1451 {
1452 if (EQ_WITH_EBOLA_NOTICE (key, elt_car))
1453 return elt;
1454 }
1455 return Qnil;
1456 }
1457
1458 /* Like Fassq but never report an error and do not allow quits.
1459 Use only on lists known never to be circular. */
1460
1461 Lisp_Object
1462 assq_no_quit (Lisp_Object key, Lisp_Object alist)
1463 {
1464 /* This cannot GC. */
1465 LIST_LOOP_2 (elt, alist)
1466 {
1467 Lisp_Object elt_car = XCAR (elt);
1468 if (EQ_WITH_EBOLA_NOTICE (key, elt_car))
1469 return elt;
1470 }
1471 return Qnil;
1472 }
1473
1474 DEFUN ("assoc*", FassocX, 2, MANY, 0, /*
1475 Find the first item whose car matches ITEM in ALIST.
1476
1477 See `member*' for the meaning of :test, :test-not and :key.
1478
1479 arguments: (ITEM ALIST &key (TEST #'eql) (KEY #'identity) TEST-NOT)
1480 */
1481 (int nargs, Lisp_Object *args))
1482 {
1483 Lisp_Object item = args[0], alist = args[1];
1484 Boolint test_not_unboundp = 1;
1485 check_test_func_t check_test = NULL;
1486
1487 PARSE_KEYWORDS (FassocX, nargs, args, 5, (test, if_, if_not, test_not, key),
1488 NULL);
1489
1490 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
1491 key, &test_not_unboundp);
1492
1493 if (check_test == check_eq_nokey)
1494 {
1495 /* TEST is #'eq, no need to call any C functions. */
1496 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
1497 {
1498 if (EQ (item, elt_car) == test_not_unboundp)
1499 {
1500 return elt;
1501 }
1502 }
1503 }
1504 else
1505 {
1506 GC_EXTERNAL_LIST_LOOP_2 (elt, alist)
1507 {
1508 if (CONSP (elt) &&
1509 check_test (test, key, item, XCAR (elt)) == test_not_unboundp)
1510 {
1511 XUNGCPRO (elt);
1512 return elt;
1513 }
1514 }
1515 END_GC_EXTERNAL_LIST_LOOP (elt);
1516 }
1517
1518 return Qnil;
1519 }
1520
1521 DEFUN ("rassoc", Frassoc, 2, 2, 0, /*
1522 Return non-nil if VALUE is `equal' to the cdr of an element of ALIST.
1523 The value is actually the element of ALIST whose cdr equals VALUE.
1524 */
1525 (value, alist))
1526 {
1527 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
1528 {
1529 if (internal_equal (value, elt_cdr, 0))
1530 return elt;
1531 }
1532 return Qnil;
1533 }
1534
1535 DEFUN ("rassq", Frassq, 2, 2, 0, /*
1536 Return non-nil if VALUE is `eq' to the cdr of an element of ALIST.
1537 The value is actually the element of ALIST whose cdr is VALUE.
1538 */
1539 (value, alist))
1540 {
1541 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
1542 {
1543 if (EQ_WITH_EBOLA_NOTICE (value, elt_cdr))
1544 return elt;
1545 }
1546 return Qnil;
1547 }
1548
1549 /* Like Frassq, but caller must ensure that ALIST is properly
1550 nil-terminated and ebola-free. */
1551 Lisp_Object
1552 rassq_no_quit (Lisp_Object value, Lisp_Object alist)
1553 {
1554 LIST_LOOP_2 (elt, alist)
1555 {
1556 Lisp_Object elt_cdr = XCDR (elt);
1557 if (EQ_WITH_EBOLA_NOTICE (value, elt_cdr))
1558 return elt;
1559 }
1560 return Qnil;
1561 }
1562
1563 DEFUN ("rassoc*", FrassocX, 2, MANY, 0, /*
1564 Find the first item whose cdr matches ITEM in ALIST.
1565
1566 See `member*' for the meaning of :test, :test-not and :key.
1567
1568 arguments: (ITEM ALIST &key (TEST #'eql) (KEY #'identity) TEST-NOT)
1569 */
1570 (int nargs, Lisp_Object *args))
1571 {
1572 Lisp_Object item = args[0], alist = args[1];
1573 Boolint test_not_unboundp = 1;
1574 check_test_func_t check_test = NULL;
1575
1576 PARSE_KEYWORDS (FrassocX, nargs, args, 5, (test, if_, if_not, test_not, key),
1577 NULL);
1578
1579 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
1580 key, &test_not_unboundp);
1581
1582 if (check_test == check_eq_nokey)
1583 {
1584 /* TEST is #'eq, no need to call any C functions. */
1585 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
1586 {
1587 if (EQ (item, elt_cdr) == test_not_unboundp)
1588 {
1589 return elt;
1590 }
1591 }
1592 }
1593 else
1594 {
1595 GC_EXTERNAL_LIST_LOOP_2 (elt, alist)
1596 {
1597 if (CONSP (elt) &&
1598 check_test (test, key, item, XCDR (elt)) == test_not_unboundp)
1599 {
1600 XUNGCPRO (elt);
1601 return elt;
1602 }
1603 }
1604 END_GC_EXTERNAL_LIST_LOOP (elt);
1605 }
1606
1607 return Qnil;
1608 }
1609
1610 /* This is the implementation of both #'find and #'position. */
1611 static Lisp_Object
1612 position (Lisp_Object *object_out, Lisp_Object item, Lisp_Object sequence,
1613 check_test_func_t check_test, Boolint test_not_unboundp,
1614 Lisp_Object test, Lisp_Object key, Lisp_Object start, Lisp_Object end,
1615 Lisp_Object from_end, Lisp_Object default_, Lisp_Object caller)
1616 {
1617 Lisp_Object result = Qnil;
1618 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, len, ii = 0;
1619
1620 CHECK_SEQUENCE (sequence);
1621 CHECK_NATNUM (start);
1622 starting = FIXNUMP (start) ? XFIXNUM (start) : 1 + MOST_POSITIVE_FIXNUM;
1623
1624 if (!NILP (end))
1625 {
1626 CHECK_NATNUM (end);
1627 ending = FIXNUMP (end) ? XFIXNUM (end) : 1 + MOST_POSITIVE_FIXNUM;
1628 }
1629
1630 *object_out = default_;
1631
1632 if (CONSP (sequence))
1633 {
1634 if (!(starting < ending))
1635 {
1636 check_sequence_range (sequence, start, end, Flength (sequence));
1637 /* starting could be equal to ending, in which case nil is what
1638 we want to return. */
1639 return Qnil;
1640 }
1641
1642 {
1643 GC_EXTERNAL_LIST_LOOP_2 (elt, sequence)
1644 {
1645 if (starting <= ii && ii < ending
1646 && check_test (test, key, item, elt) == test_not_unboundp)
1647 {
1648 result = make_integer (ii);
1649 *object_out = elt;
1650
1651 if (NILP (from_end))
1652 {
1653 XUNGCPRO (elt);
1654 return result;
1655 }
1656 }
1657 else if (ii == ending)
1658 {
1659 break;
1660 }
1661
1662 ii++;
1663 }
1664 END_GC_EXTERNAL_LIST_LOOP (elt);
1665 }
1666
1667 if (ii < starting || (ii < ending && !NILP (end)))
1668 {
1669 check_sequence_range (sequence, start, end, Flength (sequence));
1670 }
1671 }
1672 else if (STRINGP (sequence))
1673 {
1674 Ibyte *startp = XSTRING_DATA (sequence), *cursor = startp;
1675 Bytecount byte_len = XSTRING_LENGTH (sequence), cursor_offset = 0;
1676 Lisp_Object character = Qnil;
1677
1678 while (cursor_offset < byte_len && ii < ending)
1679 {
1680 if (ii >= starting)
1681 {
1682 character = make_char (itext_ichar (cursor));
1683
1684 if (check_test (test, key, item, character) == test_not_unboundp)
1685 {
1686 result = make_integer (ii);
1687 *object_out = character;
1688
1689 if (NILP (from_end))
1690 {
1691 return result;
1692 }
1693 }
1694
1695 startp = XSTRING_DATA (sequence);
1696 cursor = startp + cursor_offset;
1697 if (byte_len != XSTRING_LENGTH (sequence)
1698 || !valid_ibyteptr_p (cursor))
1699 {
1700 mapping_interaction_error (caller, sequence);
1701 }
1702 }
1703
1704 INC_IBYTEPTR (cursor);
1705 cursor_offset = cursor - startp;
1706 ii++;
1707 }
1708
1709 if (ii < starting || (ii < ending && !NILP (end)))
1710 {
1711 check_sequence_range (sequence, start, end, Flength (sequence));
1712 }
1713 }
1714 else
1715 {
1716 Lisp_Object object = Qnil;
1717 len = XFIXNUM (Flength (sequence));
1718 check_sequence_range (sequence, start, end, make_fixnum (len));
1719
1720 ending = min (ending, len);
1721 if (0 == len)
1722 {
1723 /* Catches the case where we have nil. */
1724 return result;
1725 }
1726
1727 if (NILP (from_end))
1728 {
1729 for (ii = starting; ii < ending; ii++)
1730 {
1731 object = Faref (sequence, make_fixnum (ii));
1732 if (check_test (test, key, item, object) == test_not_unboundp)
1733 {
1734 result = make_integer (ii);
1735 *object_out = object;
1736 return result;
1737 }
1738 }
1739 }
1740 else
1741 {
1742 for (ii = ending - 1; ii >= starting; ii--)
1743 {
1744 object = Faref (sequence, make_fixnum (ii));
1745 if (check_test (test, key, item, object) == test_not_unboundp)
1746 {
1747 result = make_integer (ii);
1748 *object_out = object;
1749 return result;
1750 }
1751 }
1752 }
1753 }
1754
1755 return result;
1756 }
1757
1758 DEFUN ("position", Fposition, 2, MANY, 0, /*
1759 Return the index of the first occurrence of ITEM in SEQUENCE.
1760
1761 Return nil if not found. See `remove*' for the meaning of the keywords.
1762
1763 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) FROM-END TEST-NOT)
1764 */
1765 (int nargs, Lisp_Object *args))
1766 {
1767 Lisp_Object object = Qnil, item = args[0], sequence = args[1];
1768 Boolint test_not_unboundp = 1;
1769 check_test_func_t check_test = NULL;
1770
1771 PARSE_KEYWORDS (Fposition, nargs, args, 8,
1772 (test, if_, test_not, if_not, key, start, end, from_end),
1773 (start = Qzero));
1774
1775 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
1776 key, &test_not_unboundp);
1777
1778 return position (&object, item, sequence, check_test, test_not_unboundp,
1779 test, key, start, end, from_end, Qnil, Qposition);
1780 }
1781
1782 DEFUN ("find", Ffind, 2, MANY, 0, /*
1783 Find the first occurrence of ITEM in SEQUENCE.
1784
1785 Return the matching ITEM, or nil if not found. See `remove*' for the
1786 meaning of the keywords.
1787
1788 The keyword :default, not specified by Common Lisp, designates an object to
1789 return instead of nil if ITEM is not found.
1790
1791 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) DEFAULT FROM-END TEST-NOT)
1792 */
1793 (int nargs, Lisp_Object *args))
1794 {
1795 Lisp_Object object = Qnil, item = args[0], sequence = args[1];
1796 Boolint test_not_unboundp = 1;
1797 check_test_func_t check_test = NULL;
1798
1799 PARSE_KEYWORDS (Ffind, nargs, args, 9,
1800 (test, if_, test_not, if_not, key, start, end, from_end,
1801 default_),
1802 (start = Qzero));
1803
1804 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
1805 key, &test_not_unboundp);
1806
1807 position (&object, item, sequence, check_test, test_not_unboundp,
1808 test, key, start, end, from_end, default_, Qposition);
1809
1810 return object;
1811 }
1812
1813 /* Like #'delq, but caller must ensure that LIST is properly
1814 nil-terminated and ebola-free. */
1815
1816 Lisp_Object
1817 delq_no_quit (Lisp_Object elt, Lisp_Object list)
1818 {
1819 LIST_LOOP_DELETE_IF (list_elt, list,
1820 (EQ_WITH_EBOLA_NOTICE (elt, list_elt)));
1821 return list;
1822 }
1823
1824 /* Be VERY careful with this. This is like delq_no_quit() but
1825 also calls free_cons() on the removed conses. You must be SURE
1826 that no pointers to the freed conses remain around (e.g.
1827 someone else is pointing to part of the list). This function
1828 is useful on internal lists that are used frequently and where
1829 the actual list doesn't escape beyond known code bounds. */
1830
1831 Lisp_Object
1832 delq_no_quit_and_free_cons (Lisp_Object elt, Lisp_Object list)
1833 {
1834 REGISTER Lisp_Object tail = list;
1835 REGISTER Lisp_Object prev = Qnil;
1836
1837 while (!NILP (tail))
1838 {
1839 REGISTER Lisp_Object tem = XCAR (tail);
1840 if (EQ (elt, tem))
1841 {
1842 Lisp_Object cons_to_free = tail;
1843 if (NILP (prev))
1844 list = XCDR (tail);
1845 else
1846 XCDR (prev) = XCDR (tail);
1847 tail = XCDR (tail);
1848 free_cons (cons_to_free);
1849 }
1850 else
1851 {
1852 prev = tail;
1853 tail = XCDR (tail);
1854 }
1855 }
1856 return list;
1857 }
1858
1859 DEFUN ("delete*", FdeleteX, 2, MANY, 0, /*
1860 Remove all occurrences of ITEM in SEQUENCE, destructively.
1861
1862 If SEQUENCE is a non-nil list, this modifies the list directly. A non-list
1863 SEQUENCE will not be destructively modified, rather, if ITEM occurs in it, a
1864 new SEQUENCE of the same type without ITEM will be returned.
1865
1866 See `remove*' for a non-destructive alternative, and for explanation of the
1867 keyword arguments.
1868
1869 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) FROM-END COUNT TEST-NOT)
1870 */
1871 (int nargs, Lisp_Object *args))
1872 {
1873 Lisp_Object item = args[0], sequence = args[1];
1874 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, counting = MOST_POSITIVE_FIXNUM;
1875 Elemcount len, ii = 0, encountered = 0, presenting = 0;
1876 Boolint test_not_unboundp = 1;
1877 check_test_func_t check_test = NULL;
1878
1879 PARSE_KEYWORDS (FdeleteX, nargs, args, 9,
1880 (test, if_not, if_, test_not, key, start, end, from_end,
1881 count), (start = Qzero, count = Qunbound));
1882
1883 CHECK_SEQUENCE (sequence);
1884 CHECK_NATNUM (start);
1885 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start);
1886
1887 if (!NILP (end))
1888 {
1889 CHECK_NATNUM (end);
1890 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end);
1891 }
1892
1893 if (!UNBOUNDP (count))
1894 {
1895 if (!NILP (count))
1896 {
1897 CHECK_INTEGER (count);
1898 if (FIXNUMP (count))
1899 {
1900 counting = XFIXNUM (count);
1901 }
1902 #ifdef HAVE_BIGNUM
1903 else
1904 {
1905 counting = bignum_sign (XBIGNUM_DATA (count)) > 0 ?
1906 1 + MOST_POSITIVE_FIXNUM : MOST_NEGATIVE_FIXNUM - 1;
1907 }
1908 #endif
1909
1910 if (counting < 1)
1911 {
1912 return sequence;
1913 }
1914
1915 if (!NILP (from_end))
1916 {
1917 /* Sigh, this is inelegant. Force count_with_tail () to ignore
1918 the count keyword, so we get the actual number of matching
1919 elements, and can start removing from the beginning for the
1920 from-end case. */
1921 for (ii = XSUBR (GET_DEFUN_LISP_OBJECT (FdeleteX))->min_args;
1922 ii < nargs; ii += 2)
1923 {
1924 if (EQ (args[ii], Q_count))
1925 {
1926 args[ii + 1] = Qnil;
1927 break;
1928 }
1929 }
1930 ii = 0;
1931 }
1932 }
1933 }
1934
1935 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
1936 key, &test_not_unboundp);
1937
1938 if (CONSP (sequence))
1939 {
1940 Lisp_Object prev_tail_list_elt = Qnil, ignore = Qnil;
1941 Elemcount list_len = 0, deleted = 0;
1942 struct gcpro gcpro1;
1943
1944 if (!NILP (count) && !NILP (from_end))
1945 {
1946 /* Both COUNT and FROM-END were specified; we need to traverse the
1947 list twice. */
1948 Lisp_Object present = count_with_tail (&ignore, nargs, args,
1949 QdeleteX);
1950
1951 if (ZEROP (present))
1952 {
1953 return sequence;
1954 }
1955
1956 presenting = XFIXNUM (present);
1957
1958 /* If there are fewer items in the list than we have permission to
1959 delete, we don't need to differentiate between the :from-end
1960 nil and :from-end t cases. Otherwise, presenting is the number
1961 of matching items we need to ignore before we start to
1962 delete. */
1963 presenting = presenting <= counting ? 0 : presenting - counting;
1964 }
1965
1966 GCPRO1 (prev_tail_list_elt);
1967 ii = -1;
1968
1969 {
1970 GC_EXTERNAL_LIST_LOOP_4 (list_elt, sequence, tail, list_len)
1971 {
1972 ii++;
1973
1974 if (starting <= ii && ii < ending &&
1975 (check_test (test, key, item, list_elt) == test_not_unboundp)
1976 && (presenting ? encountered++ >= presenting
1977 : encountered++ < counting))
1978 {
1979 if (NILP (prev_tail_list_elt))
1980 {
1981 sequence = XCDR (tail);
1982 }
1983 else
1984 {
1985 XSETCDR (prev_tail_list_elt, XCDR (tail));
1986 }
1987
1988 /* Keep tortoise from ever passing hare. */
1989 list_len = 0;
1990 deleted++;
1991 }
1992 else
1993 {
1994 prev_tail_list_elt = tail;
1995 if (ii >= ending || (!presenting && encountered > counting))
1996 {
1997 break;
1998 }
1999 }
2000 }
2001 END_GC_EXTERNAL_LIST_LOOP (list_elt);
2002 }
2003
2004 UNGCPRO;
2005
2006 if ((ii < starting || (ii < ending && !NILP (end))) &&
2007 !(presenting ? encountered == presenting : encountered == counting))
2008 {
2009 check_sequence_range (args[1], start, end,
2010 make_fixnum (deleted + XFIXNUM (Flength (args[1]))));
2011 }
2012
2013 return sequence;
2014 }
2015 else if (STRINGP (sequence))
2016 {
2017 Ibyte *staging = alloca_ibytes (XSTRING_LENGTH (sequence));
2018 Ibyte *staging_cursor = staging, *startp = XSTRING_DATA (sequence);
2019 Ibyte *cursor = startp;
2020 Bytecount cursor_offset = 0, byte_len = XSTRING_LENGTH (sequence);
2021 Lisp_Object character, result = sequence;
2022
2023 if (!NILP (count) && !NILP (from_end))
2024 {
2025 Lisp_Object present = count_with_tail (&character, nargs, args,
2026 QdeleteX);
2027
2028 if (ZEROP (present))
2029 {
2030 return sequence;
2031 }
2032
2033 presenting = XFIXNUM (present);
2034
2035 /* If there are fewer items in the list than we have permission to
2036 delete, we don't need to differentiate between the :from-end
2037 nil and :from-end t cases. Otherwise, presenting is the number
2038 of matching items we need to ignore before we start to
2039 delete. */
2040 presenting = presenting <= counting ? 0 : presenting - counting;
2041 }
2042
2043 ii = 0;
2044 while (cursor_offset < byte_len)
2045 {
2046 if (ii >= starting && ii < ending)
2047 {
2048 character = make_char (itext_ichar (cursor));
2049
2050 if ((check_test (test, key, item, character)
2051 == test_not_unboundp)
2052 && (presenting ? encountered++ >= presenting :
2053 encountered++ < counting))
2054 {
2055 DO_NOTHING;
2056 }
2057 else
2058 {
2059 staging_cursor
2060 += set_itext_ichar (staging_cursor, XCHAR (character));
2061 }
2062
2063 startp = XSTRING_DATA (sequence);
2064 cursor = startp + cursor_offset;
2065 if (byte_len != XSTRING_LENGTH (sequence)
2066 || !valid_ibyteptr_p (cursor))
2067 {
2068 mapping_interaction_error (QdeleteX, sequence);
2069 }
2070 }
2071 else
2072 {
2073 staging_cursor += itext_copy_ichar (cursor, staging_cursor);
2074 }
2075
2076 INC_IBYTEPTR (cursor);
2077 cursor_offset = cursor - startp;
2078 ii++;
2079 }
2080
2081 if (ii < starting || (ii < ending && !NILP (end)))
2082 {
2083 check_sequence_range (sequence, start, end, Flength (sequence));
2084 }
2085
2086 if (0 != encountered)
2087 {
2088 result = make_string (staging, staging_cursor - staging);
2089 copy_string_extents (result, sequence, 0, 0,
2090 staging_cursor - staging);
2091 sequence = result;
2092 }
2093
2094 return sequence;
2095 }
2096 else
2097 {
2098 Lisp_Object position0 = Qnil, object = Qnil;
2099 Lisp_Object *staging = NULL, *staging_cursor, *staging_limit;
2100 Elemcount positioning;
2101
2102 len = XFIXNUM (Flength (sequence));
2103
2104 check_sequence_range (sequence, start, end, make_fixnum (len));
2105
2106 position0 = position (&object, item, sequence, check_test,
2107 test_not_unboundp, test, key, start, end,
2108 from_end, Qnil, QdeleteX);
2109 if (NILP (position0))
2110 {
2111 return sequence;
2112 }
2113
2114 ending = min (ending, len);
2115 positioning = XFIXNUM (position0);
2116 encountered = 1;
2117
2118 if (NILP (from_end))
2119 {
2120 staging = alloca_array (Lisp_Object, len - 1);
2121 staging_cursor = staging;
2122
2123 ii = 0;
2124 while (ii < positioning)
2125 {
2126 *staging_cursor++ = Faref (sequence, make_fixnum (ii));
2127 ii++;
2128 }
2129
2130 ii = positioning + 1;
2131 while (ii < ending)
2132 {
2133 object = Faref (sequence, make_fixnum (ii));
2134 if (encountered < counting
2135 && (check_test (test, key, item, object)
2136 == test_not_unboundp))
2137 {
2138 encountered++;
2139 }
2140 else
2141 {
2142 *staging_cursor++ = object;
2143 }
2144 ii++;
2145 }
2146
2147 while (ii < len)
2148 {
2149 *staging_cursor++ = Faref (sequence, make_fixnum (ii));
2150 ii++;
2151 }
2152 }
2153 else
2154 {
2155 staging = alloca_array (Lisp_Object, len - 1);
2156 staging_cursor = staging_limit = staging + len - 1;
2157
2158 ii = len - 1;
2159 while (ii > positioning)
2160 {
2161 *--staging_cursor = Faref (sequence, make_fixnum (ii));
2162 ii--;
2163 }
2164
2165 ii = positioning - 1;
2166 while (ii >= starting)
2167 {
2168 object = Faref (sequence, make_fixnum (ii));
2169 if (encountered < counting
2170 && (check_test (test, key, item, object) ==
2171 test_not_unboundp))
2172 {
2173 encountered++;
2174 }
2175 else
2176 {
2177 *--staging_cursor = object;
2178 }
2179
2180 ii--;
2181 }
2182
2183 while (ii >= 0)
2184 {
2185 *--staging_cursor = Faref (sequence, make_fixnum (ii));
2186 ii--;
2187 }
2188
2189 staging = staging_cursor;
2190 staging_cursor = staging_limit;
2191 }
2192
2193 if (VECTORP (sequence))
2194 {
2195 return Fvector (staging_cursor - staging, staging);
2196 }
2197 else if (BIT_VECTORP (sequence))
2198 {
2199 return Fbit_vector (staging_cursor - staging, staging);
2200 }
2201
2202 /* A nil sequence will have given us a nil #'position,
2203 above. */
2204 ABORT ();
2205
2206 return Qnil;
2207 }
2208 }
2209
2210 DEFUN ("remove*", FremoveX, 2, MANY, 0, /*
2211 Remove all occurrences of ITEM in SEQUENCE, non-destructively.
2212
2213 If SEQUENCE is a list, `remove*' makes a copy if that is necessary to avoid
2214 corrupting the original SEQUENCE.
2215
2216 The keywords :test and :test-not specify two-argument test and negated-test
2217 predicates, respectively; :test defaults to `eql'. :key specifies a
2218 one-argument function that transforms elements of SEQUENCE into \"comparison
2219 keys\" before the test predicate is applied. See `member*' for more
2220 information on these keywords.
2221
2222 :start and :end, if given, specify indices of a subsequence of SEQUENCE to
2223 be processed. Indices are 0-based and processing involves the subsequence
2224 starting at the index given by :start and ending just before the index given
2225 by :end.
2226
2227 :count, if given, limits the number of items removed to the number
2228 specified. :from-end, if given, causes processing to proceed starting from
2229 the end instead of the beginning; in this case, this matters only if :count
2230 is given.
2231
2232 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) FROM-END COUNT TEST-NOT)
2233 */
2234 (int nargs, Lisp_Object *args))
2235 {
2236 Lisp_Object item = args[0], sequence = args[1], matched_count = Qnil,
2237 tail = Qnil;
2238 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, counting = MOST_POSITIVE_FIXNUM;
2239 Elemcount ii = 0, encountered = 0, presenting = 0;
2240 Boolint test_not_unboundp = 1;
2241 check_test_func_t check_test = NULL;
2242
2243 PARSE_KEYWORDS (FremoveX, nargs, args, 9,
2244 (test, if_not, if_, test_not, key, start, end, from_end,
2245 count), (start = Qzero));
2246
2247 if (!CONSP (sequence))
2248 {
2249 return FdeleteX (nargs, args);
2250 }
2251
2252 CHECK_NATNUM (start);
2253 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start);
2254
2255 if (!NILP (end))
2256 {
2257 CHECK_NATNUM (end);
2258 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end);
2259 }
2260
2261 if (!NILP (count))
2262 {
2263 CHECK_INTEGER (count);
2264 if (FIXNUMP (count))
2265 {
2266 counting = XFIXNUM (count);
2267 }
2268 #ifdef HAVE_BIGNUM
2269 else
2270 {
2271 counting = bignum_sign (XBIGNUM_DATA (count)) > 0 ?
2272 1 + MOST_POSITIVE_FIXNUM : -1 + MOST_NEGATIVE_FIXNUM;
2273 }
2274 #endif
2275
2276 if (counting <= 0)
2277 {
2278 return sequence;
2279 }
2280
2281 if (!NILP (from_end))
2282 {
2283 /* Sigh, this is inelegant. Force count_with_tail () to ignore the
2284 count keyword, so we get the actual number of matching
2285 elements, and can start removing from the beginning for the
2286 from-end case. */
2287 for (ii = XSUBR (GET_DEFUN_LISP_OBJECT (FremoveX))->min_args;
2288 ii < nargs; ii += 2)
2289 {
2290 if (EQ (args[ii], Q_count))
2291 {
2292 args[ii + 1] = Qnil;
2293 break;
2294 }
2295 }
2296 ii = 0;
2297 }
2298 }
2299
2300 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
2301 key, &test_not_unboundp);
2302
2303 matched_count = count_with_tail (&tail, nargs, args, QremoveX);
2304
2305 if (!ZEROP (matched_count))
2306 {
2307 Lisp_Object result = Qnil, result_tail = Qnil;
2308 struct gcpro gcpro1, gcpro2;
2309
2310 if (!NILP (count) && !NILP (from_end))
2311 {
2312 presenting = XFIXNUM (matched_count);
2313
2314 /* If there are fewer matching elements in the list than we have
2315 permission to delete, we don't need to differentiate between
2316 the :from-end nil and :from-end t cases. Otherwise, presenting
2317 is the number of matching items we need to ignore before we
2318 start to delete. */
2319 presenting = presenting <= counting ? 0 : presenting - counting;
2320 }
2321
2322 GCPRO2 (result, tail);
2323 {
2324 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tailing)
2325 {
2326 if (EQ (tail, tailing))
2327 {
2328 XUNGCPRO (elt);
2329 UNGCPRO;
2330
2331 if (NILP (result))
2332 {
2333 return XCDR (tail);
2334 }
2335
2336 XSETCDR (result_tail, XCDR (tail));
2337 return result;
2338 }
2339 else if (starting <= ii && ii < ending &&
2340 (check_test (test, key, item, elt) == test_not_unboundp)
2341 && (presenting ? encountered++ >= presenting
2342 : encountered++ < counting))
2343 {
2344 DO_NOTHING;
2345 }
2346 else if (NILP (result))
2347 {
2348 result = result_tail = Fcons (elt, Qnil);
2349 }
2350 else
2351 {
2352 XSETCDR (result_tail, Fcons (elt, Qnil));
2353 result_tail = XCDR (result_tail);
2354 }
2355
2356 if (ii == ending)
2357 {
2358 break;
2359 }
2360
2361 ii++;
2362 }
2363 END_GC_EXTERNAL_LIST_LOOP (elt);
2364 }
2365 UNGCPRO;
2366
2367 if (ii < starting || (ii < ending && !NILP (end)))
2368 {
2369 check_sequence_range (args[0], start, end, Flength (args[0]));
2370 }
2371
2372 return result;
2373 }
2374
2375 return sequence;
2376 }
2377
2378 Lisp_Object
2379 remassoc_no_quit (Lisp_Object key, Lisp_Object alist)
2380 {
2381 LIST_LOOP_DELETE_IF (elt, alist,
2382 (CONSP (elt) &&
2383 internal_equal (key, XCAR (elt), 0)));
2384 return alist;
2385 }
2386
2387 /* no quit, no errors; be careful */
2388
2389 Lisp_Object
2390 remassq_no_quit (Lisp_Object key, Lisp_Object alist)
2391 {
2392 LIST_LOOP_DELETE_IF (elt, alist,
2393 (CONSP (elt) &&
2394 EQ_WITH_EBOLA_NOTICE (key, XCAR (elt))));
2395 return alist;
2396 }
2397
2398 /* Like Fremrassq, fast and unsafe; be careful */
2399 Lisp_Object
2400 remrassq_no_quit (Lisp_Object value, Lisp_Object alist)
2401 {
2402 LIST_LOOP_DELETE_IF (elt, alist,
2403 (CONSP (elt) &&
2404 EQ_WITH_EBOLA_NOTICE (value, XCDR (elt))));
2405 return alist;
2406 }
2407
2408 /* Remove duplicate elements between START and END from LIST, a non-nil
2409 list; if COPY is zero, do so destructively. Items to delete are selected
2410 according to the algorithm used when :from-end t is passed to
2411 #'delete-duplicates. Error if LIST is ill-formed or circular.
2412
2413 TEST and KEY are as in #'remove*; CHECK_TEST and TEST_NOT_UNBOUNDP should
2414 reflect them, having been initialised with get_check_match_function() or
2415 get_check_test_function(). */
2416 static Lisp_Object
2417 list_delete_duplicates_from_end (Lisp_Object list,
2418 check_test_func_t check_test,
2419 Boolint test_not_unboundp,
2420 Lisp_Object test, Lisp_Object key,
2421 Lisp_Object start,
2422 Lisp_Object end, Boolint copy)
2423 {
2424 Lisp_Object checking = Qnil, result = list;
2425 Lisp_Object keyed, positioned, position_cons = Qnil, result_tail;
2426 Elemcount len = XFIXNUM (Flength (list)), pos, starting = XFIXNUM (start);
2427 Elemcount ending = (NILP (end) ? len : XFIXNUM (end)), greatest_pos_seen = -1;
2428 Elemcount ii = 0;
2429 struct gcpro gcpro1;
2430
2431 /* We can't delete (or remove) as we go, because that breaks START and
2432 END. We could if END were nil, and that would change an ON(N + 2)
2433 algorithm to an ON^2 algorithm. Here and now it doesn't matter, though,
2434 #'delete-duplicates is relatively expensive no matter what. */
2435 struct Lisp_Bit_Vector *deleting
2436 = (Lisp_Bit_Vector *) ALLOCA (sizeof (struct Lisp_Bit_Vector)
2437 + (sizeof (long)
2438 * (BIT_VECTOR_LONG_STORAGE (len)
2439 - 1)));
2440
2441 check_sequence_range (list, start, end, make_integer (len));
2442
2443 deleting->size = len;
2444 memset (&(deleting->bits), 0,
2445 sizeof (long) * BIT_VECTOR_LONG_STORAGE (len));
2446
2447 GCPRO1 (keyed);
2448
2449 {
2450 GC_EXTERNAL_LIST_LOOP_3 (elt, list, tail)
2451 {
2452 if (!(starting <= ii && ii <= ending) || bit_vector_bit (deleting, ii))
2453 {
2454 ii++;
2455 continue;
2456 }
2457
2458 keyed = KEY (key, elt);
2459 checking = XCDR (tail);
2460 pos = ii + 1;
2461
2462 while (!NILP ((positioned = list_position_cons_before
2463 (&position_cons, keyed, checking, check_test,
2464 test_not_unboundp, test, key, 0,
2465 make_fixnum (max (starting - pos, 0)),
2466 make_fixnum (ending - pos)))))
2467 {
2468 pos = XFIXNUM (positioned) + pos;
2469 set_bit_vector_bit (deleting, pos, 1);
2470 greatest_pos_seen = max (greatest_pos_seen, pos);
2471 checking = NILP (position_cons) ?
2472 XCDR (checking) : XCDR (XCDR (position_cons));
2473 pos += 1;
2474 }
2475 ii++;
2476 }
2477 END_GC_EXTERNAL_LIST_LOOP (elt);
2478 }
2479
2480 UNGCPRO;
2481
2482 ii = 0;
2483
2484 if (greatest_pos_seen > -1)
2485 {
2486 if (copy)
2487 {
2488 result = result_tail = Fcons (XCAR (list), Qnil);
2489 list = XCDR (list);
2490 ii = 1;
2491
2492 {
2493 EXTERNAL_LIST_LOOP_3 (elt, list, tail)
2494 {
2495 if (ii == greatest_pos_seen)
2496 {
2497 XSETCDR (result_tail, XCDR (tail));
2498 break;
2499 }
2500 else if (!bit_vector_bit (deleting, ii))
2501 {
2502 XSETCDR (result_tail, Fcons (elt, Qnil));
2503 result_tail = XCDR (result_tail);
2504 }
2505 ii++;
2506 }
2507 }
2508 }
2509 else
2510 {
2511 EXTERNAL_LIST_LOOP_DELETE_IF (elt, list,
2512 bit_vector_bit (deleting, ii++));
2513 }
2514 }
2515
2516 return result;
2517 }
2518
2519 DEFUN ("delete-duplicates", Fdelete_duplicates, 1, MANY, 0, /*
2520 Remove all duplicate elements from SEQUENCE, destructively.
2521
2522 If SEQUENCE is a list and has duplicates, modify and return it. Note that
2523 SEQUENCE may start with an element to be deleted; because of this, if
2524 modifying a variable, be sure to write `(setq VARIABLE (delete-duplicates
2525 VARIABLE))' to be certain to have a list without duplicate elements.
2526
2527 If SEQUENCE is an array and has duplicates, return a newly-allocated array
2528 of the same type comprising all unique elements of SEQUENCE.
2529
2530 If there are no duplicate elements in SEQUENCE, return it unmodified.
2531
2532 See `remove*' for the meaning of the keywords. See `remove-duplicates' for
2533 a non-destructive version of this function.
2534
2535 arguments: (SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) END FROM-END TEST-NOT)
2536 */
2537 (int nargs, Lisp_Object *args))
2538 {
2539 Lisp_Object sequence = args[0], keyed = Qnil;
2540 Lisp_Object positioned = Qnil, ignore = Qnil;
2541 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, len, ii = 0, jj = 0;
2542 Boolint test_not_unboundp = 1;
2543 check_test_func_t check_test = NULL;
2544 struct gcpro gcpro1, gcpro2;
2545
2546 PARSE_KEYWORDS (Fdelete_duplicates, nargs, args, 6,
2547 (test, key, test_not, start, end, from_end),
2548 (start = Qzero));
2549
2550 CHECK_SEQUENCE (sequence);
2551 CHECK_NATNUM (start);
2552 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start);
2553
2554 if (!NILP (end))
2555 {
2556 CHECK_NATNUM (end);
2557 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end);
2558 }
2559
2560 CHECK_KEY_ARGUMENT (key);
2561
2562 get_check_match_function (&test, test_not, Qnil, Qnil, key,
2563 &test_not_unboundp, &check_test);
2564
2565 if (CONSP (sequence))
2566 {
2567 if (NILP (from_end))
2568 {
2569 Lisp_Object prev_tail = Qnil;
2570 Elemcount deleted = 0;
2571
2572 GCPRO2 (keyed, prev_tail);
2573
2574 {
2575 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail)
2576 {
2577 if (starting <= ii && ii < ending)
2578 {
2579 keyed = KEY (key, elt);
2580 positioned
2581 = list_position_cons_before (&ignore, keyed,
2582 XCDR (tail), check_test,
2583 test_not_unboundp, test, key,
2584 0, make_fixnum (max (starting
2585 - (ii + 1),
2586 0)),
2587 make_fixnum (ending
2588 - (ii + 1)));
2589 if (!NILP (positioned))
2590 {
2591 sequence = XCDR (tail);
2592 deleted++;
2593 }
2594 else
2595 {
2596 break;
2597 }
2598 }
2599 else
2600 {
2601 break;
2602 }
2603
2604 ii++;
2605 }
2606 END_GC_EXTERNAL_LIST_LOOP (elt);
2607 }
2608 {
2609 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail)
2610 {
2611 if (!(starting <= ii && ii <= ending))
2612 {
2613 prev_tail = tail;
2614 ii++;
2615 continue;
2616 }
2617
2618 keyed = KEY (key, elt);
2619 positioned
2620 = list_position_cons_before (&ignore, keyed, XCDR (tail),
2621 check_test, test_not_unboundp,
2622 test, key, 0,
2623 make_fixnum (max (starting
2624 - (ii + 1), 0)),
2625 make_fixnum (ending - (ii + 1)));
2626 if (!NILP (positioned))
2627 {
2628 /* We know this isn't the first iteration of the loop,
2629 because we advanced above to the point where we have at
2630 least one non-duplicate entry at the head of the
2631 list. */
2632 XSETCDR (prev_tail, XCDR (tail));
2633 len = 0;
2634 deleted++;
2635 }
2636 else
2637 {
2638 prev_tail = tail;
2639 if (ii >= ending)
2640 {
2641 break;
2642 }
2643 }
2644
2645 ii++;
2646 }
2647 END_GC_EXTERNAL_LIST_LOOP (elt);
2648 }
2649
2650 UNGCPRO;
2651
2652 if ((ii < starting || (ii < ending && !NILP (end))))
2653 {
2654 check_sequence_range (args[0], start, end,
2655 make_fixnum (deleted
2656 + XFIXNUM (Flength (args[0]))));
2657 }
2658 }
2659 else
2660 {
2661 sequence = list_delete_duplicates_from_end (sequence, check_test,
2662 test_not_unboundp,
2663 test, key, start, end,
2664 0);
2665 }
2666 }
2667 else if (STRINGP (sequence))
2668 {
2669 Lisp_Object elt = Qnil;
2670
2671 if (EQ (Qidentity, key))
2672 {
2673 /* We know all the elements will be characters; set check_test to
2674 reflect that. This isn't useful if KEY is not #'identity, since
2675 it may return non-characters for the elements. */
2676 check_test = get_check_test_function (make_char ('a'),
2677 &test, test_not,
2678 Qnil, Qnil, key,
2679 &test_not_unboundp);
2680 }
2681
2682 if (NILP (from_end))
2683 {
2684 Bytecount byte_len = XSTRING_LENGTH (sequence), cursor_offset = 0;
2685 Ibyte *staging = alloca_ibytes (byte_len), *staging_cursor = staging;
2686 Ibyte *cursor = XSTRING_DATA (sequence), *startp = cursor;
2687 Elemcount deleted = 0;
2688
2689 GCPRO1 (elt);
2690
2691 while (cursor_offset < byte_len)
2692 {
2693 if (starting <= ii && ii < ending)
2694 {
2695 Ibyte *cursor0 = cursor;
2696 Bytecount cursor0_offset;
2697 Boolint delete_this = 0;
2698
2699 elt = KEY (key, make_char (itext_ichar (cursor)));
2700 INC_IBYTEPTR (cursor0);
2701 cursor0_offset = cursor0 - startp;
2702
2703 for (jj = ii + 1; jj < ending && cursor0_offset < byte_len;
2704 jj++)
2705 {
2706 if (check_test (test, key, elt,
2707 make_char (itext_ichar (cursor0)))
2708 == test_not_unboundp)
2709 {
2710 delete_this = 1;
2711 deleted++;
2712 break;
2713 }
2714
2715 startp = XSTRING_DATA (sequence);
2716 cursor0 = startp + cursor0_offset;
2717 if (byte_len != XSTRING_LENGTH (sequence)
2718 || !valid_ibyteptr_p (cursor0))
2719 {
2720 mapping_interaction_error (Qdelete_duplicates,
2721 sequence);
2722 }
2723
2724 INC_IBYTEPTR (cursor0);
2725 cursor0_offset = cursor0 - startp;
2726 }
2727
2728 startp = XSTRING_DATA (sequence);
2729 cursor = startp + cursor_offset;
2730
2731 if (byte_len != XSTRING_LENGTH (sequence)
2732 || !valid_ibyteptr_p (cursor))
2733 {
2734 mapping_interaction_error (Qdelete_duplicates, sequence);
2735 }
2736
2737 if (!delete_this)
2738 {
2739 staging_cursor
2740 += itext_copy_ichar (cursor, staging_cursor);
2741
2742 }
2743 }
2744 else
2745 {
2746 staging_cursor += itext_copy_ichar (cursor, staging_cursor);
2747 }
2748
2749 INC_IBYTEPTR (cursor);
2750 cursor_offset = cursor - startp;
2751 ii++;
2752 }
2753
2754 UNGCPRO;
2755
2756 if (ii < starting || (ii < ending && !NILP (end)))
2757 {
2758 check_sequence_range (sequence, start, end, Flength (sequence));
2759 }
2760
2761 if (0 != deleted)
2762 {
2763 sequence = make_string (staging, staging_cursor - staging);
2764 }
2765 }
2766 else
2767 {
2768 Elemcount deleted = 0;
2769 Ibyte *staging = alloca_ibytes ((len = string_char_length (sequence))
2770 * MAX_ICHAR_LEN);
2771 Ibyte *staging_cursor = staging, *startp = XSTRING_DATA (sequence);
2772 Ibyte *endp = startp + XSTRING_LENGTH (sequence);
2773 struct Lisp_Bit_Vector *deleting
2774 = (Lisp_Bit_Vector *) ALLOCA (sizeof (struct Lisp_Bit_Vector)
2775 + (sizeof (long)
2776 * (BIT_VECTOR_LONG_STORAGE (len)
2777 - 1)));
2778
2779 check_sequence_range (sequence, start, end, make_integer (len));
2780
2781 /* For the from_end t case; transform contents to an array with
2782 elements addressable in constant time, use the same algorithm
2783 as for vectors. */
2784 deleting->size = len;
2785 memset (&(deleting->bits), 0,
2786 sizeof (long) * BIT_VECTOR_LONG_STORAGE (len));
2787
2788 while (startp < endp)
2789 {
2790 itext_copy_ichar (startp, staging + (ii * MAX_ICHAR_LEN));
2791 INC_IBYTEPTR (startp);
2792 ii++;
2793 }
2794
2795 GCPRO1 (elt);
2796
2797 ending = min (ending, len);
2798
2799 for (ii = ending - 1; ii >= starting; ii--)
2800 {
2801 elt = KEY (key, make_char (itext_ichar (staging +
2802 (ii * MAX_ICHAR_LEN))));
2803 for (jj = ii - 1; jj >= starting; jj--)
2804 {
2805 if (check_test (test, key, elt,
2806 make_char (itext_ichar
2807 (staging + (jj * MAX_ICHAR_LEN))))
2808 == test_not_unboundp)
2809 {
2810 set_bit_vector_bit (deleting, ii, 1);
2811 deleted++;
2812 break;
2813 }
2814 }
2815 }
2816
2817 UNGCPRO;
2818
2819 if (0 != deleted)
2820 {
2821 startp = XSTRING_DATA (sequence);
2822
2823 for (ii = 0; ii < len; ii++)
2824 {
2825 if (!bit_vector_bit (deleting, ii))
2826 {
2827 staging_cursor
2828 += itext_copy_ichar (startp, staging_cursor);
2829 }
2830
2831 INC_IBYTEPTR (startp);
2832 }
2833
2834 sequence = make_string (staging, staging_cursor - staging);
2835 }
2836 }
2837 }
2838 else if (VECTORP (sequence))
2839 {
2840 Elemcount deleted = 0;
2841 Lisp_Object *content = XVECTOR_DATA (sequence);
2842 struct Lisp_Bit_Vector *deleting;
2843 Lisp_Object elt = Qnil;
2844
2845 len = XVECTOR_LENGTH (sequence);
2846 check_sequence_range (sequence, start, end, make_integer (len));
2847
2848 deleting = (Lisp_Bit_Vector *) ALLOCA (sizeof (struct Lisp_Bit_Vector)
2849 + (sizeof (long)
2850 * (BIT_VECTOR_LONG_STORAGE (len)
2851 - 1)));
2852 deleting->size = len;
2853 memset (&(deleting->bits), 0,
2854 sizeof (long) * BIT_VECTOR_LONG_STORAGE (len));
2855
2856 GCPRO1 (elt);
2857
2858 ending = min (ending, len);
2859
2860 if (NILP (from_end))
2861 {
2862 for (ii = starting; ii < ending; ii++)
2863 {
2864 elt = KEY (key, content[ii]);
2865
2866 for (jj = ii + 1; jj < ending; jj++)
2867 {
2868 if (check_test (test, key, elt, content[jj])
2869 == test_not_unboundp)
2870 {
2871 set_bit_vector_bit (deleting, ii, 1);
2872 deleted++;
2873 break;
2874 }
2875 }
2876 }
2877 }
2878 else
2879 {
2880 for (ii = ending - 1; ii >= starting; ii--)
2881 {
2882 elt = KEY (key, content[ii]);
2883
2884 for (jj = ii - 1; jj >= starting; jj--)
2885 {
2886 if (check_test (test, key, elt, content[jj])
2887 == test_not_unboundp)
2888 {
2889 set_bit_vector_bit (deleting, ii, 1);
2890 deleted++;
2891 break;
2892 }
2893 }
2894 }
2895 }
2896
2897 UNGCPRO;
2898
2899 if (deleted)
2900 {
2901 Lisp_Object res = make_vector (len - deleted, Qnil),
2902 *res_content = XVECTOR_DATA (res);
2903
2904 for (ii = jj = 0; ii < len; ii++)
2905 {
2906 if (!bit_vector_bit (deleting, ii))
2907 {
2908 res_content[jj++] = content[ii];
2909 }
2910 }
2911
2912 sequence = res;
2913 }
2914 }
2915 else if (BIT_VECTORP (sequence))
2916 {
2917 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence);
2918 Elemcount deleted = 0;
2919 /* I'm a little irritated at this. Basically, the only reasonable
2920 thing delete-duplicates should do if handed a bit vector is return
2921 something of maximum length two and minimum length 0 (because
2922 that's the possible number of distinct elements if EQ is regarded
2923 as identity, which it should be). But to support arbitrary TEST
2924 and KEY arguments, which may be non-deterministic from our
2925 perspective, we need the same algorithm as for vectors. */
2926 struct Lisp_Bit_Vector *deleting;
2927 Lisp_Object elt = Qnil;
2928
2929 len = bit_vector_length (bv);
2930
2931 if (EQ (Qidentity, key))
2932 {
2933 /* We know all the elements will be bits; set check_test to
2934 reflect that. This isn't useful if KEY is not #'identity, since
2935 it may return non-bits for the elements. */
2936 check_test = get_check_test_function (Qzero, &test, test_not,
2937 Qnil, Qnil, key,
2938 &test_not_unboundp);
2939 }
2940
2941 check_sequence_range (sequence, start, end, make_integer (len));
2942
2943 deleting = (Lisp_Bit_Vector *) ALLOCA (sizeof (struct Lisp_Bit_Vector)
2944 + (sizeof (long)
2945 * (BIT_VECTOR_LONG_STORAGE (len)
2946 - 1)));
2947 deleting->size = len;
2948 memset (&(deleting->bits), 0,
2949 sizeof (long) * BIT_VECTOR_LONG_STORAGE (len));
2950
2951 ending = min (ending, len);
2952
2953 GCPRO1 (elt);
2954
2955 if (NILP (from_end))
2956 {
2957 for (ii = starting; ii < ending; ii++)
2958 {
2959 elt = KEY (key, make_fixnum (bit_vector_bit (bv, ii)));
2960
2961 for (jj = ii + 1; jj < ending; jj++)
2962 {
2963 if (check_test (test, key, elt,
2964 make_fixnum (bit_vector_bit (bv, jj)))
2965 == test_not_unboundp)
2966 {
2967 set_bit_vector_bit (deleting, ii, 1);
2968 deleted++;
2969 break;
2970 }
2971 }
2972 }
2973 }
2974 else
2975 {
2976 for (ii = ending - 1; ii >= starting; ii--)
2977 {
2978 elt = KEY (key, make_fixnum (bit_vector_bit (bv, ii)));
2979
2980 for (jj = ii - 1; jj >= starting; jj--)
2981 {
2982 if (check_test (test, key, elt,
2983 make_fixnum (bit_vector_bit (bv, jj)))
2984 == test_not_unboundp)
2985 {
2986 set_bit_vector_bit (deleting, ii, 1);
2987 deleted++;
2988 break;
2989 }
2990 }
2991 }
2992 }
2993
2994 UNGCPRO;
2995
2996 if (deleted)
2997 {
2998 Lisp_Object res = make_bit_vector (len - deleted, Qzero);
2999 Lisp_Bit_Vector *resbv = XBIT_VECTOR (res);
3000
3001 for (ii = jj = 0; ii < len; ii++)
3002 {
3003 if (!bit_vector_bit (deleting, ii))
3004 {
3005 set_bit_vector_bit (resbv, jj++, bit_vector_bit (bv, ii));
3006 }
3007 }
3008
3009 sequence = res;
3010 }
3011 }
3012
3013 return sequence;
3014 }
3015
3016 DEFUN ("remove-duplicates", Fremove_duplicates, 1, MANY, 0, /*
3017 Remove duplicate elements from SEQUENCE, non-destructively.
3018
3019 If there are no duplicate elements in SEQUENCE, return it unmodified;
3020 otherwise, return a new object. If SEQUENCE is a list, the new object may
3021 share list structure with SEQUENCE.
3022
3023 See `remove*' for the meaning of the keywords.
3024
3025 arguments: (SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) END FROM-END TEST-NOT)
3026 */
3027 (int nargs, Lisp_Object *args))
3028 {
3029 Lisp_Object sequence = args[0], keyed, positioned = Qnil;
3030 Lisp_Object result = sequence, result_tail = result, cursor = Qnil;
3031 Lisp_Object cons_with_shared_tail = Qnil;
3032 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, ii = 0;
3033 Boolint test_not_unboundp = 1;
3034 check_test_func_t check_test = NULL;
3035 struct gcpro gcpro1, gcpro2;
3036
3037 PARSE_KEYWORDS (Fremove_duplicates, nargs, args, 6,
3038 (test, key, test_not, start, end, from_end),
3039 (start = Qzero));
3040
3041 CHECK_SEQUENCE (sequence);
3042
3043 if (!CONSP (sequence))
3044 {
3045 return Fdelete_duplicates (nargs, args);
3046 }
3047
3048 CHECK_NATNUM (start);
3049 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start);
3050
3051 if (!NILP (end))
3052 {
3053 CHECK_NATNUM (end);
3054 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end);
3055 }
3056
3057 if (NILP (key))
3058 {
3059 key = Qidentity;
3060 }
3061
3062 get_check_match_function (&test, test_not, Qnil, Qnil, key,
3063 &test_not_unboundp, &check_test);
3064
3065 if (NILP (from_end))
3066 {
3067 Lisp_Object ignore = Qnil;
3068
3069 GCPRO2 (keyed, result);
3070
3071 {
3072 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail)
3073 {
3074 if (starting <= ii && ii <= ending)
3075 {
3076 keyed = KEY (key, elt);
3077 positioned
3078 = list_position_cons_before (&ignore, keyed, XCDR (tail),
3079 check_test, test_not_unboundp,
3080 test, key, 0,
3081 make_fixnum (max (starting
3082 - (ii + 1), 0)),
3083 make_fixnum (ending - (ii + 1)));
3084 if (!NILP (positioned))
3085 {
3086 sequence = result = result_tail = XCDR (tail);
3087 }
3088 else
3089 {
3090 break;
3091 }
3092 }
3093 else
3094 {
3095 break;
3096 }
3097
3098 ii++;
3099 }
3100 END_GC_EXTERNAL_LIST_LOOP (elt);
3101 }
3102
3103 {
3104 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail)
3105 {
3106 if (!(starting <= ii && ii <= ending))
3107 {
3108 ii++;
3109 continue;
3110 }
3111
3112 /* For this algorithm, each time we encounter an object to be
3113 removed, copy the output list from the tail beyond the last
3114 removed cons to this one. Otherwise, the tail of the output list
3115 is shared with the input list, which is OK. */
3116
3117 keyed = KEY (key, elt);
3118 positioned
3119 = list_position_cons_before (&ignore, keyed, XCDR (tail),
3120 check_test, test_not_unboundp,
3121 test, key, 0,
3122 make_fixnum (max (starting - (ii + 1),
3123 0)),
3124 make_fixnum (ending - (ii + 1)));
3125 if (!NILP (positioned))
3126 {
3127 if (EQ (result, sequence))
3128 {
3129 result = cons_with_shared_tail
3130 = Fcons (XCAR (sequence), XCDR (sequence));
3131 }
3132
3133 result_tail = cons_with_shared_tail;
3134 cursor = XCDR (cons_with_shared_tail);
3135
3136 while (!EQ (cursor, tail) && !NILP (cursor))
3137 {
3138 XSETCDR (result_tail, Fcons (XCAR (cursor), Qnil));
3139 result_tail = XCDR (result_tail);
3140 cursor = XCDR (cursor);
3141 }
3142
3143 XSETCDR (result_tail, XCDR (tail));
3144 cons_with_shared_tail = result_tail;
3145 }
3146
3147 ii++;
3148 }
3149 END_GC_EXTERNAL_LIST_LOOP (elt);
3150 }
3151
3152 UNGCPRO;
3153
3154 if ((ii < starting || (ii < ending && !NILP (end))))
3155 {
3156 check_sequence_range (args[0], start, end, Flength (args[0]));
3157 }
3158 }
3159 else
3160 {
3161 result = list_delete_duplicates_from_end (sequence, check_test,
3162 test_not_unboundp, test, key,
3163 start, end, 1);
3164 }
3165
3166 return result;
3167 }
3168 #undef KEY
3169
3170 DEFUN ("nreverse", Fnreverse, 1, 1, 0, /*
3171 Reverse SEQUENCE, destructively.
3172
3173 Return the beginning of the reversed sequence, which will be a distinct Lisp
3174 object if SEQUENCE is a list with length greater than one. See also
3175 `reverse', the non-destructive version of this function.
3176 */
3177 (sequence))
3178 {
3179 CHECK_SEQUENCE (sequence);
3180
3181 if (CONSP (sequence))
3182 {
3183 struct gcpro gcpro1, gcpro2;
3184 Lisp_Object prev = Qnil;
3185 Lisp_Object tail = sequence;
3186
3187 /* We gcpro our args; see `nconc' */
3188 GCPRO2 (prev, tail);
3189 while (!NILP (tail))
3190 {
3191 REGISTER Lisp_Object next;
3192 CONCHECK_CONS (tail);
3193 next = XCDR (tail);
3194 XCDR (tail) = prev;
3195 prev = tail;
3196 tail = next;
3197 }
3198 UNGCPRO;
3199 return prev;
3200 }
3201 else if (VECTORP (sequence))
3202 {
3203 Elemcount length = XVECTOR_LENGTH (sequence), ii = length;
3204 Elemcount half = length / 2;
3205 Lisp_Object swap = Qnil;
3206 CHECK_LISP_WRITEABLE (sequence);
3207
3208 while (ii > half)
3209 {
3210 swap = XVECTOR_DATA (sequence) [length - ii];
3211 XVECTOR_DATA (sequence) [length - ii]
3212 = XVECTOR_DATA (sequence) [ii - 1];
3213 XVECTOR_DATA (sequence) [ii - 1] = swap;
3214 --ii;
3215 }
3216 }
3217 else if (STRINGP (sequence))
3218 {
3219 Elemcount length = XSTRING_LENGTH (sequence);
3220 Ibyte *staging = alloca_ibytes (length), *staging_end = staging + length;
3221 Ibyte *cursor = XSTRING_DATA (sequence), *endp = cursor + length;
3222
3223 CHECK_LISP_WRITEABLE (sequence);
3224 while (cursor < endp)
3225 {
3226 staging_end -= itext_ichar_len (cursor);
3227 itext_copy_ichar (cursor, staging_end);
3228 INC_IBYTEPTR (cursor);
3229 }
3230
3231 assert (staging == staging_end);
3232
3233 memcpy (XSTRING_DATA (sequence), staging, length);
3234 init_string_ascii_begin (sequence);
3235 bump_string_modiff (sequence);
3236 sledgehammer_check_ascii_begin (sequence);
3237 }
3238 else if (BIT_VECTORP (sequence))
3239 {
3240 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence);
3241 Elemcount length = bit_vector_length (bv), ii = length;
3242 Elemcount half = length / 2;
3243 int swap = 0;
3244
3245 CHECK_LISP_WRITEABLE (sequence);
3246 while (ii > half)
3247 {
3248 swap = bit_vector_bit (bv, length - ii);
3249 set_bit_vector_bit (bv, length - ii, bit_vector_bit (bv, ii - 1));
3250 set_bit_vector_bit (bv, ii - 1, swap);
3251 --ii;
3252 }
3253 }
3254 else
3255 {
3256 assert (NILP (sequence));
3257 }
3258
3259 return sequence;
3260 }
3261
3262 DEFUN ("reverse", Freverse, 1, 1, 0, /*
3263 Reverse SEQUENCE, copying. Return the reversed sequence.
3264 See also the function `nreverse', which is used more often.
3265 */
3266 (sequence))
3267 {
3268 Lisp_Object result = Qnil;
3269
3270 CHECK_SEQUENCE (sequence);
3271
3272 if (CONSP (sequence))
3273 {
3274 EXTERNAL_LIST_LOOP_2 (elt, sequence)
3275 {
3276 result = Fcons (elt, result);
3277 }
3278 }
3279 else if (VECTORP (sequence))
3280 {
3281 Elemcount length = XVECTOR_LENGTH (sequence), ii = length;
3282 Lisp_Object *staging = alloca_array (Lisp_Object, length);
3283
3284 while (ii > 0)
3285 {
3286 staging[length - ii] = XVECTOR_DATA (sequence) [ii - 1];
3287 --ii;
3288 }
3289
3290 result = Fvector (length, staging);
3291 }
3292 else if (STRINGP (sequence))
3293 {
3294 Elemcount length = XSTRING_LENGTH (sequence);
3295 Ibyte *staging = alloca_ibytes (length), *staging_end = staging + length;
3296 Ibyte *cursor = XSTRING_DATA (sequence), *endp = cursor + length;
3297
3298 while (cursor < endp)
3299 {
3300 staging_end -= itext_ichar_len (cursor);
3301 itext_copy_ichar (cursor, staging_end);
3302 INC_IBYTEPTR (cursor);
3303 }
3304
3305 assert (staging == staging_end);
3306
3307 result = make_string (staging, length);
3308 }
3309 else if (BIT_VECTORP (sequence))
3310 {
3311 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence), *res;
3312 Elemcount length = bit_vector_length (bv), ii = length;
3313
3314 result = make_bit_vector (length, Qzero);
3315 res = XBIT_VECTOR (result);
3316
3317 while (ii > 0)
3318 {
3319 set_bit_vector_bit (res, length - ii, bit_vector_bit (bv, ii - 1));
3320 --ii;
3321 }
3322 }
3323 else
3324 {
3325 assert (NILP (sequence));
3326 }
3327
3328 return result;
3329 }
3330
3331 Lisp_Object
3332 list_merge (Lisp_Object org_l1, Lisp_Object org_l2,
3333 check_test_func_t check_merge,
3334 Lisp_Object predicate, Lisp_Object key)
3335 {
3336 Lisp_Object value;
3337 Lisp_Object tail;
3338 Lisp_Object tem;
3339 Lisp_Object l1, l2;
3340 Lisp_Object tortoises[2];
3341 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
3342 int l1_count = 0, l2_count = 0;
3343
3344 l1 = org_l1;
3345 l2 = org_l2;
3346 tail = Qnil;
3347 value = Qnil;
3348 tortoises[0] = org_l1;
3349 tortoises[1] = org_l2;
3350
3351 /* It is sufficient to protect org_l1 and org_l2. When l1 and l2 are
3352 updated, we copy the new values back into the org_ vars. */
3353
3354 GCPRO5 (org_l1, org_l2, predicate, value, tortoises[0]);
3355 gcpro5.nvars = 2;
3356
3357 while (1)
3358 {
3359 if (NILP (l1))
3360 {
3361 UNGCPRO;
3362 if (NILP (tail))
3363 return l2;
3364 Fsetcdr (tail, l2);
3365 return value;
3366 }
3367 if (NILP (l2))
3368 {
3369 UNGCPRO;
3370 if (NILP (tail))
3371 return l1;
3372 Fsetcdr (tail, l1);
3373 return value;
3374 }
3375
3376 if (check_merge (predicate, key, Fcar (l2), Fcar (l1)) == 0)
3377 {
3378 tem = l1;
3379 l1 = Fcdr (l1);
3380 org_l1 = l1;
3381
3382 if (l1_count++ > CIRCULAR_LIST_SUSPICION_LENGTH)
3383 {
3384 if (l1_count & 1)
3385 {
3386 if (!CONSP (tortoises[0]))
3387 {
3388 mapping_interaction_error (Qmerge, tortoises[0]);
3389 }
3390
3391 tortoises[0] = XCDR (tortoises[0]);
3392 }
3393
3394 if (EQ (org_l1, tortoises[0]))
3395 {
3396 signal_circular_list_error (org_l1);
3397 }
3398 }
3399 }
3400 else
3401 {
3402 tem = l2;
3403 l2 = Fcdr (l2);
3404 org_l2 = l2;
3405
3406 if (l2_count++ > CIRCULAR_LIST_SUSPICION_LENGTH)
3407 {
3408 if (l2_count & 1)
3409 {
3410 if (!CONSP (tortoises[1]))
3411 {
3412 mapping_interaction_error (Qmerge, tortoises[1]);
3413 }
3414
3415 tortoises[1] = XCDR (tortoises[1]);
3416 }
3417
3418 if (EQ (org_l2, tortoises[1]))
3419 {
3420 signal_circular_list_error (org_l2);
3421 }
3422 }
3423 }
3424
3425 if (NILP (tail))
3426 value = tem;
3427 else
3428 Fsetcdr (tail, tem);
3429
3430 tail = tem;
3431 }
3432 }
3433
3434 static void
3435 array_merge (Lisp_Object *dest, Elemcount dest_len,
3436 Lisp_Object *front, Elemcount front_len,
3437 Lisp_Object *back, Elemcount back_len,
3438 check_test_func_t check_merge,
3439 Lisp_Object predicate, Lisp_Object key)
3440 {
3441 Elemcount ii, fronting, backing;
3442 Lisp_Object *front_staging = front;
3443 Lisp_Object *back_staging = back;
3444 struct gcpro gcpro1, gcpro2;
3445
3446 assert (dest_len == (back_len + front_len));
3447
3448 if (0 == dest_len)
3449 {
3450 return;
3451 }
3452
3453 if (front >= dest && front < (dest + dest_len))
3454 {
3455 front_staging = alloca_array (Lisp_Object, front_len);
3456
3457 for (ii = 0; ii < front_len; ++ii)
3458 {
3459 front_staging[ii] = front[ii];
3460 }
3461 }
3462
3463 if (back >= dest && back < (dest + dest_len))
3464 {
3465 back_staging = alloca_array (Lisp_Object, back_len);
3466
3467 for (ii = 0; ii < back_len; ++ii)
3468 {
3469 back_staging[ii] = back[ii];
3470 }
3471 }
3472
3473 GCPRO2 (front_staging[0], back_staging[0]);
3474 gcpro1.nvars = front_len;
3475 gcpro2.nvars = back_len;
3476
3477 for (ii = fronting = backing = 0; ii < dest_len; ++ii)
3478 {
3479 if (fronting >= front_len)
3480 {
3481 while (ii < dest_len)
3482 {
3483 dest[ii] = back_staging[backing];
3484 ++ii, ++backing;
3485 }
3486 UNGCPRO;
3487 return;
3488 }
3489
3490 if (backing >= back_len)
3491 {
3492 while (ii < dest_len)
3493 {
3494 dest[ii] = front_staging[fronting];
3495 ++ii, ++fronting;
3496 }
3497 UNGCPRO;
3498 return;
3499 }
3500
3501 if (check_merge (predicate, key, back_staging[backing],
3502 front_staging[fronting]) == 0)
3503 {
3504 dest[ii] = front_staging[fronting];
3505 ++fronting;
3506 }
3507 else
3508 {
3509 dest[ii] = back_staging[backing];
3510 ++backing;
3511 }
3512 }
3513
3514 UNGCPRO;
3515 }
3516
3517 static Lisp_Object
3518 list_array_merge_into_list (Lisp_Object list,
3519 Lisp_Object *array, Elemcount array_len,
3520 check_test_func_t check_merge,
3521 Lisp_Object predicate, Lisp_Object key,
3522 Boolint reverse_order)
3523 {
3524 Lisp_Object tail = Qnil, value = Qnil, tortoise = list;
3525 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3526 Elemcount array_index = 0;
3527 int looped = 0;
3528
3529 GCPRO4 (list, tail, value, tortoise);
3530
3531 while (1)
3532 {
3533 if (NILP (list))
3534 {
3535 UNGCPRO;
3536
3537 if (NILP (tail))
3538 {
3539 return Flist (array_len, array);
3540 }
3541
3542 Fsetcdr (tail, Flist (array_len - array_index, array + array_index));
3543 return value;
3544 }
3545
3546 if (array_index >= array_len)
3547 {
3548 UNGCPRO;
3549 if (NILP (tail))
3550 {
3551 return list;
3552 }
3553
3554 Fsetcdr (tail, list);
3555 return value;
3556 }
3557
3558
3559 if (reverse_order ?
3560 check_merge (predicate, key, Fcar (list), array [array_index])
3561 : !check_merge (predicate, key, array [array_index], Fcar (list)))
3562 {
3563 if (NILP (tail))
3564 {
3565 value = tail = list;
3566 }
3567 else
3568 {
3569 Fsetcdr (tail, list);
3570 tail = XCDR (tail);
3571 }
3572
3573 list = Fcdr (list);
3574 }
3575 else
3576 {
3577 if (NILP (tail))
3578 {
3579 value = tail = Fcons (array [array_index], Qnil);
3580 }
3581 else
3582 {
3583 Fsetcdr (tail, Fcons (array [array_index], tail));
3584 tail = XCDR (tail);
3585 }
3586 ++array_index;
3587 }
3588
3589 if (++looped > CIRCULAR_LIST_SUSPICION_LENGTH)
3590 {
3591 if (looped & 1)
3592 {
3593 tortoise = XCDR (tortoise);
3594 }
3595
3596 if (EQ (list, tortoise))
3597 {
3598 signal_circular_list_error (list);
3599 }
3600 }
3601 }
3602 }
3603
3604 static void
3605 list_list_merge_into_array (Lisp_Object *output, Elemcount output_len,
3606 Lisp_Object list_one, Lisp_Object list_two,
3607 check_test_func_t check_merge,
3608 Lisp_Object predicate, Lisp_Object key)
3609 {
3610 Elemcount output_index = 0;
3611
3612 while (output_index < output_len)
3613 {
3614 if (NILP (list_one))
3615 {
3616 while (output_index < output_len)
3617 {
3618 output [output_index] = Fcar (list_two);
3619 list_two = Fcdr (list_two), ++output_index;
3620 }
3621 return;
3622 }
3623
3624 if (NILP (list_two))
3625 {
3626 while (output_index < output_len)
3627 {
3628 output [output_index] = Fcar (list_one);
3629 list_one = Fcdr (list_one), ++output_index;
3630 }
3631 return;
3632 }
3633
3634 if (check_merge (predicate, key, Fcar (list_two), Fcar (list_one))
3635 == 0)
3636 {
3637 output [output_index] = XCAR (list_one);
3638 list_one = XCDR (list_one);
3639 }
3640 else
3641 {
3642 output [output_index] = XCAR (list_two);
3643 list_two = XCDR (list_two);
3644 }
3645
3646 ++output_index;
3647
3648 /* No need to check for circularity. */
3649 }
3650 }
3651
3652 static void
3653 list_array_merge_into_array (Lisp_Object *output, Elemcount output_len,
3654 Lisp_Object list,
3655 Lisp_Object *array, Elemcount array_len,
3656 check_test_func_t check_merge,
3657 Lisp_Object predicate, Lisp_Object key,
3658 Boolint reverse_order)
3659 {
3660 Elemcount output_index = 0, array_index = 0;
3661
3662 while (output_index < output_len)
3663 {
3664 if (NILP (list))
3665 {
3666 if (array_len - array_index != output_len - output_index)
3667 {
3668 mapping_interaction_error (Qmerge, list);
3669 }
3670
3671 while (array_index < array_len)
3672 {
3673 output [output_index++] = array [array_index++];
3674 }
3675
3676 return;
3677 }
3678
3679 if (array_index >= array_len)
3680 {
3681 while (output_index < output_len)
3682 {
3683 output [output_index++] = Fcar (list);
3684 list = Fcdr (list);
3685 }
3686
3687 return;
3688 }
3689
3690 if (reverse_order ?
3691 check_merge (predicate, key, Fcar (list), array [array_index]) :
3692 !check_merge (predicate, key, array [array_index], Fcar (list)))
3693 {
3694 output [output_index] = XCAR (list);
3695 list = XCDR (list);
3696 }
3697 else
3698 {
3699 output [output_index] = array [array_index];
3700 ++array_index;
3701 }
3702
3703 ++output_index;
3704 }
3705 }
3706
3707 #define STRING_DATA_TO_OBJECT_ARRAY(strdata, c_array, counter, len) \
3708 do { \
3709 c_array = alloca_array (Lisp_Object, len); \
3710 for (counter = 0; counter < len; ++counter) \
3711 { \
3712 c_array[counter] = make_char (itext_ichar (strdata)); \
3713 INC_IBYTEPTR (strdata); \
3714 } \
3715 } while (0)
3716
3717 #define BIT_VECTOR_TO_OBJECT_ARRAY(v, c_array, counter, len) do { \
3718 c_array = alloca_array (Lisp_Object, len); \
3719 for (counter = 0; counter < len; ++counter) \
3720 { \
3721 c_array[counter] = make_fixnum (bit_vector_bit (v, counter)); \
3722 } \
3723 } while (0)
3724
3725 DEFUN ("merge", Fmerge, 4, MANY, 0, /*
3726 Destructively merge SEQUENCE-ONE and SEQUENCE-TWO, producing a new sequence.
3727
3728 TYPE is the type of sequence to return. PREDICATE is a `less-than'
3729 predicate on the elements.
3730
3731 Optional keyword argument KEY is a function used to extract an object to be
3732 used for comparison from each element of SEQUENCE-ONE and SEQUENCE-TWO.
3733
3734 arguments: (TYPE SEQUENCE-ONE SEQUENCE-TWO PREDICATE &key (KEY #'IDENTITY))
3735 */
3736 (int nargs, Lisp_Object *args))
3737 {
3738 Lisp_Object type = args[0], sequence_one = args[1], sequence_two = args[2],
3739 predicate = args[3], result = Qnil;
3740 check_test_func_t check_merge = NULL;
3741
3742 PARSE_KEYWORDS (Fmerge, nargs, args, 1, (key), NULL);
3743
3744 CHECK_SEQUENCE (sequence_one);
3745 CHECK_SEQUENCE (sequence_two);
3746
3747 CHECK_KEY_ARGUMENT (key);
3748
3749 check_merge = get_merge_predicate (predicate, key);
3750
3751 if (EQ (type, Qlist) && (LISTP (sequence_one) || LISTP (sequence_two)))
3752 {
3753 if (NILP (sequence_two))
3754 {
3755 result = Fappend (2, args + 1);
3756 }
3757 else if (NILP (sequence_one))
3758 {
3759 args[3] = Qnil; /* Overwriting PREDICATE, and losing its GC
3760 protection, but that doesn't matter. */
3761 result = Fappend (2, args + 2);
3762 }
3763 else if (CONSP (sequence_one) && CONSP (sequence_two))
3764 {
3765 result = list_merge (sequence_one, sequence_two, check_merge,
3766 predicate, key);
3767 }
3768 else
3769 {
3770 Lisp_Object *array_storage, swap;
3771 Elemcount array_length, i;
3772 Boolint reverse_order = 0;
3773
3774 if (!CONSP (sequence_one))
3775 {
3776 /* Make sequence_one the cons, sequence_two the array: */
3777 swap = sequence_one;
3778 sequence_one = sequence_two;
3779 sequence_two = swap;
3780 reverse_order = 1;
3781 }
3782
3783 if (VECTORP (sequence_two))
3784 {
3785 array_storage = XVECTOR_DATA (sequence_two);
3786 array_length = XVECTOR_LENGTH (sequence_two);
3787 }
3788 else if (STRINGP (sequence_two))
3789 {
3790 Ibyte *strdata = XSTRING_DATA (sequence_two);
3791 array_length = string_char_length (sequence_two);
3792 /* No need to GCPRO, characters are immediate. */
3793 STRING_DATA_TO_OBJECT_ARRAY (strdata, array_storage, i,
3794 array_length);
3795
3796 }
3797 else
3798 {
3799 Lisp_Bit_Vector *v = XBIT_VECTOR (sequence_two);
3800 array_length = bit_vector_length (v);
3801 /* No need to GCPRO, fixnums are immediate. */
3802 BIT_VECTOR_TO_OBJECT_ARRAY (v, array_storage, i, array_length);
3803 }
3804
3805 result = list_array_merge_into_list (sequence_one,
3806 array_storage, array_length,
3807 check_merge, predicate, key,
3808 reverse_order);
3809 }
3810 }
3811 else
3812 {
3813 Elemcount sequence_one_len = XFIXNUM (Flength (sequence_one)),
3814 sequence_two_len = XFIXNUM (Flength (sequence_two)), i;
3815 Elemcount output_len = 1 + sequence_one_len + sequence_two_len;
3816 Lisp_Object *output = alloca_array (Lisp_Object, output_len),
3817 *sequence_one_storage = NULL, *sequence_two_storage = NULL;
3818 Boolint do_coerce = !(EQ (type, Qvector) || EQ (type, Qstring)
3819 || EQ (type, Qbit_vector) || EQ (type, Qlist));
3820 Ibyte *strdata = NULL;
3821 Lisp_Bit_Vector *v = NULL;
3822 struct gcpro gcpro1;
3823
3824 output[0] = do_coerce ? Qlist : type;
3825 for (i = 1; i < output_len; ++i)
3826 {
3827 output[i] = Qnil;
3828 }
3829
3830 GCPRO1 (output[0]);
3831 gcpro1.nvars = output_len;
3832
3833 if (VECTORP (sequence_one))
3834 {
3835 sequence_one_storage = XVECTOR_DATA (sequence_one);
3836 }
3837 else if (STRINGP (sequence_one))
3838 {
3839 strdata = XSTRING_DATA (sequence_one);
3840 STRING_DATA_TO_OBJECT_ARRAY (strdata, sequence_one_storage,
3841 i, sequence_one_len);
3842 }
3843 else if (BIT_VECTORP (sequence_one))
3844 {
3845 v = XBIT_VECTOR (sequence_one);
3846 BIT_VECTOR_TO_OBJECT_ARRAY (v, sequence_one_storage,
3847 i, sequence_one_len);
3848 }
3849
3850 if (VECTORP (sequence_two))
3851 {
3852 sequence_two_storage = XVECTOR_DATA (sequence_two);
3853 }
3854 else if (STRINGP (sequence_two))
3855 {
3856 strdata = XSTRING_DATA (sequence_two);
3857 STRING_DATA_TO_OBJECT_ARRAY (strdata, sequence_two_storage,
3858 i, sequence_two_len);
3859 }
3860 else if (BIT_VECTORP (sequence_two))
3861 {
3862 v = XBIT_VECTOR (sequence_two);
3863 BIT_VECTOR_TO_OBJECT_ARRAY (v, sequence_two_storage,
3864 i, sequence_two_len);
3865 }
3866
3867 if (LISTP (sequence_one) && LISTP (sequence_two))
3868 {
3869 list_list_merge_into_array (output + 1, output_len - 1,
3870 sequence_one, sequence_two,
3871 check_merge, predicate, key);
3872 }
3873 else if (LISTP (sequence_one))
3874 {
3875 list_array_merge_into_array (output + 1, output_len - 1,
3876 sequence_one,
3877 sequence_two_storage,
3878 sequence_two_len,
3879 check_merge, predicate, key, 0);
3880 }
3881 else if (LISTP (sequence_two))
3882 {
3883 list_array_merge_into_array (output + 1, output_len - 1,
3884 sequence_two,
3885 sequence_one_storage,
3886 sequence_one_len,
3887 check_merge, predicate, key, 1);
3888 }
3889 else
3890 {
3891 array_merge (output + 1, output_len - 1,
3892 sequence_one_storage, sequence_one_len,
3893 sequence_two_storage, sequence_two_len,
3894 check_merge, predicate,
3895 key);
3896 }
3897
3898 result = Ffuncall (output_len, output);
3899
3900 if (do_coerce)
3901 {
3902 result = call2 (Qcoerce, result, type);
3903 }
3904
3905 UNGCPRO;
3906 }
3907
3908 return result;
3909 }
3910
3911 Lisp_Object
3912 list_sort (Lisp_Object list, check_test_func_t check_merge,
3913 Lisp_Object predicate, Lisp_Object key)
3914 {
3915 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3916 Lisp_Object back, tem;
3917 Lisp_Object front = list;
3918 Lisp_Object len = Flength (list);
3919
3920 if (XFIXNUM (len) < 2)
3921 return list;
3922
3923 len = make_fixnum (XFIXNUM (len) / 2 - 1);
3924 tem = Fnthcdr (len, list);
3925 back = Fcdr (tem);
3926 Fsetcdr (tem, Qnil);
3927
3928 GCPRO4 (front, back, predicate, key);
3929 front = list_sort (front, check_merge, predicate, key);
3930 back = list_sort (back, check_merge, predicate, key);
3931
3932 RETURN_UNGCPRO (list_merge (front, back, check_merge, predicate, key));
3933 }
3934
3935 static void
3936 array_sort (Lisp_Object *array, Elemcount array_len,
3937 check_test_func_t check_merge,
3938 Lisp_Object predicate, Lisp_Object key)
3939 {
3940 Elemcount split;
3941
3942 if (array_len < 2)
3943 return;
3944
3945 split = array_len / 2;
3946
3947 array_sort (array, split, check_merge, predicate, key);
3948 array_sort (array + split, array_len - split, check_merge, predicate,
3949 key);
3950 array_merge (array, array_len, array, split, array + split,
3951 array_len - split, check_merge, predicate, key);
3952 }
3953
3954 DEFUN ("sort*", FsortX, 2, MANY, 0, /*
3955 Sort SEQUENCE, comparing elements using PREDICATE.
3956 Returns the sorted sequence. SEQUENCE is modified by side effect.
3957
3958 PREDICATE is called with two elements of SEQUENCE, and should return t if
3959 the first element is `less' than the second.
3960
3961 Optional keyword argument KEY is a function used to extract an object to be
3962 used for comparison from each element of SEQUENCE.
3963
3964 In this implementation, sorting is always stable; but call `stable-sort' if
3965 this stability is important to you, other implementations may not make the
3966 same guarantees.
3967
3968 arguments: (SEQUENCE PREDICATE &key (KEY #'IDENTITY))
3969 */
3970 (int nargs, Lisp_Object *args))
3971 {
3972 Lisp_Object sequence = args[0], predicate = args[1];
3973 Lisp_Object *sequence_carray;
3974 check_test_func_t check_merge = NULL;
3975 Elemcount sequence_len, i;
3976
3977 PARSE_KEYWORDS (FsortX, nargs, args, 1, (key), NULL);
3978
3979 CHECK_SEQUENCE (sequence);
3980
3981 CHECK_KEY_ARGUMENT (key);
3982
3983 check_merge = get_merge_predicate (predicate, key);
3984
3985 if (LISTP (sequence))
3986 {
3987 sequence = list_sort (sequence, check_merge, predicate, key);
3988 }
3989 else if (VECTORP (sequence))
3990 {
3991 array_sort (XVECTOR_DATA (sequence), XVECTOR_LENGTH (sequence),
3992 check_merge, predicate, key);
3993 }
3994 else if (STRINGP (sequence))
3995 {
3996 Ibyte *strdata = XSTRING_DATA (sequence);
3997
3998 sequence_len = string_char_length (sequence);
3999
4000 STRING_DATA_TO_OBJECT_ARRAY (strdata, sequence_carray, i, sequence_len);
4001
4002 /* No GCPRO necessary, characters are immediate. */
4003 array_sort (sequence_carray, sequence_len, check_merge, predicate, key);
4004
4005 strdata = XSTRING_DATA (sequence);
4006
4007 CHECK_LISP_WRITEABLE (sequence);
4008 for (i = 0; i < sequence_len; ++i)
4009 {
4010 strdata += set_itext_ichar (strdata, XCHAR (sequence_carray[i]));
4011 }
4012
4013 init_string_ascii_begin (sequence);
4014 bump_string_modiff (sequence);
4015 sledgehammer_check_ascii_begin (sequence);
4016 }
4017 else if (BIT_VECTORP (sequence))
4018 {
4019 Lisp_Bit_Vector *v = XBIT_VECTOR (sequence);
4020 sequence_len = bit_vector_length (v);
4021
4022 BIT_VECTOR_TO_OBJECT_ARRAY (v, sequence_carray, i, sequence_len);
4023
4024 /* No GCPRO necessary, bits are immediate. */
4025 array_sort (sequence_carray, sequence_len, check_merge, predicate, key);
4026
4027 for (i = 0; i < sequence_len; ++i)
4028 {
4029 set_bit_vector_bit (v, i, XFIXNUM (sequence_carray [i]));
4030 }
4031 }
4032
4033 return sequence;
4034 }
4035
4036
4037 static Lisp_Object replace_string_range_1 (Lisp_Object dest,
4038 Lisp_Object start,
4039 Lisp_Object end,
4040 const Ibyte *source,
4041 const Ibyte *source_limit,
4042 Lisp_Object item);
4043
4044 /* Fill the substring of DEST beginning at START and ending before END with
4045 the character ITEM. If DEST does not have sufficient space for END -
4046 START characters at START, write as many as is possible without changing
4047 the character length of DEST. Update the string modification flag and do
4048 any sledgehammer checks we have turned on.
4049
4050 START must be a Lisp integer. END can be nil, indicating the length of the
4051 string, or a Lisp integer. The condition (<= 0 START END (length DEST))
4052 must hold, or fill_string_range() will signal an error. */
4053 static Lisp_Object
4054 fill_string_range (Lisp_Object dest, Lisp_Object item, Lisp_Object start,
4055 Lisp_Object end)
4056 {
4057 return replace_string_range_1 (dest, start, end, NULL, NULL, item);
4058 }
4059
4060 DEFUN ("fill", Ffill, 2, MANY, 0, /*
4061 Destructively modify SEQUENCE by replacing each element with ITEM.
4062 SEQUENCE is a list, vector, bit vector, or string.
4063
4064 Optional keyword START is the index of the first element of SEQUENCE
4065 to be modified, and defaults to zero. Optional keyword END is the
4066 exclusive upper bound on the elements of SEQUENCE to be modified, and
4067 defaults to the length of SEQUENCE.
4068
4069 arguments: (SEQUENCE ITEM &key (START 0) (END (length SEQUENCE)))
4070 */
4071 (int nargs, Lisp_Object *args))
4072 {
4073 Lisp_Object sequence = args[0];
4074 Lisp_Object item = args[1];
4075 Elemcount starting, ending = MOST_POSITIVE_FIXNUM + 1, ii, len;
4076
4077 PARSE_KEYWORDS (Ffill, nargs, args, 2, (start, end), (start = Qzero));
4078
4079 CHECK_NATNUM (start);
4080 starting = BIGNUMP (start) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start);
4081
4082 if (!NILP (end))
4083 {
4084 CHECK_NATNUM (end);
4085 ending = BIGNUMP (end) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end);
4086 }
4087
4088 retry:
4089 if (STRINGP (sequence))
4090 {
4091 CHECK_CHAR_COERCE_INT (item);
4092 CHECK_LISP_WRITEABLE (sequence);
4093
4094 fill_string_range (sequence, item, start, end);
4095 }
4096 else if (VECTORP (sequence))
4097 {
4098 Lisp_Object *p = XVECTOR_DATA (sequence);
4099
4100 CHECK_LISP_WRITEABLE (sequence);
4101 len = XVECTOR_LENGTH (sequence);
4102
4103 check_sequence_range (sequence, start, end, make_fixnum (len));
4104 ending = min (ending, len);
4105
4106 for (ii = starting; ii < ending; ++ii)
4107 {
4108 p[ii] = item;
4109 }
4110 }
4111 else if (BIT_VECTORP (sequence))
4112 {
4113 Lisp_Bit_Vector *v = XBIT_VECTOR (sequence);
4114 int bit;
4115
4116 CHECK_BIT (item);
4117 bit = XFIXNUM (item);
4118 CHECK_LISP_WRITEABLE (sequence);
4119 len = bit_vector_length (v);
4120
4121 check_sequence_range (sequence, start, end, make_fixnum (len));
4122 ending = min (ending, len);
4123
4124 for (ii = starting; ii < ending; ++ii)
4125 {
4126 set_bit_vector_bit (v, ii, bit);
4127 }
4128 }
4129 else if (LISTP (sequence))
4130 {
4131 Elemcount counting = 0;
4132
4133 {
4134 EXTERNAL_LIST_LOOP_3 (elt, sequence, tail)
4135 {
4136 if (counting >= starting)
4137 {
4138 if (counting < ending)
4139 {
4140 XSETCAR (tail, item);
4141 }
4142 else if (counting == ending)
4143 {
4144 break;
4145 }
4146 }
4147 ++counting;
4148 }
4149 }
4150
4151 if (counting < starting || (counting != ending && !NILP (end)))
4152 {
4153 check_sequence_range (args[0], start, end, Flength (args[0]));
4154 }
4155 }
4156 else
4157 {
4158 sequence = wrong_type_argument (Qsequencep, sequence);
4159 goto retry;
4160 }
4161 return sequence;
4162 }
4163
4164
4165 /* Replace the substring of DEST beginning at START and ending before END
4166 with the text at SOURCE, which is END - START characters long and
4167 SOURCE_LIMIT - SOURCE octets long. If DEST does not have sufficient
4168 space for END - START characters at START, write as many as is possible
4169 without changing the length of DEST. Update the string modification flag
4170 and do any sledgehammer checks we have turned on in this build.
4171
4172 START must be a Lisp integer. END can be nil, indicating the length of the
4173 string, or a Lisp integer. The condition (<= 0 START END (length DEST))
4174 must hold, or replace_string_range() will signal an error. */
4175 static Lisp_Object
4176 replace_string_range (Lisp_Object dest, Lisp_Object start, Lisp_Object end,
4177 const Ibyte *source, const Ibyte *source_limit)
4178 {
4179 return replace_string_range_1 (dest, start, end, source, source_limit,
4180 Qnil);
4181 }
4182
4183 /* This is the guts of several mapping functions.
4184
4185 Call FUNCTION CALL_COUNT times, with NSEQUENCES arguments each time,
4186 taking the elements from SEQUENCES. If VALS is non-NULL, store the
4187 results into VALS, a C array of Lisp_Objects; else, if LISP_VALS is
4188 non-nil, store the results into LISP_VALS, a sequence with sufficient
4189 room for CALL_COUNT results (but see the documentation of SOME_OR_EVERY.)
4190 Else, do not accumulate any result.
4191
4192 If VALS is non-NULL, NSEQUENCES is one, and SEQUENCES[0] is a cons,
4193 mapcarX will store the elements of SEQUENCES[0] in stack and GCPRO them,
4194 so FUNCTION cannot insert a non-cons into SEQUENCES[0] and throw off
4195 mapcarX.
4196
4197 Otherwise, mapcarX signals an invalid state error (see
4198 mapping_interaction_error(), above) if it encounters a non-cons,
4199 non-array when traversing SEQUENCES. Common Lisp specifies in
4200 MAPPING-DESTRUCTIVE-INTERACTION that it is an error when FUNCTION
4201 destructively modifies SEQUENCES in a way that might affect the ongoing
4202 traversal operation.
4203
4204 CALLER is a symbol describing the Lisp-visible function that was called,
4205 and any errors thrown because SEQUENCES was modified will reflect it.
4206
4207 If CALLER is Qsome, return the (possibly multiple) values given by
4208 FUNCTION the first time it is non-nil, and abandon the iterations.
4209 LISP_VALS must be the result of calling STORE_VOID_IN_LISP on the address
4210 of a Lisp object, and the return value will be stored at that address.
4211 If CALLER is Qevery, LISP_VALS must also reflect a pointer to a Lisp
4212 object, and Qnil will be stored at that address if FUNCTION gives nil;
4213 otherwise it will be left alone. */
4214
4215 static void
4216 mapcarX (Elemcount call_count, Lisp_Object *vals, Lisp_Object lisp_vals,
4217 Lisp_Object function, int nsequences, Lisp_Object *sequences,
4218 Lisp_Object caller)
4219 {
4220 Lisp_Object called, *args;
4221 struct gcpro gcpro1, gcpro2;
4222 Ibyte *lisp_vals_staging = NULL, *cursor = NULL;
4223 int i, j;
4224
4225 assert ((EQ (caller, Qsome) || EQ (caller, Qevery)) ? vals == NULL : 1);
4226
4227 args = alloca_array (Lisp_Object, nsequences + 1);
4228 args[0] = function;
4229 for (i = 1; i <= nsequences; ++i)
4230 {
4231 args[i] = Qnil;
4232 }
4233
4234 if (vals != NULL)
4235 {
4236 GCPRO2 (args[0], vals[0]);
4237 gcpro1.nvars = nsequences + 1;
4238 gcpro2.nvars = 0;
4239 }
4240 else
4241 {
4242 GCPRO1 (args[0]);
4243 gcpro1.nvars = nsequences + 1;
4244 }
4245
4246 /* Be extra nice in the event that we've been handed one list and one
4247 only; make it possible for FUNCTION to set cdrs not yet processed to
4248 non-cons, non-nil objects without ill-effect, if we have been handed
4249 the stack space to do that. */
4250 if (vals != NULL && 1 == nsequences && CONSP (sequences[0]))
4251 {
4252 Lisp_Object lst = sequences[0];
4253 Lisp_Object *val = vals;
4254 for (i = 0; i < call_count; ++i)
4255 {
4256 *val++ = XCAR (lst);
4257 lst = XCDR (lst);
4258 }
4259 gcpro2.nvars = call_count;
4260
4261 for (i = 0; i < call_count; ++i)
4262 {
4263 args[1] = vals[i];
4264 vals[i] = IGNORE_MULTIPLE_VALUES (Ffuncall (nsequences + 1, args));
4265 }
4266 }
4267 else
4268 {
4269 enum lrecord_type lisp_vals_type = lrecord_type_symbol;
4270 Binbyte *sequence_types = alloca_array (Binbyte, nsequences);
4271 for (j = 0; j < nsequences; ++j)
4272 {
4273 sequence_types[j] = XRECORD_LHEADER (sequences[j])->type;
4274 }
4275
4276 if (!EQ (caller, Qsome) && !EQ (caller, Qevery))
4277 {
4278 assert (LRECORDP (lisp_vals));
4279
4280 lisp_vals_type
4281 = (enum lrecord_type) XRECORD_LHEADER (lisp_vals)->type;
4282
4283 if (lrecord_type_string == lisp_vals_type)
4284 {
4285 lisp_vals_staging = cursor
4286 = alloca_ibytes (call_count * MAX_ICHAR_LEN);
4287 }
4288 else if (ARRAYP (lisp_vals))
4289 {
4290 CHECK_LISP_WRITEABLE (lisp_vals);
4291 }
4292 }
4293
4294 for (i = 0; i < call_count; ++i)
4295 {
4296 for (j = 0; j < nsequences; ++j)
4297 {
4298 switch (sequence_types[j])
4299 {
4300 case lrecord_type_cons:
4301 {
4302 if (!CONSP (sequences[j]))
4303 {
4304 /* This means FUNCTION has messed around with a cons
4305 in one of the sequences, since we checked the
4306 type (CHECK_SEQUENCE()) and the length and
4307 structure (with Flength()) correctly in our
4308 callers. */
4309 mapping_interaction_error (caller, sequences[j]);
4310 }
4311 args[j + 1] = XCAR (sequences[j]);
4312 sequences[j] = XCDR (sequences[j]);
4313 break;
4314 }
4315 case lrecord_type_vector:
4316 {
4317 args[j + 1] = XVECTOR_DATA (sequences[j])[i];
4318 break;
4319 }
4320 case lrecord_type_string:
4321 {
4322 args[j + 1] = make_char (string_ichar (sequences[j], i));
4323 break;
4324 }
4325 case lrecord_type_bit_vector:
4326 {
4327 args[j + 1]
4328 = make_fixnum (bit_vector_bit (XBIT_VECTOR (sequences[j]),
4329 i));
4330 break;
4331 }
4332 default:
4333 ABORT();
4334 }
4335 }
4336 called = Ffuncall (nsequences + 1, args);
4337 if (vals != NULL)
4338 {
4339 vals[i] = IGNORE_MULTIPLE_VALUES (called);
4340 gcpro2.nvars += 1;
4341 }
4342 else if (EQ (Qsome, caller))
4343 {
4344 if (!NILP (IGNORE_MULTIPLE_VALUES (called)))
4345 {
4346 Lisp_Object *result
4347 = (Lisp_Object *) GET_VOID_FROM_LISP (lisp_vals);
4348 *result = called;
4349 UNGCPRO;
4350 return;
4351 }
4352 }
4353 else if (EQ (Qevery, caller))
4354 {
4355 if (NILP (IGNORE_MULTIPLE_VALUES (called)))
4356 {
4357 Lisp_Object *result
4358 = (Lisp_Object *) GET_VOID_FROM_LISP (lisp_vals);
4359 *result = Qnil;
4360 UNGCPRO;
4361 return;
4362 }
4363 }
4364 else
4365 {
4366 called = IGNORE_MULTIPLE_VALUES (called);
4367 switch (lisp_vals_type)
4368 {
4369 case lrecord_type_symbol:
4370 /* Discard the result of funcall. */
4371 break;
4372 case lrecord_type_cons:
4373 {
4374 if (!CONSP (lisp_vals))
4375 {
4376 /* If FUNCTION has inserted a non-cons non-nil
4377 cdr into the list before we've processed the
4378 relevant part, error. */
4379 mapping_interaction_error (caller, lisp_vals);
4380 }
4381 XSETCAR (lisp_vals, called);
4382 lisp_vals = XCDR (lisp_vals);
4383 break;
4384 }
4385 case lrecord_type_vector:
4386 {
4387 i < XVECTOR_LENGTH (lisp_vals) ?
4388 (XVECTOR_DATA (lisp_vals)[i] = called) :
4389 /* Let #'aset error. */
4390 Faset (lisp_vals, make_fixnum (i), called);
4391 break;
4392 }
4393 case lrecord_type_string:
4394 {
4395 CHECK_CHAR_COERCE_INT (called);
4396 cursor += set_itext_ichar (cursor, XCHAR (called));
4397 break;
4398 }
4399 case lrecord_type_bit_vector:
4400 {
4401 (BITP (called) &&
4402 i < bit_vector_length (XBIT_VECTOR (lisp_vals))) ?
4403 set_bit_vector_bit (XBIT_VECTOR (lisp_vals), i,
4404 XFIXNUM (called)) :
4405 (void) Faset (lisp_vals, make_fixnum (i), called);
4406 break;
4407 }
4408 default:
4409 {
4410 ABORT();
4411 break;
4412 }
4413 }
4414 }
4415 }
4416
4417 if (lisp_vals_staging != NULL)
4418 {
4419 CHECK_LISP_WRITEABLE (lisp_vals);
4420 replace_string_range (lisp_vals, Qzero, make_fixnum (call_count),
4421 lisp_vals_staging, cursor);
4422 }
4423 }
4424
4425 UNGCPRO;
4426 }
4427
4428 /* Given NSEQUENCES objects at the address pointed to by SEQUENCES, return
4429 the length of the shortest sequence. Error if all are circular, or if any
4430 one of them is not a sequence. */
4431 static Elemcount
4432 shortest_length_among_sequences (int nsequences, Lisp_Object *sequences)
4433 {
4434 Elemcount len = 1 + MOST_POSITIVE_FIXNUM;
4435 Lisp_Object length = Qnil;
4436 int i;
4437
4438 for (i = 0; i < nsequences; ++i)
4439 {
4440 if (CONSP (sequences[i]))
4441 {
4442 length = Flist_length (sequences[i]);
4443 if (!NILP (length))
4444 {
4445 len = min (len, XFIXNUM (length));
4446 }
4447 }
4448 else
4449 {
4450 CHECK_SEQUENCE (sequences[i]);
4451 length = Flength (sequences[i]);
4452 len = min (len, XFIXNUM (length));
4453 }
4454 }
4455
4456 if (len == 1 + MOST_POSITIVE_FIXNUM)
4457 {
4458 signal_circular_list_error (sequences[0]);
4459 }
4460
4461 return len;
4462 }
4463
4464 DEFUN ("mapconcat", Fmapconcat, 3, MANY, 0, /*
4465 Call FUNCTION on each element of SEQUENCE, and concat results to a string.
4466 Between each pair of results, insert SEPARATOR.
4467
4468 Each result, and SEPARATOR, should be strings. Thus, using " " as SEPARATOR
4469 results in spaces between the values returned by FUNCTION. SEQUENCE itself
4470 may be a list, a vector, a bit vector, or a string.
4471
4472 With optional SEQUENCES, call FUNCTION each time with as many arguments as
4473 there are SEQUENCES, plus one for the element from SEQUENCE. One element
4474 from each sequence will be used each time FUNCTION is called, and
4475 `mapconcat' will give up once the shortest sequence is exhausted.
4476
4477 arguments: (FUNCTION SEQUENCE SEPARATOR &rest SEQUENCES)
4478 */
4479 (int nargs, Lisp_Object *args))
4480 {
4481 Lisp_Object function = args[0];
4482 Lisp_Object sequence = args[1];
4483 Lisp_Object separator = args[2];
4484 Elemcount len = MOST_POSITIVE_FIXNUM;
4485 Lisp_Object *args0;
4486 EMACS_INT i, nargs0;
4487
4488 args[2] = sequence;
4489 args[1] = separator;
4490
4491 len = shortest_length_among_sequences (nargs - 2, args + 2);
4492
4493 if (len == 0) return build_ascstring ("");
4494
4495 nargs0 = len + len - 1;
4496 args0 = alloca_array (Lisp_Object, nargs0);
4497
4498 /* Special-case this, it's very common and doesn't require any
4499 funcalls. Upside of doing it here, instead of cl-macs.el: no consing,
4500 apart from the final string, we allocate everything on the stack. */
4501 if (EQ (function, Qidentity) && 3 == nargs && CONSP (sequence))
4502 {
4503 for (i = 0; i < len; ++i)
4504 {
4505 args0[i] = XCAR (sequence);
4506 sequence = XCDR (sequence);
4507 }
4508 }
4509 else
4510 {
4511 mapcarX (len, args0, Qnil, function, nargs - 2, args + 2, Qmapconcat);
4512 }
4513
4514 for (i = len - 1; i >= 0; i--)
4515 args0[i + i] = args0[i];
4516
4517 for (i = 1; i < nargs0; i += 2)
4518 args0[i] = separator;
4519
4520 return Fconcat (nargs0, args0);
4521 }
4522
4523 DEFUN ("mapcar*", FmapcarX, 2, MANY, 0, /*
4524 Call FUNCTION on each element of SEQUENCE; return a list of the results.
4525 The result is a list of the same length as SEQUENCE.
4526 SEQUENCE may be a list, a vector, a bit vector, or a string.
4527
4528 With optional SEQUENCES, call FUNCTION each time with as many arguments as
4529 there are SEQUENCES, plus one for the element from SEQUENCE. One element
4530 from each sequence will be used each time FUNCTION is called, and `mapcar'
4531 stops calling FUNCTION once the shortest sequence is exhausted.
4532
4533 arguments: (FUNCTION SEQUENCE &rest SEQUENCES)
4534 */
4535 (int nargs, Lisp_Object *args))
4536 {
4537 Lisp_Object function = args[0];
4538 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4539 Lisp_Object *args0;
4540
4541 args0 = alloca_array (Lisp_Object, len);
4542 mapcarX (len, args0, Qnil, function, nargs - 1, args + 1, QmapcarX);
4543
4544 return Flist ((int) len, args0);
4545 }
4546
4547 DEFUN ("mapvector", Fmapvector, 2, MANY, 0, /*
4548 Call FUNCTION on each element of SEQUENCE; return a vector of the results.
4549 The result is a vector of the same length as SEQUENCE.
4550 SEQUENCE may be a list, a vector, a bit vector, or a string.
4551
4552 With optional SEQUENCES, call FUNCTION each time with as many arguments as
4553 there are SEQUENCES, plus one for the element from SEQUENCE. One element
4554 from each sequence will be used each time FUNCTION is called, and
4555 `mapvector' stops calling FUNCTION once the shortest sequence is exhausted.
4556
4557 arguments: (FUNCTION SEQUENCE &rest SEQUENCES)
4558 */
4559 (int nargs, Lisp_Object *args))
4560 {
4561 Lisp_Object function = args[0];
4562 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4563 Lisp_Object result = make_vector (len, Qnil);
4564
4565 struct gcpro gcpro1;
4566 GCPRO1 (result);
4567 /* Don't pass result as the lisp_object argument, we want mapcarX to protect
4568 a single list argument's elements from being garbage-collected. */
4569 mapcarX (len, XVECTOR_DATA (result), Qnil, function, nargs - 1, args +1,
4570 Qmapvector);
4571 RETURN_UNGCPRO (result);
4572 }
4573
4574 DEFUN ("mapcan", Fmapcan, 2, MANY, 0, /*
4575 Call FUNCTION on each element of SEQUENCE; chain the results together.
4576
4577 FUNCTION must normally return a list; the results will be concatenated
4578 together using `nconc'.
4579
4580 With optional SEQUENCES, call FUNCTION each time with as many arguments as
4581 there are SEQUENCES, plus one for the element from SEQUENCE. One element
4582 from each sequence will be used each time FUNCTION is called, and
4583 `mapcan' stops calling FUNCTION once the shortest sequence is exhausted.
4584
4585 arguments: (FUNCTION SEQUENCE &rest SEQUENCES)
4586 */
4587 (int nargs, Lisp_Object *args))
4588 {
4589 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4590 Lisp_Object function = args[0], *result = alloca_array (Lisp_Object, len);
4591
4592 mapcarX (len, result, Qnil, function, nargs - 1, args + 1, Qmapcan);
4593
4594 /* #'nconc GCPROs its args in case of signals and error. */
4595 return Fnconc (len, result);
4596 }
4597
4598 DEFUN ("mapc", Fmapc, 2, MANY, 0, /*
4599 Call FUNCTION on each element of SEQUENCE.
4600
4601 SEQUENCE may be a list, a vector, a bit vector, or a string.
4602 This function is like `mapcar' but does not accumulate the results,
4603 which is more efficient if you do not use the results.
4604
4605 With optional SEQUENCES, call FUNCTION each time with as many arguments as
4606 there are SEQUENCES, plus one for the elements from SEQUENCE. One element
4607 from each sequence will be used each time FUNCTION is called, and
4608 `mapc' stops calling FUNCTION once the shortest sequence is exhausted.
4609
4610 Return SEQUENCE.
4611
4612 arguments: (FUNCTION SEQUENCE &rest SEQUENCES)
4613 */
4614 (int nargs, Lisp_Object *args))
4615 {
4616 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4617 Lisp_Object sequence = args[1];
4618 struct gcpro gcpro1;
4619 /* We need to GCPRO sequence, because mapcarX will modify the
4620 elements of the args array handed to it, and this may involve
4621 elements of sequence getting garbage collected. */
4622 GCPRO1 (sequence);
4623 mapcarX (len, NULL, Qnil, args[0], nargs - 1, args + 1, Qmapc);
4624 RETURN_UNGCPRO (sequence);
4625 }
4626
4627 DEFUN ("map", Fmap, 3, MANY, 0, /*
4628 Map FUNCTION across one or more sequences, returning a sequence.
4629
4630 TYPE is the sequence type to return, FUNCTION is the function, SEQUENCE is
4631 the first argument sequence, SEQUENCES are the other argument sequences.
4632
4633 FUNCTION will be called with (1+ (length SEQUENCES)) arguments, and must be
4634 capable of accepting this number of arguments.
4635
4636 Certain TYPEs are recognised internally by `map', but others are not, and
4637 `coerce' may throw an error on an attempt to convert to a TYPE it does not
4638 understand. A null TYPE means do not accumulate any values.
4639
4640 arguments: (TYPE FUNCTION SEQUENCE &rest SEQUENCES)
4641 */
4642 (int nargs, Lisp_Object *args))
4643 {
4644 Lisp_Object type = args[0];
4645 Lisp_Object function = args[1];
4646 Lisp_Object result = Qnil;
4647 Lisp_Object *args0 = NULL;
4648 Elemcount len = shortest_length_among_sequences (nargs - 2, args + 2);
4649 struct gcpro gcpro1;
4650
4651 if (!NILP (type))
4652 {
4653 args0 = alloca_array (Lisp_Object, len);
4654 }
4655
4656 mapcarX (len, args0, Qnil, function, nargs - 2, args + 2, Qmap);
4657
4658 if (EQ (type, Qnil))
4659 {
4660 return result;
4661 }
4662
4663 if (EQ (type, Qvector) || EQ (type, Qarray))
4664 {
4665 result = Fvector (len, args0);
4666 }
4667 else if (EQ (type, Qstring))
4668 {
4669 result = Fstring (len, args0);
4670 }
4671 else if (EQ (type, Qlist))
4672 {
4673 result = Flist (len, args0);
4674 }
4675 else if (EQ (type, Qbit_vector))
4676 {
4677 result = Fbit_vector (len, args0);
4678 }
4679 else
4680 {
4681 result = Flist (len, args0);
4682 GCPRO1 (result);
4683 result = call2 (Qcoerce, result, type);
4684 UNGCPRO;
4685 }
4686
4687 return result;
4688 }
4689
4690 DEFUN ("map-into", Fmap_into, 2, MANY, 0, /*
4691 Modify RESULT-SEQUENCE using the return values of FUNCTION on SEQUENCES.
4692
4693 RESULT-SEQUENCE and SEQUENCES can be lists or arrays.
4694
4695 FUNCTION must accept at least as many arguments as there are SEQUENCES
4696 \(possibly zero). If RESULT-SEQUENCE and the elements of SEQUENCES are not
4697 the same length, stop when the shortest is exhausted; any elements of
4698 RESULT-SEQUENCE beyond that are unmodified.
4699
4700 Return RESULT-SEQUENCE.
4701
4702 arguments: (RESULT-SEQUENCE FUNCTION &rest SEQUENCES)
4703 */
4704 (int nargs, Lisp_Object *args))
4705 {
4706 Elemcount len;
4707 Lisp_Object result_sequence = args[0];
4708 Lisp_Object function = args[1];
4709
4710 args[0] = function;
4711 args[1] = result_sequence;
4712
4713 len = shortest_length_among_sequences (nargs - 1, args + 1);
4714
4715 mapcarX (len, NULL, result_sequence, function, nargs - 2, args + 2,
4716 Qmap_into);
4717
4718 return result_sequence;
4719 }
4720
4721 DEFUN ("some", Fsome, 2, MANY, 0, /*
4722 Return true if PREDICATE gives non-nil for an element of SEQUENCE.
4723
4724 If so, return the value (possibly multiple) given by PREDICATE.
4725
4726 With optional SEQUENCES, call PREDICATE each time with as many arguments as
4727 there are SEQUENCES (plus one for the element from SEQUENCE).
4728
4729 See also `find-if', which returns the corresponding element of SEQUENCE,
4730 rather than the value given by PREDICATE, and accepts bounding index
4731 keywords.
4732
4733 arguments: (PREDICATE SEQUENCE &rest SEQUENCES)
4734 */
4735 (int nargs, Lisp_Object *args))
4736 {
4737 Lisp_Object result = Qnil,
4738 result_ptr = STORE_VOID_IN_LISP ((void *) &result);
4739 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4740
4741 mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qsome);
4742
4743 return result;
4744 }
4745
4746 DEFUN ("every", Fevery, 2, MANY, 0, /*
4747 Return true if PREDICATE is true of every element of SEQUENCE.
4748
4749 With optional SEQUENCES, call PREDICATE each time with as many arguments as
4750 there are SEQUENCES (plus one for the element from SEQUENCE).
4751
4752 In contrast to `some', `every' never returns multiple values.
4753
4754 arguments: (PREDICATE SEQUENCE &rest SEQUENCES)
4755 */
4756 (int nargs, Lisp_Object *args))
4757 {
4758 Lisp_Object result = Qt, result_ptr = STORE_VOID_IN_LISP ((void *) &result);
4759 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4760
4761 mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qevery);
4762
4763 return result;
4764 }
4765
4766
4767 DEFUN ("reduce", Freduce, 2, MANY, 0, /*
4768 Combine the elements of SEQUENCE using FUNCTION, a binary operation.
4769
4770 For example, `(reduce #'+ SEQUENCE)' returns the sum of all elements in
4771 SEQUENCE, and `(reduce #'union SEQUENCE)' returns the union of all elements
4772 in SEQUENCE.
4773
4774 Keywords supported: :start :end :from-end :initial-value :key
4775 See `remove*' for the meaning of :start, :end, :from-end and :key.
4776
4777 :initial-value specifies an element (typically an identity element, such as
4778 0) that is conceptually prepended to the sequence (or appended, when
4779 :from-end is given).
4780
4781 If the sequence has one element, that element is returned directly.
4782 If the sequence has no elements, :initial-value is returned if given;
4783 otherwise, FUNCTION is called with no arguments, and its result returned.
4784
4785 arguments: (FUNCTION SEQUENCE &key (START 0) (END (length SEQUENCE)) FROM-END INITIAL-VALUE (KEY #'identity))
4786 */
4787 (int nargs, Lisp_Object *args))
4788 {
4789 Lisp_Object function = args[0], sequence = args[1], accum = Qunbound;
4790 Elemcount starting, ending = MOST_POSITIVE_FIXNUM + 1, ii = 0;
4791
4792 PARSE_KEYWORDS (Freduce, nargs, args, 5,
4793 (start, end, from_end, initial_value, key),
4794 (start = Qzero, initial_value = Qunbound));
4795
4796 CHECK_SEQUENCE (sequence);
4797 CHECK_NATNUM (start);
4798 starting = BIGNUMP (start) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start);
4799 CHECK_KEY_ARGUMENT (key);
4800
4801 #define KEY(key, item) (EQ (Qidentity, key) ? item : \
4802 IGNORE_MULTIPLE_VALUES (call1 (key, item)))
4803 #define CALL2(function, accum, item) \
4804 IGNORE_MULTIPLE_VALUES (call2 (function, accum, item))
4805
4806 if (!NILP (end))
4807 {
4808 CHECK_NATNUM (end);
4809 ending = BIGNUMP (end) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end);
4810 }
4811
4812 if (VECTORP (sequence))
4813 {
4814 Lisp_Vector *vv = XVECTOR (sequence);
4815 struct gcpro gcpro1;
4816
4817 check_sequence_range (sequence, start, end, make_fixnum (vv->size));
4818
4819 ending = min (ending, vv->size);
4820
4821 GCPRO1 (accum);
4822
4823 if (!UNBOUNDP (initial_value))
4824 {
4825 accum = initial_value;
4826 }
4827 else if (ending - starting)
4828 {
4829 if (NILP (from_end))
4830 {
4831 accum = KEY (key, vv->contents[starting]);
4832 starting++;
4833 }
4834 else
4835 {
4836 accum = KEY (key, vv->contents[ending - 1]);
4837 ending--;
4838 }
4839 }
4840
4841 if (NILP (from_end))
4842 {
4843 for (ii = starting; ii < ending; ++ii)
4844 {
4845 accum = CALL2 (function, accum, KEY (key, vv->contents[ii]));
4846 }
4847 }
4848 else
4849 {
4850 for (ii = ending - 1; ii >= starting; --ii)
4851 {
4852 accum = CALL2 (function, KEY (key, vv->contents[ii]), accum);
4853 }
4854 }
4855
4856 UNGCPRO;
4857 }
4858 else if (BIT_VECTORP (sequence))
4859 {
4860 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence);
4861 struct gcpro gcpro1;
4862
4863 check_sequence_range (sequence, start, end, make_fixnum (bv->size));
4864 ending = min (ending, bv->size);
4865
4866 GCPRO1 (accum);
4867
4868 if (!UNBOUNDP (initial_value))
4869 {
4870 accum = initial_value;
4871 }
4872 else if (ending - starting)
4873 {
4874 if (NILP (from_end))
4875 {
4876 accum = KEY (key, make_fixnum (bit_vector_bit (bv, starting)));
4877 starting++;
4878 }
4879 else
4880 {
4881 accum = KEY (key, make_fixnum (bit_vector_bit (bv, ending - 1)));
4882 ending--;
4883 }
4884 }
4885
4886 if (NILP (from_end))
4887 {
4888 for (ii = starting; ii < ending; ++ii)
4889 {
4890 accum = CALL2 (function, accum,
4891 KEY (key, make_fixnum (bit_vector_bit (bv, ii))));
4892 }
4893 }
4894 else
4895 {
4896 for (ii = ending - 1; ii >= starting; --ii)
4897 {
4898 accum = CALL2 (function, KEY (key,
4899 make_fixnum (bit_vector_bit (bv,
4900 ii))),
4901 accum);
4902 }
4903 }
4904
4905 UNGCPRO;
4906
4907 }
4908 else if (STRINGP (sequence))
4909 {
4910 struct gcpro gcpro1;
4911
4912 GCPRO1 (accum);
4913
4914 if (NILP (from_end))
4915 {
4916 Bytecount byte_len = XSTRING_LENGTH (sequence);
4917 Bytecount cursor_offset = 0;
4918 const Ibyte *startp = XSTRING_DATA (sequence);
4919 const Ibyte *cursor = startp;
4920
4921 for (ii = 0; ii != starting && cursor_offset < byte_len; ++ii)
4922 {
4923 INC_IBYTEPTR (cursor);
4924 cursor_offset = cursor - startp;
4925 }
4926
4927 if (!UNBOUNDP (initial_value))
4928 {
4929 accum = initial_value;
4930 }
4931 else if (ending - starting && cursor_offset < byte_len)
4932 {
4933 accum = KEY (key, make_char (itext_ichar (cursor)));
4934 starting++;
4935 startp = XSTRING_DATA (sequence);
4936 cursor = startp + cursor_offset;
4937
4938 if (byte_len != XSTRING_LENGTH (sequence)
4939 || !valid_ibyteptr_p (cursor))
4940 {
4941 mapping_interaction_error (Qreduce, sequence);
4942 }
4943
4944 INC_IBYTEPTR (cursor);
4945 cursor_offset = cursor - startp;
4946 ii++;
4947 }
4948
4949 while (cursor_offset < byte_len && ii < ending)
4950 {
4951 accum = CALL2 (function, accum,
4952 KEY (key, make_char (itext_ichar (cursor))));
4953
4954 startp = XSTRING_DATA (sequence);
4955 cursor = startp + cursor_offset;
4956
4957 if (byte_len != XSTRING_LENGTH (sequence)
4958 || !valid_ibyteptr_p (cursor))
4959 {
4960 mapping_interaction_error (Qreduce, sequence);
4961 }
4962
4963 INC_IBYTEPTR (cursor);
4964 cursor_offset = cursor - startp;
4965 ++ii;
4966 }
4967
4968 if (ii < starting || (ii < ending && !NILP (end)))
4969 {
4970 check_sequence_range (sequence, start, end, Flength (sequence));
4971 }
4972 }
4973 else
4974 {
4975 Elemcount len = string_char_length (sequence);
4976 Bytecount cursor_offset, byte_len = XSTRING_LENGTH (sequence);
4977 const Ibyte *cursor;
4978
4979 check_sequence_range (sequence, start, end, make_fixnum (len));
4980 ending = min (ending, len);
4981 starting = XFIXNUM (start);
4982
4983 cursor = string_char_addr (sequence, ending - 1);
4984 cursor_offset = cursor - XSTRING_DATA (sequence);
4985
4986 if (!UNBOUNDP (initial_value))
4987 {
4988 accum = initial_value;
4989 }
4990 else if (ending - starting)
4991 {
4992 accum = KEY (key, make_char (itext_ichar (cursor)));
4993 ending--;
4994 if (ending > 0)
4995 {
4996 cursor = XSTRING_DATA (sequence) + cursor_offset;
4997
4998 if (!valid_ibyteptr_p (cursor))
4999 {
5000 mapping_interaction_error (Qreduce, sequence);
5001 }
5002
5003 DEC_IBYTEPTR (cursor);
5004 cursor_offset = cursor - XSTRING_DATA (sequence);
5005 }
5006 }
5007
5008 for (ii = ending - 1; ii >= starting; --ii)
5009 {
5010 accum = CALL2 (function, KEY (key,
5011 make_char (itext_ichar (cursor))),
5012 accum);
5013 if (ii > 0)
5014 {
5015 cursor = XSTRING_DATA (sequence) + cursor_offset;
5016
5017 if (byte_len != XSTRING_LENGTH (sequence)
5018 || !valid_ibyteptr_p (cursor))
5019 {
5020 mapping_interaction_error (Qreduce, sequence);
5021 }
5022
5023 DEC_IBYTEPTR (cursor);
5024 cursor_offset = cursor - XSTRING_DATA (sequence);
5025 }
5026 }
5027 }
5028
5029 UNGCPRO;
5030 }
5031 else if (LISTP (sequence))
5032 {
5033 if (NILP (from_end))
5034 {
5035 struct gcpro gcpro1;
5036
5037 GCPRO1 (accum);
5038
5039 if (!UNBOUNDP (initial_value))
5040 {
5041 accum = initial_value;
5042 }
5043 else if (ending - starting)
5044 {
5045 GC_EXTERNAL_LIST_LOOP_2 (elt, sequence)
5046 {
5047 if (ii == starting)
5048 {
5049 accum = KEY (key, elt);
5050 starting++;
5051 break;
5052 }
5053 ++ii;
5054 }
5055 END_GC_EXTERNAL_LIST_LOOP (elt);
5056 }
5057
5058 ii = 0;
5059
5060 if (ending - starting)
5061 {
5062 GC_EXTERNAL_LIST_LOOP_2 (elt, sequence)
5063 {
5064 if (ii >= starting)
5065 {
5066 if (ii < ending)
5067 {
5068 accum = CALL2 (function, accum, KEY (key, elt));
5069 }
5070 else if (ii == ending)
5071 {
5072 break;
5073 }
5074 }
5075 ++ii;
5076 }
5077 END_GC_EXTERNAL_LIST_LOOP (elt);
5078 }
5079
5080 UNGCPRO;
5081
5082 if (ii < starting || (ii < ending && !NILP (end)))
5083 {
5084 check_sequence_range (sequence, start, end, Flength (sequence));
5085 }
5086 }
5087 else
5088 {
5089 Boolint need_accum = 0;
5090 Lisp_Object *subsequence = NULL;
5091 Elemcount counting = 0, len = 0;
5092 struct gcpro gcpro1;
5093
5094 len = XFIXNUM (Flength (sequence));
5095 check_sequence_range (sequence, start, end, make_fixnum (len));
5096 ending = min (ending, len);
5097
5098 /* :from-end with a list; make an alloca copy of the relevant list
5099 data, attempting to go backwards isn't worth the trouble. */
5100 if (!UNBOUNDP (initial_value))
5101 {
5102 accum = initial_value;
5103 if (ending - starting && starting < ending)
5104 {
5105 subsequence = alloca_array (Lisp_Object, ending - starting);
5106 }
5107 }
5108 else if (ending - starting && starting < ending)
5109 {
5110 subsequence = alloca_array (Lisp_Object, ending - starting);
5111 need_accum = 1;
5112 }
5113
5114 if (ending - starting && starting < ending)
5115 {
5116 EXTERNAL_LIST_LOOP_3 (elt, sequence, tail)
5117 {
5118 if (counting >= starting)
5119 {
5120 if (counting < ending)
5121 {
5122 subsequence[ii++] = elt;
5123 }
5124 else if (counting == ending)
5125 {
5126 break;
5127 }
5128 }
5129 ++counting;
5130 }
5131 }
5132
5133 if (subsequence != NULL)
5134 {
5135 len = ending - starting;
5136 /* If we could be sure that neither FUNCTION nor KEY modify
5137 SEQUENCE, this wouldn't be necessary, since all the
5138 elements of SUBSEQUENCE would definitely always be
5139 reachable via SEQUENCE. */
5140 GCPRO1 (subsequence[0]);
5141 gcpro1.nvars = len;
5142 }
5143
5144 if (need_accum)
5145 {
5146 accum = KEY (key, subsequence[len - 1]);
5147 --len;
5148 }
5149
5150 for (ii = len; ii != 0;)
5151 {
5152 --ii;
5153 accum = CALL2 (function, KEY (key, subsequence[ii]), accum);
5154 }
5155
5156 if (subsequence != NULL)
5157 {
5158 UNGCPRO;
5159 }
5160 }
5161 }
5162
5163 /* At this point, if ACCUM is unbound, SEQUENCE has no elements; we
5164 need to return the result of calling FUNCTION with zero
5165 arguments. */
5166 if (UNBOUNDP (accum))
5167 {
5168 accum = IGNORE_MULTIPLE_VALUES (call0 (function));
5169 }
5170
5171 return accum;
5172 }
5173
5174 /* This function is the implementation of fill_string_range() and
5175 replace_string_range(); see the comments for those functions. */
5176 static Lisp_Object
5177 replace_string_range_1 (Lisp_Object dest, Lisp_Object start, Lisp_Object end,
5178 const Ibyte *source, const Ibyte *source_limit,
5179 Lisp_Object item)
5180 {
5181 Ibyte *destp = XSTRING_DATA (dest), *p = destp,
5182 *pend = p + XSTRING_LENGTH (dest), *pcursor, item_buf[MAX_ICHAR_LEN];
5183 Bytecount prefix_bytecount, source_len = source_limit - source;
5184 Charcount ii = 0, ending, len;
5185 Charcount starting = BIGNUMP (start) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start);
5186 Elemcount delta;
5187
5188 while (ii < starting && p < pend)
5189 {
5190 INC_IBYTEPTR (p);
5191 ii++;
5192 }
5193
5194 pcursor = p;
5195
5196 if (NILP (end))
5197 {
5198 while (pcursor < pend)
5199 {
5200 INC_IBYTEPTR (pcursor);
5201 ii++;
5202 }
5203
5204 ending = len = ii;
5205 }
5206 else
5207 {
5208 ending = BIGNUMP (end) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end);
5209 while (ii < ending && pcursor < pend)
5210 {
5211 INC_IBYTEPTR (pcursor);
5212 ii++;
5213 }
5214 }
5215
5216 if (pcursor == pend)
5217 {
5218 /* We have the length, check it for our callers. */
5219 check_sequence_range (dest, start, end, make_fixnum (ii));
5220 }
5221
5222 if (!(p == pend || p == pcursor))
5223 {
5224 prefix_bytecount = p - destp;
5225
5226 if (!NILP (item))
5227 {
5228 assert (source == NULL && source_limit == NULL);
5229 source_len = set_itext_ichar (item_buf, XCHAR (item));
5230 delta = (source_len * (ending - starting)) - (pcursor - p);
5231 }
5232 else
5233 {
5234 assert (source != NULL && source_limit != NULL);
5235 delta = source_len - (pcursor - p);
5236 }
5237
5238 if (delta)
5239 {
5240 resize_string (dest, prefix_bytecount, delta);
5241 destp = XSTRING_DATA (dest);
5242 pcursor = destp + prefix_bytecount + (pcursor - p);
5243 p = destp + prefix_bytecount;
5244 }
5245
5246 if (CHARP (item))
5247 {
5248 while (starting < ending)
5249 {
5250 memcpy (p, item_buf, source_len);
5251 p += source_len;
5252 starting++;
5253 }
5254 }
5255 else
5256 {
5257 while (starting < ending && source < source_limit)
5258 {
5259 source_len = itext_copy_ichar (source, p);
5260 p += source_len, source += source_len;
5261 }
5262 }
5263
5264 init_string_ascii_begin (dest);
5265 bump_string_modiff (dest);
5266 sledgehammer_check_ascii_begin (dest);
5267 }
5268
5269 return dest;
5270 }
5271
5272 DEFUN ("replace", Freplace, 2, MANY, 0, /*
5273 Replace the elements of SEQUENCE-ONE with the elements of SEQUENCE-TWO.
5274
5275 SEQUENCE-ONE is destructively modified, and returned. Its length is not
5276 changed.
5277
5278 Keywords :start1 and :end1 specify a subsequence of SEQUENCE-ONE, and
5279 :start2 and :end2 a subsequence of SEQUENCE-TWO. See `search' for more
5280 information.
5281
5282 arguments: (SEQUENCE-ONE SEQUENCE-TWO &key (START1 0) (END1 (length SEQUENCE-ONE)) (START2 0) (END2 (length SEQUENCE-TWO)))
5283 */
5284 (int nargs, Lisp_Object *args))
5285 {
5286 Lisp_Object sequence1 = args[0], sequence2 = args[1],
5287 result = sequence1;
5288 Elemcount starting1, ending1 = MOST_POSITIVE_FIXNUM + 1, starting2;
5289 Elemcount ending2 = MOST_POSITIVE_FIXNUM + 1, counting = 0, startcounting;
5290 Boolint sequence1_listp, sequence2_listp,
5291 overwriting = EQ (sequence1, sequence2);
5292
5293 PARSE_KEYWORDS (Freplace, nargs, args, 4, (start1, end1, start2, end2),
5294 (start1 = start2 = Qzero));
5295
5296 CHECK_SEQUENCE (sequence1);
5297 CHECK_LISP_WRITEABLE (sequence1);
5298
5299 CHECK_SEQUENCE (sequence2);
5300
5301 CHECK_NATNUM (start1);
5302 starting1 = BIGNUMP (start1) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start1);
5303 CHECK_NATNUM (start2);
5304 starting2 = BIGNUMP (start2) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start2);
5305
5306 if (!NILP (end1))
5307 {
5308 CHECK_NATNUM (end1);
5309 ending1 = BIGNUMP (end1) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end1);
5310 }
5311
5312 if (!NILP (end2))
5313 {
5314 CHECK_NATNUM (end2);
5315 ending2 = BIGNUMP (end2) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end2);
5316 }
5317
5318 sequence1_listp = LISTP (sequence1);
5319 sequence2_listp = LISTP (sequence2);
5320
5321 overwriting = overwriting && starting2 <= starting1;
5322
5323 if (sequence1_listp && !ZEROP (start1))
5324 {
5325 sequence1 = Fnthcdr (start1, sequence1);
5326
5327 if (NILP (sequence1))
5328 {
5329 check_sequence_range (args[0], start1, end1, Flength (args[0]));
5330 /* Give up early here. */
5331 return result;
5332 }
5333
5334 ending1 -= starting1;
5335 starting1 = 0;
5336 }
5337
5338 if (sequence2_listp && !ZEROP (start2))
5339 {
5340 sequence2 = Fnthcdr (start2, sequence2);
5341
5342 if (NILP (sequence2))
5343 {
5344 check_sequence_range (args[1], start1, end1, Flength (args[1]));
5345 /* Nothing available to replace sequence1's contents. */
5346 return result;
5347 }
5348
5349 ending2 -= starting2;
5350 starting2 = 0;
5351 }
5352
5353 if (overwriting)
5354 {
5355 if (EQ (start1, start2))
5356 {
5357 return result;
5358 }
5359
5360 /* Our ranges may overlap. Save the data that might be overwritten. */
5361
5362 if (CONSP (sequence2))
5363 {
5364 Elemcount len = XFIXNUM (Flength (sequence2));
5365 Lisp_Object *subsequence
5366 = alloca_array (Lisp_Object, min (ending2, len));
5367 Elemcount ii = 0;
5368
5369 LIST_LOOP_2 (elt, sequence2)
5370 {
5371 if (counting == ending2)
5372 {
5373 break;
5374 }
5375
5376 subsequence[ii++] = elt;
5377 counting++;
5378 }
5379
5380 check_sequence_range (sequence1, start1, end1,
5381 /* The XFIXNUM (start2) is intentional here; we
5382 called #'length after doing (nthcdr
5383 start2 sequence2). */
5384 make_fixnum (XFIXNUM (start2) + len));
5385 check_sequence_range (sequence2, start2, end2,
5386 make_fixnum (XFIXNUM (start2) + len));
5387
5388 while (starting1 < ending1
5389 && starting2 < ending2 && !NILP (sequence1))
5390 {
5391 XSETCAR (sequence1, subsequence[starting2]);
5392 sequence1 = XCDR (sequence1);
5393 starting1++;
5394 starting2++;
5395 }
5396 }
5397 else if (STRINGP (sequence2))
5398 {
5399 Ibyte *p = XSTRING_DATA (sequence2),
5400 *pend = p + XSTRING_LENGTH (sequence2), *pcursor,
5401 *staging;
5402 Bytecount ii = 0;
5403
5404 while (ii < starting2 && p < pend)
5405 {
5406 INC_IBYTEPTR (p);
5407 ii++;
5408 }
5409
5410 pcursor = p;
5411
5412 while (ii < ending2 && starting1 < ending1 && pcursor < pend)
5413 {
5414 INC_IBYTEPTR (pcursor);
5415 starting1++;
5416 ii++;
5417 }
5418
5419 if (pcursor == pend)
5420 {
5421 check_sequence_range (sequence1, start1, end1, make_fixnum (ii));
5422 check_sequence_range (sequence2, start2, end2, make_fixnum (ii));
5423 }
5424 else
5425 {
5426 assert ((pcursor - p) > 0);
5427 staging = alloca_ibytes (pcursor - p);
5428 memcpy (staging, p, pcursor - p);
5429 replace_string_range (result, start1,
5430 make_fixnum (starting1),
5431 staging, staging + (pcursor - p));
5432 }
5433 }
5434 else
5435 {
5436 Elemcount seq_len = XFIXNUM (Flength (sequence2)), ii = 0,
5437 subseq_len = min (min (ending1 - starting1, seq_len - starting1),
5438 min (ending2 - starting2, seq_len - starting2));
5439 Lisp_Object *subsequence = alloca_array (Lisp_Object, subseq_len);
5440
5441 check_sequence_range (sequence1, start1, end1, make_fixnum (seq_len));
5442 check_sequence_range (sequence2, start2, end2, make_fixnum (seq_len));
5443
5444 while (starting2 < ending2 && ii < seq_len)
5445 {
5446 subsequence[ii] = Faref (sequence2, make_fixnum (starting2));
5447 ii++, starting2++;
5448 }
5449
5450 ii = 0;
5451
5452 while (starting1 < ending1 && ii < seq_len)
5453 {
5454 Faset (sequence1, make_fixnum (starting1), subsequence[ii]);
5455 ii++, starting1++;
5456 }
5457 }
5458 }
5459 else if (sequence1_listp && sequence2_listp)
5460 {
5461 Lisp_Object sequence1_tortoise = sequence1,
5462 sequence2_tortoise = sequence2;
5463 Elemcount shortest_len = 0;
5464
5465 counting = startcounting = min (ending1, ending2);
5466
5467 while (counting-- > 0 && !NILP (sequence1) && !NILP (sequence2))
5468 {
5469 XSETCAR (sequence1,
5470 CONSP (sequence2) ? XCAR (sequence2)
5471 : Fcar (sequence2));
5472 sequence1 = CONSP (sequence1) ? XCDR (sequence1)
5473 : Fcdr (sequence1);
5474 sequence2 = CONSP (sequence2) ? XCDR (sequence2)
5475 : Fcdr (sequence2);
5476
5477 shortest_len++;
5478
5479 if (startcounting - counting > CIRCULAR_LIST_SUSPICION_LENGTH)
5480 {
5481 if (counting & 1)
5482 {
5483 sequence1_tortoise = XCDR (sequence1_tortoise);
5484 sequence2_tortoise = XCDR (sequence2_tortoise);
5485 }
5486
5487 if (EQ (sequence1, sequence1_tortoise))
5488 {
5489 signal_circular_list_error (sequence1);
5490 }
5491
5492 if (EQ (sequence2, sequence2_tortoise))
5493 {
5494 signal_circular_list_error (sequence2);
5495 }
5496 }
5497 }
5498
5499 if (NILP (sequence1))
5500 {
5501 check_sequence_range (args[0], start1, end1,
5502 make_fixnum (XFIXNUM (start1) + shortest_len));
5503 }
5504 else if (NILP (sequence2))
5505 {
5506 check_sequence_range (args[1], start2, end2,
5507 make_fixnum (XFIXNUM (start2) + shortest_len));
5508 }
5509 }
5510 else if (sequence1_listp)
5511 {
5512 if (STRINGP (sequence2))
5513 {
5514 Ibyte *s2_data = XSTRING_DATA (sequence2),
5515 *s2_end = s2_data + XSTRING_LENGTH (sequence2);
5516 Elemcount char_count = 0;
5517 Lisp_Object character;
5518
5519 while (char_count < starting2 && s2_data < s2_end)
5520 {
5521 INC_IBYTEPTR (s2_data);
5522 char_count++;
5523 }
5524
5525 while (starting1 < ending1 && starting2 < ending2
5526 && s2_data < s2_end && !NILP (sequence1))
5527 {
5528 character = make_char (itext_ichar (s2_data));
5529 CONSP (sequence1) ?
5530 XSETCAR (sequence1, character)
5531 : Fsetcar (sequence1, character);
5532 sequence1 = XCDR (sequence1);
5533 starting1++;
5534 starting2++;
5535 char_count++;
5536 INC_IBYTEPTR (s2_data);
5537 }
5538
5539 if (NILP (sequence1))
5540 {
5541 check_sequence_range (sequence1, start1, end1,
5542 make_fixnum (XFIXNUM (start1) + starting1));
5543 }
5544
5545 if (s2_data == s2_end)
5546 {
5547 check_sequence_range (sequence2, start2, end2,
5548 make_fixnum (char_count));
5549 }
5550 }
5551 else
5552 {
5553 Elemcount len2 = XFIXNUM (Flength (sequence2));
5554 check_sequence_range (sequence2, start2, end2, make_fixnum (len2));
5555
5556 ending2 = min (ending2, len2);
5557 while (starting2 < ending2
5558 && starting1 < ending1 && !NILP (sequence1))
5559 {
5560 CHECK_CONS (sequence1);
5561 XSETCAR (sequence1, Faref (sequence2, make_fixnum (starting2)));
5562 sequence1 = XCDR (sequence1);
5563 starting1++;
5564 starting2++;
5565 }
5566
5567 if (NILP (sequence1))
5568 {
5569 check_sequence_range (args[0], start1, end1,
5570 make_fixnum (XFIXNUM (start1) + starting1));
5571 }
5572 }
5573 }
5574 else if (sequence2_listp)
5575 {
5576 if (STRINGP (sequence1))
5577 {
5578 Elemcount ii = 0, count, len = string_char_length (sequence1);
5579 Ibyte *staging, *cursor;
5580 Lisp_Object obj;
5581
5582 check_sequence_range (sequence1, start1, end1, make_fixnum (len));
5583 ending1 = min (ending1, len);
5584 count = ending1 - starting1;
5585 staging = cursor = alloca_ibytes (count * MAX_ICHAR_LEN);
5586
5587 while (ii < count && !NILP (sequence2))
5588 {
5589 obj = CONSP (sequence2) ? XCAR (sequence2)
5590 : Fcar (sequence2);
5591
5592 CHECK_CHAR_COERCE_INT (obj);
5593 cursor += set_itext_ichar (cursor, XCHAR (obj));
5594 ii++;
5595 sequence2 = XCDR (sequence2);
5596 }
5597
5598 if (NILP (sequence2))
5599 {
5600 check_sequence_range (sequence2, start2, end2,
5601 make_fixnum (XFIXNUM (start2) + ii));
5602 }
5603
5604 replace_string_range (result, start1, make_fixnum (XFIXNUM (start1) + ii),
5605 staging, cursor);
5606 }
5607 else
5608 {
5609 Elemcount len = XFIXNUM (Flength (sequence1));
5610
5611 check_sequence_range (sequence1, start2, end1, make_fixnum (len));
5612 ending1 = min (ending2, min (ending1, len));
5613
5614 while (starting1 < ending1 && !NILP (sequence2))
5615 {
5616 Faset (sequence1, make_fixnum (starting1),
5617 CONSP (sequence2) ? XCAR (sequence2)
5618 : Fcar (sequence2));
5619 sequence2 = XCDR (sequence2);
5620 starting1++;
5621 starting2++;
5622 }
5623
5624 if (NILP (sequence2))
5625 {
5626 check_sequence_range (args[1], start2, end2,
5627 make_fixnum (XFIXNUM (start2) + starting2));
5628 }
5629 }
5630 }
5631 else
5632 {
5633 if (STRINGP (sequence1) && STRINGP (sequence2))
5634 {
5635 Ibyte *p2 = XSTRING_DATA (sequence2),
5636 *p2end = p2 + XSTRING_LENGTH (sequence2), *p2cursor;
5637 Charcount ii = 0, len1 = string_char_length (sequence1);
5638
5639 check_sequence_range (sequence1, start1, end1, make_fixnum (len1));
5640
5641 while (ii < starting2 && p2 < p2end)
5642 {
5643 INC_IBYTEPTR (p2);
5644 ii++;
5645 }
5646
5647 p2cursor = p2;
5648 ending1 = min (ending1, len1);
5649
5650 while (ii < ending2 && starting1 < ending1 && p2cursor < p2end)
5651 {
5652 INC_IBYTEPTR (p2cursor);
5653 ii++;
5654 starting1++;
5655 }
5656
5657 if (p2cursor == p2end)
5658 {
5659 check_sequence_range (sequence2, start2, end2, make_fixnum (ii));
5660 }
5661
5662 /* This isn't great; any error message won't necessarily reflect
5663 the END1 that was supplied to #'replace. */
5664 replace_string_range (result, start1, make_fixnum (starting1),
5665 p2, p2cursor);
5666 }
5667 else if (STRINGP (sequence1))
5668 {
5669 Ibyte *staging, *cursor;
5670 Elemcount count, len1 = string_char_length (sequence1);
5671 Elemcount len2 = XFIXNUM (Flength (sequence2)), ii = 0;
5672 Lisp_Object obj;
5673
5674 check_sequence_range (sequence1, start1, end1, make_fixnum (len1));
5675 check_sequence_range (sequence2, start2, end2, make_fixnum (len2));
5676
5677 ending1 = min (ending1, len1);
5678 ending2 = min (ending2, len2);
5679 count = min (ending1 - starting1, ending2 - starting2);
5680 staging = cursor = alloca_ibytes (count * MAX_ICHAR_LEN);
5681
5682 ii = 0;
5683 while (ii < count)
5684 {
5685 obj = Faref (sequence2, make_fixnum (starting2));
5686
5687 CHECK_CHAR_COERCE_INT (obj);
5688 cursor += set_itext_ichar (cursor, XCHAR (obj));
5689 starting2++, ii++;
5690 }
5691
5692 replace_string_range (result, start1,
5693 make_fixnum (XFIXNUM (start1) + count),
5694 staging, cursor);
5695 }
5696 else if (STRINGP (sequence2))
5697 {
5698 Ibyte *p2 = XSTRING_DATA (sequence2),
5699 *p2end = p2 + XSTRING_LENGTH (sequence2);
5700 Elemcount len1 = XFIXNUM (Flength (sequence1)), ii = 0;
5701
5702 check_sequence_range (sequence1, start1, end1, make_fixnum (len1));
5703 ending1 = min (ending1, len1);
5704
5705 while (ii < starting2 && p2 < p2end)
5706 {
5707 INC_IBYTEPTR (p2);
5708 ii++;
5709 }
5710
5711 while (p2 < p2end && starting1 < ending1 && starting2 < ending2)
5712 {
5713 Faset (sequence1, make_fixnum (starting1),
5714 make_char (itext_ichar (p2)));
5715 INC_IBYTEPTR (p2);
5716 starting1++;
5717 starting2++;
5718 ii++;
5719 }
5720
5721 if (p2 == p2end)
5722 {
5723 check_sequence_range (sequence2, start2, end2, make_fixnum (ii));
5724 }
5725 }
5726 else
5727 {
5728 Elemcount len1 = XFIXNUM (Flength (sequence1)),
5729 len2 = XFIXNUM (Flength (sequence2));
5730
5731 check_sequence_range (sequence1, start1, end1, make_fixnum (len1));
5732 check_sequence_range (sequence2, start2, end2, make_fixnum (len2));
5733
5734 ending1 = min (ending1, len1);
5735 ending2 = min (ending2, len2);
5736
5737 while (starting1 < ending1 && starting2 < ending2)
5738 {
5739 Faset (sequence1, make_fixnum (starting1),
5740 Faref (sequence2, make_fixnum (starting2)));
5741 starting1++;
5742 starting2++;
5743 }
5744 }
5745 }
5746
5747 return result;
5748 }
5749
5750 DEFUN ("nsubstitute", Fnsubstitute, 3, MANY, 0, /*
5751 Substitute NEW for OLD in SEQUENCE.
5752
5753 This is a destructive function; it reuses the storage of SEQUENCE whenever
5754 possible. See `remove*' for the meaning of the keywords.
5755
5756 arguments: (NEW OLD SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) FROM-END COUNT)
5757 */
5758 (int nargs, Lisp_Object *args))
5759 {
5760 Lisp_Object new_ = args[0], item = args[1], sequence = args[2];
5761 Lisp_Object object_, position0;
5762 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, encountered = 0;
5763 Elemcount len, ii = 0, counting = MOST_POSITIVE_FIXNUM, presenting = 0;
5764 Boolint test_not_unboundp = 1;
5765 check_test_func_t check_test = NULL;
5766
5767 PARSE_KEYWORDS (Fnsubstitute, nargs, args, 9,
5768 (test, if_, if_not, test_not, key, start, end, count,
5769 from_end), (start = Qzero));
5770
5771 CHECK_SEQUENCE (sequence);
5772 CHECK_NATNUM (start);
5773 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start);
5774
5775 if (!NILP (end))
5776 {
5777 CHECK_NATNUM (end);
5778 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end);
5779 }
5780
5781 if (!NILP (count))
5782 {
5783 CHECK_INTEGER (count);
5784 if (FIXNUMP (count))
5785 {
5786 counting = XFIXNUM (count);
5787 }
5788 #ifdef HAVE_BIGNUM
5789 else
5790 {
5791 counting = bignum_sign (XBIGNUM_DATA (count)) > 0 ?
5792 1 + MOST_POSITIVE_FIXNUM : -1 + MOST_NEGATIVE_FIXNUM;
5793 }
5794 #endif
5795
5796 if (counting <= 0)
5797 {
5798 return sequence;
5799 }
5800 }
5801
5802 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
5803 key, &test_not_unboundp);
5804
5805 if (CONSP (sequence))
5806 {
5807 if (!NILP (count) && !NILP (from_end))
5808 {
5809 Lisp_Object present = count_with_tail (&object_, nargs - 1, args + 1,
5810 Qnsubstitute);
5811
5812 if (ZEROP (present))
5813 {
5814 return sequence;
5815 }
5816
5817 presenting = XFIXNUM (present);
5818 presenting = presenting <= counting ? 0 : presenting - counting;
5819 }
5820
5821 {
5822 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail)
5823 {
5824 if (!(ii < ending))
5825 {
5826 break;
5827 }
5828
5829 if (starting <= ii &&
5830 check_test (test, key, item, elt) == test_not_unboundp
5831 && (presenting ? encountered++ >= presenting
5832 : encountered++ < counting))
5833 {
5834 CHECK_LISP_WRITEABLE (tail);
5835 XSETCAR (tail, new_);
5836 }
5837 else if (!presenting && encountered >= counting)
5838 {
5839 break;
5840 }
5841
5842 ii++;
5843 }
5844 END_GC_EXTERNAL_LIST_LOOP (elt);
5845 }
5846
5847 if ((ii < starting || (ii < ending && !NILP (end)))
5848 && encountered < counting)
5849 {
5850 check_sequence_range (args[0], start, end, Flength (args[0]));
5851 }
5852 }
5853 else if (STRINGP (sequence))
5854 {
5855 Ibyte *staging, new_bytes[MAX_ICHAR_LEN], *staging_cursor;
5856 Ibyte *startp = XSTRING_DATA (sequence), *cursor = startp;
5857 Bytecount cursor_offset = 0, byte_len = XSTRING_LENGTH (sequence);
5858 Bytecount new_len;
5859 Lisp_Object character;
5860
5861 CHECK_CHAR_COERCE_INT (new_);
5862
5863 new_len = set_itext_ichar (new_bytes, XCHAR (new_));
5864
5865 /* Worst case scenario; new char is four octets long, all the old ones
5866 were one octet long, all the old ones match. */
5867 staging = alloca_ibytes (XSTRING_LENGTH (sequence) * new_len);
5868 staging_cursor = staging;
5869
5870 if (!NILP (count) && !NILP (from_end))
5871 {
5872 Lisp_Object present = count_with_tail (&character, nargs - 1,
5873 args + 1, Qnsubstitute);
5874
5875 if (ZEROP (present))
5876 {
5877 return sequence;
5878 }
5879
5880 presenting = XFIXNUM (present);
5881
5882 /* If there are fewer items in the string than we have
5883 permission to change, we don't need to differentiate
5884 between the :from-end nil and :from-end t
5885 cases. Otherwise, presenting is the number of matching
5886 items we need to ignore before we start to change. */
5887 presenting = presenting <= counting ? 0 : presenting - counting;
5888 }
5889
5890 ii = 0;
5891 while (cursor_offset < byte_len && ii < ending)
5892 {
5893 if (ii >= starting)
5894 {
5895 character = make_char (itext_ichar (cursor));
5896
5897 if ((check_test (test, key, item, character)
5898 == test_not_unboundp)
5899 && (presenting ? encountered++ >= presenting :
5900 encountered++ < counting))
5901 {
5902 staging_cursor
5903 += itext_copy_ichar (new_bytes, staging_cursor);
5904 }
5905 else
5906 {
5907 staging_cursor
5908 += itext_copy_ichar (cursor, staging_cursor);
5909 }
5910
5911 startp = XSTRING_DATA (sequence);
5912 cursor = startp + cursor_offset;
5913
5914 if (byte_len != XSTRING_LENGTH (sequence)
5915 || !valid_ibyteptr_p (cursor))
5916 {
5917 mapping_interaction_error (Qnsubstitute, sequence);
5918 }
5919 }
5920 else
5921 {
5922 staging_cursor += itext_copy_ichar (cursor, staging_cursor);
5923 }
5924
5925 INC_IBYTEPTR (cursor);
5926 cursor_offset = cursor - startp;
5927 ii++;
5928 }
5929
5930 if (ii < starting || (ii < ending && !NILP (end)))
5931 {
5932 check_sequence_range (sequence, start, end, Flength (sequence));
5933 }
5934
5935 if (0 != encountered)
5936 {
5937 CHECK_LISP_WRITEABLE (sequence);
5938 replace_string_range (sequence, Qzero, make_fixnum (ii),
5939 staging, staging_cursor);
5940 }
5941 }
5942 else
5943 {
5944 Elemcount positioning;
5945 Lisp_Object object = Qnil;
5946
5947 len = XFIXNUM (Flength (sequence));
5948 check_sequence_range (sequence, start, end, make_fixnum (len));
5949
5950 position0 = position (&object, item, sequence, check_test,
5951 test_not_unboundp, test, key, start, end, from_end,
5952 Qnil, Qnsubstitute);
5953
5954 if (NILP (position0))
5955 {
5956 return sequence;
5957 }
5958
5959 positioning = XFIXNUM (position0);
5960 ending = min (len, ending);
5961
5962 Faset (sequence, position0, new_);
5963 encountered = 1;
5964
5965 if (NILP (from_end))
5966 {
5967 for (ii = positioning + 1; ii < ending; ii++)
5968 {
5969 object_ = Faref (sequence, make_fixnum (ii));
5970
5971 if (check_test (test, key, item, object_) == test_not_unboundp
5972 && encountered++ < counting)
5973 {
5974 Faset (sequence, make_fixnum (ii), new_);
5975 }
5976 else if (encountered == counting)
5977 {
5978 break;
5979 }
5980 }
5981 }
5982 else
5983 {
5984 for (ii = positioning - 1; ii >= starting; ii--)
5985 {
5986 object_ = Faref (sequence, make_fixnum (ii));
5987
5988 if (check_test (test, key, item, object_) == test_not_unboundp
5989 && encountered++ < counting)
5990 {
5991 Faset (sequence, make_fixnum (ii), new_);
5992 }
5993 else if (encountered == counting)
5994 {
5995 break;
5996 }
5997 }
5998 }
5999 }
6000
6001 return sequence;
6002 }
6003
6004 DEFUN ("substitute", Fsubstitute, 3, MANY, 0, /*
6005 Substitute NEW for OLD in SEQUENCE.
6006
6007 This is a non-destructive function; it makes a copy of SEQUENCE if necessary
6008 to avoid corrupting the original SEQUENCE.
6009
6010 See `remove*' for the meaning of the keywords.
6011
6012 arguments: (NEW OLD SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) COUNT)
6013 */
6014 (int nargs, Lisp_Object *args))
6015 {
6016 Lisp_Object new_ = args[0], item = args[1], sequence = args[2], tail = Qnil;
6017 Lisp_Object result = Qnil, result_tail = Qnil;
6018 Lisp_Object object, position0, matched_count;
6019 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, encountered = 0;
6020 Elemcount ii = 0, counting = MOST_POSITIVE_FIXNUM, presenting = 0;
6021 Boolint test_not_unboundp = 1;
6022 check_test_func_t check_test = NULL;
6023 struct gcpro gcpro1;
6024
6025 PARSE_KEYWORDS (Fsubstitute, nargs, args, 9,
6026 (test, if_, if_not, test_not, key, start, end, count,
6027 from_end), (start = Qzero, count = Qunbound));
6028
6029 CHECK_SEQUENCE (sequence);
6030
6031 CHECK_NATNUM (start);
6032 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start);
6033
6034 if (!NILP (end))
6035 {
6036 CHECK_NATNUM (end);
6037 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end);
6038 }
6039
6040 check_test = get_check_test_function (item, &test, test_not, if_, if_not,
6041 key, &test_not_unboundp);
6042
6043 if (!UNBOUNDP (count))
6044 {
6045 if (!NILP (count))
6046 {
6047 CHECK_INTEGER (count);
6048 if (FIXNUMP (count))
6049 {
6050 counting = XFIXNUM (count);
6051 }
6052 #ifdef HAVE_BIGNUM
6053 else
6054 {
6055 counting = bignum_sign (XBIGNUM_DATA (count)) > 0 ?
6056 1 + MOST_POSITIVE_FIXNUM : -1 + MOST_NEGATIVE_FIXNUM;
6057 }
6058 #endif
6059
6060 if (counting <= 0)
6061 {
6062 return sequence;
6063 }
6064 }
6065 }
6066
6067 if (!CONSP (sequence))
6068 {
6069 position0 = position (&object, item, sequence, check_test,
6070 test_not_unboundp, test, key, start, end, from_end,
6071 Qnil, Qsubstitute);
6072
6073 if (NILP (position0))
6074 {
6075 return sequence;
6076 }
6077 else
6078 {
6079 args[2] = Fcopy_sequence (sequence);
6080 return Fnsubstitute (nargs, args);
6081 }
6082 }
6083
6084 matched_count = count_with_tail (&tail, nargs - 1, args + 1, Qsubstitute);
6085
6086 if (ZEROP (matched_count))
6087 {
6088 return sequence;
6089 }
6090
6091 if (!NILP (count) && !NILP (from_end))
6092 {
6093 presenting = XFIXNUM (matched_count);
6094 presenting = presenting <= counting ? 0 : presenting - counting;
6095 }
6096
6097 GCPRO1 (result);
6098 {
6099 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tailing)
6100 {
6101 if (EQ (tail, tailing))
6102 {
6103 XUNGCPRO (elt);
6104 UNGCPRO;
6105
6106 if (NILP (result))
6107 {
6108 return XCDR (tail);
6109 }
6110
6111 XSETCDR (result_tail, XCDR (tail));
6112 return result;
6113 }
6114 else if (starting <= ii && ii < ending &&
6115 (check_test (test, key, item, elt) == test_not_unboundp)
6116 && (presenting ? encountered++ >= presenting
6117 : encountered++ < counting))
6118 {
6119 if (NILP (result))
6120 {
6121 result = result_tail = Fcons (new_, Qnil);
6122 }
6123 else
6124 {
6125 XSETCDR (result_tail, Fcons (new_, Qnil));
6126 result_tail = XCDR (result_tail);
6127 }
6128 }
6129 else if (NILP (result))
6130 {
6131 result = result_tail = Fcons (elt, Qnil);
6132 }
6133 else
6134 {
6135 XSETCDR (result_tail, Fcons (elt, Qnil));
6136 result_tail = XCDR (result_tail);
6137 }
6138
6139 if (ii == ending)
6140 {
6141 break;
6142 }
6143
6144 ii++;
6145 }
6146 END_GC_EXTERNAL_LIST_LOOP (elt);
6147 }
6148 UNGCPRO;
6149
6150 if (ii < starting || (ii < ending && !NILP (end)))
6151 {
6152 check_sequence_range (args[0], start, end, Flength (args[0]));
6153 }
6154
6155 return result;
6156 }
6157
6158 static Lisp_Object
6159 subst (Lisp_Object new_, Lisp_Object old, Lisp_Object tree, int depth)
6160 {
6161 if (depth + lisp_eval_depth > max_lisp_eval_depth)
6162 {
6163 stack_overflow ("Stack overflow in subst", tree);
6164 }
6165
6166 if (EQ (tree, old))
6167 {
6168 return new_;
6169 }
6170 else if (CONSP (tree))
6171 {
6172 Lisp_Object aa = subst (new_, old, XCAR (tree), depth + 1);
6173 Lisp_Object dd = subst (new_, old, XCDR (tree), depth + 1);
6174
6175 if (EQ (aa, XCAR (tree)) && EQ (dd, XCDR (tree)))
6176 {
6177 return tree;
6178 }
6179 else
6180 {
6181 return Fcons (aa, dd);
6182 }
6183 }
6184 else
6185 {
6186 return tree;
6187 }
6188 }
6189
6190 static Lisp_Object
6191 sublis (Lisp_Object alist, Lisp_Object tree,
6192 check_test_func_t check_test, Boolint test_not_unboundp,
6193 Lisp_Object test, Lisp_Object key, int depth)
6194 {
6195 Lisp_Object keyed = KEY (key, tree), aa, dd;
6196
6197 if (depth + lisp_eval_depth > max_lisp_eval_depth)
6198 {
6199 stack_overflow ("Stack overflow in sublis", tree);
6200 }
6201
6202 {
6203 GC_EXTERNAL_LIST_LOOP_2 (elt, alist)
6204 {
6205 if (CONSP (elt) &&
6206 check_test (test, key, XCAR (elt), keyed) == test_not_unboundp)
6207 {
6208 XUNGCPRO (elt);
6209 return XCDR (elt);
6210 }
6211 }
6212 END_GC_EXTERNAL_LIST_LOOP (elt);
6213 }
6214
6215 if (!CONSP (tree))
6216 {
6217 return tree;
6218 }
6219
6220 aa = sublis (alist, XCAR (tree), check_test, test_not_unboundp, test, key,
6221 depth + 1);
6222 dd = sublis (alist, XCDR (tree), check_test, test_not_unboundp, test, key,
6223 depth + 1);
6224
6225 if (EQ (aa, XCAR (tree)) && EQ (dd, XCDR (tree)))
6226 {
6227 return tree;
6228 }
6229
6230 return Fcons (aa, dd);
6231 }
6232
6233 DEFUN ("sublis", Fsublis, 2, MANY, 0, /*
6234 Perform substitutions indicated by ALIST in TREE (non-destructively).
6235 Return a copy of TREE with all matching elements replaced.
6236
6237 See `member*' for the meaning of :test, :test-not and :key.
6238
6239 arguments: (ALIST TREE &key (TEST #'eql) (KEY #'identity) TEST-NOT)
6240 */
6241 (int nargs, Lisp_Object *args))
6242 {
6243 Lisp_Object alist = args[0], tree = args[1];
6244 Boolint test_not_unboundp = 1;
6245 check_test_func_t check_test = NULL;
6246
6247 PARSE_KEYWORDS (Fsublis, nargs, args, 5, (test, if_, test_not, if_not, key),
6248 (key = Qidentity));
6249
6250 if (NILP (key))
6251 {
6252 key = Qidentity;
6253 }
6254
6255 get_check_match_function (&test, test_not, if_, if_not,
6256 /* sublis() is going to apply the key, don't ask
6257 for a match function that will do it for
6258 us. */
6259 Qidentity, &test_not_unboundp, &check_test);
6260
6261 if (CONSP (alist) && NILP (XCDR (alist)) && CONSP (XCAR (alist))
6262 && EQ (key, Qidentity) && 1 == test_not_unboundp
6263 && (check_eq_nokey == check_test ||
6264 (check_eql_nokey == check_test &&
6265 !NON_FIXNUM_NUMBER_P (XCAR (XCAR (alist))))))
6266 {
6267 /* #'subst with #'eq is very cheap indeed; call it. */
6268 return subst (XCDR (XCAR (alist)), XCAR (XCAR (alist)), tree, 0);
6269 }
6270
6271 return sublis (alist, tree, check_test, test_not_unboundp, test, key, 0);
6272 }
6273
6274 static Lisp_Object
6275 nsublis (Lisp_Object alist, Lisp_Object tree,
6276 check_test_func_t check_test,
6277 Boolint test_not_unboundp,
6278 Lisp_Object test, Lisp_Object key, int depth)
6279 {
6280 Lisp_Object tree_saved = tree, tortoise = tree, keyed = Qnil;
6281 struct gcpro gcpro1, gcpro2;
6282 int count = 0;
6283
6284 if (depth + lisp_eval_depth > max_lisp_eval_depth)
6285 {
6286 stack_overflow ("Stack overflow in nsublis", tree);
6287 }
6288
6289 GCPRO2 (tree_saved, keyed);
6290
6291 while (CONSP (tree))
6292 {
6293 Boolint replaced = 0;
6294 keyed = KEY (key, XCAR (tree));
6295
6296 {
6297 GC_EXTERNAL_LIST_LOOP_2 (elt, alist)
6298 {
6299 if (CONSP (elt) &&
6300 check_test (test, key, XCAR (elt), keyed) == test_not_unboundp)
6301 {
6302 CHECK_LISP_WRITEABLE (tree);
6303 /* See comment in sublis() on using elt_cdr. */
6304 XSETCAR (tree, XCDR (elt));
6305 replaced = 1;
6306 break;
6307 }
6308 }
6309 END_GC_EXTERNAL_LIST_LOOP (elt);
6310 }
6311
6312 if (!replaced)
6313 {
6314 if (CONSP (XCAR (tree)))
6315 {
6316 nsublis (alist, XCAR (tree), check_test, test_not_unboundp,
6317 test, key, depth + 1);
6318 }
6319 }
6320
6321 keyed = KEY (key, XCDR (tree));
6322 replaced = 0;
6323
6324 {
6325 GC_EXTERNAL_LIST_LOOP_2 (elt, alist)
6326 {
6327 if (CONSP (elt) &&
6328 check_test (test, key, XCAR (elt), keyed) == test_not_unboundp)
6329 {
6330 CHECK_LISP_WRITEABLE (tree);
6331 XSETCDR (tree, XCDR (elt));
6332 tree = Qnil;
6333 break;
6334 }
6335 }
6336 END_GC_EXTERNAL_LIST_LOOP (elt);
6337 }
6338
6339 if (!NILP (tree))
6340 {
6341 tree = XCDR (tree);
6342 }
6343
6344 if (++count > CIRCULAR_LIST_SUSPICION_LENGTH)
6345 {
6346 if (count & 1)
6347 {
6348 tortoise = XCDR (tortoise);
6349 }
6350
6351 if (EQ (tortoise, tree))
6352 {
6353 signal_circular_list_error (tree);
6354 }
6355 }
6356 }
6357
6358 RETURN_UNGCPRO (tree_saved);
6359 }
6360
6361 DEFUN ("nsublis", Fnsublis, 2, MANY, 0, /*
6362 Perform substitutions indicated by ALIST in TREE (destructively).
6363 Any matching element of TREE is changed via a call to `setcar'.
6364
6365 See `member*' for the meaning of :test, :test-not and :key.
6366
6367 arguments: (ALIST TREE &key (TEST #'eql) (KEY #'identity) TEST-NOT)
6368 */
6369 (int nargs, Lisp_Object *args))
6370 {
6371 Lisp_Object alist = args[0], tree = args[1], tailed = Qnil, keyed = Qnil;
6372 Boolint test_not_unboundp = 1;
6373 check_test_func_t check_test = NULL;
6374 struct gcpro gcpro1, gcpro2;
6375
6376 PARSE_KEYWORDS (Fnsublis, nargs, args, 5, (test, if_, test_not, if_not, key),
6377 (key = Qidentity));
6378
6379 if (NILP (key))
6380 {
6381 key = Qidentity;
6382 }
6383
6384 get_check_match_function (&test, test_not, if_, if_not,
6385 /* nsublis() is going to apply the key, don't ask
6386 for a match function that will do it for
6387 us. */
6388 Qidentity, &test_not_unboundp, &check_test);
6389
6390 GCPRO2 (tailed, keyed);
6391
6392 keyed = KEY (key, tree);
6393
6394 {
6395 /* nsublis() won't attempt to replace a cons handed to it, do that
6396 ourselves. */
6397 GC_EXTERNAL_LIST_LOOP_2 (elt, alist)
6398 {
6399 if (CONSP (elt) &&
6400 check_test (test, key, XCAR (elt), keyed) == test_not_unboundp)
6401 {
6402 XUNGCPRO (elt);
6403 return XCDR (elt);
6404 }
6405 }
6406 END_GC_EXTERNAL_LIST_LOOP (elt);
6407 }
6408
6409 UNGCPRO;
6410
6411 return nsublis (alist, tree, check_test, test_not_unboundp, test, key, 0);
6412 }
6413
6414 DEFUN ("subst", Fsubst, 3, MANY, 0, /*
6415 Substitute NEW for OLD everywhere in TREE (non-destructively).
6416
6417 Return a copy of TREE with all elements `eql' to OLD replaced by NEW.
6418
6419 See `member*' for the meaning of :test, :test-not and :key.
6420
6421 arguments: (NEW OLD TREE &key (TEST #'eql) (KEY #'identity) TEST-NOT)
6422 */
6423 (int nargs, Lisp_Object *args))
6424 {
6425 Lisp_Object result, alist = noseeum_cons (noseeum_cons (args[1], args[0]),
6426 Qnil);
6427 args[1] = alist;
6428 result = Fsublis (nargs - 1, args + 1);
6429 free_cons (XCAR (alist));
6430 free_cons (alist);
6431
6432 return result;
6433 }
6434
6435 DEFUN ("nsubst", Fnsubst, 3, MANY, 0, /*
6436 Substitute NEW for OLD everywhere in TREE (destructively).
6437
6438 Any element of TREE which is `eql' to OLD is changed to NEW (via a call to
6439 `setcar').
6440
6441 See `member*' for the meaning of the keywords. The keyword
6442 :descend-structures, not specified by Common Lisp, allows callers to specify
6443 that non-cons objects (vectors and range tables, among others) should also
6444 undergo substitution.
6445
6446 arguments: (NEW OLD TREE &key (TEST #'eql) (KEY #'identity) TEST-NOT DESCEND-STRUCTURES)
6447 */
6448 (int nargs, Lisp_Object *args))
6449 {
6450 Lisp_Object new_ = args[0], old = args[1], tree = args[2], result, alist;
6451 Boolint test_not_unboundp = 1;
6452 check_test_func_t check_test = NULL;
6453
6454 PARSE_KEYWORDS (Fnsubst, nargs, args, 6, (test, if_, test_not, if_not, key,
6455 descend_structures), NULL);
6456 if (!NILP (descend_structures))
6457 {
6458 check_test = get_check_test_function (old, &test, test_not, if_, if_not,
6459 key, &test_not_unboundp);
6460
6461 return nsubst_structures (new_, old, tree, check_test, test_not_unboundp,
6462 test, key);
6463
6464 }
6465
6466 alist = noseeum_cons (noseeum_cons (old, new_), Qnil);
6467 args[1] = alist;
6468 result = Fnsublis (nargs - 1, args + 1);
6469 free_cons (XCAR (alist));
6470 free_cons (alist);
6471
6472 return result;
6473 }
6474
6475 static Boolint
6476 tree_equal (Lisp_Object tree1, Lisp_Object tree2,
6477 check_test_func_t check_test, Boolint test_not_unboundp,
6478 Lisp_Object test, Lisp_Object key, int depth)
6479 {
6480 Lisp_Object tortoise1 = tree1, tortoise2 = tree2;
6481 struct gcpro gcpro1, gcpro2;
6482 int count = 0;
6483 Boolint result;
6484
6485 if (depth + lisp_eval_depth > max_lisp_eval_depth)
6486 {
6487 stack_overflow ("Stack overflow in tree-equal", tree1);
6488 }
6489
6490 GCPRO2 (tree1, tree2);
6491
6492 while (CONSP (tree1) && CONSP (tree2)
6493 && tree_equal (XCAR (tree1), XCAR (tree2), check_test,
6494 test_not_unboundp, test, key, depth + 1))
6495 {
6496 tree1 = XCDR (tree1);
6497 tree2 = XCDR (tree2);
6498
6499 if (++count > CIRCULAR_LIST_SUSPICION_LENGTH)
6500 {
6501 if (count & 1)
6502 {
6503 tortoise1 = XCDR (tortoise1);
6504 tortoise2 = XCDR (tortoise2);
6505 }
6506
6507 if (EQ (tortoise1, tree1))
6508 {
6509 signal_circular_list_error (tree1);
6510 }
6511
6512 if (EQ (tortoise2, tree2))
6513 {
6514 signal_circular_list_error (tree2);
6515 }
6516 }
6517 }
6518
6519 if (CONSP (tree1) || CONSP (tree2))
6520 {
6521 UNGCPRO;
6522 return 0;
6523 }
6524
6525 result = check_test (test, key, tree1, tree2) == test_not_unboundp;
6526 UNGCPRO;
6527
6528 return result;
6529 }
6530
6531 DEFUN ("tree-equal", Ftree_equal, 2, MANY, 0, /*
6532 Return t if TREE1 and TREE2 have `eql' leaves.
6533
6534 Atoms are compared by `eql', unless another test is specified using
6535 :test; cons cells are compared recursively.
6536
6537 See `union' for the meaning of :test, :test-not and :key.
6538
6539 arguments: (TREE1 TREE2 &key (TEST #'eql) (KEY #'identity) TEST-NOT)
6540 */
6541 (int nargs, Lisp_Object *args))
6542 {
6543 Lisp_Object tree1 = args[0], tree2 = args[1];
6544 Boolint test_not_unboundp = 1;
6545 check_test_func_t check_test = NULL;
6546
6547 PARSE_KEYWORDS (Ftree_equal, nargs, args, 3, (test, key, test_not),
6548 (key = Qidentity));
6549
6550 get_check_match_function (&test, test_not, Qnil, Qnil, key,
6551 &test_not_unboundp, &check_test);
6552
6553 return tree_equal (tree1, tree2, check_test, test_not_unboundp, test, key,
6554 0) ? Qt : Qnil;
6555 }
6556
6557 static Lisp_Object
6558 mismatch_from_end (Lisp_Object sequence1, Lisp_Object start1, Lisp_Object end1,
6559 Lisp_Object sequence2, Lisp_Object start2, Lisp_Object end2,
6560 check_test_func_t check_match, Boolint test_not_unboundp,
6561 Lisp_Object test, Lisp_Object key,
6562 Boolint UNUSED (return_sequence1_index))
6563 {
6564 Elemcount sequence1_len = XFIXNUM (Flength (sequence1));
6565 Elemcount sequence2_len = XFIXNUM (Flength (sequence2)), ii = 0;
6566 Elemcount starting1, ending1, starting2, ending2;
6567 Lisp_Object *sequence1_storage = NULL, *sequence2_storage = NULL;
6568 struct gcpro gcpro1, gcpro2;
6569
6570 check_sequence_range (sequence1, start1, end1, make_fixnum (sequence1_len));
6571 starting1 = XFIXNUM (start1);
6572 ending1 = FIXNUMP (end1) ? XFIXNUM (end1) : 1 + MOST_POSITIVE_FIXNUM;
6573 ending1 = min (ending1, sequence1_len);
6574
6575 check_sequence_range (sequence2, start2, end2, make_fixnum (sequence2_len));
6576 starting2 = XFIXNUM (start2);
6577 ending2 = FIXNUMP (end2) ? XFIXNUM (end2) : 1 + MOST_POSITIVE_FIXNUM;
6578 ending2 = min (ending2, sequence2_len);
6579
6580 if (LISTP (sequence1))
6581 {
6582 Lisp_Object *saving;
6583 sequence1_storage = saving
6584 = alloca_array (Lisp_Object, ending1 - starting1);
6585
6586 {
6587 EXTERNAL_LIST_LOOP_2 (elt, sequence1)
6588 {
6589 if (starting1 <= ii && ii < ending1)
6590 {
6591 *saving++ = elt;
6592 }
6593 else if (ii == ending1)
6594 {
6595 break;
6596 }
6597
6598 ++ii;
6599 }
6600 }
6601 }
6602 else if (STRINGP (sequence1))
6603 {
6604 const Ibyte *cursor = string_char_addr (sequence1, starting1);
6605
6606 STRING_DATA_TO_OBJECT_ARRAY (cursor, sequence1_storage, ii,
6607 ending1 - starting1);
6608
6609 }
6610 else if (BIT_VECTORP (sequence1))
6611 {
6612 Lisp_Bit_Vector *vv = XBIT_VECTOR (sequence1);
6613 sequence1_storage = alloca_array (Lisp_Object, ending1 - starting1);
6614 for (ii = starting1; ii < ending1; ++ii)
6615 {
6616 sequence1_storage[ii - starting1]
6617 = make_fixnum (bit_vector_bit (vv, ii));
6618 }
6619 }
6620 else
6621 {
6622 sequence1_storage = XVECTOR_DATA (sequence1) + starting1;
6623 }
6624
6625 ii = 0;
6626
6627 if (LISTP (sequence2))
6628 {
6629 Lisp_Object *saving;
6630 sequence2_storage = saving
6631 = alloca_array (Lisp_Object, ending2 - starting2);
6632
6633 {
6634 EXTERNAL_LIST_LOOP_2 (elt, sequence2)
6635 {
6636 if (starting2 <= ii && ii < ending2)
6637 {
6638 *saving++ = elt;
6639 }
6640 else if (ii == ending2)
6641 {
6642 break;
6643 }
6644
6645 ++ii;
6646 }
6647 }
6648 }
6649 else if (STRINGP (sequence2))
6650 {
6651 const Ibyte *cursor = string_char_addr (sequence2, starting2);
6652
6653 STRING_DATA_TO_OBJECT_ARRAY (cursor, sequence2_storage, ii,
6654 ending2 - starting2);
6655
6656 }
6657 else if (BIT_VECTORP (sequence2))
6658 {
6659 Lisp_Bit_Vector *vv = XBIT_VECTOR (sequence2);
6660 sequence2_storage = alloca_array (Lisp_Object, ending2 - starting2);
6661 for (ii = starting2; ii < ending2; ++ii)
6662 {
6663 sequence2_storage[ii - starting2]
6664 = make_fixnum (bit_vector_bit (vv, ii));
6665 }
6666 }
6667 else
6668 {
6669 sequence2_storage = XVECTOR_DATA (sequence2) + starting2;
6670 }
6671
6672 GCPRO2 (sequence1_storage[0], sequence2_storage[0]);
6673 gcpro1.nvars = ending1 - starting1;
6674 gcpro2.nvars = ending2 - starting2;
6675
6676 while (ending1 > starting1 && ending2 > starting2)
6677 {
6678 --ending1;
6679 --ending2;
6680
6681 if (check_match (test, key, sequence1_storage[ending1 - starting1],
6682 sequence2_storage[ending2 - starting2])
6683 != test_not_unboundp)
6684 {
6685 UNGCPRO;
6686 return make_integer (ending1 + 1);
6687 }
6688 }
6689
6690 UNGCPRO;
6691
6692 if (ending1 > starting1 || ending2 > starting2)
6693 {
6694 return make_integer (ending1);
6695 }
6696
6697 return Qnil;
6698 }
6699
6700 static Lisp_Object
6701 mismatch_list_list (Lisp_Object sequence1, Lisp_Object start1, Lisp_Object end1,
6702 Lisp_Object sequence2, Lisp_Object start2, Lisp_Object end2,
6703 check_test_func_t check_match, Boolint test_not_unboundp,
6704 Lisp_Object test, Lisp_Object key,
6705 Boolint UNUSED (return_list_index))
6706 {
6707 Lisp_Object sequence1_tortoise = sequence1, sequence2_tortoise = sequence2;
6708 Lisp_Object orig_sequence1 = sequence1, orig_sequence2 = sequence2;
6709 Elemcount ending1 = MOST_POSITIVE_FIXNUM, ending2 = MOST_POSITIVE_FIXNUM;
6710 Elemcount starting1, starting2, counting, startcounting;
6711 Elemcount shortest_len = 0;
6712 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
6713
6714 starting1 = FIXNUMP (start1) ? XFIXNUM (start1) : 1 + MOST_POSITIVE_FIXNUM;
6715 starting2 = FIXNUMP (start2) ? XFIXNUM (start2) : 1 + MOST_POSITIVE_FIXNUM;
6716
6717 if (!NILP (end1))
6718 {
6719 ending1 = FIXNUMP (end1) ? XFIXNUM (end1) : 1 + MOST_POSITIVE_FIXNUM;
6720 }
6721
6722 if (!NILP (end2))
6723 {
6724 ending2 = FIXNUMP (end2) ? XFIXNUM (end2) : 1 + MOST_POSITIVE_FIXNUM;
6725 }
6726
6727 if (!ZEROP (start1))
6728 {
6729 sequence1 = Fnthcdr (start1, sequence1);
6730
6731 if (NILP (sequence1))
6732 {
6733 check_sequence_range (sequence1_tortoise, start1, end1,
6734 Flength (sequence1_tortoise));
6735 /* Give up early here. */
6736 return Qnil;
6737 }
6738
6739 ending1 -= starting1;
6740 starting1 = 0;
6741 sequence1_tortoise = sequence1;
6742 }
6743
6744 if (!ZEROP (start2))
6745 {
6746 sequence2 = Fnthcdr (start2, sequence2);
6747
6748 if (NILP (sequence2))
6749 {
6750 check_sequence_range (sequence2_tortoise, start2, end2,
6751 Flength (sequence2_tortoise));
6752 return Qnil;
6753 }
6754
6755 ending2 -= starting2;
6756 starting2 = 0;
6757 sequence2_tortoise = sequence2;
6758 }
6759
6760 GCPRO4 (sequence1, sequence2, sequence1_tortoise, sequence2_tortoise);
6761
6762 counting = startcounting = min (ending1, ending2);
6763
6764 while (counting-- > 0 && !NILP (sequence1) && !NILP (sequence2))
6765 {
6766 if (check_match (test, key,
6767 CONSP (sequence1) ? XCAR (sequence1)
6768 : Fcar (sequence1),
6769 CONSP (sequence2) ? XCAR (sequence2)
6770 : Fcar (sequence2) ) != test_not_unboundp)
6771 {
6772 UNGCPRO;
6773 return make_integer (XFIXNUM (start1) + shortest_len);
6774 }
6775
6776 sequence1 = CONSP (sequence1) ? XCDR (sequence1) : Fcdr (sequence1);
6777 sequence2 = CONSP (sequence2) ? XCDR (sequence2) : Fcdr (sequence2);
6778
6779 shortest_len++;
6780
6781 if (startcounting - counting > CIRCULAR_LIST_SUSPICION_LENGTH)
6782 {
6783 if (counting & 1)
6784 {
6785 sequence1_tortoise = XCDR (sequence1_tortoise);
6786 sequence2_tortoise = XCDR (sequence2_tortoise);
6787 }
6788
6789 if (EQ (sequence1, sequence1_tortoise))
6790 {
6791 signal_circular_list_error (sequence1);
6792 }
6793
6794 if (EQ (sequence2, sequence2_tortoise))
6795 {
6796 signal_circular_list_error (sequence2);
6797 }
6798 }
6799 }
6800
6801 UNGCPRO;
6802
6803 if (NILP (sequence1))
6804 {
6805 Lisp_Object args[] = { start1, make_fixnum (shortest_len) };
6806 check_sequence_range (orig_sequence1, start1, end1,
6807 Fplus (countof (args), args));
6808 }
6809
6810 if (NILP (sequence2))
6811 {
6812 Lisp_Object args[] = { start2, make_fixnum (shortest_len) };
6813 check_sequence_range (orig_sequence2, start2, end2,
6814 Fplus (countof (args), args));
6815 }
6816
6817 if ((!NILP (end1) && shortest_len != ending1 - starting1) ||
6818 (!NILP (end2) && shortest_len != ending2 - starting2))
6819 {
6820 return make_integer (XFIXNUM (start1) + shortest_len);
6821 }
6822
6823 if ((NILP (end1) && CONSP (sequence1)) || (NILP (end2) && CONSP (sequence2)))
6824 {
6825 return make_integer (XFIXNUM (start1) + shortest_len);
6826 }
6827
6828 return Qnil;
6829 }
6830
6831 static Lisp_Object
6832 mismatch_list_string (Lisp_Object list, Lisp_Object list_start,
6833 Lisp_Object list_end,
6834 Lisp_Object string, Lisp_Object string_start,
6835 Lisp_Object string_end,
6836 check_test_func_t check_match,
6837 Boolint test_not_unboundp,
6838 Lisp_Object test, Lisp_Object key,
6839 Boolint return_list_index)
6840 {
6841 Ibyte *string_data = XSTRING_DATA (string), *startp = string_data;
6842 Bytecount string_offset = 0, string_len = XSTRING_LENGTH (string);
6843 Elemcount char_count = 0, list_starting, list_ending;
6844 Elemcount string_starting, string_ending;
6845 Lisp_Object character, orig_list = list;
6846 struct gcpro gcpro1;
6847
6848 list_ending = FIXNUMP (list_end) ? XFIXNUM (list_end) : 1 + MOST_POSITIVE_FIXNUM;
6849 list_starting = FIXNUMP (list_start) ? XFIXNUM (list_start) : 1 + MOST_POSITIVE_FIXNUM;
6850
6851 string_ending = FIXNUMP (string_end) ? XFIXNUM (string_end) : 1 + MOST_POSITIVE_FIXNUM;
6852 string_starting
6853 = FIXNUMP (string_start) ? XFIXNUM (string_start) : 1 + MOST_POSITIVE_FIXNUM;
6854
6855 while (char_count < string_starting && string_offset < string_len)
6856 {
6857 INC_IBYTEPTR (string_data);
6858 string_offset = string_data - startp;
6859 char_count++;
6860 }
6861
6862 if (!ZEROP (list_start))
6863 {
6864 list = Fnthcdr (list_start, list);
6865 if (NILP (list))
6866 {
6867 check_sequence_range (orig_list, list_start, list_end,
6868 Flength (orig_list));
6869 return Qnil;
6870 }
6871
6872 list_ending -= list_starting;
6873 list_starting = 0;
6874 }
6875
6876 GCPRO1 (list);
6877
6878 while (list_starting < list_ending && string_starting < string_ending
6879 && string_offset < string_len && !NILP (list))
6880 {
6881 character = make_char (itext_ichar (string_data));
6882
6883 if (return_list_index)
6884 {
6885 if (check_match (test, key, CONSP (list) ? XCAR (list) : Fcar (list),
6886 character)
6887 != test_not_unboundp)
6888 {
6889 UNGCPRO;
6890 return make_integer (XFIXNUM (list_start) + char_count);
6891 }
6892 }
6893 else
6894 {
6895 if (check_match (test, key, character,
6896 CONSP (list) ? XCAR (list) : Fcar (list))
6897 != test_not_unboundp)
6898 {
6899 UNGCPRO;
6900 return make_integer (char_count);
6901 }
6902 }
6903
6904 list = CONSP (list) ? XCDR (list) : Fcdr (list);
6905
6906 startp = XSTRING_DATA (string);
6907 string_data = startp + string_offset;
6908 if (string_len != XSTRING_LENGTH (string)
6909 || !valid_ibyteptr_p (string_data))
6910 {
6911 mapping_interaction_error (Qmismatch, string);
6912 }
6913
6914 list_starting++;
6915 string_starting++;
6916 char_count++;
6917 INC_IBYTEPTR (string_data);
6918 string_offset = string_data - startp;
6919 }
6920
6921 UNGCPRO;
6922
6923 if (NILP (list))
6924 {
6925 Lisp_Object args[] = { list_start, make_fixnum (char_count) };
6926 check_sequence_range (orig_list, list_start, list_end,
6927 Fplus (countof (args), args));
6928 }
6929
6930 if (string_data == XSTRING_DATA (string) + XSTRING_LENGTH (string))
6931 {
6932 check_sequence_range (string, string_start, string_end,
6933 make_fixnum (char_count));
6934 }
6935
6936 if ((NILP (string_end) ?
6937 string_offset < string_len : string_starting < string_ending) ||
6938 (NILP (list_end) ? !NILP (list) : list_starting < list_ending))
6939 {
6940 return make_integer (return_list_index ? XFIXNUM (list_start) + char_count :
6941 char_count);
6942 }
6943
6944 return Qnil;
6945 }
6946
6947 static Lisp_Object
6948 mismatch_list_array (Lisp_Object list, Lisp_Object list_start,
6949 Lisp_Object list_end,
6950 Lisp_Object array, Lisp_Object array_start,
6951 Lisp_Object array_end,
6952 check_test_func_t check_match,
6953 Boolint test_not_unboundp,
6954 Lisp_Object test, Lisp_Object key,
6955 Boolint return_list_index)
6956 {
6957 Elemcount ii = 0, list_starting, list_ending;
6958 Elemcount array_starting, array_ending, array_len;
6959 Lisp_Object orig_list = list;
6960 struct gcpro gcpro1;
6961
6962 list_ending = FIXNUMP (list_end) ? XFIXNUM (list_end) : 1 + MOST_POSITIVE_FIXNUM;
6963 list_starting = FIXNUMP (list_start) ? XFIXNUM (list_start) : 1 + MOST_POSITIVE_FIXNUM;
6964
6965 array_ending = FIXNUMP (array_end) ? XFIXNUM (array_end) : 1 + MOST_POSITIVE_FIXNUM;
6966 array_starting = FIXNUMP (array_start) ? XFIXNUM (array_start) : 1 + MOST_POSITIVE_FIXNUM;
6967 array_len = XFIXNUM (Flength (array));
6968
6969 array_ending = min (array_ending, array_len);
6970
6971 check_sequence_range (array, array_start, array_end, make_fixnum (array_len));
6972
6973 if (!ZEROP (list_start))
6974 {
6975 list = Fnthcdr (list_start, list);
6976 if (NILP (list))
6977 {
6978 check_sequence_range (orig_list, list_start, list_end,
6979 Flength (orig_list));
6980 return Qnil;
6981 }
6982
6983 list_ending -= list_starting;
6984 list_starting = 0;
6985 }
6986
6987 GCPRO1 (list);
6988
6989 while (list_starting < list_ending && array_starting < array_ending
6990 && !NILP (list))
6991 {
6992 if (return_list_index)
6993 {
6994 if (check_match (test, key, CONSP (list) ? XCAR (list) : Fcar (list),
6995 Faref (array, make_fixnum (array_starting)))
6996 != test_not_unboundp)
6997 {
6998 UNGCPRO;
6999 return make_integer (XFIXNUM (list_start) + ii);
7000 }
7001 }
7002 else
7003 {
7004 if (check_match (test, key, Faref (array, make_fixnum (array_starting)),
7005 CONSP (list) ? XCAR (list) : Fcar (list))
7006 != test_not_unboundp)
7007 {
7008 UNGCPRO;
7009 return make_integer (array_starting);
7010 }
7011 }
7012
7013 list = CONSP (list) ? XCDR (list) : Fcdr (list);
7014 list_starting++;
7015 array_starting++;
7016 ii++;
7017 }
7018
7019 UNGCPRO;
7020
7021 if (NILP (list))
7022 {
7023 Lisp_Object args[] = { list_start, make_fixnum (ii) };
7024 check_sequence_range (orig_list, list_start, list_end,
7025 Fplus (countof (args), args));
7026 }
7027
7028 if (array_starting < array_ending ||
7029 (NILP (list_end) ? !NILP (list) : list_starting < list_ending))
7030 {
7031 return make_integer (return_list_index ? XFIXNUM (list_start) + ii :
7032 array_starting);
7033 }
7034
7035 return Qnil;
7036 }
7037
7038 static Lisp_Object
7039 mismatch_string_array (Lisp_Object string, Lisp_Object string_start,
7040 Lisp_Object string_end,
7041 Lisp_Object array, Lisp_Object array_start,
7042 Lisp_Object array_end,
7043 check_test_func_t check_match, Boolint test_not_unboundp,
7044 Lisp_Object test, Lisp_Object key,
7045 Boolint return_string_index)
7046 {
7047 Ibyte *string_data = XSTRING_DATA (string), *startp = string_data;
7048 Bytecount string_offset = 0, string_len = XSTRING_LENGTH (string);
7049 Elemcount char_count = 0, array_starting, array_ending, array_length;
7050 Elemcount string_starting, string_ending;
7051 Lisp_Object character;
7052
7053 array_starting = FIXNUMP (array_start) ? XFIXNUM (array_start) : 1 + MOST_POSITIVE_FIXNUM;
7054 array_ending = FIXNUMP (array_end) ? XFIXNUM (array_end) : 1 + MOST_POSITIVE_FIXNUM;
7055 array_length = XFIXNUM (Flength (array));
7056 check_sequence_range (array, array_start, array_end, make_fixnum (array_length));
7057 array_ending = min (array_ending, array_length);
7058
7059 string_ending = FIXNUMP (string_end) ? XFIXNUM (string_end) : 1 + MOST_POSITIVE_FIXNUM;
7060 string_starting
7061 = FIXNUMP (string_start) ? XFIXNUM (string_start) : 1 + MOST_POSITIVE_FIXNUM;
7062
7063 while (char_count < string_starting && string_offset < string_len)
7064 {
7065 INC_IBYTEPTR (string_data);
7066 string_offset = string_data - startp;
7067 char_count++;
7068 }
7069
7070 while (array_starting < array_ending && string_starting < string_ending
7071 && string_offset < string_len)
7072 {
7073 character = make_char (itext_ichar (string_data));
7074
7075 if (return_string_index)
7076 {
7077 if (check_match (test, key, character,
7078 Faref (array, make_fixnum (array_starting)))
7079 != test_not_unboundp)
7080 {
7081 return make_integer (char_count);
7082 }
7083 }
7084 else
7085 {
7086 if (check_match (test, key,
7087 Faref (array, make_fixnum (array_starting)),
7088 character)
7089 != test_not_unboundp)
7090 {
7091 return make_integer (XFIXNUM (array_start) + char_count);
7092 }
7093 }
7094
7095 startp = XSTRING_DATA (string);
7096 string_data = startp + string_offset;
7097 if (string_len != XSTRING_LENGTH (string)
7098 || !valid_ibyteptr_p (string_data))
7099 {
7100 mapping_interaction_error (Qmismatch, string);
7101 }
7102
7103 array_starting++;
7104 string_starting++;
7105 char_count++;
7106 INC_IBYTEPTR (string_data);
7107 string_offset = string_data - startp;
7108 }
7109
7110 if (string_data == XSTRING_DATA (string) + XSTRING_LENGTH (string))
7111 {
7112 check_sequence_range (string, string_start, string_end,
7113 make_fixnum (char_count));
7114 }
7115
7116 if ((NILP (string_end) ?
7117 string_offset < string_len : string_starting < string_ending) ||
7118 (NILP (array_end) ? !NILP (array) : array_starting < array_ending))
7119 {
7120 return make_integer (return_string_index ? char_count :
7121 XFIXNUM (array_start) + char_count);
7122 }
7123
7124 return Qnil;
7125 }
7126
7127 static Lisp_Object
7128 mismatch_string_string (Lisp_Object string1,
7129 Lisp_Object string1_start, Lisp_Object string1_end,
7130 Lisp_Object string2, Lisp_Object string2_start,
7131 Lisp_Object string2_end,
7132 check_test_func_t check_match,
7133 Boolint test_not_unboundp,
7134 Lisp_Object test, Lisp_Object key,
7135 Boolint UNUSED (return_string1_index))
7136 {
7137 Ibyte *string1_data = XSTRING_DATA (string1), *startp1 = string1_data;
7138 Bytecount string1_offset = 0, string1_len = XSTRING_LENGTH (string1);
7139 Ibyte *string2_data = XSTRING_DATA (string2), *startp2 = string2_data;
7140 Bytecount string2_offset = 0, string2_len = XSTRING_LENGTH (string2);
7141 Elemcount char_count1 = 0, string1_starting, string1_ending;
7142 Elemcount char_count2 = 0, string2_starting, string2_ending;
7143 Lisp_Object character1, character2;
7144
7145 string1_ending = FIXNUMP (string1_end) ? XFIXNUM (string1_end) : 1 + MOST_POSITIVE_FIXNUM;
7146 string1_starting
7147 = FIXNUMP (string1_start) ? XFIXNUM (string1_start) : 1 + MOST_POSITIVE_FIXNUM;
7148
7149 string2_starting
7150 = FIXNUMP (string2_start) ? XFIXNUM (string2_start) : 1 + MOST_POSITIVE_FIXNUM;
7151 string2_ending = FIXNUMP (string2_end) ? XFIXNUM (string2_end) : 1 + MOST_POSITIVE_FIXNUM;
7152
7153 while (char_count1 < string1_starting && string1_offset < string1_len)
7154 {
7155 INC_IBYTEPTR (string1_data);
7156 string1_offset = string1_data - startp1;
7157 char_count1++;
7158 }
7159
7160 while (char_count2 < string2_starting && string2_offset < string2_len)
7161 {
7162 INC_IBYTEPTR (string2_data);
7163 string2_offset = string2_data - startp2;
7164 char_count2++;
7165 }
7166
7167 while (string2_starting < string2_ending && string1_starting < string1_ending
7168 && string1_offset < string1_len && string2_offset < string2_len)
7169 {
7170 character1 = make_char (itext_ichar (string1_data));
7171 character2 = make_char (itext_ichar (string2_data));
7172
7173 if (check_match (test, key, character1, character2)
7174 != test_not_unboundp)
7175 {
7176 return make_integer (char_count1);
7177 }
7178
7179 startp1 = XSTRING_DATA (string1);
7180 string1_data = startp1 + string1_offset;
7181 if (string1_len != XSTRING_LENGTH (string1)
7182 || !valid_ibyteptr_p (string1_data))
7183 {
7184 mapping_interaction_error (Qmismatch, string1);
7185 }
7186
7187 startp2 = XSTRING_DATA (string2);
7188 string2_data = startp2 + string2_offset;
7189 if (string2_len != XSTRING_LENGTH (string2)
7190 || !valid_ibyteptr_p (string2_data))
7191 {
7192 mapping_interaction_error (Qmismatch, string2);
7193 }
7194
7195 string2_starting++;
7196 string1_starting++;
7197 char_count1++;
7198 char_count2++;
7199 INC_IBYTEPTR (string1_data);
7200 string1_offset = string1_data - startp1;
7201 INC_IBYTEPTR (string2_data);
7202 string2_offset = string2_data - startp2;
7203 }
7204
7205 if (string1_data == XSTRING_DATA (string1) + XSTRING_LENGTH (string1))
7206 {
7207 check_sequence_range (string1, string1_start, string1_end,
7208 make_fixnum (char_count1));
7209 }
7210
7211 if (string2_data == XSTRING_DATA (string2) + XSTRING_LENGTH (string2))
7212 {
7213 check_sequence_range (string2, string2_start, string2_end,
7214 make_fixnum (char_count2));
7215 }
7216
7217 if ((!NILP (string1_end) && string1_starting < string1_ending) ||
7218 (!NILP (string2_end) && string2_starting < string2_ending))
7219 {
7220 return make_integer (char_count1);
7221 }
7222
7223 if ((NILP (string1_end) && string1_data
7224 < (XSTRING_DATA (string1) + XSTRING_LENGTH (string1))) ||
7225 (NILP (string2_end) && string2_data
7226 < (XSTRING_DATA (string2) + XSTRING_LENGTH (string2))))
7227 {
7228 return make_integer (char_count1);
7229 }
7230
7231 return Qnil;
7232 }
7233
7234 static Lisp_Object
7235 mismatch_array_array (Lisp_Object array1, Lisp_Object start1, Lisp_Object end1,
7236 Lisp_Object array2, Lisp_Object start2, Lisp_Object end2,
7237 check_test_func_t check_match, Boolint test_not_unboundp,
7238 Lisp_Object test, Lisp_Object key,
7239 Boolint UNUSED (return_array1_index))
7240 {
7241 Elemcount len1 = XFIXNUM (Flength (array1)), len2 = XFIXNUM (Flength (array2));
7242 Elemcount ending1 = MOST_POSITIVE_FIXNUM, ending2 = MOST_POSITIVE_FIXNUM;
7243 Elemcount starting1, starting2;
7244
7245 check_sequence_range (array1, start1, end1, make_fixnum (len1));
7246 check_sequence_range (array2, start2, end2, make_fixnum (len2));
7247
7248 starting1 = FIXNUMP (start1) ? XFIXNUM (start1) : 1 + MOST_POSITIVE_FIXNUM;
7249 starting2 = FIXNUMP (start2) ? XFIXNUM (start2) : 1 + MOST_POSITIVE_FIXNUM;
7250
7251 if (!NILP (end1))
7252 {
7253 ending1 = FIXNUMP (end1) ? XFIXNUM (end1) : 1 + MOST_POSITIVE_FIXNUM;
7254 }
7255
7256 if (!NILP (end2))
7257 {
7258 ending2 = FIXNUMP (end2) ? XFIXNUM (end2) : 1 + MOST_POSITIVE_FIXNUM;
7259 }
7260
7261 ending1 = min (ending1, len1);
7262 ending2 = min (ending2, len2);
7263
7264 while (starting1 < ending1 && starting2 < ending2)
7265 {
7266 if (check_match (test, key, Faref (array1, make_fixnum (starting1)),
7267 Faref (array2, make_fixnum (starting2)))
7268 != test_not_unboundp)
7269 {
7270 return make_integer (starting1);
7271 }
7272 starting1++;
7273 starting2++;
7274 }
7275
7276 if (starting1 < ending1 || starting2 < ending2)
7277 {
7278 return make_integer (starting1);
7279 }
7280
7281 return Qnil;
7282 }
7283
7284 typedef Lisp_Object
7285 (*mismatch_func_t) (Lisp_Object sequence1, Lisp_Object start1, Lisp_Object end1,
7286 Lisp_Object sequence2, Lisp_Object start2, Lisp_Object end2,
7287 check_test_func_t check_match, Boolint test_not_unboundp,
7288 Lisp_Object test, Lisp_Object key,
7289 Boolint return_list_index);
7290
7291 static mismatch_func_t
7292 get_mismatch_func (Lisp_Object sequence1, Lisp_Object sequence2,
7293 Lisp_Object from_end, Boolint *return_sequence1_index_out)
7294 {
7295 CHECK_SEQUENCE (sequence1);
7296 CHECK_SEQUENCE (sequence2);
7297
7298 if (!NILP (from_end))
7299 {
7300 *return_sequence1_index_out = 1;
7301 return mismatch_from_end;
7302 }
7303
7304 if (LISTP (sequence1))
7305 {
7306 if (LISTP (sequence2))
7307 {
7308 *return_sequence1_index_out = 1;
7309 return mismatch_list_list;
7310 }
7311
7312 if (STRINGP (sequence2))
7313 {
7314 *return_sequence1_index_out = 1;
7315 return mismatch_list_string;
7316 }
7317
7318 *return_sequence1_index_out = 1;
7319 return mismatch_list_array;
7320 }
7321
7322 if (STRINGP (sequence1))
7323 {
7324 if (STRINGP (sequence2))
7325 {
7326 *return_sequence1_index_out = 1;
7327 return mismatch_string_string;
7328 }
7329
7330 if (LISTP (sequence2))
7331 {
7332 *return_sequence1_index_out = 0;
7333 return mismatch_list_string;
7334 }
7335
7336 *return_sequence1_index_out = 1;
7337 return mismatch_string_array;
7338 }
7339
7340 if (ARRAYP (sequence1))
7341 {
7342 if (STRINGP (sequence2))
7343 {
7344 *return_sequence1_index_out = 0;
7345 return mismatch_string_array;
7346 }
7347
7348 if (LISTP (sequence2))
7349 {
7350 *return_sequence1_index_out = 0;
7351 return mismatch_list_array;
7352 }
7353
7354 *return_sequence1_index_out = 1;
7355 return mismatch_array_array;
7356 }
7357
7358 RETURN_NOT_REACHED (NULL);
7359 return NULL;
7360 }
7361
7362 DEFUN ("mismatch", Fmismatch, 2, MANY, 0, /*
7363 Compare SEQUENCE1 with SEQUENCE2, return index of first mismatching element.
7364
7365 Return nil if the sequences match. If one sequence is a prefix of the
7366 other, the return value indicates the end of the shorter sequence. A
7367 non-nil return value always reflects an index into SEQUENCE1.
7368
7369 See `search' for the meaning of the keywords."
7370
7371 arguments: (SEQUENCE1 SEQUENCE2 &key (TEST #'eql) (KEY #'identity) (START1 0) END1 (START2 0) END2 FROM-END TEST-NOT)
7372 */
7373 (int nargs, Lisp_Object *args))
7374 {
7375 Lisp_Object sequence1 = args[0], sequence2 = args[1];
7376 Boolint test_not_unboundp = 1, return_first_index = 0;
7377 check_test_func_t check_match = NULL;
7378 mismatch_func_t mismatch = NULL;
7379
7380 PARSE_KEYWORDS (Fmismatch, nargs, args, 8,
7381 (test, key, from_end, start1, end1, start2, end2, test_not),
7382 (start1 = start2 = Qzero));
7383
7384 CHECK_SEQUENCE (sequence1);
7385 CHECK_SEQUENCE (sequence2);
7386
7387 CHECK_NATNUM (start1);
7388 CHECK_NATNUM (start2);
7389
7390 if (!NILP (end1))
7391 {
7392 CHECK_NATNUM (end1);
7393 }
7394
7395 if (!NILP (end2))
7396 {
7397 CHECK_NATNUM (end2);
7398 }
7399
7400 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key,
7401 &test_not_unboundp, NULL);
7402 mismatch = get_mismatch_func (sequence1, sequence2, from_end,
7403 &return_first_index);
7404
7405 if (return_first_index)
7406 {
7407 return mismatch (sequence1, start1, end1, sequence2, start2, end2,
7408 check_match, test_not_unboundp, test, key, 1);
7409 }
7410
7411 return mismatch (sequence2, start2, end2, sequence1, start1, end1,
7412 check_match, test_not_unboundp, test, key, 0);
7413 }
7414
7415 DEFUN ("search", Fsearch, 2, MANY, 0, /*
7416 Search for SEQUENCE1 as a subsequence of SEQUENCE2.
7417
7418 Return the index of the leftmost element of the first match found; return
7419 nil if there are no matches.
7420
7421 In this function, :start1 and :end1 specify a subsequence of SEQUENCE1, and
7422 :start2 and :end2 specify a subsequence of SEQUENCE2. See `remove*' for
7423 details of the other keywords.
7424
7425 arguments: (SEQUENCE1 SEQUENCE2 &key (TEST #'eql) (KEY #'identity) (START1 0) END1 (START2 0) END2 FROM-END TEST-NOT)
7426 */
7427 (int nargs, Lisp_Object *args))
7428 {
7429 Lisp_Object sequence1 = args[0], sequence2 = args[1], position0 = Qnil;
7430 Boolint test_not_unboundp = 1, return_first = 0;
7431 check_test_func_t check_test = NULL, check_match = NULL;
7432 mismatch_func_t mismatch = NULL;
7433 Elemcount starting1 = 0, ending1 = 1 + MOST_POSITIVE_FIXNUM, starting2 = 0;
7434 Elemcount ending2 = 1 + MOST_POSITIVE_FIXNUM, ii = 0;
7435 Elemcount length1;
7436 Lisp_Object object = Qnil;
7437 struct gcpro gcpro1, gcpro2;
7438
7439 PARSE_KEYWORDS (Fsearch, nargs, args, 8,
7440 (test, key, from_end, start1, end1, start2, end2, test_not),
7441 (start1 = start2 = Qzero));
7442
7443 CHECK_SEQUENCE (sequence1);
7444 CHECK_SEQUENCE (sequence2);
7445 CHECK_KEY_ARGUMENT (key);
7446
7447 CHECK_NATNUM (start1);
7448 starting1 = FIXNUMP (start1) ? XFIXNUM (start1) : 1 + MOST_POSITIVE_FIXNUM;
7449 CHECK_NATNUM (start2);
7450 starting2 = FIXNUMP (start2) ? XFIXNUM (start2) : 1 + MOST_POSITIVE_FIXNUM;
7451
7452 if (!NILP (end1))
7453 {
7454 Lisp_Object len1 = Flength (sequence1);
7455
7456 CHECK_NATNUM (end1);
7457 check_sequence_range (sequence1, start1, end1, len1);
7458 ending1 = min (XFIXNUM (end1), XFIXNUM (len1));
7459 }
7460 else
7461 {
7462 end1 = Flength (sequence1);
7463 check_sequence_range (sequence1, start1, end1, end1);
7464 ending1 = XFIXNUM (end1);
7465 }
7466
7467 length1 = ending1 - starting1;
7468
7469 if (!NILP (end2))
7470 {
7471 Lisp_Object len2 = Flength (sequence2);
7472
7473 CHECK_NATNUM (end2);
7474 check_sequence_range (sequence2, start2, end2, len2);
7475 ending2 = min (XFIXNUM (end2), XFIXNUM (len2));
7476 }
7477 else
7478 {
7479 end2 = Flength (sequence2);
7480 check_sequence_range (sequence2, start2, end2, end2);
7481 ending2 = XFIXNUM (end2);
7482 }
7483
7484 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key,
7485 &test_not_unboundp, &check_test);
7486 mismatch = get_mismatch_func (sequence1, sequence2, from_end, &return_first);
7487
7488 if (bytecode_arithcompare (start1, make_integer (ending1)) >= 0)
7489 {
7490 if (NILP (from_end))
7491 {
7492 return start2;
7493 }
7494
7495 if (NILP (end2))
7496 {
7497 return Flength (sequence2);
7498 }
7499
7500 return end2;
7501 }
7502
7503 if (NILP (from_end))
7504 {
7505 Lisp_Object mismatch_start1 = Fadd1 (start1);
7506 Lisp_Object first = KEY (key, Felt (sequence1, start1));
7507 GCPRO2 (first, mismatch_start1);
7508
7509 ii = starting2;
7510 while (ii < ending2)
7511 {
7512 position0 = position (&object, first, sequence2, check_test,
7513 test_not_unboundp, test, key, make_fixnum (ii),
7514 end2, Qnil, Qnil, Qsearch);
7515 if (NILP (position0))
7516 {
7517 UNGCPRO;
7518 return Qnil;
7519 }
7520
7521 if (length1 + XFIXNUM (position0) <= ending2 &&
7522 (return_first ?
7523 NILP (mismatch (sequence1, mismatch_start1, end1,
7524 sequence2,
7525 make_fixnum (1 + XFIXNUM (position0)),
7526 make_fixnum (length1 + XFIXNUM (position0)),
7527 check_match, test_not_unboundp, test, key, 1)) :
7528 NILP (mismatch (sequence2,
7529 make_fixnum (1 + XFIXNUM (position0)),
7530 make_fixnum (length1 + XFIXNUM (position0)),
7531 sequence1, mismatch_start1, end1,
7532 check_match, test_not_unboundp, test, key, 0))))
7533
7534
7535 {
7536 UNGCPRO;
7537 return position0;
7538 }
7539
7540 ii = XFIXNUM (position0) + 1;
7541 }
7542
7543 UNGCPRO;
7544 }
7545 else
7546 {
7547 Lisp_Object mismatch_end1 = make_integer (ending1 - 1);
7548 Lisp_Object last = KEY (key, Felt (sequence1, mismatch_end1));
7549 GCPRO2 (last, mismatch_end1);
7550
7551 ii = ending2;
7552 while (ii > starting2)
7553 {
7554 position0 = position (&object, last, sequence2, check_test,
7555 test_not_unboundp, test, key, start2,
7556 make_fixnum (ii), Qt, Qnil, Qsearch);
7557
7558 if (NILP (position0))
7559 {
7560 UNGCPRO;
7561 return Qnil;
7562 }
7563
7564 if (XFIXNUM (position0) - length1 + 1 >= starting2 &&
7565 (return_first ?
7566 NILP (mismatch (sequence1, start1, mismatch_end1,
7567 sequence2,
7568 make_fixnum (XFIXNUM (position0) - length1 + 1),
7569 make_fixnum (XFIXNUM (position0)),
7570 check_match, test_not_unboundp, test, key, 1)) :
7571 NILP (mismatch (sequence2,
7572 make_fixnum (XFIXNUM (position0) - length1 + 1),
7573 make_fixnum (XFIXNUM (position0)),
7574 sequence1, start1, mismatch_end1,
7575 check_match, test_not_unboundp, test, key, 0))))
7576 {
7577 UNGCPRO;
7578 return make_fixnum (XFIXNUM (position0) - length1 + 1);
7579 }
7580
7581 ii = XFIXNUM (position0);
7582 }
7583
7584 UNGCPRO;
7585 }
7586
7587 return Qnil;
7588 }
7589
7590 /* These two functions do set operations, those that can be visualised with
7591 Venn diagrams. */
7592 static Lisp_Object
7593 venn (Lisp_Object caller, int nargs, Lisp_Object *args, Boolint intersectionp)
7594 {
7595 Lisp_Object liszt1 = args[0], liszt2 = args[1];
7596 Lisp_Object result = EQ (caller, Qsubsetp) ? Qt : Qnil, result_tail = Qnil;
7597 Lisp_Object keyed = Qnil, ignore = Qnil;
7598 Boolint test_not_unboundp = 1;
7599 check_test_func_t check_test = NULL;
7600 struct gcpro gcpro1, gcpro2;
7601
7602 PARSE_KEYWORDS_8 (caller, nargs, args, 4, (test, key, test_not, stable),
7603 NULL, 2, 0);
7604
7605 CHECK_LIST (liszt1);
7606 CHECK_LIST (liszt2);
7607
7608 CHECK_KEY_ARGUMENT (key);
7609
7610 if (NILP (liszt1) && intersectionp)
7611 {
7612 return Qnil;
7613 }
7614
7615 if (NILP (liszt2))
7616 {
7617 return intersectionp ? Qnil : liszt1;
7618 }
7619
7620 get_check_match_function (&test, test_not, Qnil, Qnil, key,
7621 &test_not_unboundp, &check_test);
7622
7623 GCPRO2 (keyed, result);
7624
7625 {
7626 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt1)
7627 {
7628 keyed = KEY (key, elt);
7629 if (NILP (list_position_cons_before (&ignore, keyed, liszt2,
7630 check_test, test_not_unboundp,
7631 test, key, 0, Qzero, Qnil))
7632 != intersectionp)
7633 {
7634 if (EQ (Qsubsetp, caller))
7635 {
7636 result = Qnil;
7637 break;
7638 }
7639 else if (NILP (stable))
7640 {
7641 result = Fcons (elt, result);
7642 }
7643 else if (NILP (result))
7644 {
7645 result = result_tail = Fcons (elt, Qnil);
7646 }
7647 else
7648 {
7649 XSETCDR (result_tail, Fcons (elt, Qnil));
7650 result_tail = XCDR (result_tail);
7651 }
7652 }
7653 }
7654 END_GC_EXTERNAL_LIST_LOOP (elt);
7655 }
7656
7657 UNGCPRO;
7658
7659 return result;
7660 }
7661
7662 static Lisp_Object
7663 nvenn (Lisp_Object caller, int nargs, Lisp_Object *args, Boolint intersectionp)
7664 {
7665 Lisp_Object liszt1 = args[0], liszt2 = args[1], tortoise_elt, ignore = Qnil;
7666 Lisp_Object elt = Qnil, tail = Qnil, keyed = Qnil, prev_tail = Qnil;
7667 Elemcount count;
7668 Boolint test_not_unboundp = 1;
7669 check_test_func_t check_test = NULL;
7670 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
7671
7672 PARSE_KEYWORDS_8 (caller, nargs, args, 3, (test, key, test_not),
7673 NULL, 2, 0);
7674
7675 CHECK_LIST (liszt1);
7676 CHECK_LIST (liszt2);
7677
7678 CHECK_KEY_ARGUMENT (key);
7679
7680 if (NILP (liszt1) && intersectionp)
7681 {
7682 return Qnil;
7683 }
7684
7685 if (NILP (liszt2))
7686 {
7687 return intersectionp ? Qnil : liszt1;
7688 }
7689
7690 get_check_match_function (&test, test_not, Qnil, Qnil, key,
7691 &test_not_unboundp, &check_test);
7692
7693 tortoise_elt = tail = liszt1, count = 0;
7694
7695 GCPRO4 (tail, keyed, liszt1, tortoise_elt);
7696
7697 while (CONSP (tail) ? (elt = XCAR (tail), 1) : NILP (tail) ? 0 :
7698 (signal_malformed_list_error (liszt1), 0))
7699 {
7700 keyed = KEY (key, elt);
7701 if (NILP (list_position_cons_before (&ignore, keyed, liszt2,
7702 check_test, test_not_unboundp,
7703 test, key, 0, Qzero, Qnil))
7704 == intersectionp)
7705 {
7706 if (NILP (prev_tail))
7707 {
7708 liszt1 = XCDR (tail);
7709 }
7710 else
7711 {
7712 XSETCDR (prev_tail, XCDR (tail));
7713 }
7714
7715 tail = XCDR (tail);
7716 /* List is definitely not circular now! */
7717 count = 0;
7718 }
7719 else
7720 {
7721 prev_tail = tail;
7722 tail = XCDR (tail);
7723 }
7724
7725 if (count++ < CIRCULAR_LIST_SUSPICION_LENGTH) continue;
7726
7727 if (count & 1)
7728 {
7729 tortoise_elt = XCDR (tortoise_elt);
7730 }
7731
7732 if (EQ (elt, tortoise_elt))
7733 {
7734 signal_circular_list_error (liszt1);
7735 }
7736 }
7737
7738 UNGCPRO;
7739
7740 return liszt1;
7741 }
7742
7743 DEFUN ("intersection", Fintersection, 2, MANY, 0, /*
7744 Combine LIST1 and LIST2 using a set-intersection operation.
7745
7746 The result list contains all items that appear in both LIST1 and LIST2.
7747 This is a non-destructive function; it makes a copy of the data if necessary
7748 to avoid corrupting the original LIST1 and LIST2.
7749
7750 A non-nil value for the :stable keyword, not specified by Common Lisp, means
7751 return the items in the order they appear in LIST1.
7752
7753 See `union' for the meaning of :test, :test-not and :key."
7754
7755 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT STABLE)
7756 */
7757 (int nargs, Lisp_Object *args))
7758 {
7759 return venn (Qintersection, nargs, args, 1);
7760 }
7761
7762 DEFUN ("nintersection", Fnintersection, 2, MANY, 0, /*
7763 Combine LIST1 and LIST2 using a set-intersection operation.
7764
7765 The result list contains all items that appear in both LIST1 and LIST2.
7766 This is a destructive function; it reuses the storage of LIST1 whenever
7767 possible.
7768
7769 See `union' for the meaning of :test, :test-not and :key."
7770
7771 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT)
7772 */
7773 (int nargs, Lisp_Object *args))
7774 {
7775 return nvenn (Qnintersection, nargs, args, 1);
7776 }
7777
7778 DEFUN ("subsetp", Fsubsetp, 2, MANY, 0, /*
7779 Return non-nil if every element of LIST1 also appears in LIST2.
7780
7781 See `union' for the meaning of the keyword arguments.
7782
7783 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT)
7784 */
7785 (int nargs, Lisp_Object *args))
7786 {
7787 return venn (Qsubsetp, nargs, args, 0);
7788 }
7789
7790 DEFUN ("set-difference", Fset_difference, 2, MANY, 0, /*
7791 Combine LIST1 and LIST2 using a set-difference operation.
7792
7793 The result list contains all items that appear in LIST1 but not LIST2. This
7794 is a non-destructive function; it makes a copy of the data if necessary to
7795 avoid corrupting the original LIST1 and LIST2.
7796
7797 See `union' for the meaning of :test, :test-not and :key.
7798
7799 A non-nil value for the :stable keyword, not specified by Common Lisp, means
7800 return the items in the order they appear in LIST1.
7801
7802 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT STABLE)
7803 */
7804 (int nargs, Lisp_Object *args))
7805 {
7806 return venn (Qset_difference, nargs, args, 0);
7807 }
7808
7809 DEFUN ("nset-difference", Fnset_difference, 2, MANY, 0, /*
7810 Combine LIST1 and LIST2 using a set-difference operation.
7811
7812 The result list contains all items that appear in LIST1 but not LIST2. This
7813 is a destructive function; it reuses the storage of LIST1 whenever possible.
7814
7815 See `union' for the meaning of :test, :test-not and :key."
7816
7817 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT)
7818 */
7819 (int nargs, Lisp_Object *args))
7820 {
7821 return nvenn (Qnset_difference, nargs, args, 0);
7822 }
7823
7824 DEFUN ("nunion", Fnunion, 2, MANY, 0, /*
7825 Combine LIST1 and LIST2 using a set-union operation.
7826 The result list contains all items that appear in either LIST1 or LIST2.
7827
7828 This is a destructive function, it reuses the storage of LIST1 whenever
7829 possible.
7830
7831 See `union' for the meaning of :test, :test-not and :key.
7832
7833 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT)
7834 */
7835 (int nargs, Lisp_Object *args))
7836 {
7837 args[0] = nvenn (Qnunion, nargs, args, 0);
7838 return bytecode_nconc2 (args);
7839 }
7840
7841 DEFUN ("union", Funion, 2, MANY, 0, /*
7842 Combine LIST1 and LIST2 using a set-union operation.
7843 The result list contains all items that appear in either LIST1 or LIST2.
7844 This is a non-destructive function; it makes a copy of the data if necessary
7845 to avoid corrupting the original LIST1 and LIST2.
7846
7847 The keywords :test and :test-not specify two-argument test and negated-test
7848 predicates, respectively; :test defaults to `eql'. See `member*' for more
7849 information.
7850
7851 :key specifies a one-argument function that transforms elements of LIST1
7852 and LIST2 into \"comparison keys\" before the test predicate is applied.
7853 For example, if :key is #'car, then the car of elements from LIST1 is
7854 compared with the car of elements from LIST2. The :key function, however,
7855 does not affect the elements in the returned list, which are taken directly
7856 from the elements in LIST1 and LIST2.
7857
7858 A non-nil value for the :stable keyword, not specified by Common Lisp, means
7859 return the items of LIST1 in order, followed by the remaining items of LIST2
7860 in the order they occur in LIST2.
7861
7862 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT STABLE)
7863 */
7864 (int nargs, Lisp_Object *args))
7865 {
7866 Lisp_Object liszt1 = args[0], liszt2 = args[1], ignore = Qnil;
7867 Lisp_Object keyed = Qnil, result, result_tail;
7868 Boolint test_not_unboundp = 1;
7869 check_test_func_t check_test = NULL, check_match = NULL;
7870 struct gcpro gcpro1, gcpro2;
7871
7872 PARSE_KEYWORDS (Funion, nargs, args, 4, (test, key, test_not, stable), NULL);
7873
7874 CHECK_LIST (liszt1);
7875 CHECK_LIST (liszt2);
7876
7877 CHECK_KEY_ARGUMENT (key);
7878
7879 if (NILP (liszt1))
7880 {
7881 return liszt2;
7882 }
7883
7884 if (NILP (liszt2))
7885 {
7886 return liszt1;
7887 }
7888
7889 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key,
7890 &test_not_unboundp, &check_test);
7891
7892 GCPRO2 (keyed, result);
7893
7894 if (NILP (stable))
7895 {
7896 result = liszt2;
7897 {
7898 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt1)
7899 {
7900 keyed = KEY (key, elt);
7901 if (NILP (list_position_cons_before (&ignore, keyed, liszt2,
7902 check_test, test_not_unboundp,
7903 test, key, 0, Qzero, Qnil)))
7904 {
7905 /* The Lisp version of #'union used to check which list was
7906 longer, and use that as the tail of the constructed
7907 list. That fails when the order of arguments to TEST is
7908 specified, as is the case for these functions. We could
7909 pass the reverse_check argument to
7910 list_position_cons_before, but that means any key argument
7911 is called an awful lot more, so it's a space win but not
7912 a time win. */
7913 result = Fcons (elt, result);
7914 }
7915 }
7916 END_GC_EXTERNAL_LIST_LOOP (elt);
7917 }
7918 }
7919 else
7920 {
7921 result = result_tail = Qnil;
7922
7923 /* The standard `union' doesn't produce a "stable" union -- it
7924 iterates over the second list instead of the first one, and returns
7925 the values in backwards order. According to the CLTL2
7926 documentation, `union' is not required to preserve the ordering of
7927 elements in any fashion; providing the functionality for a stable
7928 union is an XEmacs extension. */
7929 {
7930 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt2)
7931 {
7932 if (NILP (list_position_cons_before (&ignore, elt, liszt1,
7933 check_match, test_not_unboundp,
7934 test, key, 1, Qzero, Qnil)))
7935 {
7936 if (NILP (result))
7937 {
7938 result = result_tail = Fcons (elt, Qnil);
7939 }
7940 else
7941 {
7942 XSETCDR (result_tail, Fcons (elt, Qnil));
7943 result_tail = XCDR (result_tail);
7944 }
7945 }
7946 }
7947 END_GC_EXTERNAL_LIST_LOOP (elt);
7948 }
7949
7950 result = NILP (result) ? liszt1 : nconc2 (Fcopy_list (liszt1), result);
7951 }
7952
7953 UNGCPRO;
7954
7955 return result;
7956 }
7957
7958 DEFUN ("set-exclusive-or", Fset_exclusive_or, 2, MANY, 0, /*
7959 Combine LIST1 and LIST2 using a set-exclusive-or operation.
7960
7961 The result list contains all items that appear in exactly one of LIST1, LIST2.
7962 This is a non-destructive function; it makes a copy of the data if necessary
7963 to avoid corrupting the original LIST1 and LIST2.
7964
7965 See `union' for the meaning of :test, :test-not and :key.
7966
7967 A non-nil value for the :stable keyword, not specified by Common Lisp, means
7968 return the items in the order they appear in LIST1, followed by the
7969 remaining items in the order they appear in LIST2.
7970
7971 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT STABLE)
7972 */
7973 (int nargs, Lisp_Object *args))
7974 {
7975 Lisp_Object liszt1 = args[0], liszt2 = args[1];
7976 Lisp_Object result = Qnil, result_tail = Qnil, keyed = Qnil, ignore = Qnil;
7977 Boolint test_not_unboundp = 1;
7978 check_test_func_t check_match = NULL, check_test = NULL;
7979 struct gcpro gcpro1, gcpro2;
7980
7981 PARSE_KEYWORDS (Fset_exclusive_or, nargs, args, 4,
7982 (test, key, test_not, stable), NULL);
7983
7984 CHECK_LIST (liszt1);
7985 CHECK_LIST (liszt2);
7986
7987 CHECK_KEY_ARGUMENT (key);
7988
7989 if (NILP (liszt2))
7990 {
7991 return liszt1;
7992 }
7993
7994 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key,
7995 &test_not_unboundp, &check_test);
7996
7997 GCPRO2 (keyed, result);
7998 {
7999 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt1)
8000 {
8001 keyed = KEY (key, elt);
8002 if (NILP (list_position_cons_before (&ignore, keyed, liszt2,
8003 check_test, test_not_unboundp,
8004 test, key, 0, Qzero, Qnil)))
8005 {
8006 if (NILP (stable))
8007 {
8008 result = Fcons (elt, result);
8009 }
8010 else if (NILP (result))
8011 {
8012 result = result_tail = Fcons (elt, Qnil);
8013 }
8014 else
8015 {
8016 XSETCDR (result_tail, Fcons (elt, Qnil));
8017 result_tail = XCDR (result_tail);
8018 }
8019 }
8020 }
8021 END_GC_EXTERNAL_LIST_LOOP (elt);
8022 }
8023
8024 {
8025 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt2)
8026 {
8027 if (NILP (list_position_cons_before (&ignore, elt, liszt1,
8028 check_match, test_not_unboundp,
8029 test, key, 1, Qzero, Qnil)))
8030 {
8031 if (NILP (stable))
8032 {
8033 result = Fcons (elt, result);
8034 }
8035 else if (NILP (result))
8036 {
8037 result = result_tail = Fcons (elt, Qnil);
8038 }
8039 else
8040 {
8041 XSETCDR (result_tail, Fcons (elt, Qnil));
8042 result_tail = XCDR (result_tail);
8043 }
8044 }
8045 }
8046 END_GC_EXTERNAL_LIST_LOOP (elt);
8047 }
8048
8049 UNGCPRO;
8050
8051 return result;
8052 }
8053
8054 DEFUN ("nset-exclusive-or", Fnset_exclusive_or, 2, MANY, 0, /*
8055 Combine LIST1 and LIST2 using a set-exclusive-or operation.
8056
8057 The result list contains all items that appear in exactly one of LIST1 and
8058 LIST2. This is a destructive function; it reuses the storage of LIST1 and
8059 LIST2 whenever possible.
8060
8061 See `union' for the meaning of :test, :test-not and :key.
8062
8063 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT)
8064 */
8065 (int nargs, Lisp_Object *args))
8066 {
8067 Lisp_Object liszt1 = args[0], liszt2 = args[1], elt = Qnil, tail = Qnil;
8068 Lisp_Object result = Qnil, tortoise_elt = Qnil, keyed = Qnil, swap;
8069 Lisp_Object prev_tail = Qnil, ignore = Qnil;
8070 Elemcount count;
8071 Boolint test_not_unboundp = 1;
8072 check_test_func_t check_match = NULL, check_test = NULL;
8073 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
8074
8075 PARSE_KEYWORDS (Fnset_exclusive_or, nargs, args, 4,
8076 (test, key, test_not, stable), NULL);
8077
8078 CHECK_LIST (liszt1);
8079 CHECK_LIST (liszt2);
8080
8081 CHECK_KEY_ARGUMENT (key);
8082
8083 if (NILP (liszt2))
8084 {
8085 return liszt1;
8086 }
8087
8088 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key,
8089 &test_not_unboundp, &check_test);
8090
8091 tortoise_elt = tail = liszt1, count = 0;
8092
8093 GCPRO4 (tail, keyed, result, tortoise_elt);
8094
8095 while (CONSP (tail) ? (elt = XCAR (tail), 1) : NILP (tail) ? 0 :
8096 (signal_malformed_list_error (liszt1), 0))
8097 {
8098 keyed = KEY (key, elt);
8099 if (NILP (list_position_cons_before (&ignore, keyed, liszt2,
8100 check_test, test_not_unboundp,
8101 test, key, 0, Qzero, Qnil)))
8102 {
8103 swap = XCDR (tail);
8104
8105 if (NILP (prev_tail))
8106 {
8107 liszt1 = XCDR (tail);
8108 }
8109 else
8110 {
8111 XSETCDR (prev_tail, swap);
8112 }
8113
8114 XSETCDR (tail, result);
8115 result = tail;
8116 tail = swap;
8117
8118 /* List is definitely not circular now! */
8119 count = 0;
8120 }
8121 else
8122 {
8123 prev_tail = tail;
8124 tail = XCDR (tail);
8125 }
8126
8127 if (count++ < CIRCULAR_LIST_SUSPICION_LENGTH) continue;
8128
8129 if (count & 1)
8130 {
8131 tortoise_elt = XCDR (tortoise_elt);
8132 }
8133
8134 if (EQ (elt, tortoise_elt))
8135 {
8136 signal_circular_list_error (liszt1);
8137 }
8138 }
8139
8140 tortoise_elt = tail = liszt2, count = 0;
8141
8142 while (CONSP (tail) ? (elt = XCAR (tail), 1) : NILP (tail) ? 0 :
8143 (signal_malformed_list_error (liszt2), 0))
8144 {
8145 /* Need to leave the key calculation to list_position_cons_before(). */
8146 if (NILP (list_position_cons_before (&ignore, elt, liszt1,
8147 check_match, test_not_unboundp,
8148 test, key, 1, Qzero, Qnil)))
8149 {
8150 swap = XCDR (tail);
8151 XSETCDR (tail, result);
8152 result = tail;
8153 tail = swap;
8154 count = 0;
8155 }
8156 else
8157 {
8158 tail = XCDR (tail);
8159 }
8160
8161 if (count++ < CIRCULAR_LIST_SUSPICION_LENGTH) continue;
8162
8163 if (count & 1)
8164 {
8165 tortoise_elt = XCDR (tortoise_elt);
8166 }
8167
8168 if (EQ (elt, tortoise_elt))
8169 {
8170 signal_circular_list_error (liszt1);
8171 }
8172 }
8173
8174 UNGCPRO;
8175
8176 return result;
8177 }
8178
8179 void
8180 syms_of_sequence (void)
8181 {
8182 DEFSYMBOL (Qstring_lessp);
8183 DEFSYMBOL (Qmerge);
8184 DEFSYMBOL (Qfill);
8185 DEFSYMBOL (Qidentity);
8186 DEFSYMBOL (Qvector);
8187 DEFSYMBOL (Qarray);
8188 DEFSYMBOL (Qstring);
8189 DEFSYMBOL (Qlist);
8190 DEFSYMBOL (Qbit_vector);
8191 defsymbol (&QsortX, "sort*");
8192 DEFSYMBOL (Qreduce);
8193 DEFSYMBOL (Qreplace);
8194 DEFSYMBOL (Qposition);
8195 DEFSYMBOL (Qfind);
8196 defsymbol (&QdeleteX, "delete*");
8197 defsymbol (&QremoveX, "remove*");
8198
8199 DEFSYMBOL (Qmapconcat);
8200 defsymbol (&QmapcarX, "mapcar*");
8201 DEFSYMBOL (Qmapvector);
8202 DEFSYMBOL (Qmapcan);
8203 DEFSYMBOL (Qmapc);
8204 DEFSYMBOL (Qmap);
8205 DEFSYMBOL (Qmap_into);
8206 DEFSYMBOL (Qsome);
8207 DEFSYMBOL (Qevery);
8208 DEFSYMBOL (Qnsubstitute);
8209 DEFSYMBOL (Qdelete_duplicates);
8210 DEFSYMBOL (Qsubstitute);
8211 DEFSYMBOL (Qmismatch);
8212 DEFSYMBOL (Qintersection);
8213 DEFSYMBOL (Qnintersection);
8214 DEFSYMBOL (Qsubsetp);
8215 DEFSYMBOL (Qcar_less_than_car);
8216 DEFSYMBOL (Qset_difference);
8217 DEFSYMBOL (Qnset_difference);
8218 DEFSYMBOL (Qnunion);
8219
8220 DEFKEYWORD (Q_from_end);
8221 DEFKEYWORD (Q_initial_value);
8222 DEFKEYWORD (Q_start1);
8223 DEFKEYWORD (Q_start2);
8224 DEFKEYWORD (Q_end1);
8225 DEFKEYWORD (Q_end2);
8226 defkeyword (&Q_if_, ":if");
8227 DEFKEYWORD (Q_if_not);
8228 DEFKEYWORD (Q_test_not);
8229 DEFKEYWORD (Q_count);
8230 DEFKEYWORD (Q_stable);
8231 DEFKEYWORD (Q_descend_structures);
8232
8233 DEFSUBR (Flength);
8234 DEFSUBR (Fcount);
8235 DEFSUBR (Fsubseq);
8236 DEFSUBR (Felt);
8237 DEFSUBR (Fcopy_tree);
8238 DEFSUBR (Fmember);
8239 DEFSUBR (Fmemq);
8240 DEFSUBR (FmemberX);
8241 DEFSUBR (Fadjoin);
8242 DEFSUBR (Fassoc);
8243 DEFSUBR (Fassq);
8244 DEFSUBR (FassocX);
8245 DEFSUBR (Frassoc);
8246 DEFSUBR (Frassq);
8247 DEFSUBR (FrassocX);
8248 DEFSUBR (Fposition);
8249 DEFSUBR (Ffind);
8250 DEFSUBR (FdeleteX);
8251 DEFSUBR (FremoveX);
8252 DEFSUBR (Fdelete_duplicates);
8253 DEFSUBR (Fremove_duplicates);
8254 DEFSUBR (Fnreverse);
8255 DEFSUBR (Freverse);
8256 DEFSUBR (Fmerge);
8257 DEFSUBR (FsortX);
8258 DEFSUBR (Ffill);
8259 DEFSUBR (Fmapconcat);
8260 DEFSUBR (FmapcarX);
8261 DEFSUBR (Fmapvector);
8262 DEFSUBR (Fmapcan);
8263 DEFSUBR (Fmapc);
8264 Ffset (intern ("mapc-internal"), Qmapc);
8265 Ffset (intern ("mapcar"), QmapcarX);
8266 DEFSUBR (Fmap);
8267 DEFSUBR (Fmap_into);
8268 DEFSUBR (Fsome);
8269 DEFSUBR (Fevery);
8270 DEFSUBR (Freduce);
8271 DEFSUBR (Freplace);
8272 DEFSUBR (Fnsubstitute);
8273 DEFSUBR (Fsubstitute);
8274 DEFSUBR (Fsublis);
8275 DEFSUBR (Fnsublis);
8276 DEFSUBR (Fsubst);
8277 DEFSUBR (Fnsubst);
8278 DEFSUBR (Ftree_equal);
8279 DEFSUBR (Fmismatch);
8280 DEFSUBR (Fsearch);
8281 DEFSUBR (Fintersection);
8282 DEFSUBR (Fnintersection);
8283 DEFSUBR (Fsubsetp);
8284 DEFSUBR (Fset_difference);
8285 DEFSUBR (Fnset_difference);
8286 DEFSUBR (Fnunion);
8287 DEFSUBR (Funion);
8288 DEFSUBR (Fset_exclusive_or);
8289 DEFSUBR (Fnset_exclusive_or);
8290 }