comparison src/fns.c @ 4997:8800b5350a13

Move #'some, #'every to C, implementing them with mapcarX. src/ChangeLog addition: 2010-02-03 Aidan Kehoe <kehoea@parhasard.net> * fns.c (mapcarX): Accept a new argument, indicating whether the function is being called from #'some or #'every. Implement it. Discard any multiple values where that is appropriate. (Fmapconcat, FmapcarX, Fmapvector, Fmapcan, Fmapc, Fmap) (Fmap_into): Pass the new flag to mapcarX. (Fsome, Fevery): Move these functions here from cl-extra.el; implement them in terms of mapcarX. (maplist): Discard multiple values where appropriate. lisp/ChangeLog addition: 2010-02-03 Aidan Kehoe <kehoea@parhasard.net> * cl-extra.el (some, every): Move these functions to C. * cl-macs.el (notany, notevery): Add compiler macros for these functions, no longer proclaim them inline (which would involve specbinding that's not necessary with the compiler macros).
author Aidan Kehoe <kehoea@parhasard.net>
date Wed, 03 Feb 2010 20:26:47 +0000
parents c17c857e20bf
children b46c89ccbed3
comparison
equal deleted inserted replaced
4996:c17c857e20bf 4997:8800b5350a13
3240 3240
3241 Otherwise, mapcarX signals a wrong-type-error if it encounters a 3241 Otherwise, mapcarX signals a wrong-type-error if it encounters a
3242 non-cons, non-array when traversing SEQUENCES. Common Lisp specifies in 3242 non-cons, non-array when traversing SEQUENCES. Common Lisp specifies in
3243 MAPPING-DESTRUCTIVE-INTERACTION that it is an error when FUNCTION 3243 MAPPING-DESTRUCTIVE-INTERACTION that it is an error when FUNCTION
3244 destructively modifies SEQUENCES in a way that might affect the ongoing 3244 destructively modifies SEQUENCES in a way that might affect the ongoing
3245 traversal operation. */ 3245 traversal operation.
3246
3247 If SOME_OR_EVERY is SOME_OR_EVERY_SOME, return the (possibly multiple)
3248 values given by FUNCTION the first time it is non-nil, and abandon the
3249 iterations. LISP_VALS in this case must be an object created by
3250 make_opaque_ptr, dereferenced as pointing to a Lisp object. If
3251 SOME_OR_EVERY is SOME_OR_EVERY_EVERY, store Qnil at the Lisp_Object
3252 pointer address provided by LISP_VALS if FUNCTION gives nil; otherwise
3253 leave it alone. */
3254
3255 #define SOME_OR_EVERY_NEITHER 0
3256 #define SOME_OR_EVERY_SOME 1
3257 #define SOME_OR_EVERY_EVERY 2
3246 3258
3247 static void 3259 static void
3248 mapcarX (Elemcount call_count, Lisp_Object *vals, Lisp_Object lisp_vals, 3260 mapcarX (Elemcount call_count, Lisp_Object *vals, Lisp_Object lisp_vals,
3249 Lisp_Object function, int nsequences, Lisp_Object *sequences) 3261 Lisp_Object function, int nsequences, Lisp_Object *sequences,
3262 int some_or_every)
3250 { 3263 {
3251 Lisp_Object called, *args; 3264 Lisp_Object called, *args;
3252 struct gcpro gcpro1, gcpro2; 3265 struct gcpro gcpro1, gcpro2;
3253 int i, j; 3266 int i, j;
3254 enum lrecord_type lisp_vals_type; 3267 enum lrecord_type lisp_vals_type;
3348 } 3361 }
3349 } 3362 }
3350 called = Ffuncall (nsequences + 1, args); 3363 called = Ffuncall (nsequences + 1, args);
3351 if (vals != NULL) 3364 if (vals != NULL)
3352 { 3365 {
3353 vals[i] = called; 3366 vals[i] = IGNORE_MULTIPLE_VALUES (called);
3354 gcpro2.nvars += 1; 3367 gcpro2.nvars += 1;
3355 } 3368 }
3356 else 3369 else
3357 { 3370 {
3358 switch (lisp_vals_type) 3371 switch (lisp_vals_type)
3359 { 3372 {
3360 case lrecord_type_symbol: 3373 case lrecord_type_symbol:
3361 break; 3374 break;
3362 case lrecord_type_cons: 3375 case lrecord_type_cons:
3363 { 3376 {
3364 if (!CONSP (lisp_vals)) 3377 if (SOME_OR_EVERY_NEITHER == some_or_every)
3365 { 3378 {
3366 /* If FUNCTION has inserted a non-cons non-nil cdr 3379 called = IGNORE_MULTIPLE_VALUES (called);
3367 into the list before we've processed the relevant 3380 if (!CONSP (lisp_vals))
3368 part, error. */ 3381 {
3369 dead_wrong_type_argument (Qconsp, lisp_vals); 3382 /* If FUNCTION has inserted a non-cons non-nil
3383 cdr into the list before we've processed the
3384 relevant part, error. */
3385 dead_wrong_type_argument (Qconsp, lisp_vals);
3386 }
3387
3388 XSETCAR (lisp_vals, called);
3389 lisp_vals = XCDR (lisp_vals);
3390 break;
3370 } 3391 }
3371 3392
3372 XSETCAR (lisp_vals, called); 3393 if (SOME_OR_EVERY_SOME == some_or_every)
3373 lisp_vals = XCDR (lisp_vals); 3394 {
3374 break; 3395 if (!NILP (IGNORE_MULTIPLE_VALUES (called)))
3396 {
3397 XCAR (lisp_vals) = called;
3398 UNGCPRO;
3399 return;
3400 }
3401 break;
3402 }
3403
3404 if (SOME_OR_EVERY_EVERY == some_or_every)
3405 {
3406 called = IGNORE_MULTIPLE_VALUES (called);
3407 if (NILP (called))
3408 {
3409 XCAR (lisp_vals) = Qnil;
3410 UNGCPRO;
3411 return;
3412 }
3413 break;
3414 }
3415
3416 goto bad_show_or_every_flag;
3375 } 3417 }
3376 case lrecord_type_vector: 3418 case lrecord_type_vector:
3377 { 3419 {
3420 called = IGNORE_MULTIPLE_VALUES (called);
3378 i < XVECTOR_LENGTH (lisp_vals) ? 3421 i < XVECTOR_LENGTH (lisp_vals) ?
3379 (XVECTOR_DATA (lisp_vals)[i] = called) : 3422 (XVECTOR_DATA (lisp_vals)[i] = called) :
3380 /* Let #'aset error. */ 3423 /* Let #'aset error. */
3381 Faset (lisp_vals, make_int (i), called); 3424 Faset (lisp_vals, make_int (i), called);
3382 break; 3425 break;
3384 case lrecord_type_string: 3427 case lrecord_type_string:
3385 { 3428 {
3386 /* If this ever becomes a code hotspot, we can keep 3429 /* If this ever becomes a code hotspot, we can keep
3387 around pointers into the data of the string, checking 3430 around pointers into the data of the string, checking
3388 each time that it hasn't been relocated. */ 3431 each time that it hasn't been relocated. */
3432 called = IGNORE_MULTIPLE_VALUES (called);
3389 Faset (lisp_vals, make_int (i), called); 3433 Faset (lisp_vals, make_int (i), called);
3390 break; 3434 break;
3391 } 3435 }
3392 case lrecord_type_bit_vector: 3436 case lrecord_type_bit_vector:
3393 { 3437 {
3438 called = IGNORE_MULTIPLE_VALUES (called);
3394 (BITP (called) && 3439 (BITP (called) &&
3395 i < bit_vector_length (XBIT_VECTOR (lisp_vals))) ? 3440 i < bit_vector_length (XBIT_VECTOR (lisp_vals))) ?
3396 set_bit_vector_bit (XBIT_VECTOR (lisp_vals), i, 3441 set_bit_vector_bit (XBIT_VECTOR (lisp_vals), i,
3397 XINT (called)) : 3442 XINT (called)) :
3398 Faset (lisp_vals, make_int (i), called); 3443 Faset (lisp_vals, make_int (i), called);
3399 break; 3444 break;
3400 } 3445 }
3446 bad_show_or_every_flag:
3401 default: 3447 default:
3402 { 3448 {
3403 ABORT(); 3449 ABORT();
3404 break; 3450 break;
3405 } 3451 }
3459 sequence = XCDR (sequence); 3505 sequence = XCDR (sequence);
3460 } 3506 }
3461 } 3507 }
3462 else 3508 else
3463 { 3509 {
3464 mapcarX (len, args0, Qnil, function, nargs - 2, args + 2); 3510 mapcarX (len, args0, Qnil, function, nargs - 2, args + 2,
3511 SOME_OR_EVERY_NEITHER);
3465 } 3512 }
3466 3513
3467 for (i = len - 1; i >= 0; i--) 3514 for (i = len - 1; i >= 0; i--)
3468 args0[i + i] = args0[i]; 3515 args0[i + i] = args0[i];
3469 3516
3497 CHECK_SEQUENCE (args[i]); 3544 CHECK_SEQUENCE (args[i]);
3498 len = min (len, XINT (Flength (args[i]))); 3545 len = min (len, XINT (Flength (args[i])));
3499 } 3546 }
3500 3547
3501 args0 = alloca_array (Lisp_Object, len); 3548 args0 = alloca_array (Lisp_Object, len);
3502 mapcarX (len, args0, Qnil, function, nargs - 1, args + 1); 3549 mapcarX (len, args0, Qnil, function, nargs - 1, args + 1,
3550 SOME_OR_EVERY_NEITHER);
3503 3551
3504 return Flist ((int) len, args0); 3552 return Flist ((int) len, args0);
3505 } 3553 }
3506 3554
3507 DEFUN ("mapvector", Fmapvector, 2, MANY, 0, /* 3555 DEFUN ("mapvector", Fmapvector, 2, MANY, 0, /*
3532 3580
3533 result = make_vector (len, Qnil); 3581 result = make_vector (len, Qnil);
3534 GCPRO1 (result); 3582 GCPRO1 (result);
3535 /* Don't pass result as the lisp_object argument, we want mapcarX to protect 3583 /* Don't pass result as the lisp_object argument, we want mapcarX to protect
3536 a single list argument's elements from being garbage-collected. */ 3584 a single list argument's elements from being garbage-collected. */
3537 mapcarX (len, XVECTOR_DATA (result), Qnil, function, nargs - 1, args +1); 3585 mapcarX (len, XVECTOR_DATA (result), Qnil, function, nargs - 1, args +1,
3586 SOME_OR_EVERY_NEITHER);
3538 UNGCPRO; 3587 UNGCPRO;
3539 3588
3540 return result; 3589 return result;
3541 } 3590 }
3542 3591
3566 CHECK_SEQUENCE (args[i]); 3615 CHECK_SEQUENCE (args[i]);
3567 len = min (len, XINT (Flength (args[i]))); 3616 len = min (len, XINT (Flength (args[i])));
3568 } 3617 }
3569 3618
3570 args0 = alloca_array (Lisp_Object, len + 1); 3619 args0 = alloca_array (Lisp_Object, len + 1);
3571 mapcarX (len, args0 + 1, Qnil, function, nargs - 1, args + 1); 3620 mapcarX (len, args0 + 1, Qnil, function, nargs - 1, args + 1,
3621 SOME_OR_EVERY_NEITHER);
3572 3622
3573 if (len < 2) 3623 if (len < 2)
3574 { 3624 {
3575 return len ? args0[1] : Qnil; 3625 return len ? args0[1] : Qnil;
3576 } 3626 }
3621 3671
3622 /* We need to GCPRO sequence, because mapcarX will modify the 3672 /* We need to GCPRO sequence, because mapcarX will modify the
3623 elements of the args array handed to it, and this may involve 3673 elements of the args array handed to it, and this may involve
3624 elements of sequence getting garbage collected. */ 3674 elements of sequence getting garbage collected. */
3625 GCPRO1 (sequence); 3675 GCPRO1 (sequence);
3626 mapcarX (len, NULL, Qnil, args[0], nargs - 1, args + 1); 3676 mapcarX (len, NULL, Qnil, args[0], nargs - 1, args + 1,
3677 SOME_OR_EVERY_NEITHER);
3627 RETURN_UNGCPRO (sequence); 3678 RETURN_UNGCPRO (sequence);
3628 } 3679 }
3629 3680
3630 DEFUN ("map", Fmap, 3, MANY, 0, /* 3681 DEFUN ("map", Fmap, 3, MANY, 0, /*
3631 Map FUNCTION across one or more sequences, returning a sequence. 3682 Map FUNCTION across one or more sequences, returning a sequence.
3661 if (!NILP (type)) 3712 if (!NILP (type))
3662 { 3713 {
3663 args0 = alloca_array (Lisp_Object, len); 3714 args0 = alloca_array (Lisp_Object, len);
3664 } 3715 }
3665 3716
3666 mapcarX (len, args0, Qnil, function, nargs - 2, args + 2); 3717 mapcarX (len, args0, Qnil, function, nargs - 2, args + 2,
3718 SOME_OR_EVERY_NEITHER);
3667 3719
3668 if (EQ (type, Qnil)) 3720 if (EQ (type, Qnil))
3669 { 3721 {
3670 return result; 3722 return result;
3671 } 3723 }
3725 { 3777 {
3726 CHECK_SEQUENCE (args[i]); 3778 CHECK_SEQUENCE (args[i]);
3727 len = min (len, XINT (Flength (args[i]))); 3779 len = min (len, XINT (Flength (args[i])));
3728 } 3780 }
3729 3781
3730 mapcarX (len, NULL, result_sequence, function, nargs - 2, args + 2); 3782 mapcarX (len, NULL, result_sequence, function, nargs - 2, args + 2,
3783 SOME_OR_EVERY_NEITHER);
3731 3784
3732 return result_sequence; 3785 return result_sequence;
3786 }
3787
3788 DEFUN ("some", Fsome, 2, MANY, 0, /*
3789 Return true if PREDICATE gives non-nil for an element of SEQUENCE.
3790
3791 If so, return the value (possibly multiple) given by PREDICATE.
3792
3793 With optional SEQUENCES, call PREDICATE each time with as many arguments as
3794 there are SEQUENCES (plus one for the element from SEQUENCE).
3795
3796 arguments: (PREDICATE SEQUENCE &rest SEQUENCES)
3797 */
3798 (int nargs, Lisp_Object *args))
3799 {
3800 Lisp_Object result_box = Fcons (Qnil, Qnil);
3801 struct gcpro gcpro1;
3802 Elemcount len = EMACS_INT_MAX;
3803 int i;
3804
3805 GCPRO1 (result_box);
3806
3807 for (i = 1; i < nargs; ++i)
3808 {
3809 CHECK_SEQUENCE (args[i]);
3810 len = min (len, XINT (Flength (args[i])));
3811 }
3812
3813 mapcarX (len, NULL, result_box, args[0], nargs - 1, args +1,
3814 SOME_OR_EVERY_SOME);
3815
3816 RETURN_UNGCPRO (XCAR (result_box));
3817 }
3818
3819 DEFUN ("every", Fevery, 2, MANY, 0, /*
3820 Return true if PREDICATE is true of every element of SEQUENCE.
3821
3822 With optional SEQUENCES, call PREDICATE each time with as many arguments as
3823 there are SEQUENCES (plus one for the element from SEQUENCE).
3824
3825 In contrast to `some', `every' never returns multiple values.
3826
3827 arguments: (PREDICATE SEQUENCE &rest SEQUENCES)
3828 */
3829 (int nargs, Lisp_Object *args))
3830 {
3831 Lisp_Object result_box = Fcons (Qt, Qnil);
3832 struct gcpro gcpro1;
3833 Elemcount len = EMACS_INT_MAX;
3834 int i;
3835
3836 GCPRO1 (result_box);
3837
3838 for (i = 1; i < nargs; ++i)
3839 {
3840 CHECK_SEQUENCE (args[i]);
3841 len = min (len, XINT (Flength (args[i])));
3842 }
3843
3844 mapcarX (len, NULL, result_box, args[0], nargs - 1, args +1,
3845 SOME_OR_EVERY_EVERY);
3846
3847 RETURN_UNGCPRO (XCAR (result_box));
3733 } 3848 }
3734 3849
3735 /* Call FUNCTION with NLISTS arguments repeatedly, each Nth argument 3850 /* Call FUNCTION with NLISTS arguments repeatedly, each Nth argument
3736 corresponding to the result of calling (nthcdr ITERATION-COUNT LISTS[N]), 3851 corresponding to the result of calling (nthcdr ITERATION-COUNT LISTS[N]),
3737 until that #'nthcdr expression gives nil for some element of LISTS. 3852 until that #'nthcdr expression gives nil for some element of LISTS.
3791 { 3906 {
3792 dead_wrong_type_argument (Qlistp, lists[j]); 3907 dead_wrong_type_argument (Qlistp, lists[j]);
3793 } 3908 }
3794 } 3909 }
3795 if (!continuing) break; 3910 if (!continuing) break;
3796 funcalled = Ffuncall (nlists + 1, args); 3911 funcalled = IGNORE_MULTIPLE_VALUES (Ffuncall (nlists + 1, args));
3797 if (!maplp) 3912 if (!maplp)
3798 { 3913 {
3799 if (nconcp) 3914 if (nconcp)
3800 { 3915 {
3801 /* This order of calls means we check that each list is 3916 /* This order of calls means we check that each list is
4637 DEFSUBR (Fmapcan); 4752 DEFSUBR (Fmapcan);
4638 DEFSUBR (Fmapc); 4753 DEFSUBR (Fmapc);
4639 DEFSUBR (Fmapconcat); 4754 DEFSUBR (Fmapconcat);
4640 DEFSUBR (Fmap); 4755 DEFSUBR (Fmap);
4641 DEFSUBR (Fmap_into); 4756 DEFSUBR (Fmap_into);
4757 DEFSUBR (Fsome);
4758 DEFSUBR (Fevery);
4642 Ffset (intern ("mapc-internal"), Fsymbol_function (intern ("mapc"))); 4759 Ffset (intern ("mapc-internal"), Fsymbol_function (intern ("mapc")));
4643 Ffset (intern ("mapcar"), Fsymbol_function (intern ("mapcar*"))); 4760 Ffset (intern ("mapcar"), Fsymbol_function (intern ("mapcar*")));
4644 DEFSUBR (Fmaplist); 4761 DEFSUBR (Fmaplist);
4645 DEFSUBR (Fmapl); 4762 DEFSUBR (Fmapl);
4646 DEFSUBR (Fmapcon); 4763 DEFSUBR (Fmapcon);