Mercurial > hg > xemacs-beta
comparison src/fns.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 | 10f179710250 |
children | e2fae7783046 |
comparison
equal
deleted
inserted
replaced
5606:7c383c5784ed | 5607:1a507c4c6c42 |
---|---|
50 #include "opaque.h" | 50 #include "opaque.h" |
51 | 51 |
52 /* NOTE: This symbol is also used in lread.c */ | 52 /* NOTE: This symbol is also used in lread.c */ |
53 #define FEATUREP_SYNTAX | 53 #define FEATUREP_SYNTAX |
54 | 54 |
55 Lisp_Object Qstring_lessp, Qmerge, Qfill, Qreplace, QassocX, QrassocX; | |
56 Lisp_Object Qposition, Qfind, QdeleteX, QremoveX, Qidentity, Qadjoin; | |
57 Lisp_Object Qvector, Qarray, Qbit_vector, QsortX, Q_from_end, Q_initial_value; | |
58 Lisp_Object Qmapconcat, QmapcarX, Qmapvector, Qmapcan, Qmapc, Qmap, Qmap_into; | |
59 Lisp_Object Qsome, Qevery, Qmaplist, Qmapl, Qmapcon, Qreduce, Qsubstitute; | |
60 Lisp_Object Q_start1, Q_start2, Q_end1, Q_end2, Q_if_, Q_if_not, Q_stable; | |
61 Lisp_Object Q_test_not, Q_count, Qnsubstitute, Qdelete_duplicates, Qmismatch; | |
62 Lisp_Object Q_descend_structures; | |
63 | |
64 Lisp_Object Qintersection, Qset_difference, Qnset_difference; | |
65 Lisp_Object Qnunion, Qnintersection, Qsubsetp, Qcar_less_than_car; | |
66 | |
67 Lisp_Object Qbase64_conversion_error; | |
68 | |
69 Lisp_Object Vpath_separator; | |
70 | |
71 extern Fixnum max_lisp_eval_depth; | 55 extern Fixnum max_lisp_eval_depth; |
72 extern int lisp_eval_depth; | 56 extern int lisp_eval_depth; |
73 | 57 |
74 Lisp_Object safe_copy_tree (Lisp_Object arg, Lisp_Object vecp, int depth); | 58 Lisp_Object Qmapl, Qmapcon, Qmaplist, Qbase64_conversion_error; |
75 | 59 |
76 static DOESNT_RETURN | 60 Lisp_Object Vpath_separator; |
77 mapping_interaction_error (Lisp_Object func, Lisp_Object object) | |
78 { | |
79 invalid_state_2 ("object modified while traversing it", func, object); | |
80 } | |
81 | |
82 static void | |
83 check_sequence_range (Lisp_Object sequence, Lisp_Object start, | |
84 Lisp_Object end, Lisp_Object length) | |
85 { | |
86 Lisp_Object args[] = { Qzero, start, NILP (end) ? length : end, length }; | |
87 | |
88 if (NILP (Fleq (countof (args), args))) | |
89 { | |
90 args_out_of_range_3 (sequence, start, end); | |
91 } | |
92 } | |
93 | |
94 static Lisp_Object | |
95 mark_bit_vector (Lisp_Object UNUSED (obj)) | |
96 { | |
97 return Qnil; | |
98 } | |
99 | |
100 static void | |
101 print_bit_vector (Lisp_Object obj, Lisp_Object printcharfun, | |
102 int UNUSED (escapeflag)) | |
103 { | |
104 Elemcount i; | |
105 Lisp_Bit_Vector *v = XBIT_VECTOR (obj); | |
106 Elemcount len = bit_vector_length (v); | |
107 Elemcount last = len; | |
108 | |
109 if (FIXNUMP (Vprint_length)) | |
110 last = min (len, XFIXNUM (Vprint_length)); | |
111 write_ascstring (printcharfun, "#*"); | |
112 for (i = 0; i < last; i++) | |
113 { | |
114 if (bit_vector_bit (v, i)) | |
115 write_ascstring (printcharfun, "1"); | |
116 else | |
117 write_ascstring (printcharfun, "0"); | |
118 } | |
119 | |
120 if (last != len) | |
121 write_ascstring (printcharfun, "..."); | |
122 } | |
123 | |
124 static int | |
125 bit_vector_equal (Lisp_Object obj1, Lisp_Object obj2, int UNUSED (depth), | |
126 int UNUSED (foldcase)) | |
127 { | |
128 Lisp_Bit_Vector *v1 = XBIT_VECTOR (obj1); | |
129 Lisp_Bit_Vector *v2 = XBIT_VECTOR (obj2); | |
130 | |
131 return ((bit_vector_length (v1) == bit_vector_length (v2)) && | |
132 !memcmp (v1->bits, v2->bits, | |
133 BIT_VECTOR_LONG_STORAGE (bit_vector_length (v1)) * | |
134 sizeof (long))); | |
135 } | |
136 | |
137 /* This needs to be algorithmically identical to internal_array_hash in | |
138 elhash.c when equalp is one, so arrays and bit vectors with the same | |
139 contents hash the same. It would be possible to enforce this by giving | |
140 internal_ARRAYLIKE_hash its own file and including it twice, but right | |
141 now that doesn't seem worth it. */ | |
142 static Hashcode | |
143 internal_bit_vector_equalp_hash (Lisp_Bit_Vector *v) | |
144 { | |
145 int ii, size = bit_vector_length (v); | |
146 Hashcode hash = 0; | |
147 | |
148 if (size <= 5) | |
149 { | |
150 for (ii = 0; ii < size; ii++) | |
151 { | |
152 hash = HASH2 | |
153 (hash, | |
154 FLOAT_HASHCODE_FROM_DOUBLE ((double) (bit_vector_bit (v, ii)))); | |
155 } | |
156 return hash; | |
157 } | |
158 | |
159 /* just pick five elements scattered throughout the array. | |
160 A slightly better approach would be to offset by some | |
161 noise factor from the points chosen below. */ | |
162 for (ii = 0; ii < 5; ii++) | |
163 hash = HASH2 (hash, | |
164 FLOAT_HASHCODE_FROM_DOUBLE | |
165 ((double) (bit_vector_bit (v, ii * size / 5)))); | |
166 | |
167 return hash; | |
168 } | |
169 | |
170 static Hashcode | |
171 bit_vector_hash (Lisp_Object obj, int UNUSED (depth), Boolint equalp) | |
172 { | |
173 Lisp_Bit_Vector *v = XBIT_VECTOR (obj); | |
174 if (equalp) | |
175 { | |
176 return HASH2 (bit_vector_length (v), | |
177 internal_bit_vector_equalp_hash (v)); | |
178 } | |
179 | |
180 return HASH2 (bit_vector_length (v), | |
181 memory_hash (v->bits, | |
182 BIT_VECTOR_LONG_STORAGE (bit_vector_length (v)) * | |
183 sizeof (long))); | |
184 } | |
185 | |
186 static Bytecount | |
187 size_bit_vector (Lisp_Object obj) | |
188 { | |
189 Lisp_Bit_Vector *v = XBIT_VECTOR (obj); | |
190 return FLEXIBLE_ARRAY_STRUCT_SIZEOF (Lisp_Bit_Vector, unsigned long, bits, | |
191 BIT_VECTOR_LONG_STORAGE (bit_vector_length (v))); | |
192 } | |
193 | |
194 static const struct memory_description bit_vector_description[] = { | |
195 { XD_END } | |
196 }; | |
197 | |
198 | |
199 DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT ("bit-vector", bit_vector, | |
200 mark_bit_vector, | |
201 print_bit_vector, 0, | |
202 bit_vector_equal, | |
203 bit_vector_hash, | |
204 bit_vector_description, | |
205 size_bit_vector, | |
206 Lisp_Bit_Vector); | |
207 | |
208 /* Various test functions for #'member*, #'assoc* and the other functions | |
209 that take both TEST and KEY arguments. */ | |
210 | |
211 Boolint | |
212 check_eq_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key), | |
213 Lisp_Object item, Lisp_Object elt) | |
214 { | |
215 return EQ (item, elt); | |
216 } | |
217 | |
218 static Boolint | |
219 check_eq_key (Lisp_Object UNUSED (test), Lisp_Object key, Lisp_Object item, | |
220 Lisp_Object elt) | |
221 { | |
222 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt)); | |
223 return EQ (item, elt); | |
224 } | |
225 | |
226 /* The next two are not used by #'member* and #'assoc*, since we can decide | |
227 on #'eq vs. #'equal when we have the type of ITEM. */ | |
228 static Boolint | |
229 check_eql_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key), | |
230 Lisp_Object elt1, Lisp_Object elt2) | |
231 { | |
232 return EQ (elt1, elt2) | |
233 || (NON_FIXNUM_NUMBER_P (elt1) && internal_equal (elt1, elt2, 0)); | |
234 } | |
235 | |
236 static Boolint | |
237 check_eql_key (Lisp_Object UNUSED (test), Lisp_Object key, Lisp_Object item, | |
238 Lisp_Object elt) | |
239 { | |
240 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt)); | |
241 return EQ (item, elt) | |
242 || (NON_FIXNUM_NUMBER_P (item) && internal_equal (item, elt, 0)); | |
243 } | |
244 | |
245 static Boolint | |
246 check_equal_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key), | |
247 Lisp_Object item, Lisp_Object elt) | |
248 { | |
249 return internal_equal (item, elt, 0); | |
250 } | |
251 | |
252 static Boolint | |
253 check_equal_key (Lisp_Object UNUSED (test), Lisp_Object key, Lisp_Object item, | |
254 Lisp_Object elt) | |
255 { | |
256 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt)); | |
257 return internal_equal (item, elt, 0); | |
258 } | |
259 | |
260 static Boolint | |
261 check_equalp_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key), | |
262 Lisp_Object item, Lisp_Object elt) | |
263 { | |
264 return internal_equalp (item, elt, 0); | |
265 } | |
266 | |
267 static Boolint | |
268 check_equalp_key (Lisp_Object UNUSED (test), Lisp_Object key, | |
269 Lisp_Object item, Lisp_Object elt) | |
270 { | |
271 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt)); | |
272 return internal_equalp (item, elt, 0); | |
273 } | |
274 | |
275 static Boolint | |
276 check_string_match_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key), | |
277 Lisp_Object item, Lisp_Object elt) | |
278 { | |
279 return !NILP (Fstring_match (item, elt, Qnil, Qnil)); | |
280 } | |
281 | |
282 static Boolint | |
283 check_string_match_key (Lisp_Object UNUSED (test), Lisp_Object key, | |
284 Lisp_Object item, Lisp_Object elt) | |
285 { | |
286 elt = IGNORE_MULTIPLE_VALUES (call1 (key, elt)); | |
287 return !NILP (Fstring_match (item, elt, Qnil, Qnil)); | |
288 } | |
289 | |
290 static Boolint | |
291 check_other_nokey (Lisp_Object test, Lisp_Object UNUSED (key), | |
292 Lisp_Object item, Lisp_Object elt) | |
293 { | |
294 Lisp_Object args[] = { test, item, elt }; | |
295 struct gcpro gcpro1; | |
296 | |
297 GCPRO1 (args[0]); | |
298 gcpro1.nvars = countof (args); | |
299 item = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args)); | |
300 UNGCPRO; | |
301 | |
302 return !NILP (item); | |
303 } | |
304 | |
305 static Boolint | |
306 check_other_key (Lisp_Object test, Lisp_Object key, | |
307 Lisp_Object item, Lisp_Object elt) | |
308 { | |
309 Lisp_Object args[] = { item, key, elt }; | |
310 struct gcpro gcpro1; | |
311 | |
312 GCPRO1 (args[0]); | |
313 gcpro1.nvars = countof (args); | |
314 args[2] = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args) - 1, args + 1)); | |
315 args[1] = item; | |
316 args[0] = test; | |
317 item = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args)); | |
318 UNGCPRO; | |
319 | |
320 return !NILP (item); | |
321 } | |
322 | |
323 static Boolint | |
324 check_if_nokey (Lisp_Object test, Lisp_Object UNUSED (key), | |
325 Lisp_Object UNUSED (item), Lisp_Object elt) | |
326 { | |
327 elt = IGNORE_MULTIPLE_VALUES (call1 (test, elt)); | |
328 return !NILP (elt); | |
329 } | |
330 | |
331 static Boolint | |
332 check_if_key (Lisp_Object test, Lisp_Object key, | |
333 Lisp_Object UNUSED (item), Lisp_Object elt) | |
334 { | |
335 Lisp_Object args[] = { key, elt }; | |
336 struct gcpro gcpro1; | |
337 | |
338 GCPRO1 (args[0]); | |
339 gcpro1.nvars = countof (args); | |
340 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args)); | |
341 args[0] = test; | |
342 elt = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args)); | |
343 UNGCPRO; | |
344 | |
345 return !NILP (elt); | |
346 } | |
347 | |
348 static Boolint | |
349 check_match_eq_key (Lisp_Object UNUSED (test), Lisp_Object key, | |
350 Lisp_Object elt1, Lisp_Object elt2) | |
351 { | |
352 Lisp_Object args[] = { key, elt1, elt2 }; | |
353 struct gcpro gcpro1; | |
354 | |
355 GCPRO1 (args[0]); | |
356 gcpro1.nvars = countof (args); | |
357 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args)); | |
358 args[1] = key; | |
359 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1)); | |
360 UNGCPRO; | |
361 | |
362 return EQ (args[0], args[1]); | |
363 } | |
364 | |
365 static Boolint | |
366 check_match_eql_key (Lisp_Object UNUSED (test), Lisp_Object key, | |
367 Lisp_Object elt1, Lisp_Object elt2) | |
368 { | |
369 Lisp_Object args[] = { key, elt1, elt2 }; | |
370 struct gcpro gcpro1; | |
371 | |
372 GCPRO1 (args[0]); | |
373 gcpro1.nvars = countof (args); | |
374 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args)); | |
375 args[1] = key; | |
376 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1)); | |
377 UNGCPRO; | |
378 | |
379 return EQ (args[0], args[1]) || | |
380 (NON_FIXNUM_NUMBER_P (args[0]) && internal_equal (args[0], args[1], 0)); | |
381 } | |
382 | |
383 static Boolint | |
384 check_match_equal_key (Lisp_Object UNUSED (test), Lisp_Object key, | |
385 Lisp_Object elt1, Lisp_Object elt2) | |
386 { | |
387 Lisp_Object args[] = { key, elt1, elt2 }; | |
388 struct gcpro gcpro1; | |
389 | |
390 GCPRO1 (args[0]); | |
391 gcpro1.nvars = countof (args); | |
392 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args)); | |
393 args[1] = key; | |
394 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1)); | |
395 UNGCPRO; | |
396 | |
397 return internal_equal (args[0], args[1], 0); | |
398 } | |
399 | |
400 static Boolint | |
401 check_match_equalp_key (Lisp_Object UNUSED (test), Lisp_Object key, | |
402 Lisp_Object elt1, Lisp_Object elt2) | |
403 { | |
404 Lisp_Object args[] = { key, elt1, elt2 }; | |
405 struct gcpro gcpro1; | |
406 | |
407 GCPRO1 (args[0]); | |
408 gcpro1.nvars = countof (args); | |
409 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args)); | |
410 args[1] = key; | |
411 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1)); | |
412 UNGCPRO; | |
413 | |
414 return internal_equalp (args[0], args[1], 0); | |
415 } | |
416 | |
417 static Boolint | |
418 check_match_other_key (Lisp_Object test, Lisp_Object key, | |
419 Lisp_Object elt1, Lisp_Object elt2) | |
420 { | |
421 Lisp_Object args[] = { key, elt1, elt2 }; | |
422 struct gcpro gcpro1; | |
423 | |
424 GCPRO1 (args[0]); | |
425 gcpro1.nvars = countof (args); | |
426 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args)); | |
427 args[1] = key; | |
428 args[2] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1)); | |
429 args[1] = args[0]; | |
430 args[0] = test; | |
431 | |
432 elt1 = IGNORE_MULTIPLE_VALUES (Ffuncall (countof (args), args)); | |
433 UNGCPRO; | |
434 | |
435 return !NILP (elt1); | |
436 } | |
437 | |
438 static Boolint | |
439 check_lss_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key), | |
440 Lisp_Object elt1, Lisp_Object elt2) | |
441 { | |
442 return bytecode_arithcompare (elt1, elt2) < 0; | |
443 } | |
444 | |
445 static Boolint | |
446 check_lss_key (Lisp_Object UNUSED (test), Lisp_Object key, | |
447 Lisp_Object elt1, Lisp_Object elt2) | |
448 { | |
449 Lisp_Object args[] = { key, elt1, elt2 }; | |
450 struct gcpro gcpro1; | |
451 | |
452 GCPRO1 (args[0]); | |
453 gcpro1.nvars = countof (args); | |
454 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args)); | |
455 args[1] = key; | |
456 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1)); | |
457 UNGCPRO; | |
458 | |
459 return bytecode_arithcompare (args[0], args[1]) < 0; | |
460 } | |
461 | |
462 Boolint | |
463 check_lss_key_car (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key), | |
464 Lisp_Object elt1, Lisp_Object elt2) | |
465 { | |
466 struct gcpro gcpro1, gcpro2; | |
467 | |
468 GCPRO2 (elt1, elt2); | |
469 elt1 = CONSP (elt1) ? XCAR (elt1) : Fcar (elt1); | |
470 elt2 = CONSP (elt2) ? XCAR (elt2) : Fcar (elt2); | |
471 UNGCPRO; | |
472 | |
473 return bytecode_arithcompare (elt1, elt2) < 0; | |
474 } | |
475 | |
476 Boolint | |
477 check_string_lessp_nokey (Lisp_Object UNUSED (test), Lisp_Object UNUSED (key), | |
478 Lisp_Object elt1, Lisp_Object elt2) | |
479 { | |
480 return !NILP (Fstring_lessp (elt1, elt2)); | |
481 } | |
482 | |
483 static Boolint | |
484 check_string_lessp_key (Lisp_Object UNUSED (test), Lisp_Object key, | |
485 Lisp_Object elt1, Lisp_Object elt2) | |
486 { | |
487 Lisp_Object args[] = { key, elt1, elt2 }; | |
488 struct gcpro gcpro1; | |
489 | |
490 GCPRO1 (args[0]); | |
491 gcpro1.nvars = countof (args); | |
492 args[0] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args)); | |
493 args[1] = key; | |
494 args[1] = IGNORE_MULTIPLE_VALUES (Ffuncall (2, args + 1)); | |
495 UNGCPRO; | |
496 | |
497 return !NILP (Fstring_lessp (args[0], args[1])); | |
498 } | |
499 | |
500 static Boolint | |
501 check_string_lessp_key_car (Lisp_Object UNUSED (test), | |
502 Lisp_Object UNUSED (key), | |
503 Lisp_Object elt1, Lisp_Object elt2) | |
504 { | |
505 struct gcpro gcpro1, gcpro2; | |
506 | |
507 GCPRO2 (elt1, elt2); | |
508 elt1 = CONSP (elt1) ? XCAR (elt1) : Fcar (elt1); | |
509 elt2 = CONSP (elt2) ? XCAR (elt2) : Fcar (elt2); | |
510 UNGCPRO; | |
511 | |
512 return !NILP (Fstring_lessp (elt1, elt2)); | |
513 } | |
514 | |
515 static check_test_func_t | |
516 get_check_match_function_1 (Lisp_Object item, | |
517 Lisp_Object *test_inout, Lisp_Object test_not, | |
518 Lisp_Object if_, Lisp_Object if_not, | |
519 Lisp_Object key, Boolint *test_not_unboundp_out, | |
520 check_test_func_t *test_func_out) | |
521 { | |
522 Lisp_Object test = *test_inout; | |
523 check_test_func_t result = NULL, test_func = NULL; | |
524 Boolint force_if = 0; | |
525 | |
526 if (!NILP (if_)) | |
527 { | |
528 if (!(NILP (test) && NILP (test_not) && NILP (if_not))) | |
529 { | |
530 invalid_argument ("only one keyword among :test :test-not " | |
531 ":if :if-not allowed", if_); | |
532 } | |
533 | |
534 test = *test_inout = if_; | |
535 force_if = 1; | |
536 } | |
537 else if (!NILP (if_not)) | |
538 { | |
539 if (!(NILP (test) && NILP (test_not))) | |
540 { | |
541 invalid_argument ("only one keyword among :test :test-not " | |
542 ":if :if-not allowed", if_not); | |
543 } | |
544 | |
545 test_not = if_not; | |
546 force_if = 1; | |
547 } | |
548 | |
549 if (NILP (test)) | |
550 { | |
551 if (!NILP (test_not)) | |
552 { | |
553 test = *test_inout = test_not; | |
554 if (NULL != test_not_unboundp_out) | |
555 { | |
556 *test_not_unboundp_out = 0; | |
557 } | |
558 } | |
559 else | |
560 { | |
561 test = Qeql; | |
562 if (NULL != test_not_unboundp_out) | |
563 { | |
564 *test_not_unboundp_out = 1; | |
565 } | |
566 } | |
567 } | |
568 else if (!NILP (test_not)) | |
569 { | |
570 invalid_argument_2 ("conflicting :test and :test-not keyword arguments", | |
571 test, test_not); | |
572 } | |
573 | |
574 test = indirect_function (test, 1); | |
575 | |
576 if (NILP (key) || | |
577 EQ (indirect_function (key, 1), XSYMBOL_FUNCTION (Qidentity))) | |
578 { | |
579 key = Qidentity; | |
580 } | |
581 | |
582 if (force_if) | |
583 { | |
584 result = EQ (key, Qidentity) ? check_if_nokey : check_if_key; | |
585 | |
586 if (NULL != test_func_out) | |
587 { | |
588 *test_func_out = result; | |
589 } | |
590 | |
591 return result; | |
592 } | |
593 | |
594 if (!UNBOUNDP (item) && EQ (test, XSYMBOL_FUNCTION (Qeql))) | |
595 { | |
596 test = XSYMBOL_FUNCTION (NON_FIXNUM_NUMBER_P (item) ? Qequal : Qeq); | |
597 } | |
598 | |
599 #define FROB(known_test, eq_condition) \ | |
600 if (EQ (test, XSYMBOL_FUNCTION (Q##known_test))) do \ | |
601 { \ | |
602 if (eq_condition) \ | |
603 { \ | |
604 test = XSYMBOL_FUNCTION (Qeq); \ | |
605 goto force_eq_check; \ | |
606 } \ | |
607 \ | |
608 if (!EQ (Qidentity, key)) \ | |
609 { \ | |
610 test_func = check_##known_test##_key; \ | |
611 result = check_match_##known_test##_key; \ | |
612 } \ | |
613 else \ | |
614 { \ | |
615 result = test_func = check_##known_test##_nokey; \ | |
616 } \ | |
617 } while (0) | |
618 | |
619 FROB (eql, 0); | |
620 else if (SUBRP (test)) | |
621 { | |
622 force_eq_check: | |
623 FROB (eq, 0); | |
624 else FROB (equal, (SYMBOLP (item) || FIXNUMP (item) || CHARP (item))); | |
625 else FROB (equalp, (SYMBOLP (item))); | |
626 else if (EQ (test, XSYMBOL_FUNCTION (Qstring_match))) | |
627 { | |
628 if (EQ (Qidentity, key)) | |
629 { | |
630 test_func = result = check_string_match_nokey; | |
631 } | |
632 else | |
633 { | |
634 test_func = check_string_match_key; | |
635 result = check_other_key; | |
636 } | |
637 } | |
638 } | |
639 | |
640 if (NULL == result) | |
641 { | |
642 if (EQ (Qidentity, key)) | |
643 { | |
644 test_func = result = check_other_nokey; | |
645 } | |
646 else | |
647 { | |
648 test_func = check_other_key; | |
649 result = check_match_other_key; | |
650 } | |
651 } | |
652 | |
653 if (NULL != test_func_out) | |
654 { | |
655 *test_func_out = test_func; | |
656 } | |
657 | |
658 return result; | |
659 } | |
660 #undef FROB | |
661 | |
662 /* Given TEST, TEST_NOT, IF, IF_NOT, KEY, and ITEM, return a C function | |
663 pointer appropriate for use in deciding whether a given element of a | |
664 sequence satisfies TEST. | |
665 | |
666 Set *test_not_unboundp_out to 1 if TEST_NOT was not bound; set it to zero | |
667 if it was bound, and set *test_inout to the value it was bound to. If | |
668 TEST was not bound, leave *test_inout alone; the value is not used by | |
669 check_eq_*key() or check_equal_*key(), which are the defaults, depending | |
670 on the type of ITEM. | |
671 | |
672 The returned function takes arguments (TEST, KEY, ITEM, ELT), where ITEM | |
673 is the item being searched for and ELT is the element of the sequence | |
674 being examined. | |
675 | |
676 Error if both TEST and TEST_NOT were specified, which Common Lisp says is | |
677 undefined behaviour. */ | |
678 | |
679 static check_test_func_t | |
680 get_check_test_function (Lisp_Object item, | |
681 Lisp_Object *test_inout, Lisp_Object test_not, | |
682 Lisp_Object if_, Lisp_Object if_not, | |
683 Lisp_Object key, Boolint *test_not_unboundp_out) | |
684 { | |
685 check_test_func_t result = NULL; | |
686 get_check_match_function_1 (item, test_inout, test_not, if_, if_not, | |
687 key, test_not_unboundp_out, &result); | |
688 return result; | |
689 } | |
690 | |
691 /* Given TEST, TEST_NOT, IF, IF_NOT and KEY, return a C function pointer | |
692 appropriate for use in deciding whether two given elements of a sequence | |
693 satisfy TEST. | |
694 | |
695 Set *test_not_unboundp_out to 1 if TEST_NOT was not bound; set it to zero | |
696 if it was bound, and set *test_inout to the value it was bound to. If | |
697 TEST was not bound, leave *test_inout alone; the value is not used by | |
698 check_eql_*key(). | |
699 | |
700 The returned function takes arguments (TEST, KEY, ELT1, ELT2), where ELT1 | |
701 and ELT2 are elements of the sequence being examined. | |
702 | |
703 The value that would be given by get_check_test_function() is returned in | |
704 *TEST_FUNC_OUT, which allows calling functions to do their own key checks | |
705 if they're processing one element at a time. | |
706 | |
707 Error if both TEST and TEST_NOT were specified, which Common Lisp says is | |
708 undefined behaviour. */ | |
709 | |
710 static check_test_func_t | |
711 get_check_match_function (Lisp_Object *test_inout, Lisp_Object test_not, | |
712 Lisp_Object if_, Lisp_Object if_not, | |
713 Lisp_Object key, Boolint *test_not_unboundp_out, | |
714 check_test_func_t *test_func_out) | |
715 { | |
716 return get_check_match_function_1 (Qunbound, test_inout, test_not, | |
717 if_, if_not, key, | |
718 test_not_unboundp_out, test_func_out); | |
719 } | |
720 | |
721 /* Given PREDICATE and KEY, return a C function pointer appropriate for use | |
722 in deciding whether one given element of a sequence is less than | |
723 another. */ | |
724 | |
725 static check_test_func_t | |
726 get_merge_predicate (Lisp_Object predicate, Lisp_Object key) | |
727 { | |
728 predicate = indirect_function (predicate, 1); | |
729 | |
730 if (NILP (key)) | |
731 { | |
732 key = Qidentity; | |
733 } | |
734 else | |
735 { | |
736 key = indirect_function (key, 1); | |
737 if (EQ (key, XSYMBOL_FUNCTION (Qidentity))) | |
738 { | |
739 key = Qidentity; | |
740 } | |
741 } | |
742 | |
743 if (EQ (key, Qidentity) && EQ (predicate, | |
744 XSYMBOL_FUNCTION (Qcar_less_than_car))) | |
745 { | |
746 key = XSYMBOL_FUNCTION (Qcar); | |
747 predicate = XSYMBOL_FUNCTION (Qlss); | |
748 } | |
749 | |
750 if (EQ (predicate, XSYMBOL_FUNCTION (Qlss))) | |
751 { | |
752 if (EQ (key, Qidentity)) | |
753 { | |
754 return check_lss_nokey; | |
755 } | |
756 | |
757 if (EQ (key, XSYMBOL_FUNCTION (Qcar))) | |
758 { | |
759 return check_lss_key_car; | |
760 } | |
761 | |
762 return check_lss_key; | |
763 } | |
764 | |
765 if (EQ (predicate, XSYMBOL_FUNCTION (Qstring_lessp))) | |
766 { | |
767 if (EQ (key, Qidentity)) | |
768 { | |
769 return check_string_lessp_nokey; | |
770 } | |
771 | |
772 if (EQ (key, XSYMBOL_FUNCTION (Qcar))) | |
773 { | |
774 return check_string_lessp_key_car; | |
775 } | |
776 | |
777 return check_string_lessp_key; | |
778 } | |
779 | |
780 if (EQ (key, Qidentity)) | |
781 { | |
782 return check_other_nokey; | |
783 } | |
784 | |
785 return check_match_other_key; | |
786 } | |
787 | 61 |
788 DEFUN ("identity", Fidentity, 1, 1, 0, /* | 62 DEFUN ("identity", Fidentity, 1, 1, 0, /* |
789 Return the argument unchanged. | 63 Return the argument unchanged. |
790 */ | 64 */ |
791 (arg)) | 65 (arg)) |
845 (Qinvalid_argument, seq, | 119 (Qinvalid_argument, seq, |
846 "As of 20.3, `%s' no longer works with compiled-function objects", | 120 "As of 20.3, `%s' no longer works with compiled-function objects", |
847 function); | 121 function); |
848 } | 122 } |
849 | 123 |
850 DEFUN ("length", Flength, 1, 1, 0, /* | |
851 Return the length of vector, bit vector, list or string SEQUENCE. | |
852 */ | |
853 (sequence)) | |
854 { | |
855 retry: | |
856 if (STRINGP (sequence)) | |
857 return make_fixnum (string_char_length (sequence)); | |
858 else if (CONSP (sequence)) | |
859 { | |
860 Elemcount len; | |
861 GET_EXTERNAL_LIST_LENGTH (sequence, len); | |
862 return make_fixnum (len); | |
863 } | |
864 else if (VECTORP (sequence)) | |
865 return make_fixnum (XVECTOR_LENGTH (sequence)); | |
866 else if (NILP (sequence)) | |
867 return Qzero; | |
868 else if (BIT_VECTORP (sequence)) | |
869 return make_fixnum (bit_vector_length (XBIT_VECTOR (sequence))); | |
870 else | |
871 { | |
872 check_losing_bytecode ("length", sequence); | |
873 sequence = wrong_type_argument (Qsequencep, sequence); | |
874 goto retry; | |
875 } | |
876 } | |
877 | |
878 DEFUN ("safe-length", Fsafe_length, 1, 1, 0, /* | 124 DEFUN ("safe-length", Fsafe_length, 1, 1, 0, /* |
879 Return the length of a list, but avoid error or infinite loop. | 125 Return the length of a list, but avoid error or infinite loop. |
880 This function never gets an error. If LIST is not really a list, | 126 This function never gets an error. If LIST is not really a list, |
881 it returns 0. If LIST is circular, it returns a finite value | 127 it returns 0. If LIST is circular, it returns a finite value |
882 which is at least the number of distinct elements. | 128 which is at least the number of distinct elements. |
922 { | 168 { |
923 signal_malformed_list_error (list); | 169 signal_malformed_list_error (list); |
924 } | 170 } |
925 | 171 |
926 return EQ (hare, tortoise) && len != 0 ? Qnil : make_fixnum (len); | 172 return EQ (hare, tortoise) && len != 0 ? Qnil : make_fixnum (len); |
927 } | |
928 | |
929 static Lisp_Object string_count_from_end (Lisp_Object, Lisp_Object , | |
930 check_test_func_t, Boolint, | |
931 Lisp_Object, Lisp_Object, | |
932 Lisp_Object, Lisp_Object); | |
933 | |
934 static Lisp_Object list_count_from_end (Lisp_Object, Lisp_Object, | |
935 check_test_func_t, Boolint, | |
936 Lisp_Object, Lisp_Object, | |
937 Lisp_Object, Lisp_Object); | |
938 | |
939 /* Count the number of occurrences of ITEM in SEQUENCE; if SEQUENCE is a | |
940 list, store the cons cell of which the car is the last ITEM in SEQUENCE, | |
941 at the address given by tail_out. */ | |
942 | |
943 static Lisp_Object | |
944 count_with_tail (Lisp_Object *tail_out, int nargs, Lisp_Object *args, | |
945 Lisp_Object caller) | |
946 { | |
947 Lisp_Object item = args[0], sequence = args[1]; | |
948 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, encountered = 0; | |
949 Elemcount len, ii = 0, counting = MOST_POSITIVE_FIXNUM; | |
950 Boolint test_not_unboundp = 1; | |
951 check_test_func_t check_test = NULL; | |
952 | |
953 PARSE_KEYWORDS_8 (caller, nargs, args, 9, | |
954 (test, key, start, end, from_end, test_not, count, | |
955 if_, if_not), (start = Qzero), 2, 0); | |
956 | |
957 CHECK_SEQUENCE (sequence); | |
958 CHECK_NATNUM (start); | |
959 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start); | |
960 | |
961 if (!NILP (end)) | |
962 { | |
963 CHECK_NATNUM (end); | |
964 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end); | |
965 } | |
966 | |
967 if (!NILP (count)) | |
968 { | |
969 CHECK_INTEGER (count); | |
970 counting = BIGNUMP (count) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (count); | |
971 | |
972 /* Our callers should have filtered out non-positive COUNT. */ | |
973 assert (counting >= 0); | |
974 /* And we're not prepared to handle COUNT from any other caller at the | |
975 moment. */ | |
976 assert (EQ (caller, QremoveX)|| EQ (caller, QdeleteX)); | |
977 } | |
978 | |
979 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
980 key, &test_not_unboundp); | |
981 | |
982 *tail_out = Qnil; | |
983 | |
984 if (CONSP (sequence)) | |
985 { | |
986 if (EQ (caller, Qcount) && !NILP (from_end) | |
987 && (!EQ (key, Qnil) || | |
988 check_test == check_other_nokey || check_test == check_if_nokey)) | |
989 { | |
990 /* #'count, #'count-if, and #'count-if-not are documented to have | |
991 a given traversal order if :from-end t is passed in, even | |
992 though forward traversal of the sequence has the same result | |
993 and is algorithmically less expensive for lists and strings. | |
994 This order isn't necessary for other callers, though. */ | |
995 return list_count_from_end (item, sequence, check_test, | |
996 test_not_unboundp, test, key, | |
997 start, end); | |
998 } | |
999 | |
1000 /* If COUNT is non-nil and FROM-END is t, we can give the tail | |
1001 containing the last match, since that's what #'remove* is | |
1002 interested in (a zero or negative COUNT won't ever reach | |
1003 count_with_tail(), our callers will return immediately on seeing | |
1004 it). */ | |
1005 if (!NILP (count) && !NILP (from_end)) | |
1006 { | |
1007 counting = MOST_POSITIVE_FIXNUM; | |
1008 } | |
1009 | |
1010 { | |
1011 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail) | |
1012 { | |
1013 if (!(ii < ending)) | |
1014 { | |
1015 break; | |
1016 } | |
1017 | |
1018 if (starting <= ii && | |
1019 check_test (test, key, item, elt) == test_not_unboundp) | |
1020 { | |
1021 encountered++; | |
1022 *tail_out = tail; | |
1023 | |
1024 if (encountered == counting) | |
1025 { | |
1026 break; | |
1027 } | |
1028 } | |
1029 | |
1030 ii++; | |
1031 } | |
1032 END_GC_EXTERNAL_LIST_LOOP (elt); | |
1033 } | |
1034 | |
1035 if ((ii < starting || (ii < ending && !NILP (end))) && | |
1036 encountered != counting) | |
1037 { | |
1038 check_sequence_range (args[1], start, end, Flength (args[1])); | |
1039 } | |
1040 } | |
1041 else if (STRINGP (sequence)) | |
1042 { | |
1043 Ibyte *startp = XSTRING_DATA (sequence), *cursor = startp; | |
1044 Bytecount byte_len = XSTRING_LENGTH (sequence), cursor_offset = 0; | |
1045 Lisp_Object character = Qnil; | |
1046 | |
1047 if (EQ (caller, Qcount) && !NILP (from_end) | |
1048 && (!EQ (key, Qnil) || | |
1049 check_test == check_other_nokey || check_test == check_if_nokey)) | |
1050 { | |
1051 /* See comment above in the list code. */ | |
1052 return string_count_from_end (item, sequence, | |
1053 check_test, test_not_unboundp, | |
1054 test, key, start, end); | |
1055 } | |
1056 | |
1057 while (cursor_offset < byte_len && ii < ending && encountered < counting) | |
1058 { | |
1059 if (ii >= starting) | |
1060 { | |
1061 character = make_char (itext_ichar (cursor)); | |
1062 | |
1063 if (check_test (test, key, item, character) | |
1064 == test_not_unboundp) | |
1065 { | |
1066 encountered++; | |
1067 } | |
1068 | |
1069 startp = XSTRING_DATA (sequence); | |
1070 cursor = startp + cursor_offset; | |
1071 if (byte_len != XSTRING_LENGTH (sequence) | |
1072 || !valid_ibyteptr_p (cursor)) | |
1073 { | |
1074 mapping_interaction_error (caller, sequence); | |
1075 } | |
1076 } | |
1077 | |
1078 INC_IBYTEPTR (cursor); | |
1079 cursor_offset = cursor - startp; | |
1080 ii++; | |
1081 } | |
1082 | |
1083 if (ii < starting || (ii < ending && !NILP (end))) | |
1084 { | |
1085 check_sequence_range (sequence, start, end, Flength (sequence)); | |
1086 } | |
1087 } | |
1088 else | |
1089 { | |
1090 Lisp_Object object = Qnil; | |
1091 | |
1092 len = XFIXNUM (Flength (sequence)); | |
1093 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
1094 | |
1095 ending = min (ending, len); | |
1096 if (0 == len) | |
1097 { | |
1098 /* Catches the case where we have nil. */ | |
1099 return make_integer (encountered); | |
1100 } | |
1101 | |
1102 if (NILP (from_end)) | |
1103 { | |
1104 for (ii = starting; ii < ending && encountered < counting; ii++) | |
1105 { | |
1106 object = Faref (sequence, make_fixnum (ii)); | |
1107 if (check_test (test, key, item, object) == test_not_unboundp) | |
1108 { | |
1109 encountered++; | |
1110 } | |
1111 } | |
1112 } | |
1113 else | |
1114 { | |
1115 for (ii = ending - 1; ii >= starting && encountered < counting; ii--) | |
1116 { | |
1117 object = Faref (sequence, make_fixnum (ii)); | |
1118 if (check_test (test, key, item, object) == test_not_unboundp) | |
1119 { | |
1120 encountered++; | |
1121 } | |
1122 } | |
1123 } | |
1124 } | |
1125 | |
1126 return make_integer (encountered); | |
1127 } | |
1128 | |
1129 static Lisp_Object | |
1130 list_count_from_end (Lisp_Object item, Lisp_Object sequence, | |
1131 check_test_func_t check_test, Boolint test_not_unboundp, | |
1132 Lisp_Object test, Lisp_Object key, | |
1133 Lisp_Object start, Lisp_Object end) | |
1134 { | |
1135 Elemcount length = XFIXNUM (Flength (sequence)), ii = 0, starting = XFIXNUM (start); | |
1136 Elemcount ending = NILP (end) ? length : XFIXNUM (end), encountered = 0; | |
1137 Lisp_Object *storage; | |
1138 struct gcpro gcpro1; | |
1139 | |
1140 check_sequence_range (sequence, start, end, make_integer (length)); | |
1141 | |
1142 storage = alloca_array (Lisp_Object, ending - starting); | |
1143 | |
1144 { | |
1145 EXTERNAL_LIST_LOOP_2 (elt, sequence) | |
1146 { | |
1147 if (starting <= ii && ii < ending) | |
1148 { | |
1149 storage[ii - starting] = elt; | |
1150 } | |
1151 ii++; | |
1152 } | |
1153 } | |
1154 | |
1155 GCPRO1 (storage[0]); | |
1156 gcpro1.nvars = ending - starting; | |
1157 | |
1158 for (ii = ending - 1; ii >= starting; ii--) | |
1159 { | |
1160 if (check_test (test, key, item, storage[ii - starting]) | |
1161 == test_not_unboundp) | |
1162 { | |
1163 encountered++; | |
1164 } | |
1165 } | |
1166 | |
1167 UNGCPRO; | |
1168 | |
1169 return make_integer (encountered); | |
1170 } | |
1171 | |
1172 static Lisp_Object | |
1173 string_count_from_end (Lisp_Object item, Lisp_Object sequence, | |
1174 check_test_func_t check_test, Boolint test_not_unboundp, | |
1175 Lisp_Object test, Lisp_Object key, | |
1176 Lisp_Object start, Lisp_Object end) | |
1177 { | |
1178 Elemcount length = string_char_length (sequence), ii = 0; | |
1179 Elemcount starting = XFIXNUM (start), ending = NILP (end) ? length : XFIXNUM (end); | |
1180 Elemcount encountered = 0; | |
1181 Ibyte *cursor = XSTRING_DATA (sequence); | |
1182 Ibyte *endp = cursor + XSTRING_LENGTH (sequence); | |
1183 Ichar *storage; | |
1184 | |
1185 check_sequence_range (sequence, start, end, make_integer (length)); | |
1186 | |
1187 storage = alloca_array (Ichar, ending - starting); | |
1188 | |
1189 while (cursor < endp && ii < ending) | |
1190 { | |
1191 if (starting <= ii && ii < ending) | |
1192 { | |
1193 storage [ii - starting] = itext_ichar (cursor); | |
1194 } | |
1195 | |
1196 ii++; | |
1197 INC_IBYTEPTR (cursor); | |
1198 } | |
1199 | |
1200 for (ii = ending - 1; ii >= starting; ii--) | |
1201 { | |
1202 if (check_test (test, key, item, make_char (storage [ii - starting])) | |
1203 == test_not_unboundp) | |
1204 { | |
1205 encountered++; | |
1206 } | |
1207 } | |
1208 | |
1209 return make_integer (encountered); | |
1210 } | |
1211 | |
1212 DEFUN ("count", Fcount, 2, MANY, 0, /* | |
1213 Count the number of occurrences of ITEM in SEQUENCE. | |
1214 | |
1215 See `remove*' for the meaning of the keywords. | |
1216 | |
1217 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) END FROM-END TEST-NOT) | |
1218 */ | |
1219 (int nargs, Lisp_Object *args)) | |
1220 { | |
1221 Lisp_Object tail = Qnil; | |
1222 | |
1223 /* count_with_tail() accepts more keywords than we do, check those we've | |
1224 been given. */ | |
1225 PARSE_KEYWORDS (Fcount, nargs, args, 8, | |
1226 (test, test_not, if_, if_not, key, start, end, from_end), | |
1227 NULL); | |
1228 | |
1229 return count_with_tail (&tail, nargs, args, Qcount); | |
1230 } | 173 } |
1231 | 174 |
1232 /*** string functions. ***/ | 175 /*** string functions. ***/ |
1233 | 176 |
1234 DEFUN ("string-equal", Fstring_equal, 2, 2, 0, /* | 177 DEFUN ("string-equal", Fstring_equal, 2, 2, 0, /* |
1834 XCAR (tail) = Fcons (XCAR (car), XCDR (car)); | 777 XCAR (tail) = Fcons (XCAR (car), XCDR (car)); |
1835 } | 778 } |
1836 return alist; | 779 return alist; |
1837 } | 780 } |
1838 | 781 |
1839 DEFUN ("copy-tree", Fcopy_tree, 1, 2, 0, /* | |
1840 Return a copy of a list and substructures. | |
1841 The argument is copied, and any lists contained within it are copied | |
1842 recursively. Circularities and shared substructures are not preserved. | |
1843 Second arg VECP causes vectors to be copied, too. Strings and bit vectors | |
1844 are not copied. | |
1845 */ | |
1846 (arg, vecp)) | |
1847 { | |
1848 return safe_copy_tree (arg, vecp, 0); | |
1849 } | |
1850 | |
1851 Lisp_Object | |
1852 safe_copy_tree (Lisp_Object arg, Lisp_Object vecp, int depth) | |
1853 { | |
1854 if (depth + lisp_eval_depth > max_lisp_eval_depth) | |
1855 stack_overflow ("Stack overflow in copy-tree", arg); | |
1856 | |
1857 if (CONSP (arg)) | |
1858 { | |
1859 Lisp_Object rest; | |
1860 rest = arg = Fcopy_sequence (arg); | |
1861 while (CONSP (rest)) | |
1862 { | |
1863 Lisp_Object elt = XCAR (rest); | |
1864 QUIT; | |
1865 if (CONSP (elt) || VECTORP (elt)) | |
1866 XCAR (rest) = safe_copy_tree (elt, vecp, depth + 1); | |
1867 if (VECTORP (XCDR (rest))) /* hack for (a b . [c d]) */ | |
1868 XCDR (rest) = safe_copy_tree (XCDR (rest), vecp, depth +1); | |
1869 rest = XCDR (rest); | |
1870 } | |
1871 } | |
1872 else if (VECTORP (arg) && ! NILP (vecp)) | |
1873 { | |
1874 int i = XVECTOR_LENGTH (arg); | |
1875 int j; | |
1876 arg = Fcopy_sequence (arg); | |
1877 for (j = 0; j < i; j++) | |
1878 { | |
1879 Lisp_Object elt = XVECTOR_DATA (arg) [j]; | |
1880 QUIT; | |
1881 if (CONSP (elt) || VECTORP (elt)) | |
1882 XVECTOR_DATA (arg) [j] = safe_copy_tree (elt, vecp, depth + 1); | |
1883 } | |
1884 } | |
1885 return arg; | |
1886 } | |
1887 | |
1888 DEFUN ("subseq", Fsubseq, 2, 3, 0, /* | |
1889 Return the subsequence of SEQUENCE starting at START and ending before END. | |
1890 END may be omitted; then the subsequence runs to the end of SEQUENCE. | |
1891 | |
1892 If START or END is negative, it counts from the end, in contravention of | |
1893 Common Lisp. | |
1894 The returned subsequence is always of the same type as SEQUENCE. | |
1895 If SEQUENCE is a string, relevant parts of the string-extent-data | |
1896 are copied to the new string. | |
1897 | |
1898 See also `substring-no-properties', which only operates on strings, and does | |
1899 not copy extent data. | |
1900 */ | |
1901 (sequence, start, end)) | |
1902 { | |
1903 Elemcount len, ss, ee = MOST_POSITIVE_FIXNUM, ii; | |
1904 Lisp_Object result = Qnil; | |
1905 | |
1906 CHECK_SEQUENCE (sequence); | |
1907 CHECK_FIXNUM (start); | |
1908 ss = XFIXNUM (start); | |
1909 | |
1910 if (!NILP (end)) | |
1911 { | |
1912 CHECK_FIXNUM (end); | |
1913 ee = XFIXNUM (end); | |
1914 } | |
1915 | |
1916 if (STRINGP (sequence)) | |
1917 { | |
1918 Bytecount bstart, blen; | |
1919 | |
1920 get_string_range_char (sequence, start, end, &ss, &ee, | |
1921 GB_HISTORICAL_STRING_BEHAVIOR); | |
1922 bstart = string_index_char_to_byte (sequence, ss); | |
1923 blen = string_offset_char_to_byte_len (sequence, bstart, ee - ss); | |
1924 | |
1925 result = make_string (XSTRING_DATA (sequence) + bstart, blen); | |
1926 /* Copy any applicable extent information into the new string. */ | |
1927 copy_string_extents (result, sequence, 0, bstart, blen); | |
1928 } | |
1929 else if (CONSP (sequence)) | |
1930 { | |
1931 Lisp_Object result_tail, saved = sequence; | |
1932 | |
1933 if (ss < 0 || ee < 0) | |
1934 { | |
1935 len = XFIXNUM (Flength (sequence)); | |
1936 if (ss < 0) | |
1937 { | |
1938 ss = len + ss; | |
1939 start = make_integer (ss); | |
1940 } | |
1941 | |
1942 if (ee < 0) | |
1943 { | |
1944 ee = len + ee; | |
1945 end = make_integer (ee); | |
1946 } | |
1947 else | |
1948 { | |
1949 ee = min (ee, len); | |
1950 } | |
1951 } | |
1952 | |
1953 if (0 != ss) | |
1954 { | |
1955 sequence = Fnthcdr (make_fixnum (ss), sequence); | |
1956 } | |
1957 | |
1958 ii = ss + 1; | |
1959 | |
1960 if (ss < ee && !NILP (sequence)) | |
1961 { | |
1962 result = result_tail = Fcons (Fcar (sequence), Qnil); | |
1963 sequence = Fcdr (sequence); | |
1964 | |
1965 { | |
1966 EXTERNAL_LIST_LOOP_2 (elt, sequence) | |
1967 { | |
1968 if (!(ii < ee)) | |
1969 { | |
1970 break; | |
1971 } | |
1972 | |
1973 XSETCDR (result_tail, Fcons (elt, Qnil)); | |
1974 result_tail = XCDR (result_tail); | |
1975 ii++; | |
1976 } | |
1977 } | |
1978 } | |
1979 | |
1980 if (NILP (result) || (ii < ee && !NILP (end))) | |
1981 { | |
1982 /* We were handed a cons, which definitely has elements. nil | |
1983 result means either ss >= ee or SEQUENCE was nil after the | |
1984 nthcdr; in both cases that means START and END were incorrectly | |
1985 specified for this sequence. ii < ee with a non-nil end means | |
1986 the user handed us a bogus end value. */ | |
1987 check_sequence_range (saved, start, end, Flength (saved)); | |
1988 } | |
1989 } | |
1990 else | |
1991 { | |
1992 len = XFIXNUM (Flength (sequence)); | |
1993 if (ss < 0) | |
1994 { | |
1995 ss = len + ss; | |
1996 start = make_integer (ss); | |
1997 } | |
1998 | |
1999 if (ee < 0) | |
2000 { | |
2001 ee = len + ee; | |
2002 end = make_integer (ee); | |
2003 } | |
2004 else | |
2005 { | |
2006 ee = min (len, ee); | |
2007 } | |
2008 | |
2009 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
2010 | |
2011 if (VECTORP (sequence)) | |
2012 { | |
2013 result = Fvector (ee - ss, XVECTOR_DATA (sequence) + ss); | |
2014 } | |
2015 else if (BIT_VECTORP (sequence)) | |
2016 { | |
2017 result = make_bit_vector (ee - ss, Qzero); | |
2018 | |
2019 for (ii = ss; ii < ee; ii++) | |
2020 { | |
2021 set_bit_vector_bit (XBIT_VECTOR (result), ii - ss, | |
2022 bit_vector_bit (XBIT_VECTOR (sequence), ii)); | |
2023 } | |
2024 } | |
2025 else if (NILP (sequence)) | |
2026 { | |
2027 DO_NOTHING; | |
2028 } | |
2029 else | |
2030 { | |
2031 /* Won't happen, since CHECK_SEQUENCE didn't error. */ | |
2032 ABORT (); | |
2033 } | |
2034 } | |
2035 | |
2036 return result; | |
2037 } | |
2038 | |
2039 DEFUN ("substring-no-properties", Fsubstring_no_properties, 1, 3, 0, /* | 782 DEFUN ("substring-no-properties", Fsubstring_no_properties, 1, 3, 0, /* |
2040 Return a substring of STRING, without copying the extents. | 783 Return a substring of STRING, without copying the extents. |
2041 END may be nil or omitted; then the substring runs to the end of STRING. | 784 END may be nil or omitted; then the substring runs to the end of STRING. |
2042 If START or END is negative, it counts from the end. | 785 If START or END is negative, it counts from the end. |
2043 | 786 |
2283 { | 1026 { |
2284 /* This function can GC */ | 1027 /* This function can GC */ |
2285 return Fcar (Fnthcdr (n, list)); | 1028 return Fcar (Fnthcdr (n, list)); |
2286 } | 1029 } |
2287 | 1030 |
2288 DEFUN ("elt", Felt, 2, 2, 0, /* | |
2289 Return element of SEQUENCE at index N. | |
2290 */ | |
2291 (sequence, n)) | |
2292 { | |
2293 /* This function can GC */ | |
2294 retry: | |
2295 CHECK_FIXNUM_COERCE_CHAR (n); /* yuck! */ | |
2296 if (LISTP (sequence)) | |
2297 { | |
2298 Lisp_Object tem = Fnthcdr (n, sequence); | |
2299 /* #### Utterly, completely, fucking disgusting. | |
2300 * #### The whole point of "elt" is that it operates on | |
2301 * #### sequences, and does error- (bounds-) checking. | |
2302 */ | |
2303 if (CONSP (tem)) | |
2304 return XCAR (tem); | |
2305 else | |
2306 #if 1 | |
2307 /* This is The Way It Has Always Been. */ | |
2308 return Qnil; | |
2309 #else | |
2310 /* This is The Way Mly and Cltl2 say It Should Be. */ | |
2311 args_out_of_range (sequence, n); | |
2312 #endif | |
2313 } | |
2314 else if (STRINGP (sequence) || | |
2315 VECTORP (sequence) || | |
2316 BIT_VECTORP (sequence)) | |
2317 return Faref (sequence, n); | |
2318 else | |
2319 { | |
2320 check_losing_bytecode ("elt", sequence); | |
2321 sequence = wrong_type_argument (Qsequencep, sequence); | |
2322 goto retry; | |
2323 } | |
2324 } | |
2325 | |
2326 DEFUN ("last", Flast, 1, 2, 0, /* | 1031 DEFUN ("last", Flast, 1, 2, 0, /* |
2327 Return the tail of list LIST, of length N (default 1). | 1032 Return the tail of list LIST, of length N (default 1). |
2328 LIST may be a dotted list, but not a circular list. | 1033 LIST may be a dotted list, but not a circular list. |
2329 Optional argument N must be a non-negative integer. | 1034 Optional argument N must be a non-negative integer. |
2330 If N is zero, then the atom that terminates the list is returned. | 1035 If N is zero, then the atom that terminates the list is returned. |
2457 } | 1162 } |
2458 | 1163 |
2459 return retval; | 1164 return retval; |
2460 } | 1165 } |
2461 | 1166 |
2462 DEFUN ("member", Fmember, 2, 2, 0, /* | |
2463 Return non-nil if ELT is an element of LIST. Comparison done with `equal'. | |
2464 The value is actually the tail of LIST whose car is ELT. | |
2465 */ | |
2466 (elt, list)) | |
2467 { | |
2468 EXTERNAL_LIST_LOOP_3 (list_elt, list, tail) | |
2469 { | |
2470 if (internal_equal (elt, list_elt, 0)) | |
2471 return tail; | |
2472 } | |
2473 return Qnil; | |
2474 } | |
2475 | |
2476 DEFUN ("memq", Fmemq, 2, 2, 0, /* | |
2477 Return non-nil if ELT is an element of LIST. Comparison done with `eq'. | |
2478 The value is actually the tail of LIST whose car is ELT. | |
2479 */ | |
2480 (elt, list)) | |
2481 { | |
2482 EXTERNAL_LIST_LOOP_3 (list_elt, list, tail) | |
2483 { | |
2484 if (EQ_WITH_EBOLA_NOTICE (elt, list_elt)) | |
2485 return tail; | |
2486 } | |
2487 return Qnil; | |
2488 } | |
2489 | |
2490 Lisp_Object | |
2491 memq_no_quit (Lisp_Object elt, Lisp_Object list) | |
2492 { | |
2493 LIST_LOOP_3 (list_elt, list, tail) | |
2494 { | |
2495 if (EQ_WITH_EBOLA_NOTICE (elt, list_elt)) | |
2496 return tail; | |
2497 } | |
2498 return Qnil; | |
2499 } | |
2500 | |
2501 /* Return the first index of ITEM in LIST. In CONS_OUT, return the cons cell | |
2502 before that containing the element. If the element is in the first cons | |
2503 cell, return Qnil in CONS_OUT. TEST, KEY, START, END are as in | |
2504 #'remove*; CHECK_TEST and TEST_NOT_UNBOUNDP should have been initialized | |
2505 with get_check_match_function() or get_check_test_function(). A non-zero | |
2506 REVERSE_TEST_ORDER means call TEST with the element from LIST as its | |
2507 first argument and ITEM as its second. Error if LIST is ill-formed, or | |
2508 circular. */ | |
2509 static Lisp_Object | |
2510 list_position_cons_before (Lisp_Object *cons_out, | |
2511 Lisp_Object item, Lisp_Object list, | |
2512 check_test_func_t check_test, | |
2513 Boolint test_not_unboundp, | |
2514 Lisp_Object test, Lisp_Object key, | |
2515 Boolint reverse_test_order, | |
2516 Lisp_Object start, Lisp_Object end) | |
2517 { | |
2518 struct gcpro gcpro1; | |
2519 Lisp_Object tail_before = Qnil; | |
2520 Elemcount ii = 0, starting = XFIXNUM (start); | |
2521 Elemcount ending = NILP (end) ? MOST_POSITIVE_FIXNUM : XFIXNUM (end); | |
2522 | |
2523 GCPRO1 (tail_before); | |
2524 | |
2525 if (check_test == check_eq_nokey) | |
2526 { | |
2527 /* TEST is #'eq, no need to call any C functions, and the test order | |
2528 won't be visible. */ | |
2529 EXTERNAL_LIST_LOOP_3 (elt, list, tail) | |
2530 { | |
2531 if (starting <= ii && ii < ending && | |
2532 EQ (item, elt) == test_not_unboundp) | |
2533 { | |
2534 *cons_out = tail_before; | |
2535 RETURN_UNGCPRO (make_integer (ii)); | |
2536 } | |
2537 else | |
2538 { | |
2539 if (ii >= ending) | |
2540 { | |
2541 break; | |
2542 } | |
2543 } | |
2544 ii++; | |
2545 tail_before = tail; | |
2546 } | |
2547 } | |
2548 else | |
2549 { | |
2550 GC_EXTERNAL_LIST_LOOP_3 (elt, list, tail) | |
2551 { | |
2552 if (starting <= ii && ii < ending && | |
2553 (reverse_test_order ? | |
2554 check_test (test, key, elt, item) : | |
2555 check_test (test, key, item, elt)) == test_not_unboundp) | |
2556 { | |
2557 *cons_out = tail_before; | |
2558 XUNGCPRO (elt); | |
2559 UNGCPRO; | |
2560 return make_integer (ii); | |
2561 } | |
2562 else | |
2563 { | |
2564 if (ii >= ending) | |
2565 { | |
2566 break; | |
2567 } | |
2568 } | |
2569 ii++; | |
2570 tail_before = tail; | |
2571 } | |
2572 END_GC_EXTERNAL_LIST_LOOP (elt); | |
2573 } | |
2574 | |
2575 RETURN_UNGCPRO (Qnil); | |
2576 } | |
2577 | |
2578 DEFUN ("member*", FmemberX, 2, MANY, 0, /* | |
2579 Return the first sublist of LIST with car ITEM, or nil if no such sublist. | |
2580 | |
2581 The keyword :test specifies a two-argument function that is used to compare | |
2582 ITEM with elements in LIST; if omitted, it defaults to `eql'. | |
2583 | |
2584 The keyword :test-not is similar, but specifies a negated function. That | |
2585 is, ITEM is considered equal to an element in LIST if the given function | |
2586 returns nil. Common Lisp deprecates :test-not, and if both are specified, | |
2587 XEmacs signals an error. | |
2588 | |
2589 :key specifies a one-argument function that transforms elements of LIST into | |
2590 \"comparison keys\" before the test predicate is applied. For example, | |
2591 if :key is #'car, then ITEM is compared with the car of elements from LIST. | |
2592 The :key function, however, is not applied to ITEM, and does not affect the | |
2593 elements in the returned list, which are taken directly from the elements in | |
2594 LIST. | |
2595 | |
2596 arguments: (ITEM LIST &key (TEST #'eql) TEST-NOT (KEY #'identity)) | |
2597 */ | |
2598 (int nargs, Lisp_Object *args)) | |
2599 { | |
2600 Lisp_Object item = args[0], list = args[1], result = Qnil, position0; | |
2601 Boolint test_not_unboundp = 1; | |
2602 check_test_func_t check_test = NULL; | |
2603 | |
2604 PARSE_KEYWORDS (FmemberX, nargs, args, 5, (test, if_not, if_, test_not, key), | |
2605 NULL); | |
2606 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
2607 key, &test_not_unboundp); | |
2608 position0 | |
2609 = list_position_cons_before (&result, item, list, check_test, | |
2610 test_not_unboundp, test, key, 0, Qzero, Qnil); | |
2611 | |
2612 return CONSP (result) ? XCDR (result) : ZEROP (position0) ? list : Qnil; | |
2613 } | |
2614 | |
2615 /* This macro might eventually find a better home than here. */ | |
2616 | |
2617 #define CHECK_KEY_ARGUMENT(key) \ | |
2618 do { \ | |
2619 if (NILP (key)) \ | |
2620 { \ | |
2621 key = Qidentity; \ | |
2622 } \ | |
2623 \ | |
2624 if (!EQ (key, Qidentity)) \ | |
2625 { \ | |
2626 key = indirect_function (key, 1); \ | |
2627 if (EQ (key, XSYMBOL_FUNCTION (Qidentity))) \ | |
2628 { \ | |
2629 key = Qidentity; \ | |
2630 } \ | |
2631 } \ | |
2632 } while (0) | |
2633 | |
2634 #define KEY(key, item) (EQ (Qidentity, key) ? item : \ | |
2635 IGNORE_MULTIPLE_VALUES (call1 (key, item))) | |
2636 | |
2637 DEFUN ("adjoin", Fadjoin, 2, MANY, 0, /* | |
2638 Return ITEM consed onto the front of LIST, if not already in LIST. | |
2639 | |
2640 Otherwise, return LIST unmodified. | |
2641 | |
2642 See `member*' for the meaning of the keywords. | |
2643 | |
2644 arguments: (ITEM LIST &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
2645 */ | |
2646 (int nargs, Lisp_Object *args)) | |
2647 { | |
2648 Lisp_Object item = args[0], list = args[1], keyed = Qnil, ignore = Qnil; | |
2649 struct gcpro gcpro1; | |
2650 Boolint test_not_unboundp = 1; | |
2651 check_test_func_t check_test = NULL; | |
2652 | |
2653 PARSE_KEYWORDS (Fadjoin, nargs, args, 3, (test, key, test_not), | |
2654 NULL); | |
2655 | |
2656 CHECK_KEY_ARGUMENT (key); | |
2657 | |
2658 keyed = KEY (key, item); | |
2659 | |
2660 GCPRO1 (keyed); | |
2661 check_test = get_check_test_function (keyed, &test, test_not, Qnil, Qnil, | |
2662 key, &test_not_unboundp); | |
2663 if (NILP (list_position_cons_before (&ignore, keyed, list, check_test, | |
2664 test_not_unboundp, test, key, 0, Qzero, | |
2665 Qnil))) | |
2666 { | |
2667 RETURN_UNGCPRO (Fcons (item, list)); | |
2668 } | |
2669 | |
2670 RETURN_UNGCPRO (list); | |
2671 } | |
2672 | |
2673 DEFUN ("assoc", Fassoc, 2, 2, 0, /* | |
2674 Return non-nil if KEY is `equal' to the car of an element of ALIST. | |
2675 The value is actually the element of ALIST whose car equals KEY. | |
2676 */ | |
2677 (key, alist)) | |
2678 { | |
2679 /* This function can GC. */ | |
2680 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist) | |
2681 { | |
2682 if (internal_equal (key, elt_car, 0)) | |
2683 return elt; | |
2684 } | |
2685 return Qnil; | |
2686 } | |
2687 | |
2688 Lisp_Object | |
2689 assoc_no_quit (Lisp_Object key, Lisp_Object alist) | |
2690 { | |
2691 int speccount = specpdl_depth (); | |
2692 specbind (Qinhibit_quit, Qt); | |
2693 return unbind_to_1 (speccount, Fassoc (key, alist)); | |
2694 } | |
2695 | |
2696 DEFUN ("assq", Fassq, 2, 2, 0, /* | |
2697 Return non-nil if KEY is `eq' to the car of an element of ALIST. | |
2698 The value is actually the element of ALIST whose car is KEY. | |
2699 Elements of ALIST that are not conses are ignored. | |
2700 */ | |
2701 (key, alist)) | |
2702 { | |
2703 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist) | |
2704 { | |
2705 if (EQ_WITH_EBOLA_NOTICE (key, elt_car)) | |
2706 return elt; | |
2707 } | |
2708 return Qnil; | |
2709 } | |
2710 | |
2711 /* Like Fassq but never report an error and do not allow quits. | |
2712 Use only on lists known never to be circular. */ | |
2713 | |
2714 Lisp_Object | |
2715 assq_no_quit (Lisp_Object key, Lisp_Object alist) | |
2716 { | |
2717 /* This cannot GC. */ | |
2718 LIST_LOOP_2 (elt, alist) | |
2719 { | |
2720 Lisp_Object elt_car = XCAR (elt); | |
2721 if (EQ_WITH_EBOLA_NOTICE (key, elt_car)) | |
2722 return elt; | |
2723 } | |
2724 return Qnil; | |
2725 } | |
2726 | |
2727 DEFUN ("assoc*", FassocX, 2, MANY, 0, /* | |
2728 Find the first item whose car matches ITEM in ALIST. | |
2729 | |
2730 See `member*' for the meaning of :test, :test-not and :key. | |
2731 | |
2732 arguments: (ITEM ALIST &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
2733 */ | |
2734 (int nargs, Lisp_Object *args)) | |
2735 { | |
2736 Lisp_Object item = args[0], alist = args[1]; | |
2737 Boolint test_not_unboundp = 1; | |
2738 check_test_func_t check_test = NULL; | |
2739 | |
2740 PARSE_KEYWORDS (FassocX, nargs, args, 5, (test, if_, if_not, test_not, key), | |
2741 NULL); | |
2742 | |
2743 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
2744 key, &test_not_unboundp); | |
2745 | |
2746 if (check_test == check_eq_nokey) | |
2747 { | |
2748 /* TEST is #'eq, no need to call any C functions. */ | |
2749 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist) | |
2750 { | |
2751 if (EQ (item, elt_car) == test_not_unboundp) | |
2752 { | |
2753 return elt; | |
2754 } | |
2755 } | |
2756 } | |
2757 else | |
2758 { | |
2759 GC_EXTERNAL_LIST_LOOP_2 (elt, alist) | |
2760 { | |
2761 if (CONSP (elt) && | |
2762 check_test (test, key, item, XCAR (elt)) == test_not_unboundp) | |
2763 { | |
2764 XUNGCPRO (elt); | |
2765 return elt; | |
2766 } | |
2767 } | |
2768 END_GC_EXTERNAL_LIST_LOOP (elt); | |
2769 } | |
2770 | |
2771 return Qnil; | |
2772 } | |
2773 | |
2774 DEFUN ("rassoc", Frassoc, 2, 2, 0, /* | |
2775 Return non-nil if VALUE is `equal' to the cdr of an element of ALIST. | |
2776 The value is actually the element of ALIST whose cdr equals VALUE. | |
2777 */ | |
2778 (value, alist)) | |
2779 { | |
2780 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist) | |
2781 { | |
2782 if (internal_equal (value, elt_cdr, 0)) | |
2783 return elt; | |
2784 } | |
2785 return Qnil; | |
2786 } | |
2787 | |
2788 DEFUN ("rassq", Frassq, 2, 2, 0, /* | |
2789 Return non-nil if VALUE is `eq' to the cdr of an element of ALIST. | |
2790 The value is actually the element of ALIST whose cdr is VALUE. | |
2791 */ | |
2792 (value, alist)) | |
2793 { | |
2794 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist) | |
2795 { | |
2796 if (EQ_WITH_EBOLA_NOTICE (value, elt_cdr)) | |
2797 return elt; | |
2798 } | |
2799 return Qnil; | |
2800 } | |
2801 | |
2802 DEFUN ("old-rassq", Fold_rassq, 2, 2, 0, /* | |
2803 Return non-nil if VALUE is `old-eq' to the cdr of an element of ALIST. | |
2804 The value is actually the element of ALIST whose cdr is VALUE. | |
2805 */ | |
2806 (value, alist)) | |
2807 { | |
2808 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist) | |
2809 { | |
2810 if (HACKEQ_UNSAFE (value, elt_cdr)) | |
2811 return elt; | |
2812 } | |
2813 return Qnil; | |
2814 } | |
2815 | |
2816 /* Like Frassq, but caller must ensure that ALIST is properly | |
2817 nil-terminated and ebola-free. */ | |
2818 Lisp_Object | |
2819 rassq_no_quit (Lisp_Object value, Lisp_Object alist) | |
2820 { | |
2821 LIST_LOOP_2 (elt, alist) | |
2822 { | |
2823 Lisp_Object elt_cdr = XCDR (elt); | |
2824 if (EQ_WITH_EBOLA_NOTICE (value, elt_cdr)) | |
2825 return elt; | |
2826 } | |
2827 return Qnil; | |
2828 } | |
2829 | |
2830 DEFUN ("rassoc*", FrassocX, 2, MANY, 0, /* | |
2831 Find the first item whose cdr matches ITEM in ALIST. | |
2832 | |
2833 See `member*' for the meaning of :test, :test-not and :key. | |
2834 | |
2835 arguments: (ITEM ALIST &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
2836 */ | |
2837 (int nargs, Lisp_Object *args)) | |
2838 { | |
2839 Lisp_Object item = args[0], alist = args[1]; | |
2840 Boolint test_not_unboundp = 1; | |
2841 check_test_func_t check_test = NULL; | |
2842 | |
2843 PARSE_KEYWORDS (FrassocX, nargs, args, 5, (test, if_, if_not, test_not, key), | |
2844 NULL); | |
2845 | |
2846 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
2847 key, &test_not_unboundp); | |
2848 | |
2849 if (check_test == check_eq_nokey) | |
2850 { | |
2851 /* TEST is #'eq, no need to call any C functions. */ | |
2852 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist) | |
2853 { | |
2854 if (EQ (item, elt_cdr) == test_not_unboundp) | |
2855 { | |
2856 return elt; | |
2857 } | |
2858 } | |
2859 } | |
2860 else | |
2861 { | |
2862 GC_EXTERNAL_LIST_LOOP_2 (elt, alist) | |
2863 { | |
2864 if (CONSP (elt) && | |
2865 check_test (test, key, item, XCDR (elt)) == test_not_unboundp) | |
2866 { | |
2867 XUNGCPRO (elt); | |
2868 return elt; | |
2869 } | |
2870 } | |
2871 END_GC_EXTERNAL_LIST_LOOP (elt); | |
2872 } | |
2873 | |
2874 return Qnil; | |
2875 } | |
2876 | |
2877 /* This is the implementation of both #'find and #'position. */ | |
2878 static Lisp_Object | |
2879 position (Lisp_Object *object_out, Lisp_Object item, Lisp_Object sequence, | |
2880 check_test_func_t check_test, Boolint test_not_unboundp, | |
2881 Lisp_Object test, Lisp_Object key, Lisp_Object start, Lisp_Object end, | |
2882 Lisp_Object from_end, Lisp_Object default_, Lisp_Object caller) | |
2883 { | |
2884 Lisp_Object result = Qnil; | |
2885 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, len, ii = 0; | |
2886 | |
2887 CHECK_SEQUENCE (sequence); | |
2888 CHECK_NATNUM (start); | |
2889 starting = FIXNUMP (start) ? XFIXNUM (start) : 1 + MOST_POSITIVE_FIXNUM; | |
2890 | |
2891 if (!NILP (end)) | |
2892 { | |
2893 CHECK_NATNUM (end); | |
2894 ending = FIXNUMP (end) ? XFIXNUM (end) : 1 + MOST_POSITIVE_FIXNUM; | |
2895 } | |
2896 | |
2897 *object_out = default_; | |
2898 | |
2899 if (CONSP (sequence)) | |
2900 { | |
2901 if (!(starting < ending)) | |
2902 { | |
2903 check_sequence_range (sequence, start, end, Flength (sequence)); | |
2904 /* starting could be equal to ending, in which case nil is what | |
2905 we want to return. */ | |
2906 return Qnil; | |
2907 } | |
2908 | |
2909 { | |
2910 GC_EXTERNAL_LIST_LOOP_2 (elt, sequence) | |
2911 { | |
2912 if (starting <= ii && ii < ending | |
2913 && check_test (test, key, item, elt) == test_not_unboundp) | |
2914 { | |
2915 result = make_integer (ii); | |
2916 *object_out = elt; | |
2917 | |
2918 if (NILP (from_end)) | |
2919 { | |
2920 XUNGCPRO (elt); | |
2921 return result; | |
2922 } | |
2923 } | |
2924 else if (ii == ending) | |
2925 { | |
2926 break; | |
2927 } | |
2928 | |
2929 ii++; | |
2930 } | |
2931 END_GC_EXTERNAL_LIST_LOOP (elt); | |
2932 } | |
2933 | |
2934 if (ii < starting || (ii < ending && !NILP (end))) | |
2935 { | |
2936 check_sequence_range (sequence, start, end, Flength (sequence)); | |
2937 } | |
2938 } | |
2939 else if (STRINGP (sequence)) | |
2940 { | |
2941 Ibyte *startp = XSTRING_DATA (sequence), *cursor = startp; | |
2942 Bytecount byte_len = XSTRING_LENGTH (sequence), cursor_offset = 0; | |
2943 Lisp_Object character = Qnil; | |
2944 | |
2945 while (cursor_offset < byte_len && ii < ending) | |
2946 { | |
2947 if (ii >= starting) | |
2948 { | |
2949 character = make_char (itext_ichar (cursor)); | |
2950 | |
2951 if (check_test (test, key, item, character) == test_not_unboundp) | |
2952 { | |
2953 result = make_integer (ii); | |
2954 *object_out = character; | |
2955 | |
2956 if (NILP (from_end)) | |
2957 { | |
2958 return result; | |
2959 } | |
2960 } | |
2961 | |
2962 startp = XSTRING_DATA (sequence); | |
2963 cursor = startp + cursor_offset; | |
2964 if (byte_len != XSTRING_LENGTH (sequence) | |
2965 || !valid_ibyteptr_p (cursor)) | |
2966 { | |
2967 mapping_interaction_error (caller, sequence); | |
2968 } | |
2969 } | |
2970 | |
2971 INC_IBYTEPTR (cursor); | |
2972 cursor_offset = cursor - startp; | |
2973 ii++; | |
2974 } | |
2975 | |
2976 if (ii < starting || (ii < ending && !NILP (end))) | |
2977 { | |
2978 check_sequence_range (sequence, start, end, Flength (sequence)); | |
2979 } | |
2980 } | |
2981 else | |
2982 { | |
2983 Lisp_Object object = Qnil; | |
2984 len = XFIXNUM (Flength (sequence)); | |
2985 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
2986 | |
2987 ending = min (ending, len); | |
2988 if (0 == len) | |
2989 { | |
2990 /* Catches the case where we have nil. */ | |
2991 return result; | |
2992 } | |
2993 | |
2994 if (NILP (from_end)) | |
2995 { | |
2996 for (ii = starting; ii < ending; ii++) | |
2997 { | |
2998 object = Faref (sequence, make_fixnum (ii)); | |
2999 if (check_test (test, key, item, object) == test_not_unboundp) | |
3000 { | |
3001 result = make_integer (ii); | |
3002 *object_out = object; | |
3003 return result; | |
3004 } | |
3005 } | |
3006 } | |
3007 else | |
3008 { | |
3009 for (ii = ending - 1; ii >= starting; ii--) | |
3010 { | |
3011 object = Faref (sequence, make_fixnum (ii)); | |
3012 if (check_test (test, key, item, object) == test_not_unboundp) | |
3013 { | |
3014 result = make_integer (ii); | |
3015 *object_out = object; | |
3016 return result; | |
3017 } | |
3018 } | |
3019 } | |
3020 } | |
3021 | |
3022 return result; | |
3023 } | |
3024 | |
3025 DEFUN ("position", Fposition, 2, MANY, 0, /* | |
3026 Return the index of the first occurrence of ITEM in SEQUENCE. | |
3027 | |
3028 Return nil if not found. See `remove*' for the meaning of the keywords. | |
3029 | |
3030 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) FROM-END TEST-NOT) | |
3031 */ | |
3032 (int nargs, Lisp_Object *args)) | |
3033 { | |
3034 Lisp_Object object = Qnil, item = args[0], sequence = args[1]; | |
3035 Boolint test_not_unboundp = 1; | |
3036 check_test_func_t check_test = NULL; | |
3037 | |
3038 PARSE_KEYWORDS (Fposition, nargs, args, 8, | |
3039 (test, if_, test_not, if_not, key, start, end, from_end), | |
3040 (start = Qzero)); | |
3041 | |
3042 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
3043 key, &test_not_unboundp); | |
3044 | |
3045 return position (&object, item, sequence, check_test, test_not_unboundp, | |
3046 test, key, start, end, from_end, Qnil, Qposition); | |
3047 } | |
3048 | |
3049 DEFUN ("find", Ffind, 2, MANY, 0, /* | |
3050 Find the first occurrence of ITEM in SEQUENCE. | |
3051 | |
3052 Return the matching ITEM, or nil if not found. See `remove*' for the | |
3053 meaning of the keywords. | |
3054 | |
3055 The keyword :default, not specified by Common Lisp, designates an object to | |
3056 return instead of nil if ITEM is not found. | |
3057 | |
3058 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) DEFAULT FROM-END TEST-NOT) | |
3059 */ | |
3060 (int nargs, Lisp_Object *args)) | |
3061 { | |
3062 Lisp_Object object = Qnil, item = args[0], sequence = args[1]; | |
3063 Boolint test_not_unboundp = 1; | |
3064 check_test_func_t check_test = NULL; | |
3065 | |
3066 PARSE_KEYWORDS (Ffind, nargs, args, 9, | |
3067 (test, if_, test_not, if_not, key, start, end, from_end, | |
3068 default_), | |
3069 (start = Qzero)); | |
3070 | |
3071 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
3072 key, &test_not_unboundp); | |
3073 | |
3074 position (&object, item, sequence, check_test, test_not_unboundp, | |
3075 test, key, start, end, from_end, default_, Qposition); | |
3076 | |
3077 return object; | |
3078 } | |
3079 | |
3080 /* Like Fdelq, but caller must ensure that LIST is properly | |
3081 nil-terminated and ebola-free. */ | |
3082 | |
3083 Lisp_Object | |
3084 delq_no_quit (Lisp_Object elt, Lisp_Object list) | |
3085 { | |
3086 LIST_LOOP_DELETE_IF (list_elt, list, | |
3087 (EQ_WITH_EBOLA_NOTICE (elt, list_elt))); | |
3088 return list; | |
3089 } | |
3090 | |
3091 /* Be VERY careful with this. This is like delq_no_quit() but | |
3092 also calls free_cons() on the removed conses. You must be SURE | |
3093 that no pointers to the freed conses remain around (e.g. | |
3094 someone else is pointing to part of the list). This function | |
3095 is useful on internal lists that are used frequently and where | |
3096 the actual list doesn't escape beyond known code bounds. */ | |
3097 | |
3098 Lisp_Object | |
3099 delq_no_quit_and_free_cons (Lisp_Object elt, Lisp_Object list) | |
3100 { | |
3101 REGISTER Lisp_Object tail = list; | |
3102 REGISTER Lisp_Object prev = Qnil; | |
3103 | |
3104 while (!NILP (tail)) | |
3105 { | |
3106 REGISTER Lisp_Object tem = XCAR (tail); | |
3107 if (EQ (elt, tem)) | |
3108 { | |
3109 Lisp_Object cons_to_free = tail; | |
3110 if (NILP (prev)) | |
3111 list = XCDR (tail); | |
3112 else | |
3113 XCDR (prev) = XCDR (tail); | |
3114 tail = XCDR (tail); | |
3115 free_cons (cons_to_free); | |
3116 } | |
3117 else | |
3118 { | |
3119 prev = tail; | |
3120 tail = XCDR (tail); | |
3121 } | |
3122 } | |
3123 return list; | |
3124 } | |
3125 | |
3126 DEFUN ("delete*", FdeleteX, 2, MANY, 0, /* | |
3127 Remove all occurrences of ITEM in SEQUENCE, destructively. | |
3128 | |
3129 If SEQUENCE is a non-nil list, this modifies the list directly. A non-list | |
3130 SEQUENCE will not be destructively modified, rather, if ITEM occurs in it, a | |
3131 new SEQUENCE of the same type without ITEM will be returned. | |
3132 | |
3133 See `remove*' for a non-destructive alternative, and for explanation of the | |
3134 keyword arguments. | |
3135 | |
3136 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) FROM-END COUNT TEST-NOT) | |
3137 */ | |
3138 (int nargs, Lisp_Object *args)) | |
3139 { | |
3140 Lisp_Object item = args[0], sequence = args[1]; | |
3141 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, counting = MOST_POSITIVE_FIXNUM; | |
3142 Elemcount len, ii = 0, encountered = 0, presenting = 0; | |
3143 Boolint test_not_unboundp = 1; | |
3144 check_test_func_t check_test = NULL; | |
3145 | |
3146 PARSE_KEYWORDS (FdeleteX, nargs, args, 9, | |
3147 (test, if_not, if_, test_not, key, start, end, from_end, | |
3148 count), (start = Qzero, count = Qunbound)); | |
3149 | |
3150 CHECK_SEQUENCE (sequence); | |
3151 CHECK_NATNUM (start); | |
3152 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start); | |
3153 | |
3154 if (!NILP (end)) | |
3155 { | |
3156 CHECK_NATNUM (end); | |
3157 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end); | |
3158 } | |
3159 | |
3160 if (!UNBOUNDP (count)) | |
3161 { | |
3162 if (!NILP (count)) | |
3163 { | |
3164 CHECK_INTEGER (count); | |
3165 if (FIXNUMP (count)) | |
3166 { | |
3167 counting = XFIXNUM (count); | |
3168 } | |
3169 #ifdef HAVE_BIGNUM | |
3170 else | |
3171 { | |
3172 counting = bignum_sign (XBIGNUM_DATA (count)) > 0 ? | |
3173 1 + MOST_POSITIVE_FIXNUM : MOST_NEGATIVE_FIXNUM - 1; | |
3174 } | |
3175 #endif | |
3176 | |
3177 if (counting < 1) | |
3178 { | |
3179 return sequence; | |
3180 } | |
3181 | |
3182 if (!NILP (from_end)) | |
3183 { | |
3184 /* Sigh, this is inelegant. Force count_with_tail () to ignore | |
3185 the count keyword, so we get the actual number of matching | |
3186 elements, and can start removing from the beginning for the | |
3187 from-end case. */ | |
3188 for (ii = XSUBR (GET_DEFUN_LISP_OBJECT (FdeleteX))->min_args; | |
3189 ii < nargs; ii += 2) | |
3190 { | |
3191 if (EQ (args[ii], Q_count)) | |
3192 { | |
3193 args[ii + 1] = Qnil; | |
3194 break; | |
3195 } | |
3196 } | |
3197 ii = 0; | |
3198 } | |
3199 } | |
3200 } | |
3201 | |
3202 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
3203 key, &test_not_unboundp); | |
3204 | |
3205 if (CONSP (sequence)) | |
3206 { | |
3207 Lisp_Object prev_tail_list_elt = Qnil, ignore = Qnil; | |
3208 Elemcount list_len = 0, deleted = 0; | |
3209 struct gcpro gcpro1; | |
3210 | |
3211 if (!NILP (count) && !NILP (from_end)) | |
3212 { | |
3213 /* Both COUNT and FROM-END were specified; we need to traverse the | |
3214 list twice. */ | |
3215 Lisp_Object present = count_with_tail (&ignore, nargs, args, | |
3216 QdeleteX); | |
3217 | |
3218 if (ZEROP (present)) | |
3219 { | |
3220 return sequence; | |
3221 } | |
3222 | |
3223 presenting = XFIXNUM (present); | |
3224 | |
3225 /* If there are fewer items in the list than we have permission to | |
3226 delete, we don't need to differentiate between the :from-end | |
3227 nil and :from-end t cases. Otherwise, presenting is the number | |
3228 of matching items we need to ignore before we start to | |
3229 delete. */ | |
3230 presenting = presenting <= counting ? 0 : presenting - counting; | |
3231 } | |
3232 | |
3233 GCPRO1 (prev_tail_list_elt); | |
3234 ii = -1; | |
3235 | |
3236 { | |
3237 GC_EXTERNAL_LIST_LOOP_4 (list_elt, sequence, tail, list_len) | |
3238 { | |
3239 ii++; | |
3240 | |
3241 if (starting <= ii && ii < ending && | |
3242 (check_test (test, key, item, list_elt) == test_not_unboundp) | |
3243 && (presenting ? encountered++ >= presenting | |
3244 : encountered++ < counting)) | |
3245 { | |
3246 if (NILP (prev_tail_list_elt)) | |
3247 { | |
3248 sequence = XCDR (tail); | |
3249 } | |
3250 else | |
3251 { | |
3252 XSETCDR (prev_tail_list_elt, XCDR (tail)); | |
3253 } | |
3254 | |
3255 /* Keep tortoise from ever passing hare. */ | |
3256 list_len = 0; | |
3257 deleted++; | |
3258 } | |
3259 else | |
3260 { | |
3261 prev_tail_list_elt = tail; | |
3262 if (ii >= ending || (!presenting && encountered > counting)) | |
3263 { | |
3264 break; | |
3265 } | |
3266 } | |
3267 } | |
3268 END_GC_EXTERNAL_LIST_LOOP (list_elt); | |
3269 } | |
3270 | |
3271 UNGCPRO; | |
3272 | |
3273 if ((ii < starting || (ii < ending && !NILP (end))) && | |
3274 !(presenting ? encountered == presenting : encountered == counting)) | |
3275 { | |
3276 check_sequence_range (args[1], start, end, | |
3277 make_fixnum (deleted + XFIXNUM (Flength (args[1])))); | |
3278 } | |
3279 | |
3280 return sequence; | |
3281 } | |
3282 else if (STRINGP (sequence)) | |
3283 { | |
3284 Ibyte *staging = alloca_ibytes (XSTRING_LENGTH (sequence)); | |
3285 Ibyte *staging_cursor = staging, *startp = XSTRING_DATA (sequence); | |
3286 Ibyte *cursor = startp; | |
3287 Bytecount cursor_offset = 0, byte_len = XSTRING_LENGTH (sequence); | |
3288 Lisp_Object character, result = sequence; | |
3289 | |
3290 if (!NILP (count) && !NILP (from_end)) | |
3291 { | |
3292 Lisp_Object present = count_with_tail (&character, nargs, args, | |
3293 QdeleteX); | |
3294 | |
3295 if (ZEROP (present)) | |
3296 { | |
3297 return sequence; | |
3298 } | |
3299 | |
3300 presenting = XFIXNUM (present); | |
3301 | |
3302 /* If there are fewer items in the list than we have permission to | |
3303 delete, we don't need to differentiate between the :from-end | |
3304 nil and :from-end t cases. Otherwise, presenting is the number | |
3305 of matching items we need to ignore before we start to | |
3306 delete. */ | |
3307 presenting = presenting <= counting ? 0 : presenting - counting; | |
3308 } | |
3309 | |
3310 ii = 0; | |
3311 while (cursor_offset < byte_len) | |
3312 { | |
3313 if (ii >= starting && ii < ending) | |
3314 { | |
3315 character = make_char (itext_ichar (cursor)); | |
3316 | |
3317 if ((check_test (test, key, item, character) | |
3318 == test_not_unboundp) | |
3319 && (presenting ? encountered++ >= presenting : | |
3320 encountered++ < counting)) | |
3321 { | |
3322 DO_NOTHING; | |
3323 } | |
3324 else | |
3325 { | |
3326 staging_cursor | |
3327 += set_itext_ichar (staging_cursor, XCHAR (character)); | |
3328 } | |
3329 | |
3330 startp = XSTRING_DATA (sequence); | |
3331 cursor = startp + cursor_offset; | |
3332 if (byte_len != XSTRING_LENGTH (sequence) | |
3333 || !valid_ibyteptr_p (cursor)) | |
3334 { | |
3335 mapping_interaction_error (QdeleteX, sequence); | |
3336 } | |
3337 } | |
3338 else | |
3339 { | |
3340 staging_cursor += itext_copy_ichar (cursor, staging_cursor); | |
3341 } | |
3342 | |
3343 INC_IBYTEPTR (cursor); | |
3344 cursor_offset = cursor - startp; | |
3345 ii++; | |
3346 } | |
3347 | |
3348 if (ii < starting || (ii < ending && !NILP (end))) | |
3349 { | |
3350 check_sequence_range (sequence, start, end, Flength (sequence)); | |
3351 } | |
3352 | |
3353 if (0 != encountered) | |
3354 { | |
3355 result = make_string (staging, staging_cursor - staging); | |
3356 copy_string_extents (result, sequence, 0, 0, | |
3357 staging_cursor - staging); | |
3358 sequence = result; | |
3359 } | |
3360 | |
3361 return sequence; | |
3362 } | |
3363 else | |
3364 { | |
3365 Lisp_Object position0 = Qnil, object = Qnil; | |
3366 Lisp_Object *staging = NULL, *staging_cursor, *staging_limit; | |
3367 Elemcount positioning; | |
3368 | |
3369 len = XFIXNUM (Flength (sequence)); | |
3370 | |
3371 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
3372 | |
3373 position0 = position (&object, item, sequence, check_test, | |
3374 test_not_unboundp, test, key, start, end, | |
3375 from_end, Qnil, QdeleteX); | |
3376 if (NILP (position0)) | |
3377 { | |
3378 return sequence; | |
3379 } | |
3380 | |
3381 ending = min (ending, len); | |
3382 positioning = XFIXNUM (position0); | |
3383 encountered = 1; | |
3384 | |
3385 if (NILP (from_end)) | |
3386 { | |
3387 staging = alloca_array (Lisp_Object, len - 1); | |
3388 staging_cursor = staging; | |
3389 | |
3390 ii = 0; | |
3391 while (ii < positioning) | |
3392 { | |
3393 *staging_cursor++ = Faref (sequence, make_fixnum (ii)); | |
3394 ii++; | |
3395 } | |
3396 | |
3397 ii = positioning + 1; | |
3398 while (ii < ending) | |
3399 { | |
3400 object = Faref (sequence, make_fixnum (ii)); | |
3401 if (encountered < counting | |
3402 && (check_test (test, key, item, object) | |
3403 == test_not_unboundp)) | |
3404 { | |
3405 encountered++; | |
3406 } | |
3407 else | |
3408 { | |
3409 *staging_cursor++ = object; | |
3410 } | |
3411 ii++; | |
3412 } | |
3413 | |
3414 while (ii < len) | |
3415 { | |
3416 *staging_cursor++ = Faref (sequence, make_fixnum (ii)); | |
3417 ii++; | |
3418 } | |
3419 } | |
3420 else | |
3421 { | |
3422 staging = alloca_array (Lisp_Object, len - 1); | |
3423 staging_cursor = staging_limit = staging + len - 1; | |
3424 | |
3425 ii = len - 1; | |
3426 while (ii > positioning) | |
3427 { | |
3428 *--staging_cursor = Faref (sequence, make_fixnum (ii)); | |
3429 ii--; | |
3430 } | |
3431 | |
3432 ii = positioning - 1; | |
3433 while (ii >= starting) | |
3434 { | |
3435 object = Faref (sequence, make_fixnum (ii)); | |
3436 if (encountered < counting | |
3437 && (check_test (test, key, item, object) == | |
3438 test_not_unboundp)) | |
3439 { | |
3440 encountered++; | |
3441 } | |
3442 else | |
3443 { | |
3444 *--staging_cursor = object; | |
3445 } | |
3446 | |
3447 ii--; | |
3448 } | |
3449 | |
3450 while (ii >= 0) | |
3451 { | |
3452 *--staging_cursor = Faref (sequence, make_fixnum (ii)); | |
3453 ii--; | |
3454 } | |
3455 | |
3456 staging = staging_cursor; | |
3457 staging_cursor = staging_limit; | |
3458 } | |
3459 | |
3460 if (VECTORP (sequence)) | |
3461 { | |
3462 return Fvector (staging_cursor - staging, staging); | |
3463 } | |
3464 else if (BIT_VECTORP (sequence)) | |
3465 { | |
3466 return Fbit_vector (staging_cursor - staging, staging); | |
3467 } | |
3468 | |
3469 /* A nil sequence will have given us a nil #'position, | |
3470 above. */ | |
3471 ABORT (); | |
3472 | |
3473 return Qnil; | |
3474 } | |
3475 } | |
3476 | |
3477 DEFUN ("remove*", FremoveX, 2, MANY, 0, /* | |
3478 Remove all occurrences of ITEM in SEQUENCE, non-destructively. | |
3479 | |
3480 If SEQUENCE is a list, `remove*' makes a copy if that is necessary to avoid | |
3481 corrupting the original SEQUENCE. | |
3482 | |
3483 The keywords :test and :test-not specify two-argument test and negated-test | |
3484 predicates, respectively; :test defaults to `eql'. :key specifies a | |
3485 one-argument function that transforms elements of SEQUENCE into \"comparison | |
3486 keys\" before the test predicate is applied. See `member*' for more | |
3487 information on these keywords. | |
3488 | |
3489 :start and :end, if given, specify indices of a subsequence of SEQUENCE to | |
3490 be processed. Indices are 0-based and processing involves the subsequence | |
3491 starting at the index given by :start and ending just before the index given | |
3492 by :end. | |
3493 | |
3494 :count, if given, limits the number of items removed to the number | |
3495 specified. :from-end, if given, causes processing to proceed starting from | |
3496 the end instead of the beginning; in this case, this matters only if :count | |
3497 is given. | |
3498 | |
3499 arguments: (ITEM SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) FROM-END COUNT TEST-NOT) | |
3500 */ | |
3501 (int nargs, Lisp_Object *args)) | |
3502 { | |
3503 Lisp_Object item = args[0], sequence = args[1], matched_count = Qnil, | |
3504 tail = Qnil; | |
3505 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, counting = MOST_POSITIVE_FIXNUM; | |
3506 Elemcount ii = 0, encountered = 0, presenting = 0; | |
3507 Boolint test_not_unboundp = 1; | |
3508 check_test_func_t check_test = NULL; | |
3509 | |
3510 PARSE_KEYWORDS (FremoveX, nargs, args, 9, | |
3511 (test, if_not, if_, test_not, key, start, end, from_end, | |
3512 count), (start = Qzero)); | |
3513 | |
3514 if (!CONSP (sequence)) | |
3515 { | |
3516 return FdeleteX (nargs, args); | |
3517 } | |
3518 | |
3519 CHECK_NATNUM (start); | |
3520 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start); | |
3521 | |
3522 if (!NILP (end)) | |
3523 { | |
3524 CHECK_NATNUM (end); | |
3525 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end); | |
3526 } | |
3527 | |
3528 if (!NILP (count)) | |
3529 { | |
3530 CHECK_INTEGER (count); | |
3531 if (FIXNUMP (count)) | |
3532 { | |
3533 counting = XFIXNUM (count); | |
3534 } | |
3535 #ifdef HAVE_BIGNUM | |
3536 else | |
3537 { | |
3538 counting = bignum_sign (XBIGNUM_DATA (count)) > 0 ? | |
3539 1 + MOST_POSITIVE_FIXNUM : -1 + MOST_NEGATIVE_FIXNUM; | |
3540 } | |
3541 #endif | |
3542 | |
3543 if (counting <= 0) | |
3544 { | |
3545 return sequence; | |
3546 } | |
3547 | |
3548 if (!NILP (from_end)) | |
3549 { | |
3550 /* Sigh, this is inelegant. Force count_with_tail () to ignore the | |
3551 count keyword, so we get the actual number of matching | |
3552 elements, and can start removing from the beginning for the | |
3553 from-end case. */ | |
3554 for (ii = XSUBR (GET_DEFUN_LISP_OBJECT (FremoveX))->min_args; | |
3555 ii < nargs; ii += 2) | |
3556 { | |
3557 if (EQ (args[ii], Q_count)) | |
3558 { | |
3559 args[ii + 1] = Qnil; | |
3560 break; | |
3561 } | |
3562 } | |
3563 ii = 0; | |
3564 } | |
3565 } | |
3566 | |
3567 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
3568 key, &test_not_unboundp); | |
3569 | |
3570 matched_count = count_with_tail (&tail, nargs, args, QremoveX); | |
3571 | |
3572 if (!ZEROP (matched_count)) | |
3573 { | |
3574 Lisp_Object result = Qnil, result_tail = Qnil; | |
3575 struct gcpro gcpro1, gcpro2; | |
3576 | |
3577 if (!NILP (count) && !NILP (from_end)) | |
3578 { | |
3579 presenting = XFIXNUM (matched_count); | |
3580 | |
3581 /* If there are fewer matching elements in the list than we have | |
3582 permission to delete, we don't need to differentiate between | |
3583 the :from-end nil and :from-end t cases. Otherwise, presenting | |
3584 is the number of matching items we need to ignore before we | |
3585 start to delete. */ | |
3586 presenting = presenting <= counting ? 0 : presenting - counting; | |
3587 } | |
3588 | |
3589 GCPRO2 (result, tail); | |
3590 { | |
3591 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tailing) | |
3592 { | |
3593 if (EQ (tail, tailing)) | |
3594 { | |
3595 XUNGCPRO (elt); | |
3596 UNGCPRO; | |
3597 | |
3598 if (NILP (result)) | |
3599 { | |
3600 return XCDR (tail); | |
3601 } | |
3602 | |
3603 XSETCDR (result_tail, XCDR (tail)); | |
3604 return result; | |
3605 } | |
3606 else if (starting <= ii && ii < ending && | |
3607 (check_test (test, key, item, elt) == test_not_unboundp) | |
3608 && (presenting ? encountered++ >= presenting | |
3609 : encountered++ < counting)) | |
3610 { | |
3611 DO_NOTHING; | |
3612 } | |
3613 else if (NILP (result)) | |
3614 { | |
3615 result = result_tail = Fcons (elt, Qnil); | |
3616 } | |
3617 else | |
3618 { | |
3619 XSETCDR (result_tail, Fcons (elt, Qnil)); | |
3620 result_tail = XCDR (result_tail); | |
3621 } | |
3622 | |
3623 if (ii == ending) | |
3624 { | |
3625 break; | |
3626 } | |
3627 | |
3628 ii++; | |
3629 } | |
3630 END_GC_EXTERNAL_LIST_LOOP (elt); | |
3631 } | |
3632 UNGCPRO; | |
3633 | |
3634 if (ii < starting || (ii < ending && !NILP (end))) | |
3635 { | |
3636 check_sequence_range (args[0], start, end, Flength (args[0])); | |
3637 } | |
3638 | |
3639 return result; | |
3640 } | |
3641 | |
3642 return sequence; | |
3643 } | |
3644 | |
3645 Lisp_Object | |
3646 remassoc_no_quit (Lisp_Object key, Lisp_Object alist) | |
3647 { | |
3648 LIST_LOOP_DELETE_IF (elt, alist, | |
3649 (CONSP (elt) && | |
3650 internal_equal (key, XCAR (elt), 0))); | |
3651 return alist; | |
3652 } | |
3653 | |
3654 /* no quit, no errors; be careful */ | |
3655 | |
3656 Lisp_Object | |
3657 remassq_no_quit (Lisp_Object key, Lisp_Object alist) | |
3658 { | |
3659 LIST_LOOP_DELETE_IF (elt, alist, | |
3660 (CONSP (elt) && | |
3661 EQ_WITH_EBOLA_NOTICE (key, XCAR (elt)))); | |
3662 return alist; | |
3663 } | |
3664 | |
3665 /* Like Fremrassq, fast and unsafe; be careful */ | |
3666 Lisp_Object | |
3667 remrassq_no_quit (Lisp_Object value, Lisp_Object alist) | |
3668 { | |
3669 LIST_LOOP_DELETE_IF (elt, alist, | |
3670 (CONSP (elt) && | |
3671 EQ_WITH_EBOLA_NOTICE (value, XCDR (elt)))); | |
3672 return alist; | |
3673 } | |
3674 | |
3675 /* Remove duplicate elements between START and END from LIST, a non-nil | |
3676 list; if COPY is zero, do so destructively. Items to delete are selected | |
3677 according to the algorithm used when :from-end t is passed to | |
3678 #'delete-duplicates. Error if LIST is ill-formed or circular. | |
3679 | |
3680 TEST and KEY are as in #'remove*; CHECK_TEST and TEST_NOT_UNBOUNDP should | |
3681 reflect them, having been initialised with get_check_match_function() or | |
3682 get_check_test_function(). */ | |
3683 static Lisp_Object | |
3684 list_delete_duplicates_from_end (Lisp_Object list, | |
3685 check_test_func_t check_test, | |
3686 Boolint test_not_unboundp, | |
3687 Lisp_Object test, Lisp_Object key, | |
3688 Lisp_Object start, | |
3689 Lisp_Object end, Boolint copy) | |
3690 { | |
3691 Lisp_Object checking = Qnil, result = list; | |
3692 Lisp_Object keyed, positioned, position_cons = Qnil, result_tail; | |
3693 Elemcount len = XFIXNUM (Flength (list)), pos, starting = XFIXNUM (start); | |
3694 Elemcount ending = (NILP (end) ? len : XFIXNUM (end)), greatest_pos_seen = -1; | |
3695 Elemcount ii = 0; | |
3696 struct gcpro gcpro1; | |
3697 | |
3698 /* We can't delete (or remove) as we go, because that breaks START and | |
3699 END. We could if END were nil, and that would change an ON(N + 2) | |
3700 algorithm to an ON^2 algorithm. Here and now it doesn't matter, though, | |
3701 #'delete-duplicates is relatively expensive no matter what. */ | |
3702 struct Lisp_Bit_Vector *deleting | |
3703 = (Lisp_Bit_Vector *) ALLOCA (sizeof (struct Lisp_Bit_Vector) | |
3704 + (sizeof (long) | |
3705 * (BIT_VECTOR_LONG_STORAGE (len) | |
3706 - 1))); | |
3707 | |
3708 check_sequence_range (list, start, end, make_integer (len)); | |
3709 | |
3710 deleting->size = len; | |
3711 memset (&(deleting->bits), 0, | |
3712 sizeof (long) * BIT_VECTOR_LONG_STORAGE (len)); | |
3713 | |
3714 GCPRO1 (keyed); | |
3715 | |
3716 { | |
3717 GC_EXTERNAL_LIST_LOOP_3 (elt, list, tail) | |
3718 { | |
3719 if (!(starting <= ii && ii <= ending) || bit_vector_bit (deleting, ii)) | |
3720 { | |
3721 ii++; | |
3722 continue; | |
3723 } | |
3724 | |
3725 keyed = KEY (key, elt); | |
3726 checking = XCDR (tail); | |
3727 pos = ii + 1; | |
3728 | |
3729 while (!NILP ((positioned = list_position_cons_before | |
3730 (&position_cons, keyed, checking, check_test, | |
3731 test_not_unboundp, test, key, 0, | |
3732 make_fixnum (max (starting - pos, 0)), | |
3733 make_fixnum (ending - pos))))) | |
3734 { | |
3735 pos = XFIXNUM (positioned) + pos; | |
3736 set_bit_vector_bit (deleting, pos, 1); | |
3737 greatest_pos_seen = max (greatest_pos_seen, pos); | |
3738 checking = NILP (position_cons) ? | |
3739 XCDR (checking) : XCDR (XCDR (position_cons)); | |
3740 pos += 1; | |
3741 } | |
3742 ii++; | |
3743 } | |
3744 END_GC_EXTERNAL_LIST_LOOP (elt); | |
3745 } | |
3746 | |
3747 UNGCPRO; | |
3748 | |
3749 ii = 0; | |
3750 | |
3751 if (greatest_pos_seen > -1) | |
3752 { | |
3753 if (copy) | |
3754 { | |
3755 result = result_tail = Fcons (XCAR (list), Qnil); | |
3756 list = XCDR (list); | |
3757 ii = 1; | |
3758 | |
3759 { | |
3760 EXTERNAL_LIST_LOOP_3 (elt, list, tail) | |
3761 { | |
3762 if (ii == greatest_pos_seen) | |
3763 { | |
3764 XSETCDR (result_tail, XCDR (tail)); | |
3765 break; | |
3766 } | |
3767 else if (!bit_vector_bit (deleting, ii)) | |
3768 { | |
3769 XSETCDR (result_tail, Fcons (elt, Qnil)); | |
3770 result_tail = XCDR (result_tail); | |
3771 } | |
3772 ii++; | |
3773 } | |
3774 } | |
3775 } | |
3776 else | |
3777 { | |
3778 EXTERNAL_LIST_LOOP_DELETE_IF (elt, list, | |
3779 bit_vector_bit (deleting, ii++)); | |
3780 } | |
3781 } | |
3782 | |
3783 return result; | |
3784 } | |
3785 | |
3786 DEFUN ("delete-duplicates", Fdelete_duplicates, 1, MANY, 0, /* | |
3787 Remove all duplicate elements from SEQUENCE, destructively. | |
3788 | |
3789 If SEQUENCE is a list and has duplicates, modify and return it. Note that | |
3790 SEQUENCE may start with an element to be deleted; because of this, if | |
3791 modifying a variable, be sure to write `(setq VARIABLE (delete-duplicates | |
3792 VARIABLE))' to be certain to have a list without duplicate elements. | |
3793 | |
3794 If SEQUENCE is an array and has duplicates, return a newly-allocated array | |
3795 of the same type comprising all unique elements of SEQUENCE. | |
3796 | |
3797 If there are no duplicate elements in SEQUENCE, return it unmodified. | |
3798 | |
3799 See `remove*' for the meaning of the keywords. See `remove-duplicates' for | |
3800 a non-destructive version of this function. | |
3801 | |
3802 arguments: (SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) END FROM-END TEST-NOT) | |
3803 */ | |
3804 (int nargs, Lisp_Object *args)) | |
3805 { | |
3806 Lisp_Object sequence = args[0], keyed = Qnil; | |
3807 Lisp_Object positioned = Qnil, ignore = Qnil; | |
3808 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, len, ii = 0, jj = 0; | |
3809 Boolint test_not_unboundp = 1; | |
3810 check_test_func_t check_test = NULL; | |
3811 struct gcpro gcpro1, gcpro2; | |
3812 | |
3813 PARSE_KEYWORDS (Fdelete_duplicates, nargs, args, 6, | |
3814 (test, key, test_not, start, end, from_end), | |
3815 (start = Qzero)); | |
3816 | |
3817 CHECK_SEQUENCE (sequence); | |
3818 CHECK_NATNUM (start); | |
3819 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start); | |
3820 | |
3821 if (!NILP (end)) | |
3822 { | |
3823 CHECK_NATNUM (end); | |
3824 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end); | |
3825 } | |
3826 | |
3827 CHECK_KEY_ARGUMENT (key); | |
3828 | |
3829 get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
3830 &test_not_unboundp, &check_test); | |
3831 | |
3832 if (CONSP (sequence)) | |
3833 { | |
3834 if (NILP (from_end)) | |
3835 { | |
3836 Lisp_Object prev_tail = Qnil; | |
3837 Elemcount deleted = 0; | |
3838 | |
3839 GCPRO2 (keyed, prev_tail); | |
3840 | |
3841 { | |
3842 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail) | |
3843 { | |
3844 if (starting <= ii && ii < ending) | |
3845 { | |
3846 keyed = KEY (key, elt); | |
3847 positioned | |
3848 = list_position_cons_before (&ignore, keyed, | |
3849 XCDR (tail), check_test, | |
3850 test_not_unboundp, test, key, | |
3851 0, make_fixnum (max (starting | |
3852 - (ii + 1), | |
3853 0)), | |
3854 make_fixnum (ending | |
3855 - (ii + 1))); | |
3856 if (!NILP (positioned)) | |
3857 { | |
3858 sequence = XCDR (tail); | |
3859 deleted++; | |
3860 } | |
3861 else | |
3862 { | |
3863 break; | |
3864 } | |
3865 } | |
3866 else | |
3867 { | |
3868 break; | |
3869 } | |
3870 | |
3871 ii++; | |
3872 } | |
3873 END_GC_EXTERNAL_LIST_LOOP (elt); | |
3874 } | |
3875 { | |
3876 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail) | |
3877 { | |
3878 if (!(starting <= ii && ii <= ending)) | |
3879 { | |
3880 prev_tail = tail; | |
3881 ii++; | |
3882 continue; | |
3883 } | |
3884 | |
3885 keyed = KEY (key, elt); | |
3886 positioned | |
3887 = list_position_cons_before (&ignore, keyed, XCDR (tail), | |
3888 check_test, test_not_unboundp, | |
3889 test, key, 0, | |
3890 make_fixnum (max (starting | |
3891 - (ii + 1), 0)), | |
3892 make_fixnum (ending - (ii + 1))); | |
3893 if (!NILP (positioned)) | |
3894 { | |
3895 /* We know this isn't the first iteration of the loop, | |
3896 because we advanced above to the point where we have at | |
3897 least one non-duplicate entry at the head of the | |
3898 list. */ | |
3899 XSETCDR (prev_tail, XCDR (tail)); | |
3900 len = 0; | |
3901 deleted++; | |
3902 } | |
3903 else | |
3904 { | |
3905 prev_tail = tail; | |
3906 if (ii >= ending) | |
3907 { | |
3908 break; | |
3909 } | |
3910 } | |
3911 | |
3912 ii++; | |
3913 } | |
3914 END_GC_EXTERNAL_LIST_LOOP (elt); | |
3915 } | |
3916 | |
3917 UNGCPRO; | |
3918 | |
3919 if ((ii < starting || (ii < ending && !NILP (end)))) | |
3920 { | |
3921 check_sequence_range (args[0], start, end, | |
3922 make_fixnum (deleted | |
3923 + XFIXNUM (Flength (args[0])))); | |
3924 } | |
3925 } | |
3926 else | |
3927 { | |
3928 sequence = list_delete_duplicates_from_end (sequence, check_test, | |
3929 test_not_unboundp, | |
3930 test, key, start, end, | |
3931 0); | |
3932 } | |
3933 } | |
3934 else if (STRINGP (sequence)) | |
3935 { | |
3936 Lisp_Object elt = Qnil; | |
3937 | |
3938 if (EQ (Qidentity, key)) | |
3939 { | |
3940 /* We know all the elements will be characters; set check_test to | |
3941 reflect that. This isn't useful if KEY is not #'identity, since | |
3942 it may return non-characters for the elements. */ | |
3943 check_test = get_check_test_function (make_char ('a'), | |
3944 &test, test_not, | |
3945 Qnil, Qnil, key, | |
3946 &test_not_unboundp); | |
3947 } | |
3948 | |
3949 if (NILP (from_end)) | |
3950 { | |
3951 Bytecount byte_len = XSTRING_LENGTH (sequence), cursor_offset = 0; | |
3952 Ibyte *staging = alloca_ibytes (byte_len), *staging_cursor = staging; | |
3953 Ibyte *cursor = XSTRING_DATA (sequence), *startp = cursor; | |
3954 Elemcount deleted = 0; | |
3955 | |
3956 GCPRO1 (elt); | |
3957 | |
3958 while (cursor_offset < byte_len) | |
3959 { | |
3960 if (starting <= ii && ii < ending) | |
3961 { | |
3962 Ibyte *cursor0 = cursor; | |
3963 Bytecount cursor0_offset; | |
3964 Boolint delete_this = 0; | |
3965 | |
3966 elt = KEY (key, make_char (itext_ichar (cursor))); | |
3967 INC_IBYTEPTR (cursor0); | |
3968 cursor0_offset = cursor0 - startp; | |
3969 | |
3970 for (jj = ii + 1; jj < ending && cursor0_offset < byte_len; | |
3971 jj++) | |
3972 { | |
3973 if (check_test (test, key, elt, | |
3974 make_char (itext_ichar (cursor0))) | |
3975 == test_not_unboundp) | |
3976 { | |
3977 delete_this = 1; | |
3978 deleted++; | |
3979 break; | |
3980 } | |
3981 | |
3982 startp = XSTRING_DATA (sequence); | |
3983 cursor0 = startp + cursor0_offset; | |
3984 if (byte_len != XSTRING_LENGTH (sequence) | |
3985 || !valid_ibyteptr_p (cursor0)) | |
3986 { | |
3987 mapping_interaction_error (Qdelete_duplicates, | |
3988 sequence); | |
3989 } | |
3990 | |
3991 INC_IBYTEPTR (cursor0); | |
3992 cursor0_offset = cursor0 - startp; | |
3993 } | |
3994 | |
3995 startp = XSTRING_DATA (sequence); | |
3996 cursor = startp + cursor_offset; | |
3997 | |
3998 if (byte_len != XSTRING_LENGTH (sequence) | |
3999 || !valid_ibyteptr_p (cursor)) | |
4000 { | |
4001 mapping_interaction_error (Qdelete_duplicates, sequence); | |
4002 } | |
4003 | |
4004 if (!delete_this) | |
4005 { | |
4006 staging_cursor | |
4007 += itext_copy_ichar (cursor, staging_cursor); | |
4008 | |
4009 } | |
4010 } | |
4011 else | |
4012 { | |
4013 staging_cursor += itext_copy_ichar (cursor, staging_cursor); | |
4014 } | |
4015 | |
4016 INC_IBYTEPTR (cursor); | |
4017 cursor_offset = cursor - startp; | |
4018 ii++; | |
4019 } | |
4020 | |
4021 UNGCPRO; | |
4022 | |
4023 if (ii < starting || (ii < ending && !NILP (end))) | |
4024 { | |
4025 check_sequence_range (sequence, start, end, Flength (sequence)); | |
4026 } | |
4027 | |
4028 if (0 != deleted) | |
4029 { | |
4030 sequence = make_string (staging, staging_cursor - staging); | |
4031 } | |
4032 } | |
4033 else | |
4034 { | |
4035 Elemcount deleted = 0; | |
4036 Ibyte *staging = alloca_ibytes ((len = string_char_length (sequence)) | |
4037 * MAX_ICHAR_LEN); | |
4038 Ibyte *staging_cursor = staging, *startp = XSTRING_DATA (sequence); | |
4039 Ibyte *endp = startp + XSTRING_LENGTH (sequence); | |
4040 struct Lisp_Bit_Vector *deleting | |
4041 = (Lisp_Bit_Vector *) ALLOCA (sizeof (struct Lisp_Bit_Vector) | |
4042 + (sizeof (long) | |
4043 * (BIT_VECTOR_LONG_STORAGE (len) | |
4044 - 1))); | |
4045 | |
4046 check_sequence_range (sequence, start, end, make_integer (len)); | |
4047 | |
4048 /* For the from_end t case; transform contents to an array with | |
4049 elements addressable in constant time, use the same algorithm | |
4050 as for vectors. */ | |
4051 deleting->size = len; | |
4052 memset (&(deleting->bits), 0, | |
4053 sizeof (long) * BIT_VECTOR_LONG_STORAGE (len)); | |
4054 | |
4055 while (startp < endp) | |
4056 { | |
4057 itext_copy_ichar (startp, staging + (ii * MAX_ICHAR_LEN)); | |
4058 INC_IBYTEPTR (startp); | |
4059 ii++; | |
4060 } | |
4061 | |
4062 GCPRO1 (elt); | |
4063 | |
4064 ending = min (ending, len); | |
4065 | |
4066 for (ii = ending - 1; ii >= starting; ii--) | |
4067 { | |
4068 elt = KEY (key, make_char (itext_ichar (staging + | |
4069 (ii * MAX_ICHAR_LEN)))); | |
4070 for (jj = ii - 1; jj >= starting; jj--) | |
4071 { | |
4072 if (check_test (test, key, elt, | |
4073 make_char (itext_ichar | |
4074 (staging + (jj * MAX_ICHAR_LEN)))) | |
4075 == test_not_unboundp) | |
4076 { | |
4077 set_bit_vector_bit (deleting, ii, 1); | |
4078 deleted++; | |
4079 break; | |
4080 } | |
4081 } | |
4082 } | |
4083 | |
4084 UNGCPRO; | |
4085 | |
4086 if (0 != deleted) | |
4087 { | |
4088 startp = XSTRING_DATA (sequence); | |
4089 | |
4090 for (ii = 0; ii < len; ii++) | |
4091 { | |
4092 if (!bit_vector_bit (deleting, ii)) | |
4093 { | |
4094 staging_cursor | |
4095 += itext_copy_ichar (startp, staging_cursor); | |
4096 } | |
4097 | |
4098 INC_IBYTEPTR (startp); | |
4099 } | |
4100 | |
4101 sequence = make_string (staging, staging_cursor - staging); | |
4102 } | |
4103 } | |
4104 } | |
4105 else if (VECTORP (sequence)) | |
4106 { | |
4107 Elemcount deleted = 0; | |
4108 Lisp_Object *content = XVECTOR_DATA (sequence); | |
4109 struct Lisp_Bit_Vector *deleting; | |
4110 Lisp_Object elt = Qnil; | |
4111 | |
4112 len = XVECTOR_LENGTH (sequence); | |
4113 check_sequence_range (sequence, start, end, make_integer (len)); | |
4114 | |
4115 deleting = (Lisp_Bit_Vector *) ALLOCA (sizeof (struct Lisp_Bit_Vector) | |
4116 + (sizeof (long) | |
4117 * (BIT_VECTOR_LONG_STORAGE (len) | |
4118 - 1))); | |
4119 deleting->size = len; | |
4120 memset (&(deleting->bits), 0, | |
4121 sizeof (long) * BIT_VECTOR_LONG_STORAGE (len)); | |
4122 | |
4123 GCPRO1 (elt); | |
4124 | |
4125 ending = min (ending, len); | |
4126 | |
4127 if (NILP (from_end)) | |
4128 { | |
4129 for (ii = starting; ii < ending; ii++) | |
4130 { | |
4131 elt = KEY (key, content[ii]); | |
4132 | |
4133 for (jj = ii + 1; jj < ending; jj++) | |
4134 { | |
4135 if (check_test (test, key, elt, content[jj]) | |
4136 == test_not_unboundp) | |
4137 { | |
4138 set_bit_vector_bit (deleting, ii, 1); | |
4139 deleted++; | |
4140 break; | |
4141 } | |
4142 } | |
4143 } | |
4144 } | |
4145 else | |
4146 { | |
4147 for (ii = ending - 1; ii >= starting; ii--) | |
4148 { | |
4149 elt = KEY (key, content[ii]); | |
4150 | |
4151 for (jj = ii - 1; jj >= starting; jj--) | |
4152 { | |
4153 if (check_test (test, key, elt, content[jj]) | |
4154 == test_not_unboundp) | |
4155 { | |
4156 set_bit_vector_bit (deleting, ii, 1); | |
4157 deleted++; | |
4158 break; | |
4159 } | |
4160 } | |
4161 } | |
4162 } | |
4163 | |
4164 UNGCPRO; | |
4165 | |
4166 if (deleted) | |
4167 { | |
4168 Lisp_Object res = make_vector (len - deleted, Qnil), | |
4169 *res_content = XVECTOR_DATA (res); | |
4170 | |
4171 for (ii = jj = 0; ii < len; ii++) | |
4172 { | |
4173 if (!bit_vector_bit (deleting, ii)) | |
4174 { | |
4175 res_content[jj++] = content[ii]; | |
4176 } | |
4177 } | |
4178 | |
4179 sequence = res; | |
4180 } | |
4181 } | |
4182 else if (BIT_VECTORP (sequence)) | |
4183 { | |
4184 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence); | |
4185 Elemcount deleted = 0; | |
4186 /* I'm a little irritated at this. Basically, the only reasonable | |
4187 thing delete-duplicates should do if handed a bit vector is return | |
4188 something of maximum length two and minimum length 0 (because | |
4189 that's the possible number of distinct elements if EQ is regarded | |
4190 as identity, which it should be). But to support arbitrary TEST | |
4191 and KEY arguments, which may be non-deterministic from our | |
4192 perspective, we need the same algorithm as for vectors. */ | |
4193 struct Lisp_Bit_Vector *deleting; | |
4194 Lisp_Object elt = Qnil; | |
4195 | |
4196 len = bit_vector_length (bv); | |
4197 | |
4198 if (EQ (Qidentity, key)) | |
4199 { | |
4200 /* We know all the elements will be bits; set check_test to | |
4201 reflect that. This isn't useful if KEY is not #'identity, since | |
4202 it may return non-bits for the elements. */ | |
4203 check_test = get_check_test_function (Qzero, &test, test_not, | |
4204 Qnil, Qnil, key, | |
4205 &test_not_unboundp); | |
4206 } | |
4207 | |
4208 check_sequence_range (sequence, start, end, make_integer (len)); | |
4209 | |
4210 deleting = (Lisp_Bit_Vector *) ALLOCA (sizeof (struct Lisp_Bit_Vector) | |
4211 + (sizeof (long) | |
4212 * (BIT_VECTOR_LONG_STORAGE (len) | |
4213 - 1))); | |
4214 deleting->size = len; | |
4215 memset (&(deleting->bits), 0, | |
4216 sizeof (long) * BIT_VECTOR_LONG_STORAGE (len)); | |
4217 | |
4218 ending = min (ending, len); | |
4219 | |
4220 GCPRO1 (elt); | |
4221 | |
4222 if (NILP (from_end)) | |
4223 { | |
4224 for (ii = starting; ii < ending; ii++) | |
4225 { | |
4226 elt = KEY (key, make_fixnum (bit_vector_bit (bv, ii))); | |
4227 | |
4228 for (jj = ii + 1; jj < ending; jj++) | |
4229 { | |
4230 if (check_test (test, key, elt, | |
4231 make_fixnum (bit_vector_bit (bv, jj))) | |
4232 == test_not_unboundp) | |
4233 { | |
4234 set_bit_vector_bit (deleting, ii, 1); | |
4235 deleted++; | |
4236 break; | |
4237 } | |
4238 } | |
4239 } | |
4240 } | |
4241 else | |
4242 { | |
4243 for (ii = ending - 1; ii >= starting; ii--) | |
4244 { | |
4245 elt = KEY (key, make_fixnum (bit_vector_bit (bv, ii))); | |
4246 | |
4247 for (jj = ii - 1; jj >= starting; jj--) | |
4248 { | |
4249 if (check_test (test, key, elt, | |
4250 make_fixnum (bit_vector_bit (bv, jj))) | |
4251 == test_not_unboundp) | |
4252 { | |
4253 set_bit_vector_bit (deleting, ii, 1); | |
4254 deleted++; | |
4255 break; | |
4256 } | |
4257 } | |
4258 } | |
4259 } | |
4260 | |
4261 UNGCPRO; | |
4262 | |
4263 if (deleted) | |
4264 { | |
4265 Lisp_Object res = make_bit_vector (len - deleted, Qzero); | |
4266 Lisp_Bit_Vector *resbv = XBIT_VECTOR (res); | |
4267 | |
4268 for (ii = jj = 0; ii < len; ii++) | |
4269 { | |
4270 if (!bit_vector_bit (deleting, ii)) | |
4271 { | |
4272 set_bit_vector_bit (resbv, jj++, bit_vector_bit (bv, ii)); | |
4273 } | |
4274 } | |
4275 | |
4276 sequence = res; | |
4277 } | |
4278 } | |
4279 | |
4280 return sequence; | |
4281 } | |
4282 | |
4283 DEFUN ("remove-duplicates", Fremove_duplicates, 1, MANY, 0, /* | |
4284 Remove duplicate elements from SEQUENCE, non-destructively. | |
4285 | |
4286 If there are no duplicate elements in SEQUENCE, return it unmodified; | |
4287 otherwise, return a new object. If SEQUENCE is a list, the new object may | |
4288 share list structure with SEQUENCE. | |
4289 | |
4290 See `remove*' for the meaning of the keywords. | |
4291 | |
4292 arguments: (SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) END FROM-END TEST-NOT) | |
4293 */ | |
4294 (int nargs, Lisp_Object *args)) | |
4295 { | |
4296 Lisp_Object sequence = args[0], keyed, positioned = Qnil; | |
4297 Lisp_Object result = sequence, result_tail = result, cursor = Qnil; | |
4298 Lisp_Object cons_with_shared_tail = Qnil; | |
4299 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, ii = 0; | |
4300 Boolint test_not_unboundp = 1; | |
4301 check_test_func_t check_test = NULL; | |
4302 struct gcpro gcpro1, gcpro2; | |
4303 | |
4304 PARSE_KEYWORDS (Fremove_duplicates, nargs, args, 6, | |
4305 (test, key, test_not, start, end, from_end), | |
4306 (start = Qzero)); | |
4307 | |
4308 CHECK_SEQUENCE (sequence); | |
4309 | |
4310 if (!CONSP (sequence)) | |
4311 { | |
4312 return Fdelete_duplicates (nargs, args); | |
4313 } | |
4314 | |
4315 CHECK_NATNUM (start); | |
4316 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start); | |
4317 | |
4318 if (!NILP (end)) | |
4319 { | |
4320 CHECK_NATNUM (end); | |
4321 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end); | |
4322 } | |
4323 | |
4324 if (NILP (key)) | |
4325 { | |
4326 key = Qidentity; | |
4327 } | |
4328 | |
4329 get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
4330 &test_not_unboundp, &check_test); | |
4331 | |
4332 if (NILP (from_end)) | |
4333 { | |
4334 Lisp_Object ignore = Qnil; | |
4335 | |
4336 GCPRO2 (keyed, result); | |
4337 | |
4338 { | |
4339 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail) | |
4340 { | |
4341 if (starting <= ii && ii <= ending) | |
4342 { | |
4343 keyed = KEY (key, elt); | |
4344 positioned | |
4345 = list_position_cons_before (&ignore, keyed, XCDR (tail), | |
4346 check_test, test_not_unboundp, | |
4347 test, key, 0, | |
4348 make_fixnum (max (starting | |
4349 - (ii + 1), 0)), | |
4350 make_fixnum (ending - (ii + 1))); | |
4351 if (!NILP (positioned)) | |
4352 { | |
4353 sequence = result = result_tail = XCDR (tail); | |
4354 } | |
4355 else | |
4356 { | |
4357 break; | |
4358 } | |
4359 } | |
4360 else | |
4361 { | |
4362 break; | |
4363 } | |
4364 | |
4365 ii++; | |
4366 } | |
4367 END_GC_EXTERNAL_LIST_LOOP (elt); | |
4368 } | |
4369 | |
4370 { | |
4371 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail) | |
4372 { | |
4373 if (!(starting <= ii && ii <= ending)) | |
4374 { | |
4375 ii++; | |
4376 continue; | |
4377 } | |
4378 | |
4379 /* For this algorithm, each time we encounter an object to be | |
4380 removed, copy the output list from the tail beyond the last | |
4381 removed cons to this one. Otherwise, the tail of the output list | |
4382 is shared with the input list, which is OK. */ | |
4383 | |
4384 keyed = KEY (key, elt); | |
4385 positioned | |
4386 = list_position_cons_before (&ignore, keyed, XCDR (tail), | |
4387 check_test, test_not_unboundp, | |
4388 test, key, 0, | |
4389 make_fixnum (max (starting - (ii + 1), | |
4390 0)), | |
4391 make_fixnum (ending - (ii + 1))); | |
4392 if (!NILP (positioned)) | |
4393 { | |
4394 if (EQ (result, sequence)) | |
4395 { | |
4396 result = cons_with_shared_tail | |
4397 = Fcons (XCAR (sequence), XCDR (sequence)); | |
4398 } | |
4399 | |
4400 result_tail = cons_with_shared_tail; | |
4401 cursor = XCDR (cons_with_shared_tail); | |
4402 | |
4403 while (!EQ (cursor, tail) && !NILP (cursor)) | |
4404 { | |
4405 XSETCDR (result_tail, Fcons (XCAR (cursor), Qnil)); | |
4406 result_tail = XCDR (result_tail); | |
4407 cursor = XCDR (cursor); | |
4408 } | |
4409 | |
4410 XSETCDR (result_tail, XCDR (tail)); | |
4411 cons_with_shared_tail = result_tail; | |
4412 } | |
4413 | |
4414 ii++; | |
4415 } | |
4416 END_GC_EXTERNAL_LIST_LOOP (elt); | |
4417 } | |
4418 | |
4419 UNGCPRO; | |
4420 | |
4421 if ((ii < starting || (ii < ending && !NILP (end)))) | |
4422 { | |
4423 check_sequence_range (args[0], start, end, Flength (args[0])); | |
4424 } | |
4425 } | |
4426 else | |
4427 { | |
4428 result = list_delete_duplicates_from_end (sequence, check_test, | |
4429 test_not_unboundp, test, key, | |
4430 start, end, 1); | |
4431 } | |
4432 | |
4433 return result; | |
4434 } | |
4435 #undef KEY | |
4436 | |
4437 DEFUN ("nreverse", Fnreverse, 1, 1, 0, /* | |
4438 Reverse SEQUENCE, destructively. | |
4439 | |
4440 Return the beginning of the reversed sequence, which will be a distinct Lisp | |
4441 object if SEQUENCE is a list with length greater than one. See also | |
4442 `reverse', the non-destructive version of this function. | |
4443 */ | |
4444 (sequence)) | |
4445 { | |
4446 CHECK_SEQUENCE (sequence); | |
4447 | |
4448 if (CONSP (sequence)) | |
4449 { | |
4450 struct gcpro gcpro1, gcpro2; | |
4451 Lisp_Object prev = Qnil; | |
4452 Lisp_Object tail = sequence; | |
4453 | |
4454 /* We gcpro our args; see `nconc' */ | |
4455 GCPRO2 (prev, tail); | |
4456 while (!NILP (tail)) | |
4457 { | |
4458 REGISTER Lisp_Object next; | |
4459 CONCHECK_CONS (tail); | |
4460 next = XCDR (tail); | |
4461 XCDR (tail) = prev; | |
4462 prev = tail; | |
4463 tail = next; | |
4464 } | |
4465 UNGCPRO; | |
4466 return prev; | |
4467 } | |
4468 else if (VECTORP (sequence)) | |
4469 { | |
4470 Elemcount length = XVECTOR_LENGTH (sequence), ii = length; | |
4471 Elemcount half = length / 2; | |
4472 Lisp_Object swap = Qnil; | |
4473 CHECK_LISP_WRITEABLE (sequence); | |
4474 | |
4475 while (ii > half) | |
4476 { | |
4477 swap = XVECTOR_DATA (sequence) [length - ii]; | |
4478 XVECTOR_DATA (sequence) [length - ii] | |
4479 = XVECTOR_DATA (sequence) [ii - 1]; | |
4480 XVECTOR_DATA (sequence) [ii - 1] = swap; | |
4481 --ii; | |
4482 } | |
4483 } | |
4484 else if (STRINGP (sequence)) | |
4485 { | |
4486 Elemcount length = XSTRING_LENGTH (sequence); | |
4487 Ibyte *staging = alloca_ibytes (length), *staging_end = staging + length; | |
4488 Ibyte *cursor = XSTRING_DATA (sequence), *endp = cursor + length; | |
4489 | |
4490 CHECK_LISP_WRITEABLE (sequence); | |
4491 while (cursor < endp) | |
4492 { | |
4493 staging_end -= itext_ichar_len (cursor); | |
4494 itext_copy_ichar (cursor, staging_end); | |
4495 INC_IBYTEPTR (cursor); | |
4496 } | |
4497 | |
4498 assert (staging == staging_end); | |
4499 | |
4500 memcpy (XSTRING_DATA (sequence), staging, length); | |
4501 init_string_ascii_begin (sequence); | |
4502 bump_string_modiff (sequence); | |
4503 sledgehammer_check_ascii_begin (sequence); | |
4504 } | |
4505 else if (BIT_VECTORP (sequence)) | |
4506 { | |
4507 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence); | |
4508 Elemcount length = bit_vector_length (bv), ii = length; | |
4509 Elemcount half = length / 2; | |
4510 int swap = 0; | |
4511 | |
4512 CHECK_LISP_WRITEABLE (sequence); | |
4513 while (ii > half) | |
4514 { | |
4515 swap = bit_vector_bit (bv, length - ii); | |
4516 set_bit_vector_bit (bv, length - ii, bit_vector_bit (bv, ii - 1)); | |
4517 set_bit_vector_bit (bv, ii - 1, swap); | |
4518 --ii; | |
4519 } | |
4520 } | |
4521 else | |
4522 { | |
4523 assert (NILP (sequence)); | |
4524 } | |
4525 | |
4526 return sequence; | |
4527 } | |
4528 | |
4529 DEFUN ("reverse", Freverse, 1, 1, 0, /* | |
4530 Reverse SEQUENCE, copying. Return the reversed sequence. | |
4531 See also the function `nreverse', which is used more often. | |
4532 */ | |
4533 (sequence)) | |
4534 { | |
4535 Lisp_Object result = Qnil; | |
4536 | |
4537 CHECK_SEQUENCE (sequence); | |
4538 | |
4539 if (CONSP (sequence)) | |
4540 { | |
4541 EXTERNAL_LIST_LOOP_2 (elt, sequence) | |
4542 { | |
4543 result = Fcons (elt, result); | |
4544 } | |
4545 } | |
4546 else if (VECTORP (sequence)) | |
4547 { | |
4548 Elemcount length = XVECTOR_LENGTH (sequence), ii = length; | |
4549 Lisp_Object *staging = alloca_array (Lisp_Object, length); | |
4550 | |
4551 while (ii > 0) | |
4552 { | |
4553 staging[length - ii] = XVECTOR_DATA (sequence) [ii - 1]; | |
4554 --ii; | |
4555 } | |
4556 | |
4557 result = Fvector (length, staging); | |
4558 } | |
4559 else if (STRINGP (sequence)) | |
4560 { | |
4561 Elemcount length = XSTRING_LENGTH (sequence); | |
4562 Ibyte *staging = alloca_ibytes (length), *staging_end = staging + length; | |
4563 Ibyte *cursor = XSTRING_DATA (sequence), *endp = cursor + length; | |
4564 | |
4565 while (cursor < endp) | |
4566 { | |
4567 staging_end -= itext_ichar_len (cursor); | |
4568 itext_copy_ichar (cursor, staging_end); | |
4569 INC_IBYTEPTR (cursor); | |
4570 } | |
4571 | |
4572 assert (staging == staging_end); | |
4573 | |
4574 result = make_string (staging, length); | |
4575 } | |
4576 else if (BIT_VECTORP (sequence)) | |
4577 { | |
4578 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence), *res; | |
4579 Elemcount length = bit_vector_length (bv), ii = length; | |
4580 | |
4581 result = make_bit_vector (length, Qzero); | |
4582 res = XBIT_VECTOR (result); | |
4583 | |
4584 while (ii > 0) | |
4585 { | |
4586 set_bit_vector_bit (res, length - ii, bit_vector_bit (bv, ii - 1)); | |
4587 --ii; | |
4588 } | |
4589 } | |
4590 else | |
4591 { | |
4592 assert (NILP (sequence)); | |
4593 } | |
4594 | |
4595 return result; | |
4596 } | |
4597 | |
4598 Lisp_Object | |
4599 list_merge (Lisp_Object org_l1, Lisp_Object org_l2, | |
4600 check_test_func_t check_merge, | |
4601 Lisp_Object predicate, Lisp_Object key) | |
4602 { | |
4603 Lisp_Object value; | |
4604 Lisp_Object tail; | |
4605 Lisp_Object tem; | |
4606 Lisp_Object l1, l2; | |
4607 Lisp_Object tortoises[2]; | |
4608 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | |
4609 int l1_count = 0, l2_count = 0; | |
4610 | |
4611 l1 = org_l1; | |
4612 l2 = org_l2; | |
4613 tail = Qnil; | |
4614 value = Qnil; | |
4615 tortoises[0] = org_l1; | |
4616 tortoises[1] = org_l2; | |
4617 | |
4618 /* It is sufficient to protect org_l1 and org_l2. When l1 and l2 are | |
4619 updated, we copy the new values back into the org_ vars. */ | |
4620 | |
4621 GCPRO5 (org_l1, org_l2, predicate, value, tortoises[0]); | |
4622 gcpro5.nvars = 2; | |
4623 | |
4624 while (1) | |
4625 { | |
4626 if (NILP (l1)) | |
4627 { | |
4628 UNGCPRO; | |
4629 if (NILP (tail)) | |
4630 return l2; | |
4631 Fsetcdr (tail, l2); | |
4632 return value; | |
4633 } | |
4634 if (NILP (l2)) | |
4635 { | |
4636 UNGCPRO; | |
4637 if (NILP (tail)) | |
4638 return l1; | |
4639 Fsetcdr (tail, l1); | |
4640 return value; | |
4641 } | |
4642 | |
4643 if (check_merge (predicate, key, Fcar (l2), Fcar (l1)) == 0) | |
4644 { | |
4645 tem = l1; | |
4646 l1 = Fcdr (l1); | |
4647 org_l1 = l1; | |
4648 | |
4649 if (l1_count++ > CIRCULAR_LIST_SUSPICION_LENGTH) | |
4650 { | |
4651 if (l1_count & 1) | |
4652 { | |
4653 if (!CONSP (tortoises[0])) | |
4654 { | |
4655 mapping_interaction_error (Qmerge, tortoises[0]); | |
4656 } | |
4657 | |
4658 tortoises[0] = XCDR (tortoises[0]); | |
4659 } | |
4660 | |
4661 if (EQ (org_l1, tortoises[0])) | |
4662 { | |
4663 signal_circular_list_error (org_l1); | |
4664 } | |
4665 } | |
4666 } | |
4667 else | |
4668 { | |
4669 tem = l2; | |
4670 l2 = Fcdr (l2); | |
4671 org_l2 = l2; | |
4672 | |
4673 if (l2_count++ > CIRCULAR_LIST_SUSPICION_LENGTH) | |
4674 { | |
4675 if (l2_count & 1) | |
4676 { | |
4677 if (!CONSP (tortoises[1])) | |
4678 { | |
4679 mapping_interaction_error (Qmerge, tortoises[1]); | |
4680 } | |
4681 | |
4682 tortoises[1] = XCDR (tortoises[1]); | |
4683 } | |
4684 | |
4685 if (EQ (org_l2, tortoises[1])) | |
4686 { | |
4687 signal_circular_list_error (org_l2); | |
4688 } | |
4689 } | |
4690 } | |
4691 | |
4692 if (NILP (tail)) | |
4693 value = tem; | |
4694 else | |
4695 Fsetcdr (tail, tem); | |
4696 | |
4697 tail = tem; | |
4698 } | |
4699 } | |
4700 | |
4701 static void | |
4702 array_merge (Lisp_Object *dest, Elemcount dest_len, | |
4703 Lisp_Object *front, Elemcount front_len, | |
4704 Lisp_Object *back, Elemcount back_len, | |
4705 check_test_func_t check_merge, | |
4706 Lisp_Object predicate, Lisp_Object key) | |
4707 { | |
4708 Elemcount ii, fronting, backing; | |
4709 Lisp_Object *front_staging = front; | |
4710 Lisp_Object *back_staging = back; | |
4711 struct gcpro gcpro1, gcpro2; | |
4712 | |
4713 assert (dest_len == (back_len + front_len)); | |
4714 | |
4715 if (0 == dest_len) | |
4716 { | |
4717 return; | |
4718 } | |
4719 | |
4720 if (front >= dest && front < (dest + dest_len)) | |
4721 { | |
4722 front_staging = alloca_array (Lisp_Object, front_len); | |
4723 | |
4724 for (ii = 0; ii < front_len; ++ii) | |
4725 { | |
4726 front_staging[ii] = front[ii]; | |
4727 } | |
4728 } | |
4729 | |
4730 if (back >= dest && back < (dest + dest_len)) | |
4731 { | |
4732 back_staging = alloca_array (Lisp_Object, back_len); | |
4733 | |
4734 for (ii = 0; ii < back_len; ++ii) | |
4735 { | |
4736 back_staging[ii] = back[ii]; | |
4737 } | |
4738 } | |
4739 | |
4740 GCPRO2 (front_staging[0], back_staging[0]); | |
4741 gcpro1.nvars = front_len; | |
4742 gcpro2.nvars = back_len; | |
4743 | |
4744 for (ii = fronting = backing = 0; ii < dest_len; ++ii) | |
4745 { | |
4746 if (fronting >= front_len) | |
4747 { | |
4748 while (ii < dest_len) | |
4749 { | |
4750 dest[ii] = back_staging[backing]; | |
4751 ++ii, ++backing; | |
4752 } | |
4753 UNGCPRO; | |
4754 return; | |
4755 } | |
4756 | |
4757 if (backing >= back_len) | |
4758 { | |
4759 while (ii < dest_len) | |
4760 { | |
4761 dest[ii] = front_staging[fronting]; | |
4762 ++ii, ++fronting; | |
4763 } | |
4764 UNGCPRO; | |
4765 return; | |
4766 } | |
4767 | |
4768 if (check_merge (predicate, key, back_staging[backing], | |
4769 front_staging[fronting]) == 0) | |
4770 { | |
4771 dest[ii] = front_staging[fronting]; | |
4772 ++fronting; | |
4773 } | |
4774 else | |
4775 { | |
4776 dest[ii] = back_staging[backing]; | |
4777 ++backing; | |
4778 } | |
4779 } | |
4780 | |
4781 UNGCPRO; | |
4782 } | |
4783 | |
4784 static Lisp_Object | |
4785 list_array_merge_into_list (Lisp_Object list, | |
4786 Lisp_Object *array, Elemcount array_len, | |
4787 check_test_func_t check_merge, | |
4788 Lisp_Object predicate, Lisp_Object key, | |
4789 Boolint reverse_order) | |
4790 { | |
4791 Lisp_Object tail = Qnil, value = Qnil, tortoise = list; | |
4792 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
4793 Elemcount array_index = 0; | |
4794 int looped = 0; | |
4795 | |
4796 GCPRO4 (list, tail, value, tortoise); | |
4797 | |
4798 while (1) | |
4799 { | |
4800 if (NILP (list)) | |
4801 { | |
4802 UNGCPRO; | |
4803 | |
4804 if (NILP (tail)) | |
4805 { | |
4806 return Flist (array_len, array); | |
4807 } | |
4808 | |
4809 Fsetcdr (tail, Flist (array_len - array_index, array + array_index)); | |
4810 return value; | |
4811 } | |
4812 | |
4813 if (array_index >= array_len) | |
4814 { | |
4815 UNGCPRO; | |
4816 if (NILP (tail)) | |
4817 { | |
4818 return list; | |
4819 } | |
4820 | |
4821 Fsetcdr (tail, list); | |
4822 return value; | |
4823 } | |
4824 | |
4825 | |
4826 if (reverse_order ? | |
4827 check_merge (predicate, key, Fcar (list), array [array_index]) | |
4828 : !check_merge (predicate, key, array [array_index], Fcar (list))) | |
4829 { | |
4830 if (NILP (tail)) | |
4831 { | |
4832 value = tail = list; | |
4833 } | |
4834 else | |
4835 { | |
4836 Fsetcdr (tail, list); | |
4837 tail = XCDR (tail); | |
4838 } | |
4839 | |
4840 list = Fcdr (list); | |
4841 } | |
4842 else | |
4843 { | |
4844 if (NILP (tail)) | |
4845 { | |
4846 value = tail = Fcons (array [array_index], Qnil); | |
4847 } | |
4848 else | |
4849 { | |
4850 Fsetcdr (tail, Fcons (array [array_index], tail)); | |
4851 tail = XCDR (tail); | |
4852 } | |
4853 ++array_index; | |
4854 } | |
4855 | |
4856 if (++looped > CIRCULAR_LIST_SUSPICION_LENGTH) | |
4857 { | |
4858 if (looped & 1) | |
4859 { | |
4860 tortoise = XCDR (tortoise); | |
4861 } | |
4862 | |
4863 if (EQ (list, tortoise)) | |
4864 { | |
4865 signal_circular_list_error (list); | |
4866 } | |
4867 } | |
4868 } | |
4869 } | |
4870 | |
4871 static void | |
4872 list_list_merge_into_array (Lisp_Object *output, Elemcount output_len, | |
4873 Lisp_Object list_one, Lisp_Object list_two, | |
4874 check_test_func_t check_merge, | |
4875 Lisp_Object predicate, Lisp_Object key) | |
4876 { | |
4877 Elemcount output_index = 0; | |
4878 | |
4879 while (output_index < output_len) | |
4880 { | |
4881 if (NILP (list_one)) | |
4882 { | |
4883 while (output_index < output_len) | |
4884 { | |
4885 output [output_index] = Fcar (list_two); | |
4886 list_two = Fcdr (list_two), ++output_index; | |
4887 } | |
4888 return; | |
4889 } | |
4890 | |
4891 if (NILP (list_two)) | |
4892 { | |
4893 while (output_index < output_len) | |
4894 { | |
4895 output [output_index] = Fcar (list_one); | |
4896 list_one = Fcdr (list_one), ++output_index; | |
4897 } | |
4898 return; | |
4899 } | |
4900 | |
4901 if (check_merge (predicate, key, Fcar (list_two), Fcar (list_one)) | |
4902 == 0) | |
4903 { | |
4904 output [output_index] = XCAR (list_one); | |
4905 list_one = XCDR (list_one); | |
4906 } | |
4907 else | |
4908 { | |
4909 output [output_index] = XCAR (list_two); | |
4910 list_two = XCDR (list_two); | |
4911 } | |
4912 | |
4913 ++output_index; | |
4914 | |
4915 /* No need to check for circularity. */ | |
4916 } | |
4917 } | |
4918 | |
4919 static void | |
4920 list_array_merge_into_array (Lisp_Object *output, Elemcount output_len, | |
4921 Lisp_Object list, | |
4922 Lisp_Object *array, Elemcount array_len, | |
4923 check_test_func_t check_merge, | |
4924 Lisp_Object predicate, Lisp_Object key, | |
4925 Boolint reverse_order) | |
4926 { | |
4927 Elemcount output_index = 0, array_index = 0; | |
4928 | |
4929 while (output_index < output_len) | |
4930 { | |
4931 if (NILP (list)) | |
4932 { | |
4933 if (array_len - array_index != output_len - output_index) | |
4934 { | |
4935 mapping_interaction_error (Qmerge, list); | |
4936 } | |
4937 | |
4938 while (array_index < array_len) | |
4939 { | |
4940 output [output_index++] = array [array_index++]; | |
4941 } | |
4942 | |
4943 return; | |
4944 } | |
4945 | |
4946 if (array_index >= array_len) | |
4947 { | |
4948 while (output_index < output_len) | |
4949 { | |
4950 output [output_index++] = Fcar (list); | |
4951 list = Fcdr (list); | |
4952 } | |
4953 | |
4954 return; | |
4955 } | |
4956 | |
4957 if (reverse_order ? | |
4958 check_merge (predicate, key, Fcar (list), array [array_index]) : | |
4959 !check_merge (predicate, key, array [array_index], Fcar (list))) | |
4960 { | |
4961 output [output_index] = XCAR (list); | |
4962 list = XCDR (list); | |
4963 } | |
4964 else | |
4965 { | |
4966 output [output_index] = array [array_index]; | |
4967 ++array_index; | |
4968 } | |
4969 | |
4970 ++output_index; | |
4971 } | |
4972 } | |
4973 | |
4974 #define STRING_DATA_TO_OBJECT_ARRAY(strdata, c_array, counter, len) \ | |
4975 do { \ | |
4976 c_array = alloca_array (Lisp_Object, len); \ | |
4977 for (counter = 0; counter < len; ++counter) \ | |
4978 { \ | |
4979 c_array[counter] = make_char (itext_ichar (strdata)); \ | |
4980 INC_IBYTEPTR (strdata); \ | |
4981 } \ | |
4982 } while (0) | |
4983 | |
4984 #define BIT_VECTOR_TO_OBJECT_ARRAY(v, c_array, counter, len) do { \ | |
4985 c_array = alloca_array (Lisp_Object, len); \ | |
4986 for (counter = 0; counter < len; ++counter) \ | |
4987 { \ | |
4988 c_array[counter] = make_fixnum (bit_vector_bit (v, counter)); \ | |
4989 } \ | |
4990 } while (0) | |
4991 | |
4992 DEFUN ("merge", Fmerge, 4, MANY, 0, /* | |
4993 Destructively merge SEQUENCE-ONE and SEQUENCE-TWO, producing a new sequence. | |
4994 | |
4995 TYPE is the type of sequence to return. PREDICATE is a `less-than' | |
4996 predicate on the elements. | |
4997 | |
4998 Optional keyword argument KEY is a function used to extract an object to be | |
4999 used for comparison from each element of SEQUENCE-ONE and SEQUENCE-TWO. | |
5000 | |
5001 arguments: (TYPE SEQUENCE-ONE SEQUENCE-TWO PREDICATE &key (KEY #'IDENTITY)) | |
5002 */ | |
5003 (int nargs, Lisp_Object *args)) | |
5004 { | |
5005 Lisp_Object type = args[0], sequence_one = args[1], sequence_two = args[2], | |
5006 predicate = args[3], result = Qnil; | |
5007 check_test_func_t check_merge = NULL; | |
5008 | |
5009 PARSE_KEYWORDS (Fmerge, nargs, args, 1, (key), NULL); | |
5010 | |
5011 CHECK_SEQUENCE (sequence_one); | |
5012 CHECK_SEQUENCE (sequence_two); | |
5013 | |
5014 CHECK_KEY_ARGUMENT (key); | |
5015 | |
5016 check_merge = get_merge_predicate (predicate, key); | |
5017 | |
5018 if (EQ (type, Qlist) && (LISTP (sequence_one) || LISTP (sequence_two))) | |
5019 { | |
5020 if (NILP (sequence_two)) | |
5021 { | |
5022 result = Fappend (2, args + 1); | |
5023 } | |
5024 else if (NILP (sequence_one)) | |
5025 { | |
5026 args[3] = Qnil; /* Overwriting PREDICATE, and losing its GC | |
5027 protection, but that doesn't matter. */ | |
5028 result = Fappend (2, args + 2); | |
5029 } | |
5030 else if (CONSP (sequence_one) && CONSP (sequence_two)) | |
5031 { | |
5032 result = list_merge (sequence_one, sequence_two, check_merge, | |
5033 predicate, key); | |
5034 } | |
5035 else | |
5036 { | |
5037 Lisp_Object *array_storage, swap; | |
5038 Elemcount array_length, i; | |
5039 Boolint reverse_order = 0; | |
5040 | |
5041 if (!CONSP (sequence_one)) | |
5042 { | |
5043 /* Make sequence_one the cons, sequence_two the array: */ | |
5044 swap = sequence_one; | |
5045 sequence_one = sequence_two; | |
5046 sequence_two = swap; | |
5047 reverse_order = 1; | |
5048 } | |
5049 | |
5050 if (VECTORP (sequence_two)) | |
5051 { | |
5052 array_storage = XVECTOR_DATA (sequence_two); | |
5053 array_length = XVECTOR_LENGTH (sequence_two); | |
5054 } | |
5055 else if (STRINGP (sequence_two)) | |
5056 { | |
5057 Ibyte *strdata = XSTRING_DATA (sequence_two); | |
5058 array_length = string_char_length (sequence_two); | |
5059 /* No need to GCPRO, characters are immediate. */ | |
5060 STRING_DATA_TO_OBJECT_ARRAY (strdata, array_storage, i, | |
5061 array_length); | |
5062 | |
5063 } | |
5064 else | |
5065 { | |
5066 Lisp_Bit_Vector *v = XBIT_VECTOR (sequence_two); | |
5067 array_length = bit_vector_length (v); | |
5068 /* No need to GCPRO, fixnums are immediate. */ | |
5069 BIT_VECTOR_TO_OBJECT_ARRAY (v, array_storage, i, array_length); | |
5070 } | |
5071 | |
5072 result = list_array_merge_into_list (sequence_one, | |
5073 array_storage, array_length, | |
5074 check_merge, predicate, key, | |
5075 reverse_order); | |
5076 } | |
5077 } | |
5078 else | |
5079 { | |
5080 Elemcount sequence_one_len = XFIXNUM (Flength (sequence_one)), | |
5081 sequence_two_len = XFIXNUM (Flength (sequence_two)), i; | |
5082 Elemcount output_len = 1 + sequence_one_len + sequence_two_len; | |
5083 Lisp_Object *output = alloca_array (Lisp_Object, output_len), | |
5084 *sequence_one_storage = NULL, *sequence_two_storage = NULL; | |
5085 Boolint do_coerce = !(EQ (type, Qvector) || EQ (type, Qstring) | |
5086 || EQ (type, Qbit_vector) || EQ (type, Qlist)); | |
5087 Ibyte *strdata = NULL; | |
5088 Lisp_Bit_Vector *v = NULL; | |
5089 struct gcpro gcpro1; | |
5090 | |
5091 output[0] = do_coerce ? Qlist : type; | |
5092 for (i = 1; i < output_len; ++i) | |
5093 { | |
5094 output[i] = Qnil; | |
5095 } | |
5096 | |
5097 GCPRO1 (output[0]); | |
5098 gcpro1.nvars = output_len; | |
5099 | |
5100 if (VECTORP (sequence_one)) | |
5101 { | |
5102 sequence_one_storage = XVECTOR_DATA (sequence_one); | |
5103 } | |
5104 else if (STRINGP (sequence_one)) | |
5105 { | |
5106 strdata = XSTRING_DATA (sequence_one); | |
5107 STRING_DATA_TO_OBJECT_ARRAY (strdata, sequence_one_storage, | |
5108 i, sequence_one_len); | |
5109 } | |
5110 else if (BIT_VECTORP (sequence_one)) | |
5111 { | |
5112 v = XBIT_VECTOR (sequence_one); | |
5113 BIT_VECTOR_TO_OBJECT_ARRAY (v, sequence_one_storage, | |
5114 i, sequence_one_len); | |
5115 } | |
5116 | |
5117 if (VECTORP (sequence_two)) | |
5118 { | |
5119 sequence_two_storage = XVECTOR_DATA (sequence_two); | |
5120 } | |
5121 else if (STRINGP (sequence_two)) | |
5122 { | |
5123 strdata = XSTRING_DATA (sequence_two); | |
5124 STRING_DATA_TO_OBJECT_ARRAY (strdata, sequence_two_storage, | |
5125 i, sequence_two_len); | |
5126 } | |
5127 else if (BIT_VECTORP (sequence_two)) | |
5128 { | |
5129 v = XBIT_VECTOR (sequence_two); | |
5130 BIT_VECTOR_TO_OBJECT_ARRAY (v, sequence_two_storage, | |
5131 i, sequence_two_len); | |
5132 } | |
5133 | |
5134 if (LISTP (sequence_one) && LISTP (sequence_two)) | |
5135 { | |
5136 list_list_merge_into_array (output + 1, output_len - 1, | |
5137 sequence_one, sequence_two, | |
5138 check_merge, predicate, key); | |
5139 } | |
5140 else if (LISTP (sequence_one)) | |
5141 { | |
5142 list_array_merge_into_array (output + 1, output_len - 1, | |
5143 sequence_one, | |
5144 sequence_two_storage, | |
5145 sequence_two_len, | |
5146 check_merge, predicate, key, 0); | |
5147 } | |
5148 else if (LISTP (sequence_two)) | |
5149 { | |
5150 list_array_merge_into_array (output + 1, output_len - 1, | |
5151 sequence_two, | |
5152 sequence_one_storage, | |
5153 sequence_one_len, | |
5154 check_merge, predicate, key, 1); | |
5155 } | |
5156 else | |
5157 { | |
5158 array_merge (output + 1, output_len - 1, | |
5159 sequence_one_storage, sequence_one_len, | |
5160 sequence_two_storage, sequence_two_len, | |
5161 check_merge, predicate, | |
5162 key); | |
5163 } | |
5164 | |
5165 result = Ffuncall (output_len, output); | |
5166 | |
5167 if (do_coerce) | |
5168 { | |
5169 result = call2 (Qcoerce, result, type); | |
5170 } | |
5171 | |
5172 UNGCPRO; | |
5173 } | |
5174 | |
5175 return result; | |
5176 } | |
5177 | |
5178 Lisp_Object | |
5179 list_sort (Lisp_Object list, check_test_func_t check_merge, | |
5180 Lisp_Object predicate, Lisp_Object key) | |
5181 { | |
5182 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
5183 Lisp_Object back, tem; | |
5184 Lisp_Object front = list; | |
5185 Lisp_Object len = Flength (list); | |
5186 | |
5187 if (XFIXNUM (len) < 2) | |
5188 return list; | |
5189 | |
5190 len = make_fixnum (XFIXNUM (len) / 2 - 1); | |
5191 tem = Fnthcdr (len, list); | |
5192 back = Fcdr (tem); | |
5193 Fsetcdr (tem, Qnil); | |
5194 | |
5195 GCPRO4 (front, back, predicate, key); | |
5196 front = list_sort (front, check_merge, predicate, key); | |
5197 back = list_sort (back, check_merge, predicate, key); | |
5198 | |
5199 RETURN_UNGCPRO (list_merge (front, back, check_merge, predicate, key)); | |
5200 } | |
5201 | |
5202 static void | |
5203 array_sort (Lisp_Object *array, Elemcount array_len, | |
5204 check_test_func_t check_merge, | |
5205 Lisp_Object predicate, Lisp_Object key) | |
5206 { | |
5207 Elemcount split; | |
5208 | |
5209 if (array_len < 2) | |
5210 return; | |
5211 | |
5212 split = array_len / 2; | |
5213 | |
5214 array_sort (array, split, check_merge, predicate, key); | |
5215 array_sort (array + split, array_len - split, check_merge, predicate, | |
5216 key); | |
5217 array_merge (array, array_len, array, split, array + split, | |
5218 array_len - split, check_merge, predicate, key); | |
5219 } | |
5220 | |
5221 DEFUN ("sort*", FsortX, 2, MANY, 0, /* | |
5222 Sort SEQUENCE, comparing elements using PREDICATE. | |
5223 Returns the sorted sequence. SEQUENCE is modified by side effect. | |
5224 | |
5225 PREDICATE is called with two elements of SEQUENCE, and should return t if | |
5226 the first element is `less' than the second. | |
5227 | |
5228 Optional keyword argument KEY is a function used to extract an object to be | |
5229 used for comparison from each element of SEQUENCE. | |
5230 | |
5231 In this implementation, sorting is always stable; but call `stable-sort' if | |
5232 this stability is important to you, other implementations may not make the | |
5233 same guarantees. | |
5234 | |
5235 arguments: (SEQUENCE PREDICATE &key (KEY #'IDENTITY)) | |
5236 */ | |
5237 (int nargs, Lisp_Object *args)) | |
5238 { | |
5239 Lisp_Object sequence = args[0], predicate = args[1]; | |
5240 Lisp_Object *sequence_carray; | |
5241 check_test_func_t check_merge = NULL; | |
5242 Elemcount sequence_len, i; | |
5243 | |
5244 PARSE_KEYWORDS (FsortX, nargs, args, 1, (key), NULL); | |
5245 | |
5246 CHECK_SEQUENCE (sequence); | |
5247 | |
5248 CHECK_KEY_ARGUMENT (key); | |
5249 | |
5250 check_merge = get_merge_predicate (predicate, key); | |
5251 | |
5252 if (LISTP (sequence)) | |
5253 { | |
5254 sequence = list_sort (sequence, check_merge, predicate, key); | |
5255 } | |
5256 else if (VECTORP (sequence)) | |
5257 { | |
5258 array_sort (XVECTOR_DATA (sequence), XVECTOR_LENGTH (sequence), | |
5259 check_merge, predicate, key); | |
5260 } | |
5261 else if (STRINGP (sequence)) | |
5262 { | |
5263 Ibyte *strdata = XSTRING_DATA (sequence); | |
5264 | |
5265 sequence_len = string_char_length (sequence); | |
5266 | |
5267 STRING_DATA_TO_OBJECT_ARRAY (strdata, sequence_carray, i, sequence_len); | |
5268 | |
5269 /* No GCPRO necessary, characters are immediate. */ | |
5270 array_sort (sequence_carray, sequence_len, check_merge, predicate, key); | |
5271 | |
5272 strdata = XSTRING_DATA (sequence); | |
5273 | |
5274 CHECK_LISP_WRITEABLE (sequence); | |
5275 for (i = 0; i < sequence_len; ++i) | |
5276 { | |
5277 strdata += set_itext_ichar (strdata, XCHAR (sequence_carray[i])); | |
5278 } | |
5279 | |
5280 init_string_ascii_begin (sequence); | |
5281 bump_string_modiff (sequence); | |
5282 sledgehammer_check_ascii_begin (sequence); | |
5283 } | |
5284 else if (BIT_VECTORP (sequence)) | |
5285 { | |
5286 Lisp_Bit_Vector *v = XBIT_VECTOR (sequence); | |
5287 sequence_len = bit_vector_length (v); | |
5288 | |
5289 BIT_VECTOR_TO_OBJECT_ARRAY (v, sequence_carray, i, sequence_len); | |
5290 | |
5291 /* No GCPRO necessary, bits are immediate. */ | |
5292 array_sort (sequence_carray, sequence_len, check_merge, predicate, key); | |
5293 | |
5294 for (i = 0; i < sequence_len; ++i) | |
5295 { | |
5296 set_bit_vector_bit (v, i, XFIXNUM (sequence_carray [i])); | |
5297 } | |
5298 } | |
5299 | |
5300 return sequence; | |
5301 } | |
5302 | 1167 |
5303 /************************************************************************/ | 1168 /************************************************************************/ |
5304 /* property-list functions */ | 1169 /* property-list functions */ |
5305 /************************************************************************/ | 1170 /************************************************************************/ |
5306 | 1171 |
6424 return elt; | 2289 return elt; |
6425 } | 2290 } |
6426 return Qnil; | 2291 return Qnil; |
6427 } | 2292 } |
6428 | 2293 |
2294 DEFUN ("old-rassq", Fold_rassq, 2, 2, 0, /* | |
2295 Return non-nil if VALUE is `old-eq' to the cdr of an element of ALIST. | |
2296 The value is actually the element of ALIST whose cdr is VALUE. | |
2297 */ | |
2298 (value, alist)) | |
2299 { | |
2300 EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist) | |
2301 { | |
2302 if (HACKEQ_UNSAFE (value, elt_cdr)) | |
2303 return elt; | |
2304 } | |
2305 return Qnil; | |
2306 } | |
2307 | |
6429 DEFUN ("old-rassoc", Fold_rassoc, 2, 2, 0, /* | 2308 DEFUN ("old-rassoc", Fold_rassoc, 2, 2, 0, /* |
6430 Return non-nil if VALUE is `old-equal' to the cdr of an element of ALIST. | 2309 Return non-nil if VALUE is `old-equal' to the cdr of an element of ALIST. |
6431 The value is actually the element of ALIST whose cdr equals VALUE. | 2310 The value is actually the element of ALIST whose cdr equals VALUE. |
6432 */ | 2311 */ |
6433 (value, alist)) | 2312 (value, alist)) |
6499 /* #### blasphemy */ | 2378 /* #### blasphemy */ |
6500 return HACKEQ_UNSAFE (object1, object2) ? Qt : Qnil; | 2379 return HACKEQ_UNSAFE (object1, object2) ? Qt : Qnil; |
6501 } | 2380 } |
6502 | 2381 |
6503 #endif | 2382 #endif |
6504 | |
6505 | |
6506 static Lisp_Object replace_string_range_1 (Lisp_Object dest, | |
6507 Lisp_Object start, | |
6508 Lisp_Object end, | |
6509 const Ibyte *source, | |
6510 const Ibyte *source_limit, | |
6511 Lisp_Object item); | |
6512 | |
6513 /* Fill the substring of DEST beginning at START and ending before END with | |
6514 the character ITEM. If DEST does not have sufficient space for END - | |
6515 START characters at START, write as many as is possible without changing | |
6516 the character length of DEST. Update the string modification flag and do | |
6517 any sledgehammer checks we have turned on. | |
6518 | |
6519 START must be a Lisp integer. END can be nil, indicating the length of the | |
6520 string, or a Lisp integer. The condition (<= 0 START END (length DEST)) | |
6521 must hold, or fill_string_range() will signal an error. */ | |
6522 static Lisp_Object | |
6523 fill_string_range (Lisp_Object dest, Lisp_Object item, Lisp_Object start, | |
6524 Lisp_Object end) | |
6525 { | |
6526 return replace_string_range_1 (dest, start, end, NULL, NULL, item); | |
6527 } | |
6528 | |
6529 DEFUN ("fill", Ffill, 2, MANY, 0, /* | |
6530 Destructively modify SEQUENCE by replacing each element with ITEM. | |
6531 SEQUENCE is a list, vector, bit vector, or string. | |
6532 | |
6533 Optional keyword START is the index of the first element of SEQUENCE | |
6534 to be modified, and defaults to zero. Optional keyword END is the | |
6535 exclusive upper bound on the elements of SEQUENCE to be modified, and | |
6536 defaults to the length of SEQUENCE. | |
6537 | |
6538 arguments: (SEQUENCE ITEM &key (START 0) (END (length SEQUENCE))) | |
6539 */ | |
6540 (int nargs, Lisp_Object *args)) | |
6541 { | |
6542 Lisp_Object sequence = args[0]; | |
6543 Lisp_Object item = args[1]; | |
6544 Elemcount starting, ending = MOST_POSITIVE_FIXNUM + 1, ii, len; | |
6545 | |
6546 PARSE_KEYWORDS (Ffill, nargs, args, 2, (start, end), (start = Qzero)); | |
6547 | |
6548 CHECK_NATNUM (start); | |
6549 starting = BIGNUMP (start) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start); | |
6550 | |
6551 if (!NILP (end)) | |
6552 { | |
6553 CHECK_NATNUM (end); | |
6554 ending = BIGNUMP (end) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end); | |
6555 } | |
6556 | |
6557 retry: | |
6558 if (STRINGP (sequence)) | |
6559 { | |
6560 CHECK_CHAR_COERCE_INT (item); | |
6561 CHECK_LISP_WRITEABLE (sequence); | |
6562 | |
6563 fill_string_range (sequence, item, start, end); | |
6564 } | |
6565 else if (VECTORP (sequence)) | |
6566 { | |
6567 Lisp_Object *p = XVECTOR_DATA (sequence); | |
6568 | |
6569 CHECK_LISP_WRITEABLE (sequence); | |
6570 len = XVECTOR_LENGTH (sequence); | |
6571 | |
6572 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
6573 ending = min (ending, len); | |
6574 | |
6575 for (ii = starting; ii < ending; ++ii) | |
6576 { | |
6577 p[ii] = item; | |
6578 } | |
6579 } | |
6580 else if (BIT_VECTORP (sequence)) | |
6581 { | |
6582 Lisp_Bit_Vector *v = XBIT_VECTOR (sequence); | |
6583 int bit; | |
6584 | |
6585 CHECK_BIT (item); | |
6586 bit = XFIXNUM (item); | |
6587 CHECK_LISP_WRITEABLE (sequence); | |
6588 len = bit_vector_length (v); | |
6589 | |
6590 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
6591 ending = min (ending, len); | |
6592 | |
6593 for (ii = starting; ii < ending; ++ii) | |
6594 { | |
6595 set_bit_vector_bit (v, ii, bit); | |
6596 } | |
6597 } | |
6598 else if (LISTP (sequence)) | |
6599 { | |
6600 Elemcount counting = 0; | |
6601 | |
6602 { | |
6603 EXTERNAL_LIST_LOOP_3 (elt, sequence, tail) | |
6604 { | |
6605 if (counting >= starting) | |
6606 { | |
6607 if (counting < ending) | |
6608 { | |
6609 XSETCAR (tail, item); | |
6610 } | |
6611 else if (counting == ending) | |
6612 { | |
6613 break; | |
6614 } | |
6615 } | |
6616 ++counting; | |
6617 } | |
6618 } | |
6619 | |
6620 if (counting < starting || (counting != ending && !NILP (end))) | |
6621 { | |
6622 check_sequence_range (args[0], start, end, Flength (args[0])); | |
6623 } | |
6624 } | |
6625 else | |
6626 { | |
6627 sequence = wrong_type_argument (Qsequencep, sequence); | |
6628 goto retry; | |
6629 } | |
6630 return sequence; | |
6631 } | |
6632 | 2383 |
6633 Lisp_Object | 2384 Lisp_Object |
6634 nconc2 (Lisp_Object arg1, Lisp_Object arg2) | 2385 nconc2 (Lisp_Object arg1, Lisp_Object arg2) |
6635 { | 2386 { |
6636 Lisp_Object args[2]; | 2387 Lisp_Object args[2]; |
6763 } | 2514 } |
6764 RETURN_UNGCPRO (Qnil); /* No non-nil args provided. */ | 2515 RETURN_UNGCPRO (Qnil); /* No non-nil args provided. */ |
6765 } | 2516 } |
6766 | 2517 |
6767 | 2518 |
6768 /* Replace the substring of DEST beginning at START and ending before END | |
6769 with the text at SOURCE, which is END - START characters long and | |
6770 SOURCE_LIMIT - SOURCE octets long. If DEST does not have sufficient | |
6771 space for END - START characters at START, write as many as is possible | |
6772 without changing the length of DEST. Update the string modification flag | |
6773 and do any sledgehammer checks we have turned on in this build. | |
6774 | |
6775 START must be a Lisp integer. END can be nil, indicating the length of the | |
6776 string, or a Lisp integer. The condition (<= 0 START END (length DEST)) | |
6777 must hold, or replace_string_range() will signal an error. */ | |
6778 static Lisp_Object | |
6779 replace_string_range (Lisp_Object dest, Lisp_Object start, Lisp_Object end, | |
6780 const Ibyte *source, const Ibyte *source_limit) | |
6781 { | |
6782 return replace_string_range_1 (dest, start, end, source, source_limit, | |
6783 Qnil); | |
6784 } | |
6785 | |
6786 /* This is the guts of several mapping functions. | |
6787 | |
6788 Call FUNCTION CALL_COUNT times, with NSEQUENCES arguments each time, | |
6789 taking the elements from SEQUENCES. If VALS is non-NULL, store the | |
6790 results into VALS, a C array of Lisp_Objects; else, if LISP_VALS is | |
6791 non-nil, store the results into LISP_VALS, a sequence with sufficient | |
6792 room for CALL_COUNT results (but see the documentation of SOME_OR_EVERY.) | |
6793 Else, do not accumulate any result. | |
6794 | |
6795 If VALS is non-NULL, NSEQUENCES is one, and SEQUENCES[0] is a cons, | |
6796 mapcarX will store the elements of SEQUENCES[0] in stack and GCPRO them, | |
6797 so FUNCTION cannot insert a non-cons into SEQUENCES[0] and throw off | |
6798 mapcarX. | |
6799 | |
6800 Otherwise, mapcarX signals an invalid state error (see | |
6801 mapping_interaction_error(), above) if it encounters a non-cons, | |
6802 non-array when traversing SEQUENCES. Common Lisp specifies in | |
6803 MAPPING-DESTRUCTIVE-INTERACTION that it is an error when FUNCTION | |
6804 destructively modifies SEQUENCES in a way that might affect the ongoing | |
6805 traversal operation. | |
6806 | |
6807 CALLER is a symbol describing the Lisp-visible function that was called, | |
6808 and any errors thrown because SEQUENCES was modified will reflect it. | |
6809 | |
6810 If CALLER is Qsome, return the (possibly multiple) values given by | |
6811 FUNCTION the first time it is non-nil, and abandon the iterations. | |
6812 LISP_VALS must be the result of calling STORE_VOID_IN_LISP on the address | |
6813 of a Lisp object, and the return value will be stored at that address. | |
6814 If CALLER is Qevery, LISP_VALS must also reflect a pointer to a Lisp | |
6815 object, and Qnil will be stored at that address if FUNCTION gives nil; | |
6816 otherwise it will be left alone. */ | |
6817 | |
6818 static void | |
6819 mapcarX (Elemcount call_count, Lisp_Object *vals, Lisp_Object lisp_vals, | |
6820 Lisp_Object function, int nsequences, Lisp_Object *sequences, | |
6821 Lisp_Object caller) | |
6822 { | |
6823 Lisp_Object called, *args; | |
6824 struct gcpro gcpro1, gcpro2; | |
6825 Ibyte *lisp_vals_staging = NULL, *cursor = NULL; | |
6826 int i, j; | |
6827 | |
6828 assert ((EQ (caller, Qsome) || EQ (caller, Qevery)) ? vals == NULL : 1); | |
6829 | |
6830 args = alloca_array (Lisp_Object, nsequences + 1); | |
6831 args[0] = function; | |
6832 for (i = 1; i <= nsequences; ++i) | |
6833 { | |
6834 args[i] = Qnil; | |
6835 } | |
6836 | |
6837 if (vals != NULL) | |
6838 { | |
6839 GCPRO2 (args[0], vals[0]); | |
6840 gcpro1.nvars = nsequences + 1; | |
6841 gcpro2.nvars = 0; | |
6842 } | |
6843 else | |
6844 { | |
6845 GCPRO1 (args[0]); | |
6846 gcpro1.nvars = nsequences + 1; | |
6847 } | |
6848 | |
6849 /* Be extra nice in the event that we've been handed one list and one | |
6850 only; make it possible for FUNCTION to set cdrs not yet processed to | |
6851 non-cons, non-nil objects without ill-effect, if we have been handed | |
6852 the stack space to do that. */ | |
6853 if (vals != NULL && 1 == nsequences && CONSP (sequences[0])) | |
6854 { | |
6855 Lisp_Object lst = sequences[0]; | |
6856 Lisp_Object *val = vals; | |
6857 for (i = 0; i < call_count; ++i) | |
6858 { | |
6859 *val++ = XCAR (lst); | |
6860 lst = XCDR (lst); | |
6861 } | |
6862 gcpro2.nvars = call_count; | |
6863 | |
6864 for (i = 0; i < call_count; ++i) | |
6865 { | |
6866 args[1] = vals[i]; | |
6867 vals[i] = IGNORE_MULTIPLE_VALUES (Ffuncall (nsequences + 1, args)); | |
6868 } | |
6869 } | |
6870 else | |
6871 { | |
6872 enum lrecord_type lisp_vals_type = lrecord_type_symbol; | |
6873 Binbyte *sequence_types = alloca_array (Binbyte, nsequences); | |
6874 for (j = 0; j < nsequences; ++j) | |
6875 { | |
6876 sequence_types[j] = XRECORD_LHEADER (sequences[j])->type; | |
6877 } | |
6878 | |
6879 if (!EQ (caller, Qsome) && !EQ (caller, Qevery)) | |
6880 { | |
6881 assert (LRECORDP (lisp_vals)); | |
6882 | |
6883 lisp_vals_type | |
6884 = (enum lrecord_type) XRECORD_LHEADER (lisp_vals)->type; | |
6885 | |
6886 if (lrecord_type_string == lisp_vals_type) | |
6887 { | |
6888 lisp_vals_staging = cursor | |
6889 = alloca_ibytes (call_count * MAX_ICHAR_LEN); | |
6890 } | |
6891 else if (ARRAYP (lisp_vals)) | |
6892 { | |
6893 CHECK_LISP_WRITEABLE (lisp_vals); | |
6894 } | |
6895 } | |
6896 | |
6897 for (i = 0; i < call_count; ++i) | |
6898 { | |
6899 for (j = 0; j < nsequences; ++j) | |
6900 { | |
6901 switch (sequence_types[j]) | |
6902 { | |
6903 case lrecord_type_cons: | |
6904 { | |
6905 if (!CONSP (sequences[j])) | |
6906 { | |
6907 /* This means FUNCTION has messed around with a cons | |
6908 in one of the sequences, since we checked the | |
6909 type (CHECK_SEQUENCE()) and the length and | |
6910 structure (with Flength()) correctly in our | |
6911 callers. */ | |
6912 mapping_interaction_error (caller, sequences[j]); | |
6913 } | |
6914 args[j + 1] = XCAR (sequences[j]); | |
6915 sequences[j] = XCDR (sequences[j]); | |
6916 break; | |
6917 } | |
6918 case lrecord_type_vector: | |
6919 { | |
6920 args[j + 1] = XVECTOR_DATA (sequences[j])[i]; | |
6921 break; | |
6922 } | |
6923 case lrecord_type_string: | |
6924 { | |
6925 args[j + 1] = make_char (string_ichar (sequences[j], i)); | |
6926 break; | |
6927 } | |
6928 case lrecord_type_bit_vector: | |
6929 { | |
6930 args[j + 1] | |
6931 = make_fixnum (bit_vector_bit (XBIT_VECTOR (sequences[j]), | |
6932 i)); | |
6933 break; | |
6934 } | |
6935 default: | |
6936 ABORT(); | |
6937 } | |
6938 } | |
6939 called = Ffuncall (nsequences + 1, args); | |
6940 if (vals != NULL) | |
6941 { | |
6942 vals[i] = IGNORE_MULTIPLE_VALUES (called); | |
6943 gcpro2.nvars += 1; | |
6944 } | |
6945 else if (EQ (Qsome, caller)) | |
6946 { | |
6947 if (!NILP (IGNORE_MULTIPLE_VALUES (called))) | |
6948 { | |
6949 Lisp_Object *result | |
6950 = (Lisp_Object *) GET_VOID_FROM_LISP (lisp_vals); | |
6951 *result = called; | |
6952 UNGCPRO; | |
6953 return; | |
6954 } | |
6955 } | |
6956 else if (EQ (Qevery, caller)) | |
6957 { | |
6958 if (NILP (IGNORE_MULTIPLE_VALUES (called))) | |
6959 { | |
6960 Lisp_Object *result | |
6961 = (Lisp_Object *) GET_VOID_FROM_LISP (lisp_vals); | |
6962 *result = Qnil; | |
6963 UNGCPRO; | |
6964 return; | |
6965 } | |
6966 } | |
6967 else | |
6968 { | |
6969 called = IGNORE_MULTIPLE_VALUES (called); | |
6970 switch (lisp_vals_type) | |
6971 { | |
6972 case lrecord_type_symbol: | |
6973 /* Discard the result of funcall. */ | |
6974 break; | |
6975 case lrecord_type_cons: | |
6976 { | |
6977 if (!CONSP (lisp_vals)) | |
6978 { | |
6979 /* If FUNCTION has inserted a non-cons non-nil | |
6980 cdr into the list before we've processed the | |
6981 relevant part, error. */ | |
6982 mapping_interaction_error (caller, lisp_vals); | |
6983 } | |
6984 XSETCAR (lisp_vals, called); | |
6985 lisp_vals = XCDR (lisp_vals); | |
6986 break; | |
6987 } | |
6988 case lrecord_type_vector: | |
6989 { | |
6990 i < XVECTOR_LENGTH (lisp_vals) ? | |
6991 (XVECTOR_DATA (lisp_vals)[i] = called) : | |
6992 /* Let #'aset error. */ | |
6993 Faset (lisp_vals, make_fixnum (i), called); | |
6994 break; | |
6995 } | |
6996 case lrecord_type_string: | |
6997 { | |
6998 CHECK_CHAR_COERCE_INT (called); | |
6999 cursor += set_itext_ichar (cursor, XCHAR (called)); | |
7000 break; | |
7001 } | |
7002 case lrecord_type_bit_vector: | |
7003 { | |
7004 (BITP (called) && | |
7005 i < bit_vector_length (XBIT_VECTOR (lisp_vals))) ? | |
7006 set_bit_vector_bit (XBIT_VECTOR (lisp_vals), i, | |
7007 XFIXNUM (called)) : | |
7008 (void) Faset (lisp_vals, make_fixnum (i), called); | |
7009 break; | |
7010 } | |
7011 default: | |
7012 { | |
7013 ABORT(); | |
7014 break; | |
7015 } | |
7016 } | |
7017 } | |
7018 } | |
7019 | |
7020 if (lisp_vals_staging != NULL) | |
7021 { | |
7022 CHECK_LISP_WRITEABLE (lisp_vals); | |
7023 replace_string_range (lisp_vals, Qzero, make_fixnum (call_count), | |
7024 lisp_vals_staging, cursor); | |
7025 } | |
7026 } | |
7027 | |
7028 UNGCPRO; | |
7029 } | |
7030 | |
7031 /* Given NSEQUENCES objects at the address pointed to by SEQUENCES, return | |
7032 the length of the shortest sequence. Error if all are circular, or if any | |
7033 one of them is not a sequence. */ | |
7034 static Elemcount | |
7035 shortest_length_among_sequences (int nsequences, Lisp_Object *sequences) | |
7036 { | |
7037 Elemcount len = 1 + MOST_POSITIVE_FIXNUM; | |
7038 Lisp_Object length = Qnil; | |
7039 int i; | |
7040 | |
7041 for (i = 0; i < nsequences; ++i) | |
7042 { | |
7043 if (CONSP (sequences[i])) | |
7044 { | |
7045 length = Flist_length (sequences[i]); | |
7046 if (!NILP (length)) | |
7047 { | |
7048 len = min (len, XFIXNUM (length)); | |
7049 } | |
7050 } | |
7051 else | |
7052 { | |
7053 CHECK_SEQUENCE (sequences[i]); | |
7054 length = Flength (sequences[i]); | |
7055 len = min (len, XFIXNUM (length)); | |
7056 } | |
7057 } | |
7058 | |
7059 if (len == 1 + MOST_POSITIVE_FIXNUM) | |
7060 { | |
7061 signal_circular_list_error (sequences[0]); | |
7062 } | |
7063 | |
7064 return len; | |
7065 } | |
7066 | |
7067 DEFUN ("mapconcat", Fmapconcat, 3, MANY, 0, /* | |
7068 Call FUNCTION on each element of SEQUENCE, and concat results to a string. | |
7069 Between each pair of results, insert SEPARATOR. | |
7070 | |
7071 Each result, and SEPARATOR, should be strings. Thus, using " " as SEPARATOR | |
7072 results in spaces between the values returned by FUNCTION. SEQUENCE itself | |
7073 may be a list, a vector, a bit vector, or a string. | |
7074 | |
7075 With optional SEQUENCES, call FUNCTION each time with as many arguments as | |
7076 there are SEQUENCES, plus one for the element from SEQUENCE. One element | |
7077 from each sequence will be used each time FUNCTION is called, and | |
7078 `mapconcat' will give up once the shortest sequence is exhausted. | |
7079 | |
7080 arguments: (FUNCTION SEQUENCE SEPARATOR &rest SEQUENCES) | |
7081 */ | |
7082 (int nargs, Lisp_Object *args)) | |
7083 { | |
7084 Lisp_Object function = args[0]; | |
7085 Lisp_Object sequence = args[1]; | |
7086 Lisp_Object separator = args[2]; | |
7087 Elemcount len = MOST_POSITIVE_FIXNUM; | |
7088 Lisp_Object *args0; | |
7089 EMACS_INT i, nargs0; | |
7090 | |
7091 args[2] = sequence; | |
7092 args[1] = separator; | |
7093 | |
7094 len = shortest_length_among_sequences (nargs - 2, args + 2); | |
7095 | |
7096 if (len == 0) return build_ascstring (""); | |
7097 | |
7098 nargs0 = len + len - 1; | |
7099 args0 = alloca_array (Lisp_Object, nargs0); | |
7100 | |
7101 /* Special-case this, it's very common and doesn't require any | |
7102 funcalls. Upside of doing it here, instead of cl-macs.el: no consing, | |
7103 apart from the final string, we allocate everything on the stack. */ | |
7104 if (EQ (function, Qidentity) && 3 == nargs && CONSP (sequence)) | |
7105 { | |
7106 for (i = 0; i < len; ++i) | |
7107 { | |
7108 args0[i] = XCAR (sequence); | |
7109 sequence = XCDR (sequence); | |
7110 } | |
7111 } | |
7112 else | |
7113 { | |
7114 mapcarX (len, args0, Qnil, function, nargs - 2, args + 2, Qmapconcat); | |
7115 } | |
7116 | |
7117 for (i = len - 1; i >= 0; i--) | |
7118 args0[i + i] = args0[i]; | |
7119 | |
7120 for (i = 1; i < nargs0; i += 2) | |
7121 args0[i] = separator; | |
7122 | |
7123 return Fconcat (nargs0, args0); | |
7124 } | |
7125 | |
7126 DEFUN ("mapcar*", FmapcarX, 2, MANY, 0, /* | |
7127 Call FUNCTION on each element of SEQUENCE; return a list of the results. | |
7128 The result is a list of the same length as SEQUENCE. | |
7129 SEQUENCE may be a list, a vector, a bit vector, or a string. | |
7130 | |
7131 With optional SEQUENCES, call FUNCTION each time with as many arguments as | |
7132 there are SEQUENCES, plus one for the element from SEQUENCE. One element | |
7133 from each sequence will be used each time FUNCTION is called, and `mapcar' | |
7134 stops calling FUNCTION once the shortest sequence is exhausted. | |
7135 | |
7136 arguments: (FUNCTION SEQUENCE &rest SEQUENCES) | |
7137 */ | |
7138 (int nargs, Lisp_Object *args)) | |
7139 { | |
7140 Lisp_Object function = args[0]; | |
7141 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); | |
7142 Lisp_Object *args0; | |
7143 | |
7144 args0 = alloca_array (Lisp_Object, len); | |
7145 mapcarX (len, args0, Qnil, function, nargs - 1, args + 1, QmapcarX); | |
7146 | |
7147 return Flist ((int) len, args0); | |
7148 } | |
7149 | |
7150 DEFUN ("mapvector", Fmapvector, 2, MANY, 0, /* | |
7151 Call FUNCTION on each element of SEQUENCE; return a vector of the results. | |
7152 The result is a vector of the same length as SEQUENCE. | |
7153 SEQUENCE may be a list, a vector, a bit vector, or a string. | |
7154 | |
7155 With optional SEQUENCES, call FUNCTION each time with as many arguments as | |
7156 there are SEQUENCES, plus one for the element from SEQUENCE. One element | |
7157 from each sequence will be used each time FUNCTION is called, and | |
7158 `mapvector' stops calling FUNCTION once the shortest sequence is exhausted. | |
7159 | |
7160 arguments: (FUNCTION SEQUENCE &rest SEQUENCES) | |
7161 */ | |
7162 (int nargs, Lisp_Object *args)) | |
7163 { | |
7164 Lisp_Object function = args[0]; | |
7165 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); | |
7166 Lisp_Object result = make_vector (len, Qnil); | |
7167 | |
7168 struct gcpro gcpro1; | |
7169 GCPRO1 (result); | |
7170 /* Don't pass result as the lisp_object argument, we want mapcarX to protect | |
7171 a single list argument's elements from being garbage-collected. */ | |
7172 mapcarX (len, XVECTOR_DATA (result), Qnil, function, nargs - 1, args +1, | |
7173 Qmapvector); | |
7174 RETURN_UNGCPRO (result); | |
7175 } | |
7176 | |
7177 DEFUN ("mapcan", Fmapcan, 2, MANY, 0, /* | |
7178 Call FUNCTION on each element of SEQUENCE; chain the results together. | |
7179 | |
7180 FUNCTION must normally return a list; the results will be concatenated | |
7181 together using `nconc'. | |
7182 | |
7183 With optional SEQUENCES, call FUNCTION each time with as many arguments as | |
7184 there are SEQUENCES, plus one for the element from SEQUENCE. One element | |
7185 from each sequence will be used each time FUNCTION is called, and | |
7186 `mapcan' stops calling FUNCTION once the shortest sequence is exhausted. | |
7187 | |
7188 arguments: (FUNCTION SEQUENCE &rest SEQUENCES) | |
7189 */ | |
7190 (int nargs, Lisp_Object *args)) | |
7191 { | |
7192 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); | |
7193 Lisp_Object function = args[0], *result = alloca_array (Lisp_Object, len); | |
7194 | |
7195 mapcarX (len, result, Qnil, function, nargs - 1, args + 1, Qmapcan); | |
7196 | |
7197 /* #'nconc GCPROs its args in case of signals and error. */ | |
7198 return Fnconc (len, result); | |
7199 } | |
7200 | |
7201 DEFUN ("mapc", Fmapc, 2, MANY, 0, /* | |
7202 Call FUNCTION on each element of SEQUENCE. | |
7203 | |
7204 SEQUENCE may be a list, a vector, a bit vector, or a string. | |
7205 This function is like `mapcar' but does not accumulate the results, | |
7206 which is more efficient if you do not use the results. | |
7207 | |
7208 With optional SEQUENCES, call FUNCTION each time with as many arguments as | |
7209 there are SEQUENCES, plus one for the elements from SEQUENCE. One element | |
7210 from each sequence will be used each time FUNCTION is called, and | |
7211 `mapc' stops calling FUNCTION once the shortest sequence is exhausted. | |
7212 | |
7213 Return SEQUENCE. | |
7214 | |
7215 arguments: (FUNCTION SEQUENCE &rest SEQUENCES) | |
7216 */ | |
7217 (int nargs, Lisp_Object *args)) | |
7218 { | |
7219 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); | |
7220 Lisp_Object sequence = args[1]; | |
7221 struct gcpro gcpro1; | |
7222 /* We need to GCPRO sequence, because mapcarX will modify the | |
7223 elements of the args array handed to it, and this may involve | |
7224 elements of sequence getting garbage collected. */ | |
7225 GCPRO1 (sequence); | |
7226 mapcarX (len, NULL, Qnil, args[0], nargs - 1, args + 1, Qmapc); | |
7227 RETURN_UNGCPRO (sequence); | |
7228 } | |
7229 | |
7230 DEFUN ("map", Fmap, 3, MANY, 0, /* | |
7231 Map FUNCTION across one or more sequences, returning a sequence. | |
7232 | |
7233 TYPE is the sequence type to return, FUNCTION is the function, SEQUENCE is | |
7234 the first argument sequence, SEQUENCES are the other argument sequences. | |
7235 | |
7236 FUNCTION will be called with (1+ (length SEQUENCES)) arguments, and must be | |
7237 capable of accepting this number of arguments. | |
7238 | |
7239 Certain TYPEs are recognised internally by `map', but others are not, and | |
7240 `coerce' may throw an error on an attempt to convert to a TYPE it does not | |
7241 understand. A null TYPE means do not accumulate any values. | |
7242 | |
7243 arguments: (TYPE FUNCTION SEQUENCE &rest SEQUENCES) | |
7244 */ | |
7245 (int nargs, Lisp_Object *args)) | |
7246 { | |
7247 Lisp_Object type = args[0]; | |
7248 Lisp_Object function = args[1]; | |
7249 Lisp_Object result = Qnil; | |
7250 Lisp_Object *args0 = NULL; | |
7251 Elemcount len = shortest_length_among_sequences (nargs - 2, args + 2); | |
7252 struct gcpro gcpro1; | |
7253 | |
7254 if (!NILP (type)) | |
7255 { | |
7256 args0 = alloca_array (Lisp_Object, len); | |
7257 } | |
7258 | |
7259 mapcarX (len, args0, Qnil, function, nargs - 2, args + 2, Qmap); | |
7260 | |
7261 if (EQ (type, Qnil)) | |
7262 { | |
7263 return result; | |
7264 } | |
7265 | |
7266 if (EQ (type, Qvector) || EQ (type, Qarray)) | |
7267 { | |
7268 result = Fvector (len, args0); | |
7269 } | |
7270 else if (EQ (type, Qstring)) | |
7271 { | |
7272 result = Fstring (len, args0); | |
7273 } | |
7274 else if (EQ (type, Qlist)) | |
7275 { | |
7276 result = Flist (len, args0); | |
7277 } | |
7278 else if (EQ (type, Qbit_vector)) | |
7279 { | |
7280 result = Fbit_vector (len, args0); | |
7281 } | |
7282 else | |
7283 { | |
7284 result = Flist (len, args0); | |
7285 GCPRO1 (result); | |
7286 result = call2 (Qcoerce, result, type); | |
7287 UNGCPRO; | |
7288 } | |
7289 | |
7290 return result; | |
7291 } | |
7292 | |
7293 DEFUN ("map-into", Fmap_into, 2, MANY, 0, /* | |
7294 Modify RESULT-SEQUENCE using the return values of FUNCTION on SEQUENCES. | |
7295 | |
7296 RESULT-SEQUENCE and SEQUENCES can be lists or arrays. | |
7297 | |
7298 FUNCTION must accept at least as many arguments as there are SEQUENCES | |
7299 \(possibly zero). If RESULT-SEQUENCE and the elements of SEQUENCES are not | |
7300 the same length, stop when the shortest is exhausted; any elements of | |
7301 RESULT-SEQUENCE beyond that are unmodified. | |
7302 | |
7303 Return RESULT-SEQUENCE. | |
7304 | |
7305 arguments: (RESULT-SEQUENCE FUNCTION &rest SEQUENCES) | |
7306 */ | |
7307 (int nargs, Lisp_Object *args)) | |
7308 { | |
7309 Elemcount len; | |
7310 Lisp_Object result_sequence = args[0]; | |
7311 Lisp_Object function = args[1]; | |
7312 | |
7313 args[0] = function; | |
7314 args[1] = result_sequence; | |
7315 | |
7316 len = shortest_length_among_sequences (nargs - 1, args + 1); | |
7317 | |
7318 mapcarX (len, NULL, result_sequence, function, nargs - 2, args + 2, | |
7319 Qmap_into); | |
7320 | |
7321 return result_sequence; | |
7322 } | |
7323 | |
7324 DEFUN ("some", Fsome, 2, MANY, 0, /* | |
7325 Return true if PREDICATE gives non-nil for an element of SEQUENCE. | |
7326 | |
7327 If so, return the value (possibly multiple) given by PREDICATE. | |
7328 | |
7329 With optional SEQUENCES, call PREDICATE each time with as many arguments as | |
7330 there are SEQUENCES (plus one for the element from SEQUENCE). | |
7331 | |
7332 See also `find-if', which returns the corresponding element of SEQUENCE, | |
7333 rather than the value given by PREDICATE, and accepts bounding index | |
7334 keywords. | |
7335 | |
7336 arguments: (PREDICATE SEQUENCE &rest SEQUENCES) | |
7337 */ | |
7338 (int nargs, Lisp_Object *args)) | |
7339 { | |
7340 Lisp_Object result = Qnil, | |
7341 result_ptr = STORE_VOID_IN_LISP ((void *) &result); | |
7342 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); | |
7343 | |
7344 mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qsome); | |
7345 | |
7346 return result; | |
7347 } | |
7348 | |
7349 DEFUN ("every", Fevery, 2, MANY, 0, /* | |
7350 Return true if PREDICATE is true of every element of SEQUENCE. | |
7351 | |
7352 With optional SEQUENCES, call PREDICATE each time with as many arguments as | |
7353 there are SEQUENCES (plus one for the element from SEQUENCE). | |
7354 | |
7355 In contrast to `some', `every' never returns multiple values. | |
7356 | |
7357 arguments: (PREDICATE SEQUENCE &rest SEQUENCES) | |
7358 */ | |
7359 (int nargs, Lisp_Object *args)) | |
7360 { | |
7361 Lisp_Object result = Qt, result_ptr = STORE_VOID_IN_LISP ((void *) &result); | |
7362 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); | |
7363 | |
7364 mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qevery); | |
7365 | |
7366 return result; | |
7367 } | |
7368 | |
7369 /* Call FUNCTION with NLISTS arguments repeatedly, each Nth argument | 2519 /* Call FUNCTION with NLISTS arguments repeatedly, each Nth argument |
7370 corresponding to the result of calling (nthcdr ITERATION-COUNT LISTS[N]), | 2520 corresponding to the result of calling (nthcdr ITERATION-COUNT LISTS[N]), |
7371 until that #'nthcdr expression gives nil for some element of LISTS. | 2521 until that #'nthcdr expression gives nil for some element of LISTS. |
7372 | 2522 |
7373 CALLER is a symbol reflecting the Lisp-visible function that was called, | 2523 CALLER is a symbol reflecting the Lisp-visible function that was called, |
7526 */ | 2676 */ |
7527 (int nargs, Lisp_Object *args)) | 2677 (int nargs, Lisp_Object *args)) |
7528 { | 2678 { |
7529 return maplist (args[0], nargs - 1, args + 1, Qmapcon); | 2679 return maplist (args[0], nargs - 1, args + 1, Qmapcon); |
7530 } | 2680 } |
7531 | |
7532 /* Extra random functions */ | |
7533 | |
7534 DEFUN ("reduce", Freduce, 2, MANY, 0, /* | |
7535 Combine the elements of sequence using FUNCTION, a binary operation. | |
7536 | |
7537 For example, `(reduce #'+ SEQUENCE)' returns the sum of all elements in | |
7538 SEQUENCE, and `(reduce #'union SEQUENCE)' returns the union of all elements | |
7539 in SEQUENCE. | |
7540 | |
7541 Keywords supported: :start :end :from-end :initial-value :key | |
7542 See `remove*' for the meaning of :start, :end, :from-end and :key. | |
7543 | |
7544 :initial-value specifies an element (typically an identity element, such as | |
7545 0) that is conceptually prepended to the sequence (or appended, when | |
7546 :from-end is given). | |
7547 | |
7548 If the sequence has one element, that element is returned directly. | |
7549 If the sequence has no elements, :initial-value is returned if given; | |
7550 otherwise, FUNCTION is called with no arguments, and its result returned. | |
7551 | |
7552 arguments: (FUNCTION SEQUENCE &key (START 0) (END (length SEQUENCE)) FROM-END INITIAL-VALUE (KEY #'identity)) | |
7553 */ | |
7554 (int nargs, Lisp_Object *args)) | |
7555 { | |
7556 Lisp_Object function = args[0], sequence = args[1], accum = Qunbound; | |
7557 Elemcount starting, ending = MOST_POSITIVE_FIXNUM + 1, ii = 0; | |
7558 | |
7559 PARSE_KEYWORDS (Freduce, nargs, args, 5, | |
7560 (start, end, from_end, initial_value, key), | |
7561 (start = Qzero, initial_value = Qunbound)); | |
7562 | |
7563 CHECK_SEQUENCE (sequence); | |
7564 CHECK_NATNUM (start); | |
7565 starting = BIGNUMP (start) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start); | |
7566 CHECK_KEY_ARGUMENT (key); | |
7567 | |
7568 #define KEY(key, item) (EQ (Qidentity, key) ? item : \ | |
7569 IGNORE_MULTIPLE_VALUES (call1 (key, item))) | |
7570 #define CALL2(function, accum, item) \ | |
7571 IGNORE_MULTIPLE_VALUES (call2 (function, accum, item)) | |
7572 | |
7573 if (!NILP (end)) | |
7574 { | |
7575 CHECK_NATNUM (end); | |
7576 ending = BIGNUMP (end) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end); | |
7577 } | |
7578 | |
7579 if (VECTORP (sequence)) | |
7580 { | |
7581 Lisp_Vector *vv = XVECTOR (sequence); | |
7582 struct gcpro gcpro1; | |
7583 | |
7584 check_sequence_range (sequence, start, end, make_fixnum (vv->size)); | |
7585 | |
7586 ending = min (ending, vv->size); | |
7587 | |
7588 GCPRO1 (accum); | |
7589 | |
7590 if (!UNBOUNDP (initial_value)) | |
7591 { | |
7592 accum = initial_value; | |
7593 } | |
7594 else if (ending - starting) | |
7595 { | |
7596 if (NILP (from_end)) | |
7597 { | |
7598 accum = KEY (key, vv->contents[starting]); | |
7599 starting++; | |
7600 } | |
7601 else | |
7602 { | |
7603 accum = KEY (key, vv->contents[ending - 1]); | |
7604 ending--; | |
7605 } | |
7606 } | |
7607 | |
7608 if (NILP (from_end)) | |
7609 { | |
7610 for (ii = starting; ii < ending; ++ii) | |
7611 { | |
7612 accum = CALL2 (function, accum, KEY (key, vv->contents[ii])); | |
7613 } | |
7614 } | |
7615 else | |
7616 { | |
7617 for (ii = ending - 1; ii >= starting; --ii) | |
7618 { | |
7619 accum = CALL2 (function, KEY (key, vv->contents[ii]), accum); | |
7620 } | |
7621 } | |
7622 | |
7623 UNGCPRO; | |
7624 } | |
7625 else if (BIT_VECTORP (sequence)) | |
7626 { | |
7627 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence); | |
7628 struct gcpro gcpro1; | |
7629 | |
7630 check_sequence_range (sequence, start, end, make_fixnum (bv->size)); | |
7631 ending = min (ending, bv->size); | |
7632 | |
7633 GCPRO1 (accum); | |
7634 | |
7635 if (!UNBOUNDP (initial_value)) | |
7636 { | |
7637 accum = initial_value; | |
7638 } | |
7639 else if (ending - starting) | |
7640 { | |
7641 if (NILP (from_end)) | |
7642 { | |
7643 accum = KEY (key, make_fixnum (bit_vector_bit (bv, starting))); | |
7644 starting++; | |
7645 } | |
7646 else | |
7647 { | |
7648 accum = KEY (key, make_fixnum (bit_vector_bit (bv, ending - 1))); | |
7649 ending--; | |
7650 } | |
7651 } | |
7652 | |
7653 if (NILP (from_end)) | |
7654 { | |
7655 for (ii = starting; ii < ending; ++ii) | |
7656 { | |
7657 accum = CALL2 (function, accum, | |
7658 KEY (key, make_fixnum (bit_vector_bit (bv, ii)))); | |
7659 } | |
7660 } | |
7661 else | |
7662 { | |
7663 for (ii = ending - 1; ii >= starting; --ii) | |
7664 { | |
7665 accum = CALL2 (function, KEY (key, | |
7666 make_fixnum (bit_vector_bit (bv, | |
7667 ii))), | |
7668 accum); | |
7669 } | |
7670 } | |
7671 | |
7672 UNGCPRO; | |
7673 | |
7674 } | |
7675 else if (STRINGP (sequence)) | |
7676 { | |
7677 struct gcpro gcpro1; | |
7678 | |
7679 GCPRO1 (accum); | |
7680 | |
7681 if (NILP (from_end)) | |
7682 { | |
7683 Bytecount byte_len = XSTRING_LENGTH (sequence); | |
7684 Bytecount cursor_offset = 0; | |
7685 const Ibyte *startp = XSTRING_DATA (sequence); | |
7686 const Ibyte *cursor = startp; | |
7687 | |
7688 for (ii = 0; ii != starting && cursor_offset < byte_len; ++ii) | |
7689 { | |
7690 INC_IBYTEPTR (cursor); | |
7691 cursor_offset = cursor - startp; | |
7692 } | |
7693 | |
7694 if (!UNBOUNDP (initial_value)) | |
7695 { | |
7696 accum = initial_value; | |
7697 } | |
7698 else if (ending - starting && cursor_offset < byte_len) | |
7699 { | |
7700 accum = KEY (key, make_char (itext_ichar (cursor))); | |
7701 starting++; | |
7702 startp = XSTRING_DATA (sequence); | |
7703 cursor = startp + cursor_offset; | |
7704 | |
7705 if (byte_len != XSTRING_LENGTH (sequence) | |
7706 || !valid_ibyteptr_p (cursor)) | |
7707 { | |
7708 mapping_interaction_error (Qreduce, sequence); | |
7709 } | |
7710 | |
7711 INC_IBYTEPTR (cursor); | |
7712 cursor_offset = cursor - startp; | |
7713 ii++; | |
7714 } | |
7715 | |
7716 while (cursor_offset < byte_len && ii < ending) | |
7717 { | |
7718 accum = CALL2 (function, accum, | |
7719 KEY (key, make_char (itext_ichar (cursor)))); | |
7720 | |
7721 startp = XSTRING_DATA (sequence); | |
7722 cursor = startp + cursor_offset; | |
7723 | |
7724 if (byte_len != XSTRING_LENGTH (sequence) | |
7725 || !valid_ibyteptr_p (cursor)) | |
7726 { | |
7727 mapping_interaction_error (Qreduce, sequence); | |
7728 } | |
7729 | |
7730 INC_IBYTEPTR (cursor); | |
7731 cursor_offset = cursor - startp; | |
7732 ++ii; | |
7733 } | |
7734 | |
7735 if (ii < starting || (ii < ending && !NILP (end))) | |
7736 { | |
7737 check_sequence_range (sequence, start, end, Flength (sequence)); | |
7738 } | |
7739 } | |
7740 else | |
7741 { | |
7742 Elemcount len = string_char_length (sequence); | |
7743 Bytecount cursor_offset, byte_len = XSTRING_LENGTH (sequence); | |
7744 const Ibyte *cursor; | |
7745 | |
7746 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
7747 ending = min (ending, len); | |
7748 starting = XFIXNUM (start); | |
7749 | |
7750 cursor = string_char_addr (sequence, ending - 1); | |
7751 cursor_offset = cursor - XSTRING_DATA (sequence); | |
7752 | |
7753 if (!UNBOUNDP (initial_value)) | |
7754 { | |
7755 accum = initial_value; | |
7756 } | |
7757 else if (ending - starting) | |
7758 { | |
7759 accum = KEY (key, make_char (itext_ichar (cursor))); | |
7760 ending--; | |
7761 if (ending > 0) | |
7762 { | |
7763 cursor = XSTRING_DATA (sequence) + cursor_offset; | |
7764 | |
7765 if (!valid_ibyteptr_p (cursor)) | |
7766 { | |
7767 mapping_interaction_error (Qreduce, sequence); | |
7768 } | |
7769 | |
7770 DEC_IBYTEPTR (cursor); | |
7771 cursor_offset = cursor - XSTRING_DATA (sequence); | |
7772 } | |
7773 } | |
7774 | |
7775 for (ii = ending - 1; ii >= starting; --ii) | |
7776 { | |
7777 accum = CALL2 (function, KEY (key, | |
7778 make_char (itext_ichar (cursor))), | |
7779 accum); | |
7780 if (ii > 0) | |
7781 { | |
7782 cursor = XSTRING_DATA (sequence) + cursor_offset; | |
7783 | |
7784 if (byte_len != XSTRING_LENGTH (sequence) | |
7785 || !valid_ibyteptr_p (cursor)) | |
7786 { | |
7787 mapping_interaction_error (Qreduce, sequence); | |
7788 } | |
7789 | |
7790 DEC_IBYTEPTR (cursor); | |
7791 cursor_offset = cursor - XSTRING_DATA (sequence); | |
7792 } | |
7793 } | |
7794 } | |
7795 | |
7796 UNGCPRO; | |
7797 } | |
7798 else if (LISTP (sequence)) | |
7799 { | |
7800 if (NILP (from_end)) | |
7801 { | |
7802 struct gcpro gcpro1; | |
7803 | |
7804 GCPRO1 (accum); | |
7805 | |
7806 if (!UNBOUNDP (initial_value)) | |
7807 { | |
7808 accum = initial_value; | |
7809 } | |
7810 else if (ending - starting) | |
7811 { | |
7812 GC_EXTERNAL_LIST_LOOP_2 (elt, sequence) | |
7813 { | |
7814 if (ii == starting) | |
7815 { | |
7816 accum = KEY (key, elt); | |
7817 starting++; | |
7818 break; | |
7819 } | |
7820 ++ii; | |
7821 } | |
7822 END_GC_EXTERNAL_LIST_LOOP (elt); | |
7823 } | |
7824 | |
7825 ii = 0; | |
7826 | |
7827 if (ending - starting) | |
7828 { | |
7829 GC_EXTERNAL_LIST_LOOP_2 (elt, sequence) | |
7830 { | |
7831 if (ii >= starting) | |
7832 { | |
7833 if (ii < ending) | |
7834 { | |
7835 accum = CALL2 (function, accum, KEY (key, elt)); | |
7836 } | |
7837 else if (ii == ending) | |
7838 { | |
7839 break; | |
7840 } | |
7841 } | |
7842 ++ii; | |
7843 } | |
7844 END_GC_EXTERNAL_LIST_LOOP (elt); | |
7845 } | |
7846 | |
7847 UNGCPRO; | |
7848 | |
7849 if (ii < starting || (ii < ending && !NILP (end))) | |
7850 { | |
7851 check_sequence_range (sequence, start, end, Flength (sequence)); | |
7852 } | |
7853 } | |
7854 else | |
7855 { | |
7856 Boolint need_accum = 0; | |
7857 Lisp_Object *subsequence = NULL; | |
7858 Elemcount counting = 0, len = 0; | |
7859 struct gcpro gcpro1; | |
7860 | |
7861 len = XFIXNUM (Flength (sequence)); | |
7862 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
7863 ending = min (ending, len); | |
7864 | |
7865 /* :from-end with a list; make an alloca copy of the relevant list | |
7866 data, attempting to go backwards isn't worth the trouble. */ | |
7867 if (!UNBOUNDP (initial_value)) | |
7868 { | |
7869 accum = initial_value; | |
7870 if (ending - starting && starting < ending) | |
7871 { | |
7872 subsequence = alloca_array (Lisp_Object, ending - starting); | |
7873 } | |
7874 } | |
7875 else if (ending - starting && starting < ending) | |
7876 { | |
7877 subsequence = alloca_array (Lisp_Object, ending - starting); | |
7878 need_accum = 1; | |
7879 } | |
7880 | |
7881 if (ending - starting && starting < ending) | |
7882 { | |
7883 EXTERNAL_LIST_LOOP_3 (elt, sequence, tail) | |
7884 { | |
7885 if (counting >= starting) | |
7886 { | |
7887 if (counting < ending) | |
7888 { | |
7889 subsequence[ii++] = elt; | |
7890 } | |
7891 else if (counting == ending) | |
7892 { | |
7893 break; | |
7894 } | |
7895 } | |
7896 ++counting; | |
7897 } | |
7898 } | |
7899 | |
7900 if (subsequence != NULL) | |
7901 { | |
7902 len = ending - starting; | |
7903 /* If we could be sure that neither FUNCTION nor KEY modify | |
7904 SEQUENCE, this wouldn't be necessary, since all the | |
7905 elements of SUBSEQUENCE would definitely always be | |
7906 reachable via SEQUENCE. */ | |
7907 GCPRO1 (subsequence[0]); | |
7908 gcpro1.nvars = len; | |
7909 } | |
7910 | |
7911 if (need_accum) | |
7912 { | |
7913 accum = KEY (key, subsequence[len - 1]); | |
7914 --len; | |
7915 } | |
7916 | |
7917 for (ii = len; ii != 0;) | |
7918 { | |
7919 --ii; | |
7920 accum = CALL2 (function, KEY (key, subsequence[ii]), accum); | |
7921 } | |
7922 | |
7923 if (subsequence != NULL) | |
7924 { | |
7925 UNGCPRO; | |
7926 } | |
7927 } | |
7928 } | |
7929 | |
7930 /* At this point, if ACCUM is unbound, SEQUENCE has no elements; we | |
7931 need to return the result of calling FUNCTION with zero | |
7932 arguments. */ | |
7933 if (UNBOUNDP (accum)) | |
7934 { | |
7935 accum = IGNORE_MULTIPLE_VALUES (call0 (function)); | |
7936 } | |
7937 | |
7938 return accum; | |
7939 } | |
7940 | 2681 |
7941 DEFUN ("replace-list", Freplace_list, 2, 2, 0, /* | 2682 DEFUN ("replace-list", Freplace_list, 2, 2, 0, /* |
7942 Destructively replace the list OLD with NEW. | 2683 Destructively replace the list OLD with NEW. |
7943 This is like (copy-sequence NEW) except that it reuses the | 2684 This is like (copy-sequence NEW) except that it reuses the |
7944 conses in OLD as much as possible. If OLD and NEW are the same | 2685 conses in OLD as much as possible. If OLD and NEW are the same |
7974 XCDR (prevoldtail) = Qnil; | 2715 XCDR (prevoldtail) = Qnil; |
7975 else | 2716 else |
7976 old = Qnil; | 2717 old = Qnil; |
7977 | 2718 |
7978 return old; | 2719 return old; |
7979 } | |
7980 | |
7981 /* This function is the implementation of fill_string_range() and | |
7982 replace_string_range(); see the comments for those functions. */ | |
7983 static Lisp_Object | |
7984 replace_string_range_1 (Lisp_Object dest, Lisp_Object start, Lisp_Object end, | |
7985 const Ibyte *source, const Ibyte *source_limit, | |
7986 Lisp_Object item) | |
7987 { | |
7988 Ibyte *destp = XSTRING_DATA (dest), *p = destp, | |
7989 *pend = p + XSTRING_LENGTH (dest), *pcursor, item_buf[MAX_ICHAR_LEN]; | |
7990 Bytecount prefix_bytecount, source_len = source_limit - source; | |
7991 Charcount ii = 0, ending, len; | |
7992 Charcount starting = BIGNUMP (start) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start); | |
7993 Elemcount delta; | |
7994 | |
7995 while (ii < starting && p < pend) | |
7996 { | |
7997 INC_IBYTEPTR (p); | |
7998 ii++; | |
7999 } | |
8000 | |
8001 pcursor = p; | |
8002 | |
8003 if (NILP (end)) | |
8004 { | |
8005 while (pcursor < pend) | |
8006 { | |
8007 INC_IBYTEPTR (pcursor); | |
8008 ii++; | |
8009 } | |
8010 | |
8011 ending = len = ii; | |
8012 } | |
8013 else | |
8014 { | |
8015 ending = BIGNUMP (end) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end); | |
8016 while (ii < ending && pcursor < pend) | |
8017 { | |
8018 INC_IBYTEPTR (pcursor); | |
8019 ii++; | |
8020 } | |
8021 } | |
8022 | |
8023 if (pcursor == pend) | |
8024 { | |
8025 /* We have the length, check it for our callers. */ | |
8026 check_sequence_range (dest, start, end, make_fixnum (ii)); | |
8027 } | |
8028 | |
8029 if (!(p == pend || p == pcursor)) | |
8030 { | |
8031 prefix_bytecount = p - destp; | |
8032 | |
8033 if (!NILP (item)) | |
8034 { | |
8035 assert (source == NULL && source_limit == NULL); | |
8036 source_len = set_itext_ichar (item_buf, XCHAR (item)); | |
8037 delta = (source_len * (ending - starting)) - (pcursor - p); | |
8038 } | |
8039 else | |
8040 { | |
8041 assert (source != NULL && source_limit != NULL); | |
8042 delta = source_len - (pcursor - p); | |
8043 } | |
8044 | |
8045 if (delta) | |
8046 { | |
8047 resize_string (dest, prefix_bytecount, delta); | |
8048 destp = XSTRING_DATA (dest); | |
8049 pcursor = destp + prefix_bytecount + (pcursor - p); | |
8050 p = destp + prefix_bytecount; | |
8051 } | |
8052 | |
8053 if (CHARP (item)) | |
8054 { | |
8055 while (starting < ending) | |
8056 { | |
8057 memcpy (p, item_buf, source_len); | |
8058 p += source_len; | |
8059 starting++; | |
8060 } | |
8061 } | |
8062 else | |
8063 { | |
8064 while (starting < ending && source < source_limit) | |
8065 { | |
8066 source_len = itext_copy_ichar (source, p); | |
8067 p += source_len, source += source_len; | |
8068 } | |
8069 } | |
8070 | |
8071 init_string_ascii_begin (dest); | |
8072 bump_string_modiff (dest); | |
8073 sledgehammer_check_ascii_begin (dest); | |
8074 } | |
8075 | |
8076 return dest; | |
8077 } | |
8078 | |
8079 DEFUN ("replace", Freplace, 2, MANY, 0, /* | |
8080 Replace the elements of SEQUENCE-ONE with the elements of SEQUENCE-TWO. | |
8081 | |
8082 SEQUENCE-ONE is destructively modified, and returned. Its length is not | |
8083 changed. | |
8084 | |
8085 Keywords :start1 and :end1 specify a subsequence of SEQUENCE-ONE, and | |
8086 :start2 and :end2 a subsequence of SEQUENCE-TWO. See `search' for more | |
8087 information. | |
8088 | |
8089 arguments: (SEQUENCE-ONE SEQUENCE-TWO &key (START1 0) (END1 (length SEQUENCE-ONE)) (START2 0) (END2 (length SEQUENCE-TWO))) | |
8090 */ | |
8091 (int nargs, Lisp_Object *args)) | |
8092 { | |
8093 Lisp_Object sequence1 = args[0], sequence2 = args[1], | |
8094 result = sequence1; | |
8095 Elemcount starting1, ending1 = MOST_POSITIVE_FIXNUM + 1, starting2; | |
8096 Elemcount ending2 = MOST_POSITIVE_FIXNUM + 1, counting = 0, startcounting; | |
8097 Boolint sequence1_listp, sequence2_listp, | |
8098 overwriting = EQ (sequence1, sequence2); | |
8099 | |
8100 PARSE_KEYWORDS (Freplace, nargs, args, 4, (start1, end1, start2, end2), | |
8101 (start1 = start2 = Qzero)); | |
8102 | |
8103 CHECK_SEQUENCE (sequence1); | |
8104 CHECK_LISP_WRITEABLE (sequence1); | |
8105 | |
8106 CHECK_SEQUENCE (sequence2); | |
8107 | |
8108 CHECK_NATNUM (start1); | |
8109 starting1 = BIGNUMP (start1) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start1); | |
8110 CHECK_NATNUM (start2); | |
8111 starting2 = BIGNUMP (start2) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (start2); | |
8112 | |
8113 if (!NILP (end1)) | |
8114 { | |
8115 CHECK_NATNUM (end1); | |
8116 ending1 = BIGNUMP (end1) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end1); | |
8117 } | |
8118 | |
8119 if (!NILP (end2)) | |
8120 { | |
8121 CHECK_NATNUM (end2); | |
8122 ending2 = BIGNUMP (end2) ? MOST_POSITIVE_FIXNUM + 1 : XFIXNUM (end2); | |
8123 } | |
8124 | |
8125 sequence1_listp = LISTP (sequence1); | |
8126 sequence2_listp = LISTP (sequence2); | |
8127 | |
8128 overwriting = overwriting && starting2 <= starting1; | |
8129 | |
8130 if (sequence1_listp && !ZEROP (start1)) | |
8131 { | |
8132 sequence1 = Fnthcdr (start1, sequence1); | |
8133 | |
8134 if (NILP (sequence1)) | |
8135 { | |
8136 check_sequence_range (args[0], start1, end1, Flength (args[0])); | |
8137 /* Give up early here. */ | |
8138 return result; | |
8139 } | |
8140 | |
8141 ending1 -= starting1; | |
8142 starting1 = 0; | |
8143 } | |
8144 | |
8145 if (sequence2_listp && !ZEROP (start2)) | |
8146 { | |
8147 sequence2 = Fnthcdr (start2, sequence2); | |
8148 | |
8149 if (NILP (sequence2)) | |
8150 { | |
8151 check_sequence_range (args[1], start1, end1, Flength (args[1])); | |
8152 /* Nothing available to replace sequence1's contents. */ | |
8153 return result; | |
8154 } | |
8155 | |
8156 ending2 -= starting2; | |
8157 starting2 = 0; | |
8158 } | |
8159 | |
8160 if (overwriting) | |
8161 { | |
8162 if (EQ (start1, start2)) | |
8163 { | |
8164 return result; | |
8165 } | |
8166 | |
8167 /* Our ranges may overlap. Save the data that might be overwritten. */ | |
8168 | |
8169 if (CONSP (sequence2)) | |
8170 { | |
8171 Elemcount len = XFIXNUM (Flength (sequence2)); | |
8172 Lisp_Object *subsequence | |
8173 = alloca_array (Lisp_Object, min (ending2, len)); | |
8174 Elemcount ii = 0; | |
8175 | |
8176 LIST_LOOP_2 (elt, sequence2) | |
8177 { | |
8178 if (counting == ending2) | |
8179 { | |
8180 break; | |
8181 } | |
8182 | |
8183 subsequence[ii++] = elt; | |
8184 counting++; | |
8185 } | |
8186 | |
8187 check_sequence_range (sequence1, start1, end1, | |
8188 /* The XFIXNUM (start2) is intentional here; we | |
8189 called #'length after doing (nthcdr | |
8190 start2 sequence2). */ | |
8191 make_fixnum (XFIXNUM (start2) + len)); | |
8192 check_sequence_range (sequence2, start2, end2, | |
8193 make_fixnum (XFIXNUM (start2) + len)); | |
8194 | |
8195 while (starting1 < ending1 | |
8196 && starting2 < ending2 && !NILP (sequence1)) | |
8197 { | |
8198 XSETCAR (sequence1, subsequence[starting2]); | |
8199 sequence1 = XCDR (sequence1); | |
8200 starting1++; | |
8201 starting2++; | |
8202 } | |
8203 } | |
8204 else if (STRINGP (sequence2)) | |
8205 { | |
8206 Ibyte *p = XSTRING_DATA (sequence2), | |
8207 *pend = p + XSTRING_LENGTH (sequence2), *pcursor, | |
8208 *staging; | |
8209 Bytecount ii = 0; | |
8210 | |
8211 while (ii < starting2 && p < pend) | |
8212 { | |
8213 INC_IBYTEPTR (p); | |
8214 ii++; | |
8215 } | |
8216 | |
8217 pcursor = p; | |
8218 | |
8219 while (ii < ending2 && starting1 < ending1 && pcursor < pend) | |
8220 { | |
8221 INC_IBYTEPTR (pcursor); | |
8222 starting1++; | |
8223 ii++; | |
8224 } | |
8225 | |
8226 if (pcursor == pend) | |
8227 { | |
8228 check_sequence_range (sequence1, start1, end1, make_fixnum (ii)); | |
8229 check_sequence_range (sequence2, start2, end2, make_fixnum (ii)); | |
8230 } | |
8231 else | |
8232 { | |
8233 assert ((pcursor - p) > 0); | |
8234 staging = alloca_ibytes (pcursor - p); | |
8235 memcpy (staging, p, pcursor - p); | |
8236 replace_string_range (result, start1, | |
8237 make_fixnum (starting1), | |
8238 staging, staging + (pcursor - p)); | |
8239 } | |
8240 } | |
8241 else | |
8242 { | |
8243 Elemcount seq_len = XFIXNUM (Flength (sequence2)), ii = 0, | |
8244 subseq_len = min (min (ending1 - starting1, seq_len - starting1), | |
8245 min (ending2 - starting2, seq_len - starting2)); | |
8246 Lisp_Object *subsequence = alloca_array (Lisp_Object, subseq_len); | |
8247 | |
8248 check_sequence_range (sequence1, start1, end1, make_fixnum (seq_len)); | |
8249 check_sequence_range (sequence2, start2, end2, make_fixnum (seq_len)); | |
8250 | |
8251 while (starting2 < ending2 && ii < seq_len) | |
8252 { | |
8253 subsequence[ii] = Faref (sequence2, make_fixnum (starting2)); | |
8254 ii++, starting2++; | |
8255 } | |
8256 | |
8257 ii = 0; | |
8258 | |
8259 while (starting1 < ending1 && ii < seq_len) | |
8260 { | |
8261 Faset (sequence1, make_fixnum (starting1), subsequence[ii]); | |
8262 ii++, starting1++; | |
8263 } | |
8264 } | |
8265 } | |
8266 else if (sequence1_listp && sequence2_listp) | |
8267 { | |
8268 Lisp_Object sequence1_tortoise = sequence1, | |
8269 sequence2_tortoise = sequence2; | |
8270 Elemcount shortest_len = 0; | |
8271 | |
8272 counting = startcounting = min (ending1, ending2); | |
8273 | |
8274 while (counting-- > 0 && !NILP (sequence1) && !NILP (sequence2)) | |
8275 { | |
8276 XSETCAR (sequence1, | |
8277 CONSP (sequence2) ? XCAR (sequence2) | |
8278 : Fcar (sequence2)); | |
8279 sequence1 = CONSP (sequence1) ? XCDR (sequence1) | |
8280 : Fcdr (sequence1); | |
8281 sequence2 = CONSP (sequence2) ? XCDR (sequence2) | |
8282 : Fcdr (sequence2); | |
8283 | |
8284 shortest_len++; | |
8285 | |
8286 if (startcounting - counting > CIRCULAR_LIST_SUSPICION_LENGTH) | |
8287 { | |
8288 if (counting & 1) | |
8289 { | |
8290 sequence1_tortoise = XCDR (sequence1_tortoise); | |
8291 sequence2_tortoise = XCDR (sequence2_tortoise); | |
8292 } | |
8293 | |
8294 if (EQ (sequence1, sequence1_tortoise)) | |
8295 { | |
8296 signal_circular_list_error (sequence1); | |
8297 } | |
8298 | |
8299 if (EQ (sequence2, sequence2_tortoise)) | |
8300 { | |
8301 signal_circular_list_error (sequence2); | |
8302 } | |
8303 } | |
8304 } | |
8305 | |
8306 if (NILP (sequence1)) | |
8307 { | |
8308 check_sequence_range (args[0], start1, end1, | |
8309 make_fixnum (XFIXNUM (start1) + shortest_len)); | |
8310 } | |
8311 else if (NILP (sequence2)) | |
8312 { | |
8313 check_sequence_range (args[1], start2, end2, | |
8314 make_fixnum (XFIXNUM (start2) + shortest_len)); | |
8315 } | |
8316 } | |
8317 else if (sequence1_listp) | |
8318 { | |
8319 if (STRINGP (sequence2)) | |
8320 { | |
8321 Ibyte *s2_data = XSTRING_DATA (sequence2), | |
8322 *s2_end = s2_data + XSTRING_LENGTH (sequence2); | |
8323 Elemcount char_count = 0; | |
8324 Lisp_Object character; | |
8325 | |
8326 while (char_count < starting2 && s2_data < s2_end) | |
8327 { | |
8328 INC_IBYTEPTR (s2_data); | |
8329 char_count++; | |
8330 } | |
8331 | |
8332 while (starting1 < ending1 && starting2 < ending2 | |
8333 && s2_data < s2_end && !NILP (sequence1)) | |
8334 { | |
8335 character = make_char (itext_ichar (s2_data)); | |
8336 CONSP (sequence1) ? | |
8337 XSETCAR (sequence1, character) | |
8338 : Fsetcar (sequence1, character); | |
8339 sequence1 = XCDR (sequence1); | |
8340 starting1++; | |
8341 starting2++; | |
8342 char_count++; | |
8343 INC_IBYTEPTR (s2_data); | |
8344 } | |
8345 | |
8346 if (NILP (sequence1)) | |
8347 { | |
8348 check_sequence_range (sequence1, start1, end1, | |
8349 make_fixnum (XFIXNUM (start1) + starting1)); | |
8350 } | |
8351 | |
8352 if (s2_data == s2_end) | |
8353 { | |
8354 check_sequence_range (sequence2, start2, end2, | |
8355 make_fixnum (char_count)); | |
8356 } | |
8357 } | |
8358 else | |
8359 { | |
8360 Elemcount len2 = XFIXNUM (Flength (sequence2)); | |
8361 check_sequence_range (sequence2, start2, end2, make_fixnum (len2)); | |
8362 | |
8363 ending2 = min (ending2, len2); | |
8364 while (starting2 < ending2 | |
8365 && starting1 < ending1 && !NILP (sequence1)) | |
8366 { | |
8367 CHECK_CONS (sequence1); | |
8368 XSETCAR (sequence1, Faref (sequence2, make_fixnum (starting2))); | |
8369 sequence1 = XCDR (sequence1); | |
8370 starting1++; | |
8371 starting2++; | |
8372 } | |
8373 | |
8374 if (NILP (sequence1)) | |
8375 { | |
8376 check_sequence_range (args[0], start1, end1, | |
8377 make_fixnum (XFIXNUM (start1) + starting1)); | |
8378 } | |
8379 } | |
8380 } | |
8381 else if (sequence2_listp) | |
8382 { | |
8383 if (STRINGP (sequence1)) | |
8384 { | |
8385 Elemcount ii = 0, count, len = string_char_length (sequence1); | |
8386 Ibyte *staging, *cursor; | |
8387 Lisp_Object obj; | |
8388 | |
8389 check_sequence_range (sequence1, start1, end1, make_fixnum (len)); | |
8390 ending1 = min (ending1, len); | |
8391 count = ending1 - starting1; | |
8392 staging = cursor = alloca_ibytes (count * MAX_ICHAR_LEN); | |
8393 | |
8394 while (ii < count && !NILP (sequence2)) | |
8395 { | |
8396 obj = CONSP (sequence2) ? XCAR (sequence2) | |
8397 : Fcar (sequence2); | |
8398 | |
8399 CHECK_CHAR_COERCE_INT (obj); | |
8400 cursor += set_itext_ichar (cursor, XCHAR (obj)); | |
8401 ii++; | |
8402 sequence2 = XCDR (sequence2); | |
8403 } | |
8404 | |
8405 if (NILP (sequence2)) | |
8406 { | |
8407 check_sequence_range (sequence2, start2, end2, | |
8408 make_fixnum (XFIXNUM (start2) + ii)); | |
8409 } | |
8410 | |
8411 replace_string_range (result, start1, make_fixnum (XFIXNUM (start1) + ii), | |
8412 staging, cursor); | |
8413 } | |
8414 else | |
8415 { | |
8416 Elemcount len = XFIXNUM (Flength (sequence1)); | |
8417 | |
8418 check_sequence_range (sequence1, start2, end1, make_fixnum (len)); | |
8419 ending1 = min (ending2, min (ending1, len)); | |
8420 | |
8421 while (starting1 < ending1 && !NILP (sequence2)) | |
8422 { | |
8423 Faset (sequence1, make_fixnum (starting1), | |
8424 CONSP (sequence2) ? XCAR (sequence2) | |
8425 : Fcar (sequence2)); | |
8426 sequence2 = XCDR (sequence2); | |
8427 starting1++; | |
8428 starting2++; | |
8429 } | |
8430 | |
8431 if (NILP (sequence2)) | |
8432 { | |
8433 check_sequence_range (args[1], start2, end2, | |
8434 make_fixnum (XFIXNUM (start2) + starting2)); | |
8435 } | |
8436 } | |
8437 } | |
8438 else | |
8439 { | |
8440 if (STRINGP (sequence1) && STRINGP (sequence2)) | |
8441 { | |
8442 Ibyte *p2 = XSTRING_DATA (sequence2), | |
8443 *p2end = p2 + XSTRING_LENGTH (sequence2), *p2cursor; | |
8444 Charcount ii = 0, len1 = string_char_length (sequence1); | |
8445 | |
8446 check_sequence_range (sequence1, start1, end1, make_fixnum (len1)); | |
8447 | |
8448 while (ii < starting2 && p2 < p2end) | |
8449 { | |
8450 INC_IBYTEPTR (p2); | |
8451 ii++; | |
8452 } | |
8453 | |
8454 p2cursor = p2; | |
8455 ending1 = min (ending1, len1); | |
8456 | |
8457 while (ii < ending2 && starting1 < ending1 && p2cursor < p2end) | |
8458 { | |
8459 INC_IBYTEPTR (p2cursor); | |
8460 ii++; | |
8461 starting1++; | |
8462 } | |
8463 | |
8464 if (p2cursor == p2end) | |
8465 { | |
8466 check_sequence_range (sequence2, start2, end2, make_fixnum (ii)); | |
8467 } | |
8468 | |
8469 /* This isn't great; any error message won't necessarily reflect | |
8470 the END1 that was supplied to #'replace. */ | |
8471 replace_string_range (result, start1, make_fixnum (starting1), | |
8472 p2, p2cursor); | |
8473 } | |
8474 else if (STRINGP (sequence1)) | |
8475 { | |
8476 Ibyte *staging, *cursor; | |
8477 Elemcount count, len1 = string_char_length (sequence1); | |
8478 Elemcount len2 = XFIXNUM (Flength (sequence2)), ii = 0; | |
8479 Lisp_Object obj; | |
8480 | |
8481 check_sequence_range (sequence1, start1, end1, make_fixnum (len1)); | |
8482 check_sequence_range (sequence2, start2, end2, make_fixnum (len2)); | |
8483 | |
8484 ending1 = min (ending1, len1); | |
8485 ending2 = min (ending2, len2); | |
8486 count = min (ending1 - starting1, ending2 - starting2); | |
8487 staging = cursor = alloca_ibytes (count * MAX_ICHAR_LEN); | |
8488 | |
8489 ii = 0; | |
8490 while (ii < count) | |
8491 { | |
8492 obj = Faref (sequence2, make_fixnum (starting2)); | |
8493 | |
8494 CHECK_CHAR_COERCE_INT (obj); | |
8495 cursor += set_itext_ichar (cursor, XCHAR (obj)); | |
8496 starting2++, ii++; | |
8497 } | |
8498 | |
8499 replace_string_range (result, start1, | |
8500 make_fixnum (XFIXNUM (start1) + count), | |
8501 staging, cursor); | |
8502 } | |
8503 else if (STRINGP (sequence2)) | |
8504 { | |
8505 Ibyte *p2 = XSTRING_DATA (sequence2), | |
8506 *p2end = p2 + XSTRING_LENGTH (sequence2); | |
8507 Elemcount len1 = XFIXNUM (Flength (sequence1)), ii = 0; | |
8508 | |
8509 check_sequence_range (sequence1, start1, end1, make_fixnum (len1)); | |
8510 ending1 = min (ending1, len1); | |
8511 | |
8512 while (ii < starting2 && p2 < p2end) | |
8513 { | |
8514 INC_IBYTEPTR (p2); | |
8515 ii++; | |
8516 } | |
8517 | |
8518 while (p2 < p2end && starting1 < ending1 && starting2 < ending2) | |
8519 { | |
8520 Faset (sequence1, make_fixnum (starting1), | |
8521 make_char (itext_ichar (p2))); | |
8522 INC_IBYTEPTR (p2); | |
8523 starting1++; | |
8524 starting2++; | |
8525 ii++; | |
8526 } | |
8527 | |
8528 if (p2 == p2end) | |
8529 { | |
8530 check_sequence_range (sequence2, start2, end2, make_fixnum (ii)); | |
8531 } | |
8532 } | |
8533 else | |
8534 { | |
8535 Elemcount len1 = XFIXNUM (Flength (sequence1)), | |
8536 len2 = XFIXNUM (Flength (sequence2)); | |
8537 | |
8538 check_sequence_range (sequence1, start1, end1, make_fixnum (len1)); | |
8539 check_sequence_range (sequence2, start2, end2, make_fixnum (len2)); | |
8540 | |
8541 ending1 = min (ending1, len1); | |
8542 ending2 = min (ending2, len2); | |
8543 | |
8544 while (starting1 < ending1 && starting2 < ending2) | |
8545 { | |
8546 Faset (sequence1, make_fixnum (starting1), | |
8547 Faref (sequence2, make_fixnum (starting2))); | |
8548 starting1++; | |
8549 starting2++; | |
8550 } | |
8551 } | |
8552 } | |
8553 | |
8554 return result; | |
8555 } | |
8556 | |
8557 DEFUN ("nsubstitute", Fnsubstitute, 3, MANY, 0, /* | |
8558 Substitute NEW for OLD in SEQUENCE. | |
8559 | |
8560 This is a destructive function; it reuses the storage of SEQUENCE whenever | |
8561 possible. See `remove*' for the meaning of the keywords. | |
8562 | |
8563 arguments: (NEW OLD SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) FROM-END COUNT) | |
8564 */ | |
8565 (int nargs, Lisp_Object *args)) | |
8566 { | |
8567 Lisp_Object new_ = args[0], item = args[1], sequence = args[2]; | |
8568 Lisp_Object object_, position0; | |
8569 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, encountered = 0; | |
8570 Elemcount len, ii = 0, counting = MOST_POSITIVE_FIXNUM, presenting = 0; | |
8571 Boolint test_not_unboundp = 1; | |
8572 check_test_func_t check_test = NULL; | |
8573 | |
8574 PARSE_KEYWORDS (Fnsubstitute, nargs, args, 9, | |
8575 (test, if_, if_not, test_not, key, start, end, count, | |
8576 from_end), (start = Qzero)); | |
8577 | |
8578 CHECK_SEQUENCE (sequence); | |
8579 CHECK_NATNUM (start); | |
8580 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start); | |
8581 | |
8582 if (!NILP (end)) | |
8583 { | |
8584 CHECK_NATNUM (end); | |
8585 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end); | |
8586 } | |
8587 | |
8588 if (!NILP (count)) | |
8589 { | |
8590 CHECK_INTEGER (count); | |
8591 if (FIXNUMP (count)) | |
8592 { | |
8593 counting = XFIXNUM (count); | |
8594 } | |
8595 #ifdef HAVE_BIGNUM | |
8596 else | |
8597 { | |
8598 counting = bignum_sign (XBIGNUM_DATA (count)) > 0 ? | |
8599 1 + MOST_POSITIVE_FIXNUM : -1 + MOST_NEGATIVE_FIXNUM; | |
8600 } | |
8601 #endif | |
8602 | |
8603 if (counting <= 0) | |
8604 { | |
8605 return sequence; | |
8606 } | |
8607 } | |
8608 | |
8609 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
8610 key, &test_not_unboundp); | |
8611 | |
8612 if (CONSP (sequence)) | |
8613 { | |
8614 if (!NILP (count) && !NILP (from_end)) | |
8615 { | |
8616 Lisp_Object present = count_with_tail (&object_, nargs - 1, args + 1, | |
8617 Qnsubstitute); | |
8618 | |
8619 if (ZEROP (present)) | |
8620 { | |
8621 return sequence; | |
8622 } | |
8623 | |
8624 presenting = XFIXNUM (present); | |
8625 presenting = presenting <= counting ? 0 : presenting - counting; | |
8626 } | |
8627 | |
8628 { | |
8629 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tail) | |
8630 { | |
8631 if (!(ii < ending)) | |
8632 { | |
8633 break; | |
8634 } | |
8635 | |
8636 if (starting <= ii && | |
8637 check_test (test, key, item, elt) == test_not_unboundp | |
8638 && (presenting ? encountered++ >= presenting | |
8639 : encountered++ < counting)) | |
8640 { | |
8641 CHECK_LISP_WRITEABLE (tail); | |
8642 XSETCAR (tail, new_); | |
8643 } | |
8644 else if (!presenting && encountered >= counting) | |
8645 { | |
8646 break; | |
8647 } | |
8648 | |
8649 ii++; | |
8650 } | |
8651 END_GC_EXTERNAL_LIST_LOOP (elt); | |
8652 } | |
8653 | |
8654 if ((ii < starting || (ii < ending && !NILP (end))) | |
8655 && encountered < counting) | |
8656 { | |
8657 check_sequence_range (args[0], start, end, Flength (args[0])); | |
8658 } | |
8659 } | |
8660 else if (STRINGP (sequence)) | |
8661 { | |
8662 Ibyte *staging, new_bytes[MAX_ICHAR_LEN], *staging_cursor; | |
8663 Ibyte *startp = XSTRING_DATA (sequence), *cursor = startp; | |
8664 Bytecount cursor_offset = 0, byte_len = XSTRING_LENGTH (sequence); | |
8665 Bytecount new_len; | |
8666 Lisp_Object character; | |
8667 | |
8668 CHECK_CHAR_COERCE_INT (new_); | |
8669 | |
8670 new_len = set_itext_ichar (new_bytes, XCHAR (new_)); | |
8671 | |
8672 /* Worst case scenario; new char is four octets long, all the old ones | |
8673 were one octet long, all the old ones match. */ | |
8674 staging = alloca_ibytes (XSTRING_LENGTH (sequence) * new_len); | |
8675 staging_cursor = staging; | |
8676 | |
8677 if (!NILP (count) && !NILP (from_end)) | |
8678 { | |
8679 Lisp_Object present = count_with_tail (&character, nargs - 1, | |
8680 args + 1, Qnsubstitute); | |
8681 | |
8682 if (ZEROP (present)) | |
8683 { | |
8684 return sequence; | |
8685 } | |
8686 | |
8687 presenting = XFIXNUM (present); | |
8688 | |
8689 /* If there are fewer items in the string than we have | |
8690 permission to change, we don't need to differentiate | |
8691 between the :from-end nil and :from-end t | |
8692 cases. Otherwise, presenting is the number of matching | |
8693 items we need to ignore before we start to change. */ | |
8694 presenting = presenting <= counting ? 0 : presenting - counting; | |
8695 } | |
8696 | |
8697 ii = 0; | |
8698 while (cursor_offset < byte_len && ii < ending) | |
8699 { | |
8700 if (ii >= starting) | |
8701 { | |
8702 character = make_char (itext_ichar (cursor)); | |
8703 | |
8704 if ((check_test (test, key, item, character) | |
8705 == test_not_unboundp) | |
8706 && (presenting ? encountered++ >= presenting : | |
8707 encountered++ < counting)) | |
8708 { | |
8709 staging_cursor | |
8710 += itext_copy_ichar (new_bytes, staging_cursor); | |
8711 } | |
8712 else | |
8713 { | |
8714 staging_cursor | |
8715 += itext_copy_ichar (cursor, staging_cursor); | |
8716 } | |
8717 | |
8718 startp = XSTRING_DATA (sequence); | |
8719 cursor = startp + cursor_offset; | |
8720 | |
8721 if (byte_len != XSTRING_LENGTH (sequence) | |
8722 || !valid_ibyteptr_p (cursor)) | |
8723 { | |
8724 mapping_interaction_error (Qnsubstitute, sequence); | |
8725 } | |
8726 } | |
8727 else | |
8728 { | |
8729 staging_cursor += itext_copy_ichar (cursor, staging_cursor); | |
8730 } | |
8731 | |
8732 INC_IBYTEPTR (cursor); | |
8733 cursor_offset = cursor - startp; | |
8734 ii++; | |
8735 } | |
8736 | |
8737 if (ii < starting || (ii < ending && !NILP (end))) | |
8738 { | |
8739 check_sequence_range (sequence, start, end, Flength (sequence)); | |
8740 } | |
8741 | |
8742 if (0 != encountered) | |
8743 { | |
8744 CHECK_LISP_WRITEABLE (sequence); | |
8745 replace_string_range (sequence, Qzero, make_fixnum (ii), | |
8746 staging, staging_cursor); | |
8747 } | |
8748 } | |
8749 else | |
8750 { | |
8751 Elemcount positioning; | |
8752 Lisp_Object object = Qnil; | |
8753 | |
8754 len = XFIXNUM (Flength (sequence)); | |
8755 check_sequence_range (sequence, start, end, make_fixnum (len)); | |
8756 | |
8757 position0 = position (&object, item, sequence, check_test, | |
8758 test_not_unboundp, test, key, start, end, from_end, | |
8759 Qnil, Qnsubstitute); | |
8760 | |
8761 if (NILP (position0)) | |
8762 { | |
8763 return sequence; | |
8764 } | |
8765 | |
8766 positioning = XFIXNUM (position0); | |
8767 ending = min (len, ending); | |
8768 | |
8769 Faset (sequence, position0, new_); | |
8770 encountered = 1; | |
8771 | |
8772 if (NILP (from_end)) | |
8773 { | |
8774 for (ii = positioning + 1; ii < ending; ii++) | |
8775 { | |
8776 object_ = Faref (sequence, make_fixnum (ii)); | |
8777 | |
8778 if (check_test (test, key, item, object_) == test_not_unboundp | |
8779 && encountered++ < counting) | |
8780 { | |
8781 Faset (sequence, make_fixnum (ii), new_); | |
8782 } | |
8783 else if (encountered == counting) | |
8784 { | |
8785 break; | |
8786 } | |
8787 } | |
8788 } | |
8789 else | |
8790 { | |
8791 for (ii = positioning - 1; ii >= starting; ii--) | |
8792 { | |
8793 object_ = Faref (sequence, make_fixnum (ii)); | |
8794 | |
8795 if (check_test (test, key, item, object_) == test_not_unboundp | |
8796 && encountered++ < counting) | |
8797 { | |
8798 Faset (sequence, make_fixnum (ii), new_); | |
8799 } | |
8800 else if (encountered == counting) | |
8801 { | |
8802 break; | |
8803 } | |
8804 } | |
8805 } | |
8806 } | |
8807 | |
8808 return sequence; | |
8809 } | |
8810 | |
8811 DEFUN ("substitute", Fsubstitute, 3, MANY, 0, /* | |
8812 Substitute NEW for OLD in SEQUENCE. | |
8813 | |
8814 This is a non-destructive function; it makes a copy of SEQUENCE if necessary | |
8815 to avoid corrupting the original SEQUENCE. | |
8816 | |
8817 See `remove*' for the meaning of the keywords. | |
8818 | |
8819 arguments: (NEW OLD SEQUENCE &key (TEST #'eql) (KEY #'identity) (START 0) (END (length SEQUENCE)) COUNT) | |
8820 */ | |
8821 (int nargs, Lisp_Object *args)) | |
8822 { | |
8823 Lisp_Object new_ = args[0], item = args[1], sequence = args[2], tail = Qnil; | |
8824 Lisp_Object result = Qnil, result_tail = Qnil; | |
8825 Lisp_Object object, position0, matched_count; | |
8826 Elemcount starting = 0, ending = MOST_POSITIVE_FIXNUM, encountered = 0; | |
8827 Elemcount ii = 0, counting = MOST_POSITIVE_FIXNUM, presenting = 0; | |
8828 Boolint test_not_unboundp = 1; | |
8829 check_test_func_t check_test = NULL; | |
8830 struct gcpro gcpro1; | |
8831 | |
8832 PARSE_KEYWORDS (Fsubstitute, nargs, args, 9, | |
8833 (test, if_, if_not, test_not, key, start, end, count, | |
8834 from_end), (start = Qzero, count = Qunbound)); | |
8835 | |
8836 CHECK_SEQUENCE (sequence); | |
8837 | |
8838 CHECK_NATNUM (start); | |
8839 starting = BIGNUMP (start) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (start); | |
8840 | |
8841 if (!NILP (end)) | |
8842 { | |
8843 CHECK_NATNUM (end); | |
8844 ending = BIGNUMP (end) ? 1 + MOST_POSITIVE_FIXNUM : XFIXNUM (end); | |
8845 } | |
8846 | |
8847 check_test = get_check_test_function (item, &test, test_not, if_, if_not, | |
8848 key, &test_not_unboundp); | |
8849 | |
8850 if (!UNBOUNDP (count)) | |
8851 { | |
8852 if (!NILP (count)) | |
8853 { | |
8854 CHECK_INTEGER (count); | |
8855 if (FIXNUMP (count)) | |
8856 { | |
8857 counting = XFIXNUM (count); | |
8858 } | |
8859 #ifdef HAVE_BIGNUM | |
8860 else | |
8861 { | |
8862 counting = bignum_sign (XBIGNUM_DATA (count)) > 0 ? | |
8863 1 + MOST_POSITIVE_FIXNUM : -1 + MOST_NEGATIVE_FIXNUM; | |
8864 } | |
8865 #endif | |
8866 | |
8867 if (counting <= 0) | |
8868 { | |
8869 return sequence; | |
8870 } | |
8871 } | |
8872 } | |
8873 | |
8874 if (!CONSP (sequence)) | |
8875 { | |
8876 position0 = position (&object, item, sequence, check_test, | |
8877 test_not_unboundp, test, key, start, end, from_end, | |
8878 Qnil, Qsubstitute); | |
8879 | |
8880 if (NILP (position0)) | |
8881 { | |
8882 return sequence; | |
8883 } | |
8884 else | |
8885 { | |
8886 args[2] = Fcopy_sequence (sequence); | |
8887 return Fnsubstitute (nargs, args); | |
8888 } | |
8889 } | |
8890 | |
8891 matched_count = count_with_tail (&tail, nargs - 1, args + 1, Qsubstitute); | |
8892 | |
8893 if (ZEROP (matched_count)) | |
8894 { | |
8895 return sequence; | |
8896 } | |
8897 | |
8898 if (!NILP (count) && !NILP (from_end)) | |
8899 { | |
8900 presenting = XFIXNUM (matched_count); | |
8901 presenting = presenting <= counting ? 0 : presenting - counting; | |
8902 } | |
8903 | |
8904 GCPRO1 (result); | |
8905 { | |
8906 GC_EXTERNAL_LIST_LOOP_3 (elt, sequence, tailing) | |
8907 { | |
8908 if (EQ (tail, tailing)) | |
8909 { | |
8910 XUNGCPRO (elt); | |
8911 UNGCPRO; | |
8912 | |
8913 if (NILP (result)) | |
8914 { | |
8915 return XCDR (tail); | |
8916 } | |
8917 | |
8918 XSETCDR (result_tail, XCDR (tail)); | |
8919 return result; | |
8920 } | |
8921 else if (starting <= ii && ii < ending && | |
8922 (check_test (test, key, item, elt) == test_not_unboundp) | |
8923 && (presenting ? encountered++ >= presenting | |
8924 : encountered++ < counting)) | |
8925 { | |
8926 if (NILP (result)) | |
8927 { | |
8928 result = result_tail = Fcons (new_, Qnil); | |
8929 } | |
8930 else | |
8931 { | |
8932 XSETCDR (result_tail, Fcons (new_, Qnil)); | |
8933 result_tail = XCDR (result_tail); | |
8934 } | |
8935 } | |
8936 else if (NILP (result)) | |
8937 { | |
8938 result = result_tail = Fcons (elt, Qnil); | |
8939 } | |
8940 else | |
8941 { | |
8942 XSETCDR (result_tail, Fcons (elt, Qnil)); | |
8943 result_tail = XCDR (result_tail); | |
8944 } | |
8945 | |
8946 if (ii == ending) | |
8947 { | |
8948 break; | |
8949 } | |
8950 | |
8951 ii++; | |
8952 } | |
8953 END_GC_EXTERNAL_LIST_LOOP (elt); | |
8954 } | |
8955 UNGCPRO; | |
8956 | |
8957 if (ii < starting || (ii < ending && !NILP (end))) | |
8958 { | |
8959 check_sequence_range (args[0], start, end, Flength (args[0])); | |
8960 } | |
8961 | |
8962 return result; | |
8963 } | |
8964 | |
8965 static Lisp_Object | |
8966 subst (Lisp_Object new_, Lisp_Object old, Lisp_Object tree, int depth) | |
8967 { | |
8968 if (depth + lisp_eval_depth > max_lisp_eval_depth) | |
8969 { | |
8970 stack_overflow ("Stack overflow in subst", tree); | |
8971 } | |
8972 | |
8973 if (EQ (tree, old)) | |
8974 { | |
8975 return new_; | |
8976 } | |
8977 else if (CONSP (tree)) | |
8978 { | |
8979 Lisp_Object aa = subst (new_, old, XCAR (tree), depth + 1); | |
8980 Lisp_Object dd = subst (new_, old, XCDR (tree), depth + 1); | |
8981 | |
8982 if (EQ (aa, XCAR (tree)) && EQ (dd, XCDR (tree))) | |
8983 { | |
8984 return tree; | |
8985 } | |
8986 else | |
8987 { | |
8988 return Fcons (aa, dd); | |
8989 } | |
8990 } | |
8991 else | |
8992 { | |
8993 return tree; | |
8994 } | |
8995 } | |
8996 | |
8997 static Lisp_Object | |
8998 sublis (Lisp_Object alist, Lisp_Object tree, | |
8999 check_test_func_t check_test, Boolint test_not_unboundp, | |
9000 Lisp_Object test, Lisp_Object key, int depth) | |
9001 { | |
9002 Lisp_Object keyed = KEY (key, tree), aa, dd; | |
9003 | |
9004 if (depth + lisp_eval_depth > max_lisp_eval_depth) | |
9005 { | |
9006 stack_overflow ("Stack overflow in sublis", tree); | |
9007 } | |
9008 | |
9009 { | |
9010 GC_EXTERNAL_LIST_LOOP_2 (elt, alist) | |
9011 { | |
9012 if (CONSP (elt) && | |
9013 check_test (test, key, XCAR (elt), keyed) == test_not_unboundp) | |
9014 { | |
9015 XUNGCPRO (elt); | |
9016 return XCDR (elt); | |
9017 } | |
9018 } | |
9019 END_GC_EXTERNAL_LIST_LOOP (elt); | |
9020 } | |
9021 | |
9022 if (!CONSP (tree)) | |
9023 { | |
9024 return tree; | |
9025 } | |
9026 | |
9027 aa = sublis (alist, XCAR (tree), check_test, test_not_unboundp, test, key, | |
9028 depth + 1); | |
9029 dd = sublis (alist, XCDR (tree), check_test, test_not_unboundp, test, key, | |
9030 depth + 1); | |
9031 | |
9032 if (EQ (aa, XCAR (tree)) && EQ (dd, XCDR (tree))) | |
9033 { | |
9034 return tree; | |
9035 } | |
9036 | |
9037 return Fcons (aa, dd); | |
9038 } | |
9039 | |
9040 DEFUN ("sublis", Fsublis, 2, MANY, 0, /* | |
9041 Perform substitutions indicated by ALIST in TREE (non-destructively). | |
9042 Return a copy of TREE with all matching elements replaced. | |
9043 | |
9044 See `member*' for the meaning of :test, :test-not and :key. | |
9045 | |
9046 arguments: (ALIST TREE &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
9047 */ | |
9048 (int nargs, Lisp_Object *args)) | |
9049 { | |
9050 Lisp_Object alist = args[0], tree = args[1]; | |
9051 Boolint test_not_unboundp = 1; | |
9052 check_test_func_t check_test = NULL; | |
9053 | |
9054 PARSE_KEYWORDS (Fsublis, nargs, args, 5, (test, if_, test_not, if_not, key), | |
9055 (key = Qidentity)); | |
9056 | |
9057 if (NILP (key)) | |
9058 { | |
9059 key = Qidentity; | |
9060 } | |
9061 | |
9062 get_check_match_function (&test, test_not, if_, if_not, | |
9063 /* sublis() is going to apply the key, don't ask | |
9064 for a match function that will do it for | |
9065 us. */ | |
9066 Qidentity, &test_not_unboundp, &check_test); | |
9067 | |
9068 if (CONSP (alist) && NILP (XCDR (alist)) && CONSP (XCAR (alist)) | |
9069 && EQ (key, Qidentity) && 1 == test_not_unboundp | |
9070 && (check_eq_nokey == check_test || | |
9071 (check_eql_nokey == check_test && | |
9072 !NON_FIXNUM_NUMBER_P (XCAR (XCAR (alist)))))) | |
9073 { | |
9074 /* #'subst with #'eq is very cheap indeed; call it. */ | |
9075 return subst (XCDR (XCAR (alist)), XCAR (XCAR (alist)), tree, 0); | |
9076 } | |
9077 | |
9078 return sublis (alist, tree, check_test, test_not_unboundp, test, key, 0); | |
9079 } | |
9080 | |
9081 static Lisp_Object | |
9082 nsublis (Lisp_Object alist, Lisp_Object tree, | |
9083 check_test_func_t check_test, | |
9084 Boolint test_not_unboundp, | |
9085 Lisp_Object test, Lisp_Object key, int depth) | |
9086 { | |
9087 Lisp_Object tree_saved = tree, tortoise = tree, keyed = Qnil; | |
9088 struct gcpro gcpro1, gcpro2; | |
9089 int count = 0; | |
9090 | |
9091 if (depth + lisp_eval_depth > max_lisp_eval_depth) | |
9092 { | |
9093 stack_overflow ("Stack overflow in nsublis", tree); | |
9094 } | |
9095 | |
9096 GCPRO2 (tree_saved, keyed); | |
9097 | |
9098 while (CONSP (tree)) | |
9099 { | |
9100 Boolint replaced = 0; | |
9101 keyed = KEY (key, XCAR (tree)); | |
9102 | |
9103 { | |
9104 GC_EXTERNAL_LIST_LOOP_2 (elt, alist) | |
9105 { | |
9106 if (CONSP (elt) && | |
9107 check_test (test, key, XCAR (elt), keyed) == test_not_unboundp) | |
9108 { | |
9109 CHECK_LISP_WRITEABLE (tree); | |
9110 /* See comment in sublis() on using elt_cdr. */ | |
9111 XSETCAR (tree, XCDR (elt)); | |
9112 replaced = 1; | |
9113 break; | |
9114 } | |
9115 } | |
9116 END_GC_EXTERNAL_LIST_LOOP (elt); | |
9117 } | |
9118 | |
9119 if (!replaced) | |
9120 { | |
9121 if (CONSP (XCAR (tree))) | |
9122 { | |
9123 nsublis (alist, XCAR (tree), check_test, test_not_unboundp, | |
9124 test, key, depth + 1); | |
9125 } | |
9126 } | |
9127 | |
9128 keyed = KEY (key, XCDR (tree)); | |
9129 replaced = 0; | |
9130 | |
9131 { | |
9132 GC_EXTERNAL_LIST_LOOP_2 (elt, alist) | |
9133 { | |
9134 if (CONSP (elt) && | |
9135 check_test (test, key, XCAR (elt), keyed) == test_not_unboundp) | |
9136 { | |
9137 CHECK_LISP_WRITEABLE (tree); | |
9138 XSETCDR (tree, XCDR (elt)); | |
9139 tree = Qnil; | |
9140 break; | |
9141 } | |
9142 } | |
9143 END_GC_EXTERNAL_LIST_LOOP (elt); | |
9144 } | |
9145 | |
9146 if (!NILP (tree)) | |
9147 { | |
9148 tree = XCDR (tree); | |
9149 } | |
9150 | |
9151 if (++count > CIRCULAR_LIST_SUSPICION_LENGTH) | |
9152 { | |
9153 if (count & 1) | |
9154 { | |
9155 tortoise = XCDR (tortoise); | |
9156 } | |
9157 | |
9158 if (EQ (tortoise, tree)) | |
9159 { | |
9160 signal_circular_list_error (tree); | |
9161 } | |
9162 } | |
9163 } | |
9164 | |
9165 RETURN_UNGCPRO (tree_saved); | |
9166 } | |
9167 | |
9168 DEFUN ("nsublis", Fnsublis, 2, MANY, 0, /* | |
9169 Perform substitutions indicated by ALIST in TREE (destructively). | |
9170 Any matching element of TREE is changed via a call to `setcar'. | |
9171 | |
9172 See `member*' for the meaning of :test, :test-not and :key. | |
9173 | |
9174 arguments: (ALIST TREE &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
9175 */ | |
9176 (int nargs, Lisp_Object *args)) | |
9177 { | |
9178 Lisp_Object alist = args[0], tree = args[1], tailed = Qnil, keyed = Qnil; | |
9179 Boolint test_not_unboundp = 1; | |
9180 check_test_func_t check_test = NULL; | |
9181 struct gcpro gcpro1, gcpro2; | |
9182 | |
9183 PARSE_KEYWORDS (Fnsublis, nargs, args, 5, (test, if_, test_not, if_not, key), | |
9184 (key = Qidentity)); | |
9185 | |
9186 if (NILP (key)) | |
9187 { | |
9188 key = Qidentity; | |
9189 } | |
9190 | |
9191 get_check_match_function (&test, test_not, if_, if_not, | |
9192 /* nsublis() is going to apply the key, don't ask | |
9193 for a match function that will do it for | |
9194 us. */ | |
9195 Qidentity, &test_not_unboundp, &check_test); | |
9196 | |
9197 GCPRO2 (tailed, keyed); | |
9198 | |
9199 keyed = KEY (key, tree); | |
9200 | |
9201 { | |
9202 /* nsublis() won't attempt to replace a cons handed to it, do that | |
9203 ourselves. */ | |
9204 GC_EXTERNAL_LIST_LOOP_2 (elt, alist) | |
9205 { | |
9206 if (CONSP (elt) && | |
9207 check_test (test, key, XCAR (elt), keyed) == test_not_unboundp) | |
9208 { | |
9209 XUNGCPRO (elt); | |
9210 return XCDR (elt); | |
9211 } | |
9212 } | |
9213 END_GC_EXTERNAL_LIST_LOOP (elt); | |
9214 } | |
9215 | |
9216 UNGCPRO; | |
9217 | |
9218 return nsublis (alist, tree, check_test, test_not_unboundp, test, key, 0); | |
9219 } | |
9220 | |
9221 DEFUN ("subst", Fsubst, 3, MANY, 0, /* | |
9222 Substitute NEW for OLD everywhere in TREE (non-destructively). | |
9223 | |
9224 Return a copy of TREE with all elements `eql' to OLD replaced by NEW. | |
9225 | |
9226 See `member*' for the meaning of :test, :test-not and :key. | |
9227 | |
9228 arguments: (NEW OLD TREE &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
9229 */ | |
9230 (int nargs, Lisp_Object *args)) | |
9231 { | |
9232 Lisp_Object result, alist = noseeum_cons (noseeum_cons (args[1], args[0]), | |
9233 Qnil); | |
9234 args[1] = alist; | |
9235 result = Fsublis (nargs - 1, args + 1); | |
9236 free_cons (XCAR (alist)); | |
9237 free_cons (alist); | |
9238 | |
9239 return result; | |
9240 } | |
9241 | |
9242 DEFUN ("nsubst", Fnsubst, 3, MANY, 0, /* | |
9243 Substitute NEW for OLD everywhere in TREE (destructively). | |
9244 | |
9245 Any element of TREE which is `eql' to OLD is changed to NEW (via a call to | |
9246 `setcar'). | |
9247 | |
9248 See `member*' for the meaning of the keywords. The keyword | |
9249 :descend-structures, not specified by Common Lisp, allows callers to specify | |
9250 that non-cons objects (vectors and range tables, among others) should also | |
9251 undergo substitution. | |
9252 | |
9253 arguments: (NEW OLD TREE &key (TEST #'eql) (KEY #'identity) TEST-NOT DESCEND-STRUCTURES) | |
9254 */ | |
9255 (int nargs, Lisp_Object *args)) | |
9256 { | |
9257 Lisp_Object new_ = args[0], old = args[1], tree = args[2], result, alist; | |
9258 Boolint test_not_unboundp = 1; | |
9259 check_test_func_t check_test = NULL; | |
9260 | |
9261 PARSE_KEYWORDS (Fnsubst, nargs, args, 6, (test, if_, test_not, if_not, key, | |
9262 descend_structures), NULL); | |
9263 if (!NILP (descend_structures)) | |
9264 { | |
9265 check_test = get_check_test_function (old, &test, test_not, if_, if_not, | |
9266 key, &test_not_unboundp); | |
9267 | |
9268 return nsubst_structures (new_, old, tree, check_test, test_not_unboundp, | |
9269 test, key); | |
9270 | |
9271 } | |
9272 | |
9273 alist = noseeum_cons (noseeum_cons (old, new_), Qnil); | |
9274 args[1] = alist; | |
9275 result = Fnsublis (nargs - 1, args + 1); | |
9276 free_cons (XCAR (alist)); | |
9277 free_cons (alist); | |
9278 | |
9279 return result; | |
9280 } | |
9281 | |
9282 static Boolint | |
9283 tree_equal (Lisp_Object tree1, Lisp_Object tree2, | |
9284 check_test_func_t check_test, Boolint test_not_unboundp, | |
9285 Lisp_Object test, Lisp_Object key, int depth) | |
9286 { | |
9287 Lisp_Object tortoise1 = tree1, tortoise2 = tree2; | |
9288 struct gcpro gcpro1, gcpro2; | |
9289 int count = 0; | |
9290 Boolint result; | |
9291 | |
9292 if (depth + lisp_eval_depth > max_lisp_eval_depth) | |
9293 { | |
9294 stack_overflow ("Stack overflow in tree-equal", tree1); | |
9295 } | |
9296 | |
9297 GCPRO2 (tree1, tree2); | |
9298 | |
9299 while (CONSP (tree1) && CONSP (tree2) | |
9300 && tree_equal (XCAR (tree1), XCAR (tree2), check_test, | |
9301 test_not_unboundp, test, key, depth + 1)) | |
9302 { | |
9303 tree1 = XCDR (tree1); | |
9304 tree2 = XCDR (tree2); | |
9305 | |
9306 if (++count > CIRCULAR_LIST_SUSPICION_LENGTH) | |
9307 { | |
9308 if (count & 1) | |
9309 { | |
9310 tortoise1 = XCDR (tortoise1); | |
9311 tortoise2 = XCDR (tortoise2); | |
9312 } | |
9313 | |
9314 if (EQ (tortoise1, tree1)) | |
9315 { | |
9316 signal_circular_list_error (tree1); | |
9317 } | |
9318 | |
9319 if (EQ (tortoise2, tree2)) | |
9320 { | |
9321 signal_circular_list_error (tree2); | |
9322 } | |
9323 } | |
9324 } | |
9325 | |
9326 if (CONSP (tree1) || CONSP (tree2)) | |
9327 { | |
9328 UNGCPRO; | |
9329 return 0; | |
9330 } | |
9331 | |
9332 result = check_test (test, key, tree1, tree2) == test_not_unboundp; | |
9333 UNGCPRO; | |
9334 | |
9335 return result; | |
9336 } | |
9337 | |
9338 DEFUN ("tree-equal", Ftree_equal, 2, MANY, 0, /* | |
9339 Return t if TREE1 and TREE2 have `eql' leaves. | |
9340 | |
9341 Atoms are compared by `eql', unless another test is specified using | |
9342 :test; cons cells are compared recursively. | |
9343 | |
9344 See `union' for the meaning of :test, :test-not and :key. | |
9345 | |
9346 arguments: (TREE1 TREE2 &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
9347 */ | |
9348 (int nargs, Lisp_Object *args)) | |
9349 { | |
9350 Lisp_Object tree1 = args[0], tree2 = args[1]; | |
9351 Boolint test_not_unboundp = 1; | |
9352 check_test_func_t check_test = NULL; | |
9353 | |
9354 PARSE_KEYWORDS (Ftree_equal, nargs, args, 3, (test, key, test_not), | |
9355 (key = Qidentity)); | |
9356 | |
9357 get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
9358 &test_not_unboundp, &check_test); | |
9359 | |
9360 return tree_equal (tree1, tree2, check_test, test_not_unboundp, test, key, | |
9361 0) ? Qt : Qnil; | |
9362 } | |
9363 | |
9364 static Lisp_Object | |
9365 mismatch_from_end (Lisp_Object sequence1, Lisp_Object start1, Lisp_Object end1, | |
9366 Lisp_Object sequence2, Lisp_Object start2, Lisp_Object end2, | |
9367 check_test_func_t check_match, Boolint test_not_unboundp, | |
9368 Lisp_Object test, Lisp_Object key, | |
9369 Boolint UNUSED (return_sequence1_index)) | |
9370 { | |
9371 Elemcount sequence1_len = XFIXNUM (Flength (sequence1)); | |
9372 Elemcount sequence2_len = XFIXNUM (Flength (sequence2)), ii = 0; | |
9373 Elemcount starting1, ending1, starting2, ending2; | |
9374 Lisp_Object *sequence1_storage = NULL, *sequence2_storage = NULL; | |
9375 struct gcpro gcpro1, gcpro2; | |
9376 | |
9377 check_sequence_range (sequence1, start1, end1, make_fixnum (sequence1_len)); | |
9378 starting1 = XFIXNUM (start1); | |
9379 ending1 = FIXNUMP (end1) ? XFIXNUM (end1) : 1 + MOST_POSITIVE_FIXNUM; | |
9380 ending1 = min (ending1, sequence1_len); | |
9381 | |
9382 check_sequence_range (sequence2, start2, end2, make_fixnum (sequence2_len)); | |
9383 starting2 = XFIXNUM (start2); | |
9384 ending2 = FIXNUMP (end2) ? XFIXNUM (end2) : 1 + MOST_POSITIVE_FIXNUM; | |
9385 ending2 = min (ending2, sequence2_len); | |
9386 | |
9387 if (LISTP (sequence1)) | |
9388 { | |
9389 Lisp_Object *saving; | |
9390 sequence1_storage = saving | |
9391 = alloca_array (Lisp_Object, ending1 - starting1); | |
9392 | |
9393 { | |
9394 EXTERNAL_LIST_LOOP_2 (elt, sequence1) | |
9395 { | |
9396 if (starting1 <= ii && ii < ending1) | |
9397 { | |
9398 *saving++ = elt; | |
9399 } | |
9400 else if (ii == ending1) | |
9401 { | |
9402 break; | |
9403 } | |
9404 | |
9405 ++ii; | |
9406 } | |
9407 } | |
9408 } | |
9409 else if (STRINGP (sequence1)) | |
9410 { | |
9411 const Ibyte *cursor = string_char_addr (sequence1, starting1); | |
9412 | |
9413 STRING_DATA_TO_OBJECT_ARRAY (cursor, sequence1_storage, ii, | |
9414 ending1 - starting1); | |
9415 | |
9416 } | |
9417 else if (BIT_VECTORP (sequence1)) | |
9418 { | |
9419 Lisp_Bit_Vector *vv = XBIT_VECTOR (sequence1); | |
9420 sequence1_storage = alloca_array (Lisp_Object, ending1 - starting1); | |
9421 for (ii = starting1; ii < ending1; ++ii) | |
9422 { | |
9423 sequence1_storage[ii - starting1] | |
9424 = make_fixnum (bit_vector_bit (vv, ii)); | |
9425 } | |
9426 } | |
9427 else | |
9428 { | |
9429 sequence1_storage = XVECTOR_DATA (sequence1) + starting1; | |
9430 } | |
9431 | |
9432 ii = 0; | |
9433 | |
9434 if (LISTP (sequence2)) | |
9435 { | |
9436 Lisp_Object *saving; | |
9437 sequence2_storage = saving | |
9438 = alloca_array (Lisp_Object, ending2 - starting2); | |
9439 | |
9440 { | |
9441 EXTERNAL_LIST_LOOP_2 (elt, sequence2) | |
9442 { | |
9443 if (starting2 <= ii && ii < ending2) | |
9444 { | |
9445 *saving++ = elt; | |
9446 } | |
9447 else if (ii == ending2) | |
9448 { | |
9449 break; | |
9450 } | |
9451 | |
9452 ++ii; | |
9453 } | |
9454 } | |
9455 } | |
9456 else if (STRINGP (sequence2)) | |
9457 { | |
9458 const Ibyte *cursor = string_char_addr (sequence2, starting2); | |
9459 | |
9460 STRING_DATA_TO_OBJECT_ARRAY (cursor, sequence2_storage, ii, | |
9461 ending2 - starting2); | |
9462 | |
9463 } | |
9464 else if (BIT_VECTORP (sequence2)) | |
9465 { | |
9466 Lisp_Bit_Vector *vv = XBIT_VECTOR (sequence2); | |
9467 sequence2_storage = alloca_array (Lisp_Object, ending2 - starting2); | |
9468 for (ii = starting2; ii < ending2; ++ii) | |
9469 { | |
9470 sequence2_storage[ii - starting2] | |
9471 = make_fixnum (bit_vector_bit (vv, ii)); | |
9472 } | |
9473 } | |
9474 else | |
9475 { | |
9476 sequence2_storage = XVECTOR_DATA (sequence2) + starting2; | |
9477 } | |
9478 | |
9479 GCPRO2 (sequence1_storage[0], sequence2_storage[0]); | |
9480 gcpro1.nvars = ending1 - starting1; | |
9481 gcpro2.nvars = ending2 - starting2; | |
9482 | |
9483 while (ending1 > starting1 && ending2 > starting2) | |
9484 { | |
9485 --ending1; | |
9486 --ending2; | |
9487 | |
9488 if (check_match (test, key, sequence1_storage[ending1 - starting1], | |
9489 sequence2_storage[ending2 - starting2]) | |
9490 != test_not_unboundp) | |
9491 { | |
9492 UNGCPRO; | |
9493 return make_integer (ending1 + 1); | |
9494 } | |
9495 } | |
9496 | |
9497 UNGCPRO; | |
9498 | |
9499 if (ending1 > starting1 || ending2 > starting2) | |
9500 { | |
9501 return make_integer (ending1); | |
9502 } | |
9503 | |
9504 return Qnil; | |
9505 } | |
9506 | |
9507 static Lisp_Object | |
9508 mismatch_list_list (Lisp_Object sequence1, Lisp_Object start1, Lisp_Object end1, | |
9509 Lisp_Object sequence2, Lisp_Object start2, Lisp_Object end2, | |
9510 check_test_func_t check_match, Boolint test_not_unboundp, | |
9511 Lisp_Object test, Lisp_Object key, | |
9512 Boolint UNUSED (return_list_index)) | |
9513 { | |
9514 Lisp_Object sequence1_tortoise = sequence1, sequence2_tortoise = sequence2; | |
9515 Lisp_Object orig_sequence1 = sequence1, orig_sequence2 = sequence2; | |
9516 Elemcount ending1 = MOST_POSITIVE_FIXNUM, ending2 = MOST_POSITIVE_FIXNUM; | |
9517 Elemcount starting1, starting2, counting, startcounting; | |
9518 Elemcount shortest_len = 0; | |
9519 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
9520 | |
9521 starting1 = FIXNUMP (start1) ? XFIXNUM (start1) : 1 + MOST_POSITIVE_FIXNUM; | |
9522 starting2 = FIXNUMP (start2) ? XFIXNUM (start2) : 1 + MOST_POSITIVE_FIXNUM; | |
9523 | |
9524 if (!NILP (end1)) | |
9525 { | |
9526 ending1 = FIXNUMP (end1) ? XFIXNUM (end1) : 1 + MOST_POSITIVE_FIXNUM; | |
9527 } | |
9528 | |
9529 if (!NILP (end2)) | |
9530 { | |
9531 ending2 = FIXNUMP (end2) ? XFIXNUM (end2) : 1 + MOST_POSITIVE_FIXNUM; | |
9532 } | |
9533 | |
9534 if (!ZEROP (start1)) | |
9535 { | |
9536 sequence1 = Fnthcdr (start1, sequence1); | |
9537 | |
9538 if (NILP (sequence1)) | |
9539 { | |
9540 check_sequence_range (sequence1_tortoise, start1, end1, | |
9541 Flength (sequence1_tortoise)); | |
9542 /* Give up early here. */ | |
9543 return Qnil; | |
9544 } | |
9545 | |
9546 ending1 -= starting1; | |
9547 starting1 = 0; | |
9548 sequence1_tortoise = sequence1; | |
9549 } | |
9550 | |
9551 if (!ZEROP (start2)) | |
9552 { | |
9553 sequence2 = Fnthcdr (start2, sequence2); | |
9554 | |
9555 if (NILP (sequence2)) | |
9556 { | |
9557 check_sequence_range (sequence2_tortoise, start2, end2, | |
9558 Flength (sequence2_tortoise)); | |
9559 return Qnil; | |
9560 } | |
9561 | |
9562 ending2 -= starting2; | |
9563 starting2 = 0; | |
9564 sequence2_tortoise = sequence2; | |
9565 } | |
9566 | |
9567 GCPRO4 (sequence1, sequence2, sequence1_tortoise, sequence2_tortoise); | |
9568 | |
9569 counting = startcounting = min (ending1, ending2); | |
9570 | |
9571 while (counting-- > 0 && !NILP (sequence1) && !NILP (sequence2)) | |
9572 { | |
9573 if (check_match (test, key, | |
9574 CONSP (sequence1) ? XCAR (sequence1) | |
9575 : Fcar (sequence1), | |
9576 CONSP (sequence2) ? XCAR (sequence2) | |
9577 : Fcar (sequence2) ) != test_not_unboundp) | |
9578 { | |
9579 UNGCPRO; | |
9580 return make_integer (XFIXNUM (start1) + shortest_len); | |
9581 } | |
9582 | |
9583 sequence1 = CONSP (sequence1) ? XCDR (sequence1) : Fcdr (sequence1); | |
9584 sequence2 = CONSP (sequence2) ? XCDR (sequence2) : Fcdr (sequence2); | |
9585 | |
9586 shortest_len++; | |
9587 | |
9588 if (startcounting - counting > CIRCULAR_LIST_SUSPICION_LENGTH) | |
9589 { | |
9590 if (counting & 1) | |
9591 { | |
9592 sequence1_tortoise = XCDR (sequence1_tortoise); | |
9593 sequence2_tortoise = XCDR (sequence2_tortoise); | |
9594 } | |
9595 | |
9596 if (EQ (sequence1, sequence1_tortoise)) | |
9597 { | |
9598 signal_circular_list_error (sequence1); | |
9599 } | |
9600 | |
9601 if (EQ (sequence2, sequence2_tortoise)) | |
9602 { | |
9603 signal_circular_list_error (sequence2); | |
9604 } | |
9605 } | |
9606 } | |
9607 | |
9608 UNGCPRO; | |
9609 | |
9610 if (NILP (sequence1)) | |
9611 { | |
9612 Lisp_Object args[] = { start1, make_fixnum (shortest_len) }; | |
9613 check_sequence_range (orig_sequence1, start1, end1, | |
9614 Fplus (countof (args), args)); | |
9615 } | |
9616 | |
9617 if (NILP (sequence2)) | |
9618 { | |
9619 Lisp_Object args[] = { start2, make_fixnum (shortest_len) }; | |
9620 check_sequence_range (orig_sequence2, start2, end2, | |
9621 Fplus (countof (args), args)); | |
9622 } | |
9623 | |
9624 if ((!NILP (end1) && shortest_len != ending1 - starting1) || | |
9625 (!NILP (end2) && shortest_len != ending2 - starting2)) | |
9626 { | |
9627 return make_integer (XFIXNUM (start1) + shortest_len); | |
9628 } | |
9629 | |
9630 if ((NILP (end1) && CONSP (sequence1)) || (NILP (end2) && CONSP (sequence2))) | |
9631 { | |
9632 return make_integer (XFIXNUM (start1) + shortest_len); | |
9633 } | |
9634 | |
9635 return Qnil; | |
9636 } | |
9637 | |
9638 static Lisp_Object | |
9639 mismatch_list_string (Lisp_Object list, Lisp_Object list_start, | |
9640 Lisp_Object list_end, | |
9641 Lisp_Object string, Lisp_Object string_start, | |
9642 Lisp_Object string_end, | |
9643 check_test_func_t check_match, | |
9644 Boolint test_not_unboundp, | |
9645 Lisp_Object test, Lisp_Object key, | |
9646 Boolint return_list_index) | |
9647 { | |
9648 Ibyte *string_data = XSTRING_DATA (string), *startp = string_data; | |
9649 Bytecount string_offset = 0, string_len = XSTRING_LENGTH (string); | |
9650 Elemcount char_count = 0, list_starting, list_ending; | |
9651 Elemcount string_starting, string_ending; | |
9652 Lisp_Object character, orig_list = list; | |
9653 struct gcpro gcpro1; | |
9654 | |
9655 list_ending = FIXNUMP (list_end) ? XFIXNUM (list_end) : 1 + MOST_POSITIVE_FIXNUM; | |
9656 list_starting = FIXNUMP (list_start) ? XFIXNUM (list_start) : 1 + MOST_POSITIVE_FIXNUM; | |
9657 | |
9658 string_ending = FIXNUMP (string_end) ? XFIXNUM (string_end) : 1 + MOST_POSITIVE_FIXNUM; | |
9659 string_starting | |
9660 = FIXNUMP (string_start) ? XFIXNUM (string_start) : 1 + MOST_POSITIVE_FIXNUM; | |
9661 | |
9662 while (char_count < string_starting && string_offset < string_len) | |
9663 { | |
9664 INC_IBYTEPTR (string_data); | |
9665 string_offset = string_data - startp; | |
9666 char_count++; | |
9667 } | |
9668 | |
9669 if (!ZEROP (list_start)) | |
9670 { | |
9671 list = Fnthcdr (list_start, list); | |
9672 if (NILP (list)) | |
9673 { | |
9674 check_sequence_range (orig_list, list_start, list_end, | |
9675 Flength (orig_list)); | |
9676 return Qnil; | |
9677 } | |
9678 | |
9679 list_ending -= list_starting; | |
9680 list_starting = 0; | |
9681 } | |
9682 | |
9683 GCPRO1 (list); | |
9684 | |
9685 while (list_starting < list_ending && string_starting < string_ending | |
9686 && string_offset < string_len && !NILP (list)) | |
9687 { | |
9688 character = make_char (itext_ichar (string_data)); | |
9689 | |
9690 if (return_list_index) | |
9691 { | |
9692 if (check_match (test, key, CONSP (list) ? XCAR (list) : Fcar (list), | |
9693 character) | |
9694 != test_not_unboundp) | |
9695 { | |
9696 UNGCPRO; | |
9697 return make_integer (XFIXNUM (list_start) + char_count); | |
9698 } | |
9699 } | |
9700 else | |
9701 { | |
9702 if (check_match (test, key, character, | |
9703 CONSP (list) ? XCAR (list) : Fcar (list)) | |
9704 != test_not_unboundp) | |
9705 { | |
9706 UNGCPRO; | |
9707 return make_integer (char_count); | |
9708 } | |
9709 } | |
9710 | |
9711 list = CONSP (list) ? XCDR (list) : Fcdr (list); | |
9712 | |
9713 startp = XSTRING_DATA (string); | |
9714 string_data = startp + string_offset; | |
9715 if (string_len != XSTRING_LENGTH (string) | |
9716 || !valid_ibyteptr_p (string_data)) | |
9717 { | |
9718 mapping_interaction_error (Qmismatch, string); | |
9719 } | |
9720 | |
9721 list_starting++; | |
9722 string_starting++; | |
9723 char_count++; | |
9724 INC_IBYTEPTR (string_data); | |
9725 string_offset = string_data - startp; | |
9726 } | |
9727 | |
9728 UNGCPRO; | |
9729 | |
9730 if (NILP (list)) | |
9731 { | |
9732 Lisp_Object args[] = { list_start, make_fixnum (char_count) }; | |
9733 check_sequence_range (orig_list, list_start, list_end, | |
9734 Fplus (countof (args), args)); | |
9735 } | |
9736 | |
9737 if (string_data == XSTRING_DATA (string) + XSTRING_LENGTH (string)) | |
9738 { | |
9739 check_sequence_range (string, string_start, string_end, | |
9740 make_fixnum (char_count)); | |
9741 } | |
9742 | |
9743 if ((NILP (string_end) ? | |
9744 string_offset < string_len : string_starting < string_ending) || | |
9745 (NILP (list_end) ? !NILP (list) : list_starting < list_ending)) | |
9746 { | |
9747 return make_integer (return_list_index ? XFIXNUM (list_start) + char_count : | |
9748 char_count); | |
9749 } | |
9750 | |
9751 return Qnil; | |
9752 } | |
9753 | |
9754 static Lisp_Object | |
9755 mismatch_list_array (Lisp_Object list, Lisp_Object list_start, | |
9756 Lisp_Object list_end, | |
9757 Lisp_Object array, Lisp_Object array_start, | |
9758 Lisp_Object array_end, | |
9759 check_test_func_t check_match, | |
9760 Boolint test_not_unboundp, | |
9761 Lisp_Object test, Lisp_Object key, | |
9762 Boolint return_list_index) | |
9763 { | |
9764 Elemcount ii = 0, list_starting, list_ending; | |
9765 Elemcount array_starting, array_ending, array_len; | |
9766 Lisp_Object orig_list = list; | |
9767 struct gcpro gcpro1; | |
9768 | |
9769 list_ending = FIXNUMP (list_end) ? XFIXNUM (list_end) : 1 + MOST_POSITIVE_FIXNUM; | |
9770 list_starting = FIXNUMP (list_start) ? XFIXNUM (list_start) : 1 + MOST_POSITIVE_FIXNUM; | |
9771 | |
9772 array_ending = FIXNUMP (array_end) ? XFIXNUM (array_end) : 1 + MOST_POSITIVE_FIXNUM; | |
9773 array_starting = FIXNUMP (array_start) ? XFIXNUM (array_start) : 1 + MOST_POSITIVE_FIXNUM; | |
9774 array_len = XFIXNUM (Flength (array)); | |
9775 | |
9776 array_ending = min (array_ending, array_len); | |
9777 | |
9778 check_sequence_range (array, array_start, array_end, make_fixnum (array_len)); | |
9779 | |
9780 if (!ZEROP (list_start)) | |
9781 { | |
9782 list = Fnthcdr (list_start, list); | |
9783 if (NILP (list)) | |
9784 { | |
9785 check_sequence_range (orig_list, list_start, list_end, | |
9786 Flength (orig_list)); | |
9787 return Qnil; | |
9788 } | |
9789 | |
9790 list_ending -= list_starting; | |
9791 list_starting = 0; | |
9792 } | |
9793 | |
9794 GCPRO1 (list); | |
9795 | |
9796 while (list_starting < list_ending && array_starting < array_ending | |
9797 && !NILP (list)) | |
9798 { | |
9799 if (return_list_index) | |
9800 { | |
9801 if (check_match (test, key, CONSP (list) ? XCAR (list) : Fcar (list), | |
9802 Faref (array, make_fixnum (array_starting))) | |
9803 != test_not_unboundp) | |
9804 { | |
9805 UNGCPRO; | |
9806 return make_integer (XFIXNUM (list_start) + ii); | |
9807 } | |
9808 } | |
9809 else | |
9810 { | |
9811 if (check_match (test, key, Faref (array, make_fixnum (array_starting)), | |
9812 CONSP (list) ? XCAR (list) : Fcar (list)) | |
9813 != test_not_unboundp) | |
9814 { | |
9815 UNGCPRO; | |
9816 return make_integer (array_starting); | |
9817 } | |
9818 } | |
9819 | |
9820 list = CONSP (list) ? XCDR (list) : Fcdr (list); | |
9821 list_starting++; | |
9822 array_starting++; | |
9823 ii++; | |
9824 } | |
9825 | |
9826 UNGCPRO; | |
9827 | |
9828 if (NILP (list)) | |
9829 { | |
9830 Lisp_Object args[] = { list_start, make_fixnum (ii) }; | |
9831 check_sequence_range (orig_list, list_start, list_end, | |
9832 Fplus (countof (args), args)); | |
9833 } | |
9834 | |
9835 if (array_starting < array_ending || | |
9836 (NILP (list_end) ? !NILP (list) : list_starting < list_ending)) | |
9837 { | |
9838 return make_integer (return_list_index ? XFIXNUM (list_start) + ii : | |
9839 array_starting); | |
9840 } | |
9841 | |
9842 return Qnil; | |
9843 } | |
9844 | |
9845 static Lisp_Object | |
9846 mismatch_string_array (Lisp_Object string, Lisp_Object string_start, | |
9847 Lisp_Object string_end, | |
9848 Lisp_Object array, Lisp_Object array_start, | |
9849 Lisp_Object array_end, | |
9850 check_test_func_t check_match, Boolint test_not_unboundp, | |
9851 Lisp_Object test, Lisp_Object key, | |
9852 Boolint return_string_index) | |
9853 { | |
9854 Ibyte *string_data = XSTRING_DATA (string), *startp = string_data; | |
9855 Bytecount string_offset = 0, string_len = XSTRING_LENGTH (string); | |
9856 Elemcount char_count = 0, array_starting, array_ending, array_length; | |
9857 Elemcount string_starting, string_ending; | |
9858 Lisp_Object character; | |
9859 | |
9860 array_starting = FIXNUMP (array_start) ? XFIXNUM (array_start) : 1 + MOST_POSITIVE_FIXNUM; | |
9861 array_ending = FIXNUMP (array_end) ? XFIXNUM (array_end) : 1 + MOST_POSITIVE_FIXNUM; | |
9862 array_length = XFIXNUM (Flength (array)); | |
9863 check_sequence_range (array, array_start, array_end, make_fixnum (array_length)); | |
9864 array_ending = min (array_ending, array_length); | |
9865 | |
9866 string_ending = FIXNUMP (string_end) ? XFIXNUM (string_end) : 1 + MOST_POSITIVE_FIXNUM; | |
9867 string_starting | |
9868 = FIXNUMP (string_start) ? XFIXNUM (string_start) : 1 + MOST_POSITIVE_FIXNUM; | |
9869 | |
9870 while (char_count < string_starting && string_offset < string_len) | |
9871 { | |
9872 INC_IBYTEPTR (string_data); | |
9873 string_offset = string_data - startp; | |
9874 char_count++; | |
9875 } | |
9876 | |
9877 while (array_starting < array_ending && string_starting < string_ending | |
9878 && string_offset < string_len) | |
9879 { | |
9880 character = make_char (itext_ichar (string_data)); | |
9881 | |
9882 if (return_string_index) | |
9883 { | |
9884 if (check_match (test, key, character, | |
9885 Faref (array, make_fixnum (array_starting))) | |
9886 != test_not_unboundp) | |
9887 { | |
9888 return make_integer (char_count); | |
9889 } | |
9890 } | |
9891 else | |
9892 { | |
9893 if (check_match (test, key, | |
9894 Faref (array, make_fixnum (array_starting)), | |
9895 character) | |
9896 != test_not_unboundp) | |
9897 { | |
9898 return make_integer (XFIXNUM (array_start) + char_count); | |
9899 } | |
9900 } | |
9901 | |
9902 startp = XSTRING_DATA (string); | |
9903 string_data = startp + string_offset; | |
9904 if (string_len != XSTRING_LENGTH (string) | |
9905 || !valid_ibyteptr_p (string_data)) | |
9906 { | |
9907 mapping_interaction_error (Qmismatch, string); | |
9908 } | |
9909 | |
9910 array_starting++; | |
9911 string_starting++; | |
9912 char_count++; | |
9913 INC_IBYTEPTR (string_data); | |
9914 string_offset = string_data - startp; | |
9915 } | |
9916 | |
9917 if (string_data == XSTRING_DATA (string) + XSTRING_LENGTH (string)) | |
9918 { | |
9919 check_sequence_range (string, string_start, string_end, | |
9920 make_fixnum (char_count)); | |
9921 } | |
9922 | |
9923 if ((NILP (string_end) ? | |
9924 string_offset < string_len : string_starting < string_ending) || | |
9925 (NILP (array_end) ? !NILP (array) : array_starting < array_ending)) | |
9926 { | |
9927 return make_integer (return_string_index ? char_count : | |
9928 XFIXNUM (array_start) + char_count); | |
9929 } | |
9930 | |
9931 return Qnil; | |
9932 } | |
9933 | |
9934 static Lisp_Object | |
9935 mismatch_string_string (Lisp_Object string1, | |
9936 Lisp_Object string1_start, Lisp_Object string1_end, | |
9937 Lisp_Object string2, Lisp_Object string2_start, | |
9938 Lisp_Object string2_end, | |
9939 check_test_func_t check_match, | |
9940 Boolint test_not_unboundp, | |
9941 Lisp_Object test, Lisp_Object key, | |
9942 Boolint UNUSED (return_string1_index)) | |
9943 { | |
9944 Ibyte *string1_data = XSTRING_DATA (string1), *startp1 = string1_data; | |
9945 Bytecount string1_offset = 0, string1_len = XSTRING_LENGTH (string1); | |
9946 Ibyte *string2_data = XSTRING_DATA (string2), *startp2 = string2_data; | |
9947 Bytecount string2_offset = 0, string2_len = XSTRING_LENGTH (string2); | |
9948 Elemcount char_count1 = 0, string1_starting, string1_ending; | |
9949 Elemcount char_count2 = 0, string2_starting, string2_ending; | |
9950 Lisp_Object character1, character2; | |
9951 | |
9952 string1_ending = FIXNUMP (string1_end) ? XFIXNUM (string1_end) : 1 + MOST_POSITIVE_FIXNUM; | |
9953 string1_starting | |
9954 = FIXNUMP (string1_start) ? XFIXNUM (string1_start) : 1 + MOST_POSITIVE_FIXNUM; | |
9955 | |
9956 string2_starting | |
9957 = FIXNUMP (string2_start) ? XFIXNUM (string2_start) : 1 + MOST_POSITIVE_FIXNUM; | |
9958 string2_ending = FIXNUMP (string2_end) ? XFIXNUM (string2_end) : 1 + MOST_POSITIVE_FIXNUM; | |
9959 | |
9960 while (char_count1 < string1_starting && string1_offset < string1_len) | |
9961 { | |
9962 INC_IBYTEPTR (string1_data); | |
9963 string1_offset = string1_data - startp1; | |
9964 char_count1++; | |
9965 } | |
9966 | |
9967 while (char_count2 < string2_starting && string2_offset < string2_len) | |
9968 { | |
9969 INC_IBYTEPTR (string2_data); | |
9970 string2_offset = string2_data - startp2; | |
9971 char_count2++; | |
9972 } | |
9973 | |
9974 while (string2_starting < string2_ending && string1_starting < string1_ending | |
9975 && string1_offset < string1_len && string2_offset < string2_len) | |
9976 { | |
9977 character1 = make_char (itext_ichar (string1_data)); | |
9978 character2 = make_char (itext_ichar (string2_data)); | |
9979 | |
9980 if (check_match (test, key, character1, character2) | |
9981 != test_not_unboundp) | |
9982 { | |
9983 return make_integer (char_count1); | |
9984 } | |
9985 | |
9986 startp1 = XSTRING_DATA (string1); | |
9987 string1_data = startp1 + string1_offset; | |
9988 if (string1_len != XSTRING_LENGTH (string1) | |
9989 || !valid_ibyteptr_p (string1_data)) | |
9990 { | |
9991 mapping_interaction_error (Qmismatch, string1); | |
9992 } | |
9993 | |
9994 startp2 = XSTRING_DATA (string2); | |
9995 string2_data = startp2 + string2_offset; | |
9996 if (string2_len != XSTRING_LENGTH (string2) | |
9997 || !valid_ibyteptr_p (string2_data)) | |
9998 { | |
9999 mapping_interaction_error (Qmismatch, string2); | |
10000 } | |
10001 | |
10002 string2_starting++; | |
10003 string1_starting++; | |
10004 char_count1++; | |
10005 char_count2++; | |
10006 INC_IBYTEPTR (string1_data); | |
10007 string1_offset = string1_data - startp1; | |
10008 INC_IBYTEPTR (string2_data); | |
10009 string2_offset = string2_data - startp2; | |
10010 } | |
10011 | |
10012 if (string1_data == XSTRING_DATA (string1) + XSTRING_LENGTH (string1)) | |
10013 { | |
10014 check_sequence_range (string1, string1_start, string1_end, | |
10015 make_fixnum (char_count1)); | |
10016 } | |
10017 | |
10018 if (string2_data == XSTRING_DATA (string2) + XSTRING_LENGTH (string2)) | |
10019 { | |
10020 check_sequence_range (string2, string2_start, string2_end, | |
10021 make_fixnum (char_count2)); | |
10022 } | |
10023 | |
10024 if ((!NILP (string1_end) && string1_starting < string1_ending) || | |
10025 (!NILP (string2_end) && string2_starting < string2_ending)) | |
10026 { | |
10027 return make_integer (char_count1); | |
10028 } | |
10029 | |
10030 if ((NILP (string1_end) && string1_data | |
10031 < (XSTRING_DATA (string1) + XSTRING_LENGTH (string1))) || | |
10032 (NILP (string2_end) && string2_data | |
10033 < (XSTRING_DATA (string2) + XSTRING_LENGTH (string2)))) | |
10034 { | |
10035 return make_integer (char_count1); | |
10036 } | |
10037 | |
10038 return Qnil; | |
10039 } | |
10040 | |
10041 static Lisp_Object | |
10042 mismatch_array_array (Lisp_Object array1, Lisp_Object start1, Lisp_Object end1, | |
10043 Lisp_Object array2, Lisp_Object start2, Lisp_Object end2, | |
10044 check_test_func_t check_match, Boolint test_not_unboundp, | |
10045 Lisp_Object test, Lisp_Object key, | |
10046 Boolint UNUSED (return_array1_index)) | |
10047 { | |
10048 Elemcount len1 = XFIXNUM (Flength (array1)), len2 = XFIXNUM (Flength (array2)); | |
10049 Elemcount ending1 = MOST_POSITIVE_FIXNUM, ending2 = MOST_POSITIVE_FIXNUM; | |
10050 Elemcount starting1, starting2; | |
10051 | |
10052 check_sequence_range (array1, start1, end1, make_fixnum (len1)); | |
10053 check_sequence_range (array2, start2, end2, make_fixnum (len2)); | |
10054 | |
10055 starting1 = FIXNUMP (start1) ? XFIXNUM (start1) : 1 + MOST_POSITIVE_FIXNUM; | |
10056 starting2 = FIXNUMP (start2) ? XFIXNUM (start2) : 1 + MOST_POSITIVE_FIXNUM; | |
10057 | |
10058 if (!NILP (end1)) | |
10059 { | |
10060 ending1 = FIXNUMP (end1) ? XFIXNUM (end1) : 1 + MOST_POSITIVE_FIXNUM; | |
10061 } | |
10062 | |
10063 if (!NILP (end2)) | |
10064 { | |
10065 ending2 = FIXNUMP (end2) ? XFIXNUM (end2) : 1 + MOST_POSITIVE_FIXNUM; | |
10066 } | |
10067 | |
10068 ending1 = min (ending1, len1); | |
10069 ending2 = min (ending2, len2); | |
10070 | |
10071 while (starting1 < ending1 && starting2 < ending2) | |
10072 { | |
10073 if (check_match (test, key, Faref (array1, make_fixnum (starting1)), | |
10074 Faref (array2, make_fixnum (starting2))) | |
10075 != test_not_unboundp) | |
10076 { | |
10077 return make_integer (starting1); | |
10078 } | |
10079 starting1++; | |
10080 starting2++; | |
10081 } | |
10082 | |
10083 if (starting1 < ending1 || starting2 < ending2) | |
10084 { | |
10085 return make_integer (starting1); | |
10086 } | |
10087 | |
10088 return Qnil; | |
10089 } | |
10090 | |
10091 typedef Lisp_Object | |
10092 (*mismatch_func_t) (Lisp_Object sequence1, Lisp_Object start1, Lisp_Object end1, | |
10093 Lisp_Object sequence2, Lisp_Object start2, Lisp_Object end2, | |
10094 check_test_func_t check_match, Boolint test_not_unboundp, | |
10095 Lisp_Object test, Lisp_Object key, | |
10096 Boolint return_list_index); | |
10097 | |
10098 static mismatch_func_t | |
10099 get_mismatch_func (Lisp_Object sequence1, Lisp_Object sequence2, | |
10100 Lisp_Object from_end, Boolint *return_sequence1_index_out) | |
10101 { | |
10102 CHECK_SEQUENCE (sequence1); | |
10103 CHECK_SEQUENCE (sequence2); | |
10104 | |
10105 if (!NILP (from_end)) | |
10106 { | |
10107 *return_sequence1_index_out = 1; | |
10108 return mismatch_from_end; | |
10109 } | |
10110 | |
10111 if (LISTP (sequence1)) | |
10112 { | |
10113 if (LISTP (sequence2)) | |
10114 { | |
10115 *return_sequence1_index_out = 1; | |
10116 return mismatch_list_list; | |
10117 } | |
10118 | |
10119 if (STRINGP (sequence2)) | |
10120 { | |
10121 *return_sequence1_index_out = 1; | |
10122 return mismatch_list_string; | |
10123 } | |
10124 | |
10125 *return_sequence1_index_out = 1; | |
10126 return mismatch_list_array; | |
10127 } | |
10128 | |
10129 if (STRINGP (sequence1)) | |
10130 { | |
10131 if (STRINGP (sequence2)) | |
10132 { | |
10133 *return_sequence1_index_out = 1; | |
10134 return mismatch_string_string; | |
10135 } | |
10136 | |
10137 if (LISTP (sequence2)) | |
10138 { | |
10139 *return_sequence1_index_out = 0; | |
10140 return mismatch_list_string; | |
10141 } | |
10142 | |
10143 *return_sequence1_index_out = 1; | |
10144 return mismatch_string_array; | |
10145 } | |
10146 | |
10147 if (ARRAYP (sequence1)) | |
10148 { | |
10149 if (STRINGP (sequence2)) | |
10150 { | |
10151 *return_sequence1_index_out = 0; | |
10152 return mismatch_string_array; | |
10153 } | |
10154 | |
10155 if (LISTP (sequence2)) | |
10156 { | |
10157 *return_sequence1_index_out = 0; | |
10158 return mismatch_list_array; | |
10159 } | |
10160 | |
10161 *return_sequence1_index_out = 1; | |
10162 return mismatch_array_array; | |
10163 } | |
10164 | |
10165 RETURN_NOT_REACHED (NULL); | |
10166 return NULL; | |
10167 } | |
10168 | |
10169 DEFUN ("mismatch", Fmismatch, 2, MANY, 0, /* | |
10170 Compare SEQUENCE1 with SEQUENCE2, return index of first mismatching element. | |
10171 | |
10172 Return nil if the sequences match. If one sequence is a prefix of the | |
10173 other, the return value indicates the end of the shorter sequence. A | |
10174 non-nil return value always reflects an index into SEQUENCE1. | |
10175 | |
10176 See `search' for the meaning of the keywords." | |
10177 | |
10178 arguments: (SEQUENCE1 SEQUENCE2 &key (TEST #'eql) (KEY #'identity) (START1 0) END1 (START2 0) END2 FROM-END TEST-NOT) | |
10179 */ | |
10180 (int nargs, Lisp_Object *args)) | |
10181 { | |
10182 Lisp_Object sequence1 = args[0], sequence2 = args[1]; | |
10183 Boolint test_not_unboundp = 1, return_first_index = 0; | |
10184 check_test_func_t check_match = NULL; | |
10185 mismatch_func_t mismatch = NULL; | |
10186 | |
10187 PARSE_KEYWORDS (Fmismatch, nargs, args, 8, | |
10188 (test, key, from_end, start1, end1, start2, end2, test_not), | |
10189 (start1 = start2 = Qzero)); | |
10190 | |
10191 CHECK_SEQUENCE (sequence1); | |
10192 CHECK_SEQUENCE (sequence2); | |
10193 | |
10194 CHECK_NATNUM (start1); | |
10195 CHECK_NATNUM (start2); | |
10196 | |
10197 if (!NILP (end1)) | |
10198 { | |
10199 CHECK_NATNUM (end1); | |
10200 } | |
10201 | |
10202 if (!NILP (end2)) | |
10203 { | |
10204 CHECK_NATNUM (end2); | |
10205 } | |
10206 | |
10207 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
10208 &test_not_unboundp, NULL); | |
10209 mismatch = get_mismatch_func (sequence1, sequence2, from_end, | |
10210 &return_first_index); | |
10211 | |
10212 if (return_first_index) | |
10213 { | |
10214 return mismatch (sequence1, start1, end1, sequence2, start2, end2, | |
10215 check_match, test_not_unboundp, test, key, 1); | |
10216 } | |
10217 | |
10218 return mismatch (sequence2, start2, end2, sequence1, start1, end1, | |
10219 check_match, test_not_unboundp, test, key, 0); | |
10220 } | |
10221 | |
10222 DEFUN ("search", Fsearch, 2, MANY, 0, /* | |
10223 Search for SEQUENCE1 as a subsequence of SEQUENCE2. | |
10224 | |
10225 Return the index of the leftmost element of the first match found; return | |
10226 nil if there are no matches. | |
10227 | |
10228 In this function, :start1 and :end1 specify a subsequence of SEQUENCE1, and | |
10229 :start2 and :end2 specify a subsequence of SEQUENCE2. See `remove*' for | |
10230 details of the other keywords. | |
10231 | |
10232 arguments: (SEQUENCE1 SEQUENCE2 &key (TEST #'eql) (KEY #'identity) (START1 0) END1 (START2 0) END2 FROM-END TEST-NOT) | |
10233 */ | |
10234 (int nargs, Lisp_Object *args)) | |
10235 { | |
10236 Lisp_Object sequence1 = args[0], sequence2 = args[1], position0 = Qnil; | |
10237 Boolint test_not_unboundp = 1, return_first = 0; | |
10238 check_test_func_t check_test = NULL, check_match = NULL; | |
10239 mismatch_func_t mismatch = NULL; | |
10240 Elemcount starting1 = 0, ending1 = 1 + MOST_POSITIVE_FIXNUM, starting2 = 0; | |
10241 Elemcount ending2 = 1 + MOST_POSITIVE_FIXNUM, ii = 0; | |
10242 Elemcount length1; | |
10243 Lisp_Object object = Qnil; | |
10244 struct gcpro gcpro1, gcpro2; | |
10245 | |
10246 PARSE_KEYWORDS (Fsearch, nargs, args, 8, | |
10247 (test, key, from_end, start1, end1, start2, end2, test_not), | |
10248 (start1 = start2 = Qzero)); | |
10249 | |
10250 CHECK_SEQUENCE (sequence1); | |
10251 CHECK_SEQUENCE (sequence2); | |
10252 CHECK_KEY_ARGUMENT (key); | |
10253 | |
10254 CHECK_NATNUM (start1); | |
10255 starting1 = FIXNUMP (start1) ? XFIXNUM (start1) : 1 + MOST_POSITIVE_FIXNUM; | |
10256 CHECK_NATNUM (start2); | |
10257 starting2 = FIXNUMP (start2) ? XFIXNUM (start2) : 1 + MOST_POSITIVE_FIXNUM; | |
10258 | |
10259 if (!NILP (end1)) | |
10260 { | |
10261 Lisp_Object len1 = Flength (sequence1); | |
10262 | |
10263 CHECK_NATNUM (end1); | |
10264 check_sequence_range (sequence1, start1, end1, len1); | |
10265 ending1 = min (XFIXNUM (end1), XFIXNUM (len1)); | |
10266 } | |
10267 else | |
10268 { | |
10269 end1 = Flength (sequence1); | |
10270 check_sequence_range (sequence1, start1, end1, end1); | |
10271 ending1 = XFIXNUM (end1); | |
10272 } | |
10273 | |
10274 length1 = ending1 - starting1; | |
10275 | |
10276 if (!NILP (end2)) | |
10277 { | |
10278 Lisp_Object len2 = Flength (sequence2); | |
10279 | |
10280 CHECK_NATNUM (end2); | |
10281 check_sequence_range (sequence2, start2, end2, len2); | |
10282 ending2 = min (XFIXNUM (end2), XFIXNUM (len2)); | |
10283 } | |
10284 else | |
10285 { | |
10286 end2 = Flength (sequence2); | |
10287 check_sequence_range (sequence2, start2, end2, end2); | |
10288 ending2 = XFIXNUM (end2); | |
10289 } | |
10290 | |
10291 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
10292 &test_not_unboundp, &check_test); | |
10293 mismatch = get_mismatch_func (sequence1, sequence2, from_end, &return_first); | |
10294 | |
10295 if (bytecode_arithcompare (start1, make_integer (ending1)) >= 0) | |
10296 { | |
10297 if (NILP (from_end)) | |
10298 { | |
10299 return start2; | |
10300 } | |
10301 | |
10302 if (NILP (end2)) | |
10303 { | |
10304 return Flength (sequence2); | |
10305 } | |
10306 | |
10307 return end2; | |
10308 } | |
10309 | |
10310 if (NILP (from_end)) | |
10311 { | |
10312 Lisp_Object mismatch_start1 = Fadd1 (start1); | |
10313 Lisp_Object first = KEY (key, Felt (sequence1, start1)); | |
10314 GCPRO2 (first, mismatch_start1); | |
10315 | |
10316 ii = starting2; | |
10317 while (ii < ending2) | |
10318 { | |
10319 position0 = position (&object, first, sequence2, check_test, | |
10320 test_not_unboundp, test, key, make_fixnum (ii), | |
10321 end2, Qnil, Qnil, Qsearch); | |
10322 if (NILP (position0)) | |
10323 { | |
10324 UNGCPRO; | |
10325 return Qnil; | |
10326 } | |
10327 | |
10328 if (length1 + XFIXNUM (position0) <= ending2 && | |
10329 (return_first ? | |
10330 NILP (mismatch (sequence1, mismatch_start1, end1, | |
10331 sequence2, | |
10332 make_fixnum (1 + XFIXNUM (position0)), | |
10333 make_fixnum (length1 + XFIXNUM (position0)), | |
10334 check_match, test_not_unboundp, test, key, 1)) : | |
10335 NILP (mismatch (sequence2, | |
10336 make_fixnum (1 + XFIXNUM (position0)), | |
10337 make_fixnum (length1 + XFIXNUM (position0)), | |
10338 sequence1, mismatch_start1, end1, | |
10339 check_match, test_not_unboundp, test, key, 0)))) | |
10340 | |
10341 | |
10342 { | |
10343 UNGCPRO; | |
10344 return position0; | |
10345 } | |
10346 | |
10347 ii = XFIXNUM (position0) + 1; | |
10348 } | |
10349 | |
10350 UNGCPRO; | |
10351 } | |
10352 else | |
10353 { | |
10354 Lisp_Object mismatch_end1 = make_integer (ending1 - 1); | |
10355 Lisp_Object last = KEY (key, Felt (sequence1, mismatch_end1)); | |
10356 GCPRO2 (last, mismatch_end1); | |
10357 | |
10358 ii = ending2; | |
10359 while (ii > starting2) | |
10360 { | |
10361 position0 = position (&object, last, sequence2, check_test, | |
10362 test_not_unboundp, test, key, start2, | |
10363 make_fixnum (ii), Qt, Qnil, Qsearch); | |
10364 | |
10365 if (NILP (position0)) | |
10366 { | |
10367 UNGCPRO; | |
10368 return Qnil; | |
10369 } | |
10370 | |
10371 if (XFIXNUM (position0) - length1 + 1 >= starting2 && | |
10372 (return_first ? | |
10373 NILP (mismatch (sequence1, start1, mismatch_end1, | |
10374 sequence2, | |
10375 make_fixnum (XFIXNUM (position0) - length1 + 1), | |
10376 make_fixnum (XFIXNUM (position0)), | |
10377 check_match, test_not_unboundp, test, key, 1)) : | |
10378 NILP (mismatch (sequence2, | |
10379 make_fixnum (XFIXNUM (position0) - length1 + 1), | |
10380 make_fixnum (XFIXNUM (position0)), | |
10381 sequence1, start1, mismatch_end1, | |
10382 check_match, test_not_unboundp, test, key, 0)))) | |
10383 { | |
10384 UNGCPRO; | |
10385 return make_fixnum (XFIXNUM (position0) - length1 + 1); | |
10386 } | |
10387 | |
10388 ii = XFIXNUM (position0); | |
10389 } | |
10390 | |
10391 UNGCPRO; | |
10392 } | |
10393 | |
10394 return Qnil; | |
10395 } | |
10396 | |
10397 /* These two functions do set operations, those that can be visualised with | |
10398 Venn diagrams. */ | |
10399 static Lisp_Object | |
10400 venn (Lisp_Object caller, int nargs, Lisp_Object *args, Boolint intersectionp) | |
10401 { | |
10402 Lisp_Object liszt1 = args[0], liszt2 = args[1]; | |
10403 Lisp_Object result = EQ (caller, Qsubsetp) ? Qt : Qnil, result_tail = Qnil; | |
10404 Lisp_Object keyed = Qnil, ignore = Qnil; | |
10405 Boolint test_not_unboundp = 1; | |
10406 check_test_func_t check_test = NULL; | |
10407 struct gcpro gcpro1, gcpro2; | |
10408 | |
10409 PARSE_KEYWORDS_8 (caller, nargs, args, 4, (test, key, test_not, stable), | |
10410 NULL, 2, 0); | |
10411 | |
10412 CHECK_LIST (liszt1); | |
10413 CHECK_LIST (liszt2); | |
10414 | |
10415 CHECK_KEY_ARGUMENT (key); | |
10416 | |
10417 if (NILP (liszt1) && intersectionp) | |
10418 { | |
10419 return Qnil; | |
10420 } | |
10421 | |
10422 if (NILP (liszt2)) | |
10423 { | |
10424 return intersectionp ? Qnil : liszt1; | |
10425 } | |
10426 | |
10427 get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
10428 &test_not_unboundp, &check_test); | |
10429 | |
10430 GCPRO2 (keyed, result); | |
10431 | |
10432 { | |
10433 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt1) | |
10434 { | |
10435 keyed = KEY (key, elt); | |
10436 if (NILP (list_position_cons_before (&ignore, keyed, liszt2, | |
10437 check_test, test_not_unboundp, | |
10438 test, key, 0, Qzero, Qnil)) | |
10439 != intersectionp) | |
10440 { | |
10441 if (EQ (Qsubsetp, caller)) | |
10442 { | |
10443 result = Qnil; | |
10444 break; | |
10445 } | |
10446 else if (NILP (stable)) | |
10447 { | |
10448 result = Fcons (elt, result); | |
10449 } | |
10450 else if (NILP (result)) | |
10451 { | |
10452 result = result_tail = Fcons (elt, Qnil); | |
10453 } | |
10454 else | |
10455 { | |
10456 XSETCDR (result_tail, Fcons (elt, Qnil)); | |
10457 result_tail = XCDR (result_tail); | |
10458 } | |
10459 } | |
10460 } | |
10461 END_GC_EXTERNAL_LIST_LOOP (elt); | |
10462 } | |
10463 | |
10464 UNGCPRO; | |
10465 | |
10466 return result; | |
10467 } | |
10468 | |
10469 static Lisp_Object | |
10470 nvenn (Lisp_Object caller, int nargs, Lisp_Object *args, Boolint intersectionp) | |
10471 { | |
10472 Lisp_Object liszt1 = args[0], liszt2 = args[1], tortoise_elt, ignore = Qnil; | |
10473 Lisp_Object elt = Qnil, tail = Qnil, keyed = Qnil, prev_tail = Qnil; | |
10474 Elemcount count; | |
10475 Boolint test_not_unboundp = 1; | |
10476 check_test_func_t check_test = NULL; | |
10477 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
10478 | |
10479 PARSE_KEYWORDS_8 (caller, nargs, args, 3, (test, key, test_not), | |
10480 NULL, 2, 0); | |
10481 | |
10482 CHECK_LIST (liszt1); | |
10483 CHECK_LIST (liszt2); | |
10484 | |
10485 CHECK_KEY_ARGUMENT (key); | |
10486 | |
10487 if (NILP (liszt1) && intersectionp) | |
10488 { | |
10489 return Qnil; | |
10490 } | |
10491 | |
10492 if (NILP (liszt2)) | |
10493 { | |
10494 return intersectionp ? Qnil : liszt1; | |
10495 } | |
10496 | |
10497 get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
10498 &test_not_unboundp, &check_test); | |
10499 | |
10500 tortoise_elt = tail = liszt1, count = 0; | |
10501 | |
10502 GCPRO4 (tail, keyed, liszt1, tortoise_elt); | |
10503 | |
10504 while (CONSP (tail) ? (elt = XCAR (tail), 1) : NILP (tail) ? 0 : | |
10505 (signal_malformed_list_error (liszt1), 0)) | |
10506 { | |
10507 keyed = KEY (key, elt); | |
10508 if (NILP (list_position_cons_before (&ignore, keyed, liszt2, | |
10509 check_test, test_not_unboundp, | |
10510 test, key, 0, Qzero, Qnil)) | |
10511 == intersectionp) | |
10512 { | |
10513 if (NILP (prev_tail)) | |
10514 { | |
10515 liszt1 = XCDR (tail); | |
10516 } | |
10517 else | |
10518 { | |
10519 XSETCDR (prev_tail, XCDR (tail)); | |
10520 } | |
10521 | |
10522 tail = XCDR (tail); | |
10523 /* List is definitely not circular now! */ | |
10524 count = 0; | |
10525 } | |
10526 else | |
10527 { | |
10528 prev_tail = tail; | |
10529 tail = XCDR (tail); | |
10530 } | |
10531 | |
10532 if (count++ < CIRCULAR_LIST_SUSPICION_LENGTH) continue; | |
10533 | |
10534 if (count & 1) | |
10535 { | |
10536 tortoise_elt = XCDR (tortoise_elt); | |
10537 } | |
10538 | |
10539 if (EQ (elt, tortoise_elt)) | |
10540 { | |
10541 signal_circular_list_error (liszt1); | |
10542 } | |
10543 } | |
10544 | |
10545 UNGCPRO; | |
10546 | |
10547 return liszt1; | |
10548 } | |
10549 | |
10550 DEFUN ("intersection", Fintersection, 2, MANY, 0, /* | |
10551 Combine LIST1 and LIST2 using a set-intersection operation. | |
10552 | |
10553 The result list contains all items that appear in both LIST1 and LIST2. | |
10554 This is a non-destructive function; it makes a copy of the data if necessary | |
10555 to avoid corrupting the original LIST1 and LIST2. | |
10556 | |
10557 A non-nil value for the :stable keyword, not specified by Common Lisp, means | |
10558 return the items in the order they appear in LIST1. | |
10559 | |
10560 See `union' for the meaning of :test, :test-not and :key." | |
10561 | |
10562 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT STABLE) | |
10563 */ | |
10564 (int nargs, Lisp_Object *args)) | |
10565 { | |
10566 return venn (Qintersection, nargs, args, 1); | |
10567 } | |
10568 | |
10569 DEFUN ("nintersection", Fnintersection, 2, MANY, 0, /* | |
10570 Combine LIST1 and LIST2 using a set-intersection operation. | |
10571 | |
10572 The result list contains all items that appear in both LIST1 and LIST2. | |
10573 This is a destructive function; it reuses the storage of LIST1 whenever | |
10574 possible. | |
10575 | |
10576 See `union' for the meaning of :test, :test-not and :key." | |
10577 | |
10578 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
10579 */ | |
10580 (int nargs, Lisp_Object *args)) | |
10581 { | |
10582 return nvenn (Qnintersection, nargs, args, 1); | |
10583 } | |
10584 | |
10585 DEFUN ("subsetp", Fsubsetp, 2, MANY, 0, /* | |
10586 Return non-nil if every element of LIST1 also appears in LIST2. | |
10587 | |
10588 See `union' for the meaning of the keyword arguments. | |
10589 | |
10590 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
10591 */ | |
10592 (int nargs, Lisp_Object *args)) | |
10593 { | |
10594 return venn (Qsubsetp, nargs, args, 0); | |
10595 } | |
10596 | |
10597 DEFUN ("set-difference", Fset_difference, 2, MANY, 0, /* | |
10598 Combine LIST1 and LIST2 using a set-difference operation. | |
10599 | |
10600 The result list contains all items that appear in LIST1 but not LIST2. This | |
10601 is a non-destructive function; it makes a copy of the data if necessary to | |
10602 avoid corrupting the original LIST1 and LIST2. | |
10603 | |
10604 See `union' for the meaning of :test, :test-not and :key. | |
10605 | |
10606 A non-nil value for the :stable keyword, not specified by Common Lisp, means | |
10607 return the items in the order they appear in LIST1. | |
10608 | |
10609 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT STABLE) | |
10610 */ | |
10611 (int nargs, Lisp_Object *args)) | |
10612 { | |
10613 return venn (Qset_difference, nargs, args, 0); | |
10614 } | |
10615 | |
10616 DEFUN ("nset-difference", Fnset_difference, 2, MANY, 0, /* | |
10617 Combine LIST1 and LIST2 using a set-difference operation. | |
10618 | |
10619 The result list contains all items that appear in LIST1 but not LIST2. This | |
10620 is a destructive function; it reuses the storage of LIST1 whenever possible. | |
10621 | |
10622 See `union' for the meaning of :test, :test-not and :key." | |
10623 | |
10624 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
10625 */ | |
10626 (int nargs, Lisp_Object *args)) | |
10627 { | |
10628 return nvenn (Qnset_difference, nargs, args, 0); | |
10629 } | |
10630 | |
10631 DEFUN ("nunion", Fnunion, 2, MANY, 0, /* | |
10632 Combine LIST1 and LIST2 using a set-union operation. | |
10633 The result list contains all items that appear in either LIST1 or LIST2. | |
10634 | |
10635 This is a destructive function, it reuses the storage of LIST1 whenever | |
10636 possible. | |
10637 | |
10638 See `union' for the meaning of :test, :test-not and :key. | |
10639 | |
10640 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
10641 */ | |
10642 (int nargs, Lisp_Object *args)) | |
10643 { | |
10644 args[0] = nvenn (Qnunion, nargs, args, 0); | |
10645 return bytecode_nconc2 (args); | |
10646 } | |
10647 | |
10648 DEFUN ("union", Funion, 2, MANY, 0, /* | |
10649 Combine LIST1 and LIST2 using a set-union operation. | |
10650 The result list contains all items that appear in either LIST1 or LIST2. | |
10651 This is a non-destructive function; it makes a copy of the data if necessary | |
10652 to avoid corrupting the original LIST1 and LIST2. | |
10653 | |
10654 The keywords :test and :test-not specify two-argument test and negated-test | |
10655 predicates, respectively; :test defaults to `eql'. See `member*' for more | |
10656 information. | |
10657 | |
10658 :key specifies a one-argument function that transforms elements of LIST1 | |
10659 and LIST2 into \"comparison keys\" before the test predicate is applied. | |
10660 For example, if :key is #'car, then the car of elements from LIST1 is | |
10661 compared with the car of elements from LIST2. The :key function, however, | |
10662 does not affect the elements in the returned list, which are taken directly | |
10663 from the elements in LIST1 and LIST2. | |
10664 | |
10665 A non-nil value for the :stable keyword, not specified by Common Lisp, means | |
10666 return the items of LIST1 in order, followed by the remaining items of LIST2 | |
10667 in the order they occur in LIST2. | |
10668 | |
10669 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT STABLE) | |
10670 */ | |
10671 (int nargs, Lisp_Object *args)) | |
10672 { | |
10673 Lisp_Object liszt1 = args[0], liszt2 = args[1], ignore = Qnil; | |
10674 Lisp_Object keyed = Qnil, result, result_tail; | |
10675 Boolint test_not_unboundp = 1; | |
10676 check_test_func_t check_test = NULL, check_match = NULL; | |
10677 struct gcpro gcpro1, gcpro2; | |
10678 | |
10679 PARSE_KEYWORDS (Funion, nargs, args, 4, (test, key, test_not, stable), NULL); | |
10680 | |
10681 CHECK_LIST (liszt1); | |
10682 CHECK_LIST (liszt2); | |
10683 | |
10684 CHECK_KEY_ARGUMENT (key); | |
10685 | |
10686 if (NILP (liszt1)) | |
10687 { | |
10688 return liszt2; | |
10689 } | |
10690 | |
10691 if (NILP (liszt2)) | |
10692 { | |
10693 return liszt1; | |
10694 } | |
10695 | |
10696 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
10697 &test_not_unboundp, &check_test); | |
10698 | |
10699 GCPRO2 (keyed, result); | |
10700 | |
10701 if (NILP (stable)) | |
10702 { | |
10703 result = liszt2; | |
10704 { | |
10705 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt1) | |
10706 { | |
10707 keyed = KEY (key, elt); | |
10708 if (NILP (list_position_cons_before (&ignore, keyed, liszt2, | |
10709 check_test, test_not_unboundp, | |
10710 test, key, 0, Qzero, Qnil))) | |
10711 { | |
10712 /* The Lisp version of #'union used to check which list was | |
10713 longer, and use that as the tail of the constructed | |
10714 list. That fails when the order of arguments to TEST is | |
10715 specified, as is the case for these functions. We could | |
10716 pass the reverse_check argument to | |
10717 list_position_cons_before, but that means any key argument | |
10718 is called an awful lot more, so it's a space win but not | |
10719 a time win. */ | |
10720 result = Fcons (elt, result); | |
10721 } | |
10722 } | |
10723 END_GC_EXTERNAL_LIST_LOOP (elt); | |
10724 } | |
10725 } | |
10726 else | |
10727 { | |
10728 result = result_tail = Qnil; | |
10729 | |
10730 /* The standard `union' doesn't produce a "stable" union -- it | |
10731 iterates over the second list instead of the first one, and returns | |
10732 the values in backwards order. According to the CLTL2 | |
10733 documentation, `union' is not required to preserve the ordering of | |
10734 elements in any fashion; providing the functionality for a stable | |
10735 union is an XEmacs extension. */ | |
10736 { | |
10737 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt2) | |
10738 { | |
10739 if (NILP (list_position_cons_before (&ignore, elt, liszt1, | |
10740 check_match, test_not_unboundp, | |
10741 test, key, 1, Qzero, Qnil))) | |
10742 { | |
10743 if (NILP (result)) | |
10744 { | |
10745 result = result_tail = Fcons (elt, Qnil); | |
10746 } | |
10747 else | |
10748 { | |
10749 XSETCDR (result_tail, Fcons (elt, Qnil)); | |
10750 result_tail = XCDR (result_tail); | |
10751 } | |
10752 } | |
10753 } | |
10754 END_GC_EXTERNAL_LIST_LOOP (elt); | |
10755 } | |
10756 | |
10757 result = NILP (result) ? liszt1 : nconc2 (Fcopy_list (liszt1), result); | |
10758 } | |
10759 | |
10760 UNGCPRO; | |
10761 | |
10762 return result; | |
10763 } | |
10764 | |
10765 DEFUN ("set-exclusive-or", Fset_exclusive_or, 2, MANY, 0, /* | |
10766 Combine LIST1 and LIST2 using a set-exclusive-or operation. | |
10767 | |
10768 The result list contains all items that appear in exactly one of LIST1, LIST2. | |
10769 This is a non-destructive function; it makes a copy of the data if necessary | |
10770 to avoid corrupting the original LIST1 and LIST2. | |
10771 | |
10772 See `union' for the meaning of :test, :test-not and :key. | |
10773 | |
10774 A non-nil value for the :stable keyword, not specified by Common Lisp, means | |
10775 return the items in the order they appear in LIST1, followed by the | |
10776 remaining items in the order they appear in LIST2. | |
10777 | |
10778 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT STABLE) | |
10779 */ | |
10780 (int nargs, Lisp_Object *args)) | |
10781 { | |
10782 Lisp_Object liszt1 = args[0], liszt2 = args[1]; | |
10783 Lisp_Object result = Qnil, result_tail = Qnil, keyed = Qnil, ignore = Qnil; | |
10784 Boolint test_not_unboundp = 1; | |
10785 check_test_func_t check_match = NULL, check_test = NULL; | |
10786 struct gcpro gcpro1, gcpro2; | |
10787 | |
10788 PARSE_KEYWORDS (Fset_exclusive_or, nargs, args, 4, | |
10789 (test, key, test_not, stable), NULL); | |
10790 | |
10791 CHECK_LIST (liszt1); | |
10792 CHECK_LIST (liszt2); | |
10793 | |
10794 CHECK_KEY_ARGUMENT (key); | |
10795 | |
10796 if (NILP (liszt2)) | |
10797 { | |
10798 return liszt1; | |
10799 } | |
10800 | |
10801 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
10802 &test_not_unboundp, &check_test); | |
10803 | |
10804 GCPRO2 (keyed, result); | |
10805 { | |
10806 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt1) | |
10807 { | |
10808 keyed = KEY (key, elt); | |
10809 if (NILP (list_position_cons_before (&ignore, keyed, liszt2, | |
10810 check_test, test_not_unboundp, | |
10811 test, key, 0, Qzero, Qnil))) | |
10812 { | |
10813 if (NILP (stable)) | |
10814 { | |
10815 result = Fcons (elt, result); | |
10816 } | |
10817 else if (NILP (result)) | |
10818 { | |
10819 result = result_tail = Fcons (elt, Qnil); | |
10820 } | |
10821 else | |
10822 { | |
10823 XSETCDR (result_tail, Fcons (elt, Qnil)); | |
10824 result_tail = XCDR (result_tail); | |
10825 } | |
10826 } | |
10827 } | |
10828 END_GC_EXTERNAL_LIST_LOOP (elt); | |
10829 } | |
10830 | |
10831 { | |
10832 GC_EXTERNAL_LIST_LOOP_2 (elt, liszt2) | |
10833 { | |
10834 if (NILP (list_position_cons_before (&ignore, elt, liszt1, | |
10835 check_match, test_not_unboundp, | |
10836 test, key, 1, Qzero, Qnil))) | |
10837 { | |
10838 if (NILP (stable)) | |
10839 { | |
10840 result = Fcons (elt, result); | |
10841 } | |
10842 else if (NILP (result)) | |
10843 { | |
10844 result = result_tail = Fcons (elt, Qnil); | |
10845 } | |
10846 else | |
10847 { | |
10848 XSETCDR (result_tail, Fcons (elt, Qnil)); | |
10849 result_tail = XCDR (result_tail); | |
10850 } | |
10851 } | |
10852 } | |
10853 END_GC_EXTERNAL_LIST_LOOP (elt); | |
10854 } | |
10855 | |
10856 UNGCPRO; | |
10857 | |
10858 return result; | |
10859 } | |
10860 | |
10861 DEFUN ("nset-exclusive-or", Fnset_exclusive_or, 2, MANY, 0, /* | |
10862 Combine LIST1 and LIST2 using a set-exclusive-or operation. | |
10863 | |
10864 The result list contains all items that appear in exactly one of LIST1 and | |
10865 LIST2. This is a destructive function; it reuses the storage of LIST1 and | |
10866 LIST2 whenever possible. | |
10867 | |
10868 See `union' for the meaning of :test, :test-not and :key. | |
10869 | |
10870 arguments: (LIST1 LIST2 &key (TEST #'eql) (KEY #'identity) TEST-NOT) | |
10871 */ | |
10872 (int nargs, Lisp_Object *args)) | |
10873 { | |
10874 Lisp_Object liszt1 = args[0], liszt2 = args[1], elt = Qnil, tail = Qnil; | |
10875 Lisp_Object result = Qnil, tortoise_elt = Qnil, keyed = Qnil, swap; | |
10876 Lisp_Object prev_tail = Qnil, ignore = Qnil; | |
10877 Elemcount count; | |
10878 Boolint test_not_unboundp = 1; | |
10879 check_test_func_t check_match = NULL, check_test = NULL; | |
10880 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
10881 | |
10882 PARSE_KEYWORDS (Fnset_exclusive_or, nargs, args, 4, | |
10883 (test, key, test_not, stable), NULL); | |
10884 | |
10885 CHECK_LIST (liszt1); | |
10886 CHECK_LIST (liszt2); | |
10887 | |
10888 CHECK_KEY_ARGUMENT (key); | |
10889 | |
10890 if (NILP (liszt2)) | |
10891 { | |
10892 return liszt1; | |
10893 } | |
10894 | |
10895 check_match = get_check_match_function (&test, test_not, Qnil, Qnil, key, | |
10896 &test_not_unboundp, &check_test); | |
10897 | |
10898 tortoise_elt = tail = liszt1, count = 0; | |
10899 | |
10900 GCPRO4 (tail, keyed, result, tortoise_elt); | |
10901 | |
10902 while (CONSP (tail) ? (elt = XCAR (tail), 1) : NILP (tail) ? 0 : | |
10903 (signal_malformed_list_error (liszt1), 0)) | |
10904 { | |
10905 keyed = KEY (key, elt); | |
10906 if (NILP (list_position_cons_before (&ignore, keyed, liszt2, | |
10907 check_test, test_not_unboundp, | |
10908 test, key, 0, Qzero, Qnil))) | |
10909 { | |
10910 swap = XCDR (tail); | |
10911 | |
10912 if (NILP (prev_tail)) | |
10913 { | |
10914 liszt1 = XCDR (tail); | |
10915 } | |
10916 else | |
10917 { | |
10918 XSETCDR (prev_tail, swap); | |
10919 } | |
10920 | |
10921 XSETCDR (tail, result); | |
10922 result = tail; | |
10923 tail = swap; | |
10924 | |
10925 /* List is definitely not circular now! */ | |
10926 count = 0; | |
10927 } | |
10928 else | |
10929 { | |
10930 prev_tail = tail; | |
10931 tail = XCDR (tail); | |
10932 } | |
10933 | |
10934 if (count++ < CIRCULAR_LIST_SUSPICION_LENGTH) continue; | |
10935 | |
10936 if (count & 1) | |
10937 { | |
10938 tortoise_elt = XCDR (tortoise_elt); | |
10939 } | |
10940 | |
10941 if (EQ (elt, tortoise_elt)) | |
10942 { | |
10943 signal_circular_list_error (liszt1); | |
10944 } | |
10945 } | |
10946 | |
10947 tortoise_elt = tail = liszt2, count = 0; | |
10948 | |
10949 while (CONSP (tail) ? (elt = XCAR (tail), 1) : NILP (tail) ? 0 : | |
10950 (signal_malformed_list_error (liszt2), 0)) | |
10951 { | |
10952 /* Need to leave the key calculation to list_position_cons_before(). */ | |
10953 if (NILP (list_position_cons_before (&ignore, elt, liszt1, | |
10954 check_match, test_not_unboundp, | |
10955 test, key, 1, Qzero, Qnil))) | |
10956 { | |
10957 swap = XCDR (tail); | |
10958 XSETCDR (tail, result); | |
10959 result = tail; | |
10960 tail = swap; | |
10961 count = 0; | |
10962 } | |
10963 else | |
10964 { | |
10965 tail = XCDR (tail); | |
10966 } | |
10967 | |
10968 if (count++ < CIRCULAR_LIST_SUSPICION_LENGTH) continue; | |
10969 | |
10970 if (count & 1) | |
10971 { | |
10972 tortoise_elt = XCDR (tortoise_elt); | |
10973 } | |
10974 | |
10975 if (EQ (elt, tortoise_elt)) | |
10976 { | |
10977 signal_circular_list_error (liszt1); | |
10978 } | |
10979 } | |
10980 | |
10981 UNGCPRO; | |
10982 | |
10983 return result; | |
10984 } | 2720 } |
10985 | 2721 |
10986 | 2722 |
10987 Lisp_Object | 2723 Lisp_Object |
10988 add_suffix_to_symbol (Lisp_Object symbol, const Ascbyte *ascii_string) | 2724 add_suffix_to_symbol (Lisp_Object symbol, const Ascbyte *ascii_string) |
11606 result = make_string (decoded, decoded_length); | 3342 result = make_string (decoded, decoded_length); |
11607 unbind_to (speccount); | 3343 unbind_to (speccount); |
11608 return result; | 3344 return result; |
11609 } | 3345 } |
11610 | 3346 |
11611 Lisp_Object Qyes_or_no_p; | |
11612 | |
11613 void | 3347 void |
11614 syms_of_fns (void) | 3348 syms_of_fns (void) |
11615 { | 3349 { |
11616 INIT_LISP_OBJECT (bit_vector); | |
11617 | |
11618 DEFSYMBOL (Qstring_lessp); | |
11619 DEFSYMBOL (Qmerge); | |
11620 DEFSYMBOL (Qfill); | |
11621 DEFSYMBOL (Qidentity); | |
11622 DEFSYMBOL (Qvector); | |
11623 DEFSYMBOL (Qarray); | |
11624 DEFSYMBOL (Qstring); | |
11625 DEFSYMBOL (Qlist); | |
11626 DEFSYMBOL (Qbit_vector); | |
11627 defsymbol (&QsortX, "sort*"); | |
11628 DEFSYMBOL (Qreduce); | |
11629 DEFSYMBOL (Qreplace); | |
11630 DEFSYMBOL (Qposition); | |
11631 DEFSYMBOL (Qfind); | |
11632 defsymbol (&QdeleteX, "delete*"); | |
11633 defsymbol (&QremoveX, "remove*"); | |
11634 | |
11635 DEFSYMBOL (Qmapconcat); | |
11636 defsymbol (&QmapcarX, "mapcar*"); | |
11637 DEFSYMBOL (Qmapvector); | |
11638 DEFSYMBOL (Qmapcan); | |
11639 DEFSYMBOL (Qmapc); | |
11640 DEFSYMBOL (Qmap); | |
11641 DEFSYMBOL (Qmap_into); | |
11642 DEFSYMBOL (Qsome); | |
11643 DEFSYMBOL (Qevery); | |
11644 DEFSYMBOL (Qmaplist); | |
11645 DEFSYMBOL (Qmapl); | 3350 DEFSYMBOL (Qmapl); |
11646 DEFSYMBOL (Qmapcon); | 3351 DEFSYMBOL (Qmapcon); |
11647 DEFSYMBOL (Qnsubstitute); | 3352 DEFSYMBOL (Qmaplist); |
11648 DEFSYMBOL (Qdelete_duplicates); | |
11649 DEFSYMBOL (Qsubstitute); | |
11650 DEFSYMBOL (Qmismatch); | |
11651 DEFSYMBOL (Qintersection); | |
11652 DEFSYMBOL (Qnintersection); | |
11653 DEFSYMBOL (Qsubsetp); | |
11654 DEFSYMBOL (Qcar_less_than_car); | |
11655 DEFSYMBOL (Qset_difference); | |
11656 DEFSYMBOL (Qnset_difference); | |
11657 DEFSYMBOL (Qnunion); | |
11658 | |
11659 DEFKEYWORD (Q_from_end); | |
11660 DEFKEYWORD (Q_initial_value); | |
11661 DEFKEYWORD (Q_start1); | |
11662 DEFKEYWORD (Q_start2); | |
11663 DEFKEYWORD (Q_end1); | |
11664 DEFKEYWORD (Q_end2); | |
11665 defkeyword (&Q_if_, ":if"); | |
11666 DEFKEYWORD (Q_if_not); | |
11667 DEFKEYWORD (Q_test_not); | |
11668 DEFKEYWORD (Q_count); | |
11669 DEFKEYWORD (Q_stable); | |
11670 DEFKEYWORD (Q_descend_structures); | |
11671 | |
11672 DEFSYMBOL (Qyes_or_no_p); | |
11673 | 3353 |
11674 DEFERROR_STANDARD (Qbase64_conversion_error, Qconversion_error); | 3354 DEFERROR_STANDARD (Qbase64_conversion_error, Qconversion_error); |
11675 | 3355 |
11676 DEFSUBR (Fidentity); | 3356 DEFSUBR (Fidentity); |
11677 DEFSUBR (Frandom); | 3357 DEFSUBR (Frandom); |
11678 DEFSUBR (Flength); | |
11679 DEFSUBR (Fsafe_length); | 3358 DEFSUBR (Fsafe_length); |
11680 DEFSUBR (Flist_length); | 3359 DEFSUBR (Flist_length); |
11681 DEFSUBR (Fcount); | |
11682 DEFSUBR (Fstring_equal); | 3360 DEFSUBR (Fstring_equal); |
11683 DEFSUBR (Fcompare_strings); | 3361 DEFSUBR (Fcompare_strings); |
11684 DEFSUBR (Fstring_lessp); | 3362 DEFSUBR (Fstring_lessp); |
11685 DEFSUBR (Fstring_modified_tick); | 3363 DEFSUBR (Fstring_modified_tick); |
11686 DEFSUBR (Fappend); | 3364 DEFSUBR (Fappend); |
11688 DEFSUBR (Fvconcat); | 3366 DEFSUBR (Fvconcat); |
11689 DEFSUBR (Fbvconcat); | 3367 DEFSUBR (Fbvconcat); |
11690 DEFSUBR (Fcopy_list); | 3368 DEFSUBR (Fcopy_list); |
11691 DEFSUBR (Fcopy_sequence); | 3369 DEFSUBR (Fcopy_sequence); |
11692 DEFSUBR (Fcopy_alist); | 3370 DEFSUBR (Fcopy_alist); |
11693 DEFSUBR (Fcopy_tree); | |
11694 DEFSUBR (Fsubseq); | |
11695 DEFSUBR (Fnthcdr); | 3371 DEFSUBR (Fnthcdr); |
11696 DEFSUBR (Fnth); | 3372 DEFSUBR (Fnth); |
11697 DEFSUBR (Felt); | |
11698 DEFSUBR (Flast); | 3373 DEFSUBR (Flast); |
11699 DEFSUBR (Fbutlast); | 3374 DEFSUBR (Fbutlast); |
11700 DEFSUBR (Fnbutlast); | 3375 DEFSUBR (Fnbutlast); |
11701 DEFSUBR (Fmember); | |
11702 DEFSUBR (Fmemq); | |
11703 DEFSUBR (FmemberX); | |
11704 DEFSUBR (Fadjoin); | |
11705 DEFSUBR (Fassoc); | |
11706 DEFSUBR (Fassq); | |
11707 DEFSUBR (Frassoc); | |
11708 DEFSUBR (Frassq); | |
11709 | |
11710 DEFSUBR (Fposition); | |
11711 DEFSUBR (Ffind); | |
11712 | |
11713 DEFSUBR (FdeleteX); | |
11714 DEFSUBR (FremoveX); | |
11715 DEFSUBR (Fdelete_duplicates); | |
11716 DEFSUBR (Fremove_duplicates); | |
11717 DEFSUBR (Fnreverse); | |
11718 DEFSUBR (Freverse); | |
11719 DEFSUBR (FsortX); | |
11720 DEFSUBR (Fmerge); | |
11721 DEFSUBR (Fplists_eq); | 3376 DEFSUBR (Fplists_eq); |
11722 DEFSUBR (Fplists_equal); | 3377 DEFSUBR (Fplists_equal); |
11723 DEFSUBR (Flax_plists_eq); | 3378 DEFSUBR (Flax_plists_eq); |
11724 DEFSUBR (Flax_plists_equal); | 3379 DEFSUBR (Flax_plists_equal); |
11725 DEFSUBR (Fplist_get); | 3380 DEFSUBR (Fplist_get); |
11740 DEFSUBR (Fremprop); | 3395 DEFSUBR (Fremprop); |
11741 DEFSUBR (Fobject_plist); | 3396 DEFSUBR (Fobject_plist); |
11742 DEFSUBR (Fobject_setplist); | 3397 DEFSUBR (Fobject_setplist); |
11743 DEFSUBR (Fequal); | 3398 DEFSUBR (Fequal); |
11744 DEFSUBR (Fequalp); | 3399 DEFSUBR (Fequalp); |
11745 DEFSUBR (Ffill); | |
11746 | 3400 |
11747 #ifdef SUPPORT_CONFOUNDING_FUNCTIONS | 3401 #ifdef SUPPORT_CONFOUNDING_FUNCTIONS |
11748 DEFSUBR (Fold_member); | 3402 DEFSUBR (Fold_member); |
11749 DEFSUBR (Fold_memq); | 3403 DEFSUBR (Fold_memq); |
11750 DEFSUBR (Fold_assoc); | 3404 DEFSUBR (Fold_assoc); |
11751 DEFSUBR (Fold_assq); | 3405 DEFSUBR (Fold_assq); |
3406 DEFSUBR (Fold_rassq); | |
11752 DEFSUBR (Fold_rassoc); | 3407 DEFSUBR (Fold_rassoc); |
11753 DEFSUBR (Fold_rassq); | |
11754 DEFSUBR (Fold_delete); | 3408 DEFSUBR (Fold_delete); |
11755 DEFSUBR (Fold_delq); | 3409 DEFSUBR (Fold_delq); |
11756 DEFSUBR (Fold_equal); | 3410 DEFSUBR (Fold_equal); |
11757 DEFSUBR (Fold_eq); | 3411 DEFSUBR (Fold_eq); |
11758 #endif | 3412 #endif |
11759 | 3413 |
11760 DEFSUBR (FassocX); | |
11761 DEFSUBR (FrassocX); | |
11762 | |
11763 DEFSUBR (Fnconc); | 3414 DEFSUBR (Fnconc); |
11764 DEFSUBR (FmapcarX); | |
11765 DEFSUBR (Fmapvector); | |
11766 DEFSUBR (Fmapcan); | |
11767 DEFSUBR (Fmapc); | |
11768 DEFSUBR (Fmapconcat); | |
11769 DEFSUBR (Fmap); | |
11770 DEFSUBR (Fmap_into); | |
11771 DEFSUBR (Fsome); | |
11772 DEFSUBR (Fevery); | |
11773 Ffset (intern ("mapc-internal"), Qmapc); | |
11774 Ffset (intern ("mapcar"), QmapcarX); | |
11775 DEFSUBR (Fmaplist); | 3415 DEFSUBR (Fmaplist); |
11776 DEFSUBR (Fmapl); | 3416 DEFSUBR (Fmapl); |
11777 DEFSUBR (Fmapcon); | 3417 DEFSUBR (Fmapcon); |
11778 | 3418 |
11779 DEFSUBR (Freduce); | |
11780 DEFSUBR (Freplace_list); | 3419 DEFSUBR (Freplace_list); |
11781 DEFSUBR (Freplace); | |
11782 DEFSUBR (Fsubsetp); | |
11783 DEFSUBR (Fnsubstitute); | |
11784 DEFSUBR (Fsubstitute); | |
11785 DEFSUBR (Fsublis); | |
11786 DEFSUBR (Fnsublis); | |
11787 DEFSUBR (Fsubst); | |
11788 DEFSUBR (Fnsubst); | |
11789 DEFSUBR (Ftree_equal); | |
11790 DEFSUBR (Fmismatch); | |
11791 DEFSUBR (Fsearch); | |
11792 DEFSUBR (Funion); | |
11793 DEFSUBR (Fnunion); | |
11794 DEFSUBR (Fintersection); | |
11795 DEFSUBR (Fnintersection); | |
11796 DEFSUBR (Fset_difference); | |
11797 DEFSUBR (Fnset_difference); | |
11798 DEFSUBR (Fset_exclusive_or); | |
11799 DEFSUBR (Fnset_exclusive_or); | |
11800 | 3420 |
11801 DEFSUBR (Fload_average); | 3421 DEFSUBR (Fload_average); |
11802 DEFSUBR (Ffeaturep); | 3422 DEFSUBR (Ffeaturep); |
11803 DEFSUBR (Frequire); | 3423 DEFSUBR (Frequire); |
11804 DEFSUBR (Fprovide); | 3424 DEFSUBR (Fprovide); |