Mercurial > hg > xemacs-beta
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); |