comparison src/fns.c @ 5273:799742b751c8

Accept circular lists where that is useful in #'mapcar*, #'map* and friends. src/ChangeLog addition: 2010-09-16 Aidan Kehoe <kehoea@parhasard.net> * fns.c (Flist_length): New, moved here from cl-extra.el, needed by the next function. (shortest_length_among_sequences): New. (Fmapconcat, FmapcarX, Fmapvector, Fmapcan, Fmapc, Fmap) (Fmap_into, Fsome, Fevery): Use shortest_length_among_sequences() when working out how many iterations to do, only giving circular list errors if all arguments are circular.
author Aidan Kehoe <kehoea@parhasard.net>
date Thu, 16 Sep 2010 20:34:49 +0100
parents 66dbef5f8076
children 5a9aa6c40c9b
comparison
equal deleted inserted replaced
5272:66dbef5f8076 5273:799742b751c8
335 if (len & 1) 335 if (len & 1)
336 tortoise = XCDR (tortoise); 336 tortoise = XCDR (tortoise);
337 } 337 }
338 338
339 return make_int (len); 339 return make_int (len);
340 }
341
342 /* This is almost the above, but is defined by Common Lisp. We need it in C
343 for shortest_length_among_sequences(), below, for the various sequence
344 functions that can usefully operate on circular lists. */
345
346 DEFUN ("list-length", Flist_length, 1, 1, 0, /*
347 Return the length of LIST. Return nil if LIST is circular.
348 */
349 (list))
350 {
351 Lisp_Object hare, tortoise;
352 Elemcount len;
353
354 for (hare = tortoise = list, len = 0;
355 CONSP (hare) && (! EQ (hare, tortoise) || len == 0);
356 hare = XCDR (hare), len++)
357 {
358 if (len & 1)
359 tortoise = XCDR (tortoise);
360 }
361
362 return EQ (hare, tortoise) && len != 0 ? Qnil : make_int (len);
340 } 363 }
341 364
342 /*** string functions. ***/ 365 /*** string functions. ***/
343 366
344 DEFUN ("string-equal", Fstring_equal, 2, 2, 0, /* 367 DEFUN ("string-equal", Fstring_equal, 2, 2, 0, /*
4456 } 4479 }
4457 4480
4458 UNGCPRO; 4481 UNGCPRO;
4459 } 4482 }
4460 4483
4484 /* Given NSEQUENCES objects at the address pointed to by SEQUENCES, return
4485 the length of the shortest sequence. Error if all are circular, or if any
4486 one of them is not a sequence. */
4487 static Elemcount
4488 shortest_length_among_sequences (int nsequences, Lisp_Object *sequences)
4489 {
4490 Elemcount len = EMACS_INT_MAX;
4491 Lisp_Object length;
4492 int i;
4493
4494 for (i = 0; i < nsequences; ++i)
4495 {
4496 if (CONSP (sequences[i]))
4497 {
4498 length = Flist_length (sequences[i]);
4499 if (!NILP (length))
4500 {
4501 len = min (len, XINT (length));
4502 }
4503 }
4504 else
4505 {
4506 CHECK_SEQUENCE (sequences[i]);
4507 length = Flength (sequences[i]);
4508 len = min (len, XINT (length));
4509 }
4510 }
4511
4512 if (NILP (length))
4513 {
4514 signal_circular_list_error (sequences[0]);
4515 }
4516
4517 return len;
4518 }
4519
4461 DEFUN ("mapconcat", Fmapconcat, 3, MANY, 0, /* 4520 DEFUN ("mapconcat", Fmapconcat, 3, MANY, 0, /*
4462 Call FUNCTION on each element of SEQUENCE, and concat results to a string. 4521 Call FUNCTION on each element of SEQUENCE, and concat results to a string.
4463 Between each pair of results, insert SEPARATOR. 4522 Between each pair of results, insert SEPARATOR.
4464 4523
4465 Each result, and SEPARATOR, should be strings. Thus, using " " as SEPARATOR 4524 Each result, and SEPARATOR, should be strings. Thus, using " " as SEPARATOR
4483 EMACS_INT i, nargs0; 4542 EMACS_INT i, nargs0;
4484 4543
4485 args[2] = sequence; 4544 args[2] = sequence;
4486 args[1] = separator; 4545 args[1] = separator;
4487 4546
4488 for (i = 2; i < nargs; ++i) 4547 len = shortest_length_among_sequences (nargs - 2, args + 2);
4489 {
4490 CHECK_SEQUENCE (args[i]);
4491 len = min (len, XINT (Flength (args[i])));
4492 }
4493 4548
4494 if (len == 0) return build_ascstring (""); 4549 if (len == 0) return build_ascstring ("");
4495 4550
4496 nargs0 = len + len - 1; 4551 nargs0 = len + len - 1;
4497 args0 = alloca_array (Lisp_Object, nargs0); 4552 args0 = alloca_array (Lisp_Object, nargs0);
4534 arguments: (FUNCTION SEQUENCE &rest SEQUENCES) 4589 arguments: (FUNCTION SEQUENCE &rest SEQUENCES)
4535 */ 4590 */
4536 (int nargs, Lisp_Object *args)) 4591 (int nargs, Lisp_Object *args))
4537 { 4592 {
4538 Lisp_Object function = args[0]; 4593 Lisp_Object function = args[0];
4539 Elemcount len = EMACS_INT_MAX; 4594 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4540 Lisp_Object *args0; 4595 Lisp_Object *args0;
4541 int i;
4542
4543 for (i = 1; i < nargs; ++i)
4544 {
4545 CHECK_SEQUENCE (args[i]);
4546 len = min (len, XINT (Flength (args[i])));
4547 }
4548 4596
4549 args0 = alloca_array (Lisp_Object, len); 4597 args0 = alloca_array (Lisp_Object, len);
4550 mapcarX (len, args0, Qnil, function, nargs - 1, args + 1, QmapcarX); 4598 mapcarX (len, args0, Qnil, function, nargs - 1, args + 1, QmapcarX);
4551 4599
4552 return Flist ((int) len, args0); 4600 return Flist ((int) len, args0);
4565 arguments: (FUNCTION SEQUENCE &rest SEQUENCES) 4613 arguments: (FUNCTION SEQUENCE &rest SEQUENCES)
4566 */ 4614 */
4567 (int nargs, Lisp_Object *args)) 4615 (int nargs, Lisp_Object *args))
4568 { 4616 {
4569 Lisp_Object function = args[0]; 4617 Lisp_Object function = args[0];
4570 Elemcount len = EMACS_INT_MAX; 4618 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4571 Lisp_Object result; 4619 Lisp_Object result = make_vector (len, Qnil);
4620
4572 struct gcpro gcpro1; 4621 struct gcpro gcpro1;
4573 int i;
4574
4575 for (i = 1; i < nargs; ++i)
4576 {
4577 CHECK_SEQUENCE (args[i]);
4578 len = min (len, XINT (Flength (args[i])));
4579 }
4580
4581 result = make_vector (len, Qnil);
4582 GCPRO1 (result); 4622 GCPRO1 (result);
4583 /* Don't pass result as the lisp_object argument, we want mapcarX to protect 4623 /* Don't pass result as the lisp_object argument, we want mapcarX to protect
4584 a single list argument's elements from being garbage-collected. */ 4624 a single list argument's elements from being garbage-collected. */
4585 mapcarX (len, XVECTOR_DATA (result), Qnil, function, nargs - 1, args +1, 4625 mapcarX (len, XVECTOR_DATA (result), Qnil, function, nargs - 1, args +1,
4586 Qmapvector); 4626 Qmapvector);
4600 4640
4601 arguments: (FUNCTION SEQUENCE &rest SEQUENCES) 4641 arguments: (FUNCTION SEQUENCE &rest SEQUENCES)
4602 */ 4642 */
4603 (int nargs, Lisp_Object *args)) 4643 (int nargs, Lisp_Object *args))
4604 { 4644 {
4605 Lisp_Object function = args[0], *result; 4645 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4606 Elemcount result_len = EMACS_INT_MAX; 4646 Lisp_Object function = args[0], *result = alloca_array (Lisp_Object, len);
4607 int i; 4647
4608 4648 mapcarX (len, result, Qnil, function, nargs - 1, args + 1, Qmapcan);
4609 for (i = 1; i < nargs; ++i)
4610 {
4611 CHECK_SEQUENCE (args[i]);
4612 result_len = min (result_len, XINT (Flength (args[i])));
4613 }
4614
4615 result = alloca_array (Lisp_Object, result_len);
4616 mapcarX (result_len, result, Qnil, function, nargs - 1, args + 1, Qmapcan);
4617 4649
4618 /* #'nconc GCPROs its args in case of signals and error. */ 4650 /* #'nconc GCPROs its args in case of signals and error. */
4619 return Fnconc (result_len, result); 4651 return Fnconc (len, result);
4620 } 4652 }
4621 4653
4622 DEFUN ("mapc", Fmapc, 2, MANY, 0, /* 4654 DEFUN ("mapc", Fmapc, 2, MANY, 0, /*
4623 Call FUNCTION on each element of SEQUENCE. 4655 Call FUNCTION on each element of SEQUENCE.
4624 4656
4635 4667
4636 arguments: (FUNCTION SEQUENCE &rest SEQUENCES) 4668 arguments: (FUNCTION SEQUENCE &rest SEQUENCES)
4637 */ 4669 */
4638 (int nargs, Lisp_Object *args)) 4670 (int nargs, Lisp_Object *args))
4639 { 4671 {
4640 Elemcount len = EMACS_INT_MAX; 4672 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4641 Lisp_Object sequence = args[1]; 4673 Lisp_Object sequence = args[1];
4642 struct gcpro gcpro1; 4674 struct gcpro gcpro1;
4643 int i;
4644
4645 for (i = 1; i < nargs; ++i)
4646 {
4647 CHECK_SEQUENCE (args[i]);
4648 len = min (len, XINT (Flength (args[i])));
4649 }
4650
4651 /* We need to GCPRO sequence, because mapcarX will modify the 4675 /* We need to GCPRO sequence, because mapcarX will modify the
4652 elements of the args array handed to it, and this may involve 4676 elements of the args array handed to it, and this may involve
4653 elements of sequence getting garbage collected. */ 4677 elements of sequence getting garbage collected. */
4654 GCPRO1 (sequence); 4678 GCPRO1 (sequence);
4655 mapcarX (len, NULL, Qnil, args[0], nargs - 1, args + 1, Qmapc); 4679 mapcarX (len, NULL, Qnil, args[0], nargs - 1, args + 1, Qmapc);
4675 { 4699 {
4676 Lisp_Object type = args[0]; 4700 Lisp_Object type = args[0];
4677 Lisp_Object function = args[1]; 4701 Lisp_Object function = args[1];
4678 Lisp_Object result = Qnil; 4702 Lisp_Object result = Qnil;
4679 Lisp_Object *args0 = NULL; 4703 Lisp_Object *args0 = NULL;
4680 Elemcount len = EMACS_INT_MAX; 4704 Elemcount len = shortest_length_among_sequences (nargs - 2, args + 2);
4681 int i;
4682 struct gcpro gcpro1; 4705 struct gcpro gcpro1;
4683
4684 for (i = 2; i < nargs; ++i)
4685 {
4686 CHECK_SEQUENCE (args[i]);
4687 len = min (len, XINT (Flength (args[i])));
4688 }
4689 4706
4690 if (!NILP (type)) 4707 if (!NILP (type))
4691 { 4708 {
4692 args0 = alloca_array (Lisp_Object, len); 4709 args0 = alloca_array (Lisp_Object, len);
4693 } 4710 }
4740 4757
4741 arguments: (RESULT-SEQUENCE FUNCTION &rest SEQUENCES) 4758 arguments: (RESULT-SEQUENCE FUNCTION &rest SEQUENCES)
4742 */ 4759 */
4743 (int nargs, Lisp_Object *args)) 4760 (int nargs, Lisp_Object *args))
4744 { 4761 {
4745 Elemcount len = EMACS_INT_MAX; 4762 Elemcount len;
4746 Lisp_Object result_sequence = args[0]; 4763 Lisp_Object result_sequence = args[0];
4747 Lisp_Object function = args[1]; 4764 Lisp_Object function = args[1];
4748 int i;
4749 4765
4750 args[0] = function; 4766 args[0] = function;
4751 args[1] = result_sequence; 4767 args[1] = result_sequence;
4752 4768
4753 for (i = 1; i < nargs; ++i) 4769 len = shortest_length_among_sequences (nargs - 1, args + 1);
4754 {
4755 CHECK_SEQUENCE (args[i]);
4756 len = min (len, XINT (Flength (args[i])));
4757 }
4758 4770
4759 mapcarX (len, NULL, result_sequence, function, nargs - 2, args + 2, 4771 mapcarX (len, NULL, result_sequence, function, nargs - 2, args + 2,
4760 Qmap_into); 4772 Qmap_into);
4761 4773
4762 return result_sequence; 4774 return result_sequence;
4774 */ 4786 */
4775 (int nargs, Lisp_Object *args)) 4787 (int nargs, Lisp_Object *args))
4776 { 4788 {
4777 Lisp_Object result = Qnil, 4789 Lisp_Object result = Qnil,
4778 result_ptr = STORE_VOID_IN_LISP ((void *) &result); 4790 result_ptr = STORE_VOID_IN_LISP ((void *) &result);
4779 Elemcount len = EMACS_INT_MAX; 4791 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4780 int i;
4781
4782 for (i = 1; i < nargs; ++i)
4783 {
4784 CHECK_SEQUENCE (args[i]);
4785 len = min (len, XINT (Flength (args[i])));
4786 }
4787 4792
4788 mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qsome); 4793 mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qsome);
4789 4794
4790 return result; 4795 return result;
4791 } 4796 }
4801 arguments: (PREDICATE SEQUENCE &rest SEQUENCES) 4806 arguments: (PREDICATE SEQUENCE &rest SEQUENCES)
4802 */ 4807 */
4803 (int nargs, Lisp_Object *args)) 4808 (int nargs, Lisp_Object *args))
4804 { 4809 {
4805 Lisp_Object result = Qt, result_ptr = STORE_VOID_IN_LISP ((void *) &result); 4810 Lisp_Object result = Qt, result_ptr = STORE_VOID_IN_LISP ((void *) &result);
4806 Elemcount len = EMACS_INT_MAX; 4811 Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1);
4807 int i;
4808
4809 for (i = 1; i < nargs; ++i)
4810 {
4811 CHECK_SEQUENCE (args[i]);
4812 len = min (len, XINT (Flength (args[i])));
4813 }
4814 4812
4815 mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qevery); 4813 mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qevery);
4816 4814
4817 return result; 4815 return result;
4818 } 4816 }
6681 6679
6682 DEFSUBR (Fidentity); 6680 DEFSUBR (Fidentity);
6683 DEFSUBR (Frandom); 6681 DEFSUBR (Frandom);
6684 DEFSUBR (Flength); 6682 DEFSUBR (Flength);
6685 DEFSUBR (Fsafe_length); 6683 DEFSUBR (Fsafe_length);
6684 DEFSUBR (Flist_length);
6686 DEFSUBR (Fstring_equal); 6685 DEFSUBR (Fstring_equal);
6687 DEFSUBR (Fcompare_strings); 6686 DEFSUBR (Fcompare_strings);
6688 DEFSUBR (Fstring_lessp); 6687 DEFSUBR (Fstring_lessp);
6689 DEFSUBR (Fstring_modified_tick); 6688 DEFSUBR (Fstring_modified_tick);
6690 DEFSUBR (Fappend); 6689 DEFSUBR (Fappend);