comparison lisp/cl-macs.el @ 4906:6ef8256a020a

implement equalp in C, fix case-folding, add equal() method for keymaps -------------------- ChangeLog entries follow: -------------------- lisp/ChangeLog addition: 2010-02-01 Ben Wing <ben@xemacs.org> * cl-extra.el: * cl-extra.el (cl-string-vector-equalp): Removed. * cl-extra.el (cl-bit-vector-vector-equalp): Removed. * cl-extra.el (cl-vector-array-equalp): Removed. * cl-extra.el (cl-hash-table-contents-equalp): Removed. * cl-extra.el (equalp): Removed. * cl-extra.el (cl-mapcar-many): Comment out the whole `equalp' implementation for the moment; remove once we're sure the C implementation works. * cl-macs.el: * cl-macs.el (equalp): Simplify the compiler-macro for `equalp' -- once it's in C, we don't need to try so hard to expand it. src/ChangeLog addition: 2010-02-01 Ben Wing <ben@xemacs.org> * abbrev.c (abbrev_match_mapper): * buffer.h (CANON_TABLE_OF): * buffer.h: * editfns.c (Fchar_equal): * minibuf.c (scmp_1): * text.c (qxestrcasecmp_i18n): * text.c (qxestrncasecmp_i18n): * text.c (qxetextcasecmp): * text.c (qxetextcasecmp_matching): Create new macro CANONCASE that converts to a canonical mapping and use it to do caseless comparisons instead of DOWNCASE. * alloc.c: * alloc.c (cons_equal): * alloc.c (vector_equal): * alloc.c (string_equal): * bytecode.c (compiled_function_equal): * chartab.c (char_table_entry_equal): * chartab.c (char_table_equal): * data.c (weak_list_equal): * data.c (weak_box_equal): * data.c (ephemeron_equal): * device-msw.c (equal_devmode): * elhash.c (hash_table_equal): * events.c (event_equal): * extents.c (properties_equal): * extents.c (extent_equal): * faces.c: * faces.c (face_equal): * faces.c (face_hash): * floatfns.c (float_equal): * fns.c: * fns.c (bit_vector_equal): * fns.c (plists_differ): * fns.c (Fplists_eq): * fns.c (Fplists_equal): * fns.c (Flax_plists_eq): * fns.c (Flax_plists_equal): * fns.c (internal_equal): * fns.c (internal_equalp): * fns.c (internal_equal_0): * fns.c (syms_of_fns): * glyphs.c (image_instance_equal): * glyphs.c (glyph_equal): * glyphs.c (glyph_hash): * gui.c (gui_item_equal): * lisp.h: * lrecord.h (struct lrecord_implementation): * marker.c (marker_equal): * number.c (bignum_equal): * number.c (ratio_equal): * number.c (bigfloat_equal): * objects.c (color_instance_equal): * objects.c (font_instance_equal): * opaque.c (equal_opaque): * opaque.c (equal_opaque_ptr): * rangetab.c (range_table_equal): * specifier.c (specifier_equal): Add a `foldcase' param to the equal() method and use it to implement `equalp' comparisons. Also add to plists_differ(), although we don't currently use it here. Rewrite internal_equalp(). Implement cross-type vector comparisons. Don't implement our own handling of numeric promotion -- just use the `=' primitive. Add internal_equal_0(), which takes a `foldcase' param and calls either internal_equal() or internal_equalp(). * buffer.h: When given a 0 for buffer (which is the norm when functions don't have a specific buffer available), use the current buffer's table, not `standard-case-table'; otherwise the current settings are ignored. * casetab.c: * casetab.c (set_case_table): When handling old-style vectors of 256 in `set-case-table' don't overwrite the existing table! Instead create a new table and populate. * device-msw.c (sync_printer_with_devmode): * lisp.h: * text.c (lisp_strcasecmp_ascii): Rename lisp_strcasecmp to lisp_strcasecmp_ascii and use lisp_strcasecmp_i18n for caseless comparisons in some places. * elhash.c: Delete unused lisp_string_hash and lisp_string_equal(). * events.h: * keymap-buttons.h: * keymap.h: * keymap.c (keymap_lookup_directly): * keymap.c (keymap_store): * keymap.c (FROB): * keymap.c (key_desc_list_to_event): * keymap.c (describe_map_mapper): * keymap.c (INCLUDE_BUTTON_ZERO): New file keymap-buttons.h; use to handle buttons 1-26 in place of duplicating code 26 times. * frame-gtk.c (allocate_gtk_frame_struct): * frame-msw.c (mswindows_init_frame_1): Fix some comments about internal_equal() in redisplay that don't apply any more. * keymap-slots.h: * keymap.c: New file keymap-slots.h. Use it to notate the slots in a keymap structure, similar to frameslots.h or coding-system-slots.h. * keymap.c (MARKED_SLOT): * keymap.c (keymap_equal): * keymap.c (keymap_hash): Implement. tests/ChangeLog addition: 2010-02-01 Ben Wing <ben@xemacs.org> * automated/case-tests.el: * automated/case-tests.el (uni-mappings): * automated/search-tests.el: Delete old pristine-case-table code. Rewrite the Unicode torture test to take into account whether overlapping mappings exist for more than one character, and not doing the upcase/downcase comparisons in such cases. * automated/lisp-tests.el (foo): * automated/lisp-tests.el (string-variable): * automated/lisp-tests.el (featurep): Replace Assert (equal ... with Assert-equal; same for other types of equality. Replace some awkward equivalents of Assert-equalp with Assert-equalp. Add lots of equalp tests. * automated/case-tests.el: * automated/regexp-tests.el: * automated/search-tests.el: Fix up the comments at the top of the files. Move rules about where to put tests into case-tests.el. * automated/test-harness.el: * automated/test-harness.el (test-harness-aborted-summary-template): New. * automated/test-harness.el (test-harness-from-buffer): * automated/test-harness.el (batch-test-emacs): Fix Assert-test-not. Create Assert-not-equal and variants. Delete the doc strings from all these convenience functions to avoid excessive repetition; instead use one copy in a comment.
author Ben Wing <ben@xemacs.org>
date Mon, 01 Feb 2010 01:02:40 -0600
parents 6772ce4d982b
children 6bc1f3f6cf0d
comparison
equal deleted inserted replaced
4903:70089046adef 4906:6ef8256a020a
1 ;;; cl-macs.el --- Common Lisp extensions for XEmacs Lisp (part four) 1 ;;; cl-macs.el --- Common Lisp extensions for XEmacs Lisp (part four)
2 2
3 ;; Copyright (C) 1993, 2003, 2004 Free Software Foundation, Inc. 3 ;; Copyright (C) 1993, 2003, 2004 Free Software Foundation, Inc.
4 ;; Copyright (C) 2002 Ben Wing. 4 ;; Copyright (C) 2002, 2010 Ben Wing.
5 5
6 ;; Author: Dave Gillespie <daveg@synaptics.com> 6 ;; Author: Dave Gillespie <daveg@synaptics.com>
7 ;; Version: 2.02 7 ;; Version: 2.02
8 ;; Keywords: extensions 8 ;; Keywords: extensions
9 9
3355 (define-compiler-macro regexp-quote (&whole form string) 3355 (define-compiler-macro regexp-quote (&whole form string)
3356 (if (stringp string) 3356 (if (stringp string)
3357 (regexp-quote string) 3357 (regexp-quote string)
3358 form)) 3358 form))
3359 3359
3360 ;; NOTE: `equalp' is now a primitive, although as of yet it still doesn't
3361 ;; have a byte-compiler opcode for it. The compiler-macro for `equalp' used
3362 ;; to try and remove as much as possible of the logic of the Lisp `equalp' as
3363 ;; possible whenever one of the arguments is a constant, boiling things down
3364 ;; to a few if-statements and some calls to various no-longer-defined
3365 ;; helper functions. Besides the fact that the helper functions aren't
3366 ;; defined, there's little point in doing any of that expansion, since it will
3367 ;; end up executing in Lisp what would otherwise be done in C by a direct
3368 ;; call to `equalp'. The only exception is when the reduction is quite
3369 ;; simple and is to functions that do have op-codes; that may gain something.
3370 ;; However, if `equalp' becomes an opcode itself, consider removing everything
3371 ;; here except maybe when the call can directly be reduced to `equal' or `eq'.
3372 ;;
3373 ;; --ben
3374
3360 (define-compiler-macro equalp (&whole form x y) 3375 (define-compiler-macro equalp (&whole form x y)
3361 "Expand calls to `equalp' where X or Y is a constant expression. 3376 "Expand calls to `equalp' where X or Y is a constant expression.
3362 3377
3363 Much of the processing that `equalp' does is dependent on the types of both 3378 Much of the processing that `equalp' does is dependent on the types of both
3364 of its arguments, and with type information for one of them, we can 3379 of its arguments, and with type information for one of them, we can
3370 ;; Cases where both arguments are constant are handled in 3385 ;; Cases where both arguments are constant are handled in
3371 ;; byte-optimize.el, we only need to handle those cases where one is 3386 ;; byte-optimize.el, we only need to handle those cases where one is
3372 ;; constant here. 3387 ;; constant here.
3373 (let* ((equalp-sym (eval-when-compile (gensym))) 3388 (let* ((equalp-sym (eval-when-compile (gensym)))
3374 (let-form '(progn)) 3389 (let-form '(progn))
3375 (check-bit-vector t)
3376 (check-string t)
3377 (original-y y) 3390 (original-y y)
3378 equalp-temp checked) 3391 equalp-temp checked)
3379 (macrolet 3392 (macrolet
3380 ((unordered-check (check) 3393 ((unordered-check (check)
3381 `(prog1 3394 `(prog1
3396 ;; zero-length. 3409 ;; zero-length.
3397 (cond 3410 (cond
3398 ((member x '("" #* [])) 3411 ((member x '("" #* []))
3399 ;; No need to protect against multiple evaluation here: 3412 ;; No need to protect against multiple evaluation here:
3400 `(and (member ,original-y '("" #* [])) t)) 3413 `(and (member ,original-y '("" #* [])) t))
3401 ((stringp x) 3414 (t form)))
3402 `(,@let-form
3403 (if (stringp ,y)
3404 (eq t (compare-strings ,x nil nil
3405 ,y nil nil t))
3406 (if (vectorp ,y)
3407 (cl-string-vector-equalp ,x ,y)))))
3408 ((bit-vector-p x)
3409 `(,@let-form
3410 (if (bit-vector-p ,y)
3411 ;; No need to call equalp on each element here:
3412 (equal ,x ,y)
3413 (if (vectorp ,y)
3414 (cl-bit-vector-vector-equalp ,x ,y)))))
3415 (t
3416 (loop
3417 for elt across x
3418 ;; We may not need to check the other argument if it's a
3419 ;; string or bit vector, depending on the contents of x:
3420 always (progn
3421 (unless (characterp elt) (setq check-string nil))
3422 (unless (and (numberp elt) (or (= elt 0) (= elt 1)))
3423 (setq check-bit-vector nil))
3424 (or check-string check-bit-vector)))
3425 `(,@let-form
3426 (cond
3427 ,@(if check-string
3428 `(((stringp ,y)
3429 (cl-string-vector-equalp ,y ,x))))
3430 ,@(if check-bit-vector
3431 `(((bit-vector-p ,y)
3432 (cl-bit-vector-vector-equalp ,y ,x))))
3433 ((vectorp ,y)
3434 (cl-vector-array-equalp ,x ,y)))))))
3435 ((unordered-check (and (characterp x) (not (cl-const-expr-p y)))) 3415 ((unordered-check (and (characterp x) (not (cl-const-expr-p y))))
3436 `(,@let-form 3416 `(,@let-form
3437 (or (eq ,x ,y) 3417 (or (eq ,x ,y)
3438 ;; eq has a bytecode, char-equal doesn't. 3418 ;; eq has a bytecode, char-equal doesn't.
3439 (and (characterp ,y) 3419 (and (characterp ,y)
3440 (eq (downcase ,x) (downcase ,y)))))) 3420 (eq (downcase ,x) (downcase ,y))))))
3441 ((unordered-check (and (numberp x) (not (cl-const-expr-p y)))) 3421 ((unordered-check (and (numberp x) (not (cl-const-expr-p y))))
3442 `(,@let-form 3422 `(,@let-form
3443 (and (numberp ,y) 3423 (and (numberp ,y)
3444 (= ,x ,y)))) 3424 (= ,x ,y))))
3445 ((unordered-check (and (hash-table-p x) (not (cl-const-expr-p y)))) 3425 ((unordered-check (and (hash-table-p x) (not (cl-const-expr-p y))))
3446 ;; Hash tables; follow the CL spec. 3426 form)
3447 `(,@let-form
3448 (and (hash-table-p ,y)
3449 (eq ',(hash-table-test x) (hash-table-test ,y))
3450 (= ,(hash-table-count x) (hash-table-count ,y))
3451 (cl-hash-table-contents-equalp ,x ,y))))
3452 ((unordered-check 3427 ((unordered-check
3453 ;; Symbols; eq. 3428 ;; Symbols; eq.
3454 (and (not (cl-const-expr-p y)) 3429 (and (not (cl-const-expr-p y))
3455 (or (memq x '(nil t)) 3430 (or (memq x '(nil t))
3456 (and (eq (car-safe x) 'quote) (symbolp (second x)))))) 3431 (and (eq (car-safe x) 'quote) (symbolp (second x))))))
3457 (cons 'eq (cdr form))) 3432 (cons 'eq (cdr form)))
3458 ((unordered-check 3433
3459 ;; Compare conses at runtime, there's no real upside to 3434 ;; This clause is wrong -- e.g. when comparing a constant char-table
3460 ;; unrolling the function -> they fall through to the next 3435 ;; against a non-constant expression that evaluates to a char-table,
3461 ;; clause in this function. 3436 ;; or some for range tables or certain other types, `equalp' is
3462 (and (cl-const-expr-p x) (not (consp x)) 3437 ;; not the same as `equal'. We could insert the known list of
3463 (not (cl-const-expr-p y)))) 3438 ;; types with special `equalp' property, but it's fragile and may
3464 ;; All other types; use equal. 3439 ;; not be much of an optimization, esp. since these types don't
3465 (cons 'equal (cdr form))) 3440 ;; occur that often are often big.
3441 ;;((unordered-check
3442 ;; ;; Compare conses at runtime, there's no real upside to
3443 ;; ;; unrolling the function -> they fall through to the next
3444 ;; ;; clause in this function.
3445 ;; (and (cl-const-expr-p x) (not (consp x))
3446 ;; (not (cl-const-expr-p y))))
3447 ;; ;; All other types; use equal.
3448 ;; (cons 'equal (cdr form)))
3449
3466 ;; Neither side is a constant expression, do all our evaluation at 3450 ;; Neither side is a constant expression, do all our evaluation at
3467 ;; runtime (or both are, and equalp will be called from 3451 ;; runtime (or both are, and equalp will be called from
3468 ;; byte-optimize.el). 3452 ;; byte-optimize.el).
3469 (t form))))) 3453 (t form)))))
3454
3455 ;;(define-compiler-macro equalp (&whole form x y)
3456 ;; "Expand calls to `equalp' where X or Y is a constant expression.
3457 ;;
3458 ;;Much of the processing that `equalp' does is dependent on the types of both
3459 ;;of its arguments, and with type information for one of them, we can
3460 ;;eliminate much of the body of the function at compile time.
3461 ;;
3462 ;;Where both X and Y are constant expressions, `equalp' is evaluated at
3463 ;;compile time by byte-optimize.el--this compiler macro passes FORM through to
3464 ;;the byte optimizer in those cases."
3465 ;; ;; Cases where both arguments are constant are handled in
3466 ;; ;; byte-optimize.el, we only need to handle those cases where one is
3467 ;; ;; constant here.
3468 ;; (let* ((equalp-sym (eval-when-compile (gensym)))
3469 ;; (let-form '(progn))
3470 ;; (check-bit-vector t)
3471 ;; (check-string t)
3472 ;; (original-y y)
3473 ;; equalp-temp checked)
3474 ;; (macrolet
3475 ;; ((unordered-check (check)
3476 ;; `(prog1
3477 ;; (setq checked
3478 ;; (or ,check
3479 ;; (prog1 ,(sublis '((x . y) (y . x)) check :test #'eq)
3480 ;; (setq equalp-temp x x y y equalp-temp))))
3481 ;; (when checked
3482 ;; (unless (symbolp y)
3483 ;; (setq let-form `(let ((,equalp-sym ,y))) y equalp-sym))))))
3484 ;; ;; In the bodies of the below clauses, x is always a constant expression
3485 ;; ;; of the type we're interested in, and y is always a symbol that refers
3486 ;; ;; to the result non-constant side of the comparison.
3487 ;; (cond ((unordered-check (and (arrayp x) (not (cl-const-expr-p y))))
3488 ;; ;; Strings and other arrays. A vector containing the same
3489 ;; ;; character elements as a given string is equalp to that string;
3490 ;; ;; a bit-vector can only be equalp to a string if both are
3491 ;; ;; zero-length.
3492 ;; (cond
3493 ;; ((member x '("" #* []))
3494 ;; ;; No need to protect against multiple evaluation here:
3495 ;; `(and (member ,original-y '("" #* [])) t))
3496 ;; ((stringp x)
3497 ;; `(,@let-form
3498 ;; (if (stringp ,y)
3499 ;; (eq t (compare-strings ,x nil nil
3500 ;; ,y nil nil t))
3501 ;; (if (vectorp ,y)
3502 ;; (cl-string-vector-equalp ,x ,y)))))
3503 ;; ((bit-vector-p x)
3504 ;; `(,@let-form
3505 ;; (if (bit-vector-p ,y)
3506 ;; ;; No need to call equalp on each element here:
3507 ;; (equal ,x ,y)
3508 ;; (if (vectorp ,y)
3509 ;; (cl-bit-vector-vector-equalp ,x ,y)))))
3510 ;; (t
3511 ;; (loop
3512 ;; for elt across x
3513 ;; ;; We may not need to check the other argument if it's a
3514 ;; ;; string or bit vector, depending on the contents of x:
3515 ;; always (progn
3516 ;; (unless (characterp elt) (setq check-string nil))
3517 ;; (unless (and (numberp elt) (or (= elt 0) (= elt 1)))
3518 ;; (setq check-bit-vector nil))
3519 ;; (or check-string check-bit-vector)))
3520 ;; `(,@let-form
3521 ;; (cond
3522 ;; ,@(if check-string
3523 ;; `(((stringp ,y)
3524 ;; (cl-string-vector-equalp ,y ,x))))
3525 ;; ,@(if check-bit-vector
3526 ;; `(((bit-vector-p ,y)
3527 ;; (cl-bit-vector-vector-equalp ,y ,x))))
3528 ;; ((vectorp ,y)
3529 ;; (cl-vector-array-equalp ,x ,y)))))))
3530 ;; ((unordered-check (and (characterp x) (not (cl-const-expr-p y))))
3531 ;; `(,@let-form
3532 ;; (or (eq ,x ,y)
3533 ;; ;; eq has a bytecode, char-equal doesn't.
3534 ;; (and (characterp ,y)
3535 ;; (eq (downcase ,x) (downcase ,y))))))
3536 ;; ((unordered-check (and (numberp x) (not (cl-const-expr-p y))))
3537 ;; `(,@let-form
3538 ;; (and (numberp ,y)
3539 ;; (= ,x ,y))))
3540 ;; ((unordered-check (and (hash-table-p x) (not (cl-const-expr-p y))))
3541 ;; ;; Hash tables; follow the CL spec.
3542 ;; `(,@let-form
3543 ;; (and (hash-table-p ,y)
3544 ;; (eq ',(hash-table-test x) (hash-table-test ,y))
3545 ;; (= ,(hash-table-count x) (hash-table-count ,y))
3546 ;; (cl-hash-table-contents-equalp ,x ,y))))
3547 ;; ((unordered-check
3548 ;; ;; Symbols; eq.
3549 ;; (and (not (cl-const-expr-p y))
3550 ;; (or (memq x '(nil t))
3551 ;; (and (eq (car-safe x) 'quote) (symbolp (second x))))))
3552 ;; (cons 'eq (cdr form)))
3553 ;; ((unordered-check
3554 ;; ;; Compare conses at runtime, there's no real upside to
3555 ;; ;; unrolling the function -> they fall through to the next
3556 ;; ;; clause in this function.
3557 ;; (and (cl-const-expr-p x) (not (consp x))
3558 ;; (not (cl-const-expr-p y))))
3559 ;; ;; All other types; use equal.
3560 ;; (cons 'equal (cdr form)))
3561 ;; ;; Neither side is a constant expression, do all our evaluation at
3562 ;; ;; runtime (or both are, and equalp will be called from
3563 ;; ;; byte-optimize.el).
3564 ;; (t form)))))
3470 3565
3471 (define-compiler-macro map (&whole form cl-type cl-func cl-seq 3566 (define-compiler-macro map (&whole form cl-type cl-func cl-seq
3472 &rest cl-rest) 3567 &rest cl-rest)
3473 "If CL-TYPE is a constant expression that we know how to handle, transform 3568 "If CL-TYPE is a constant expression that we know how to handle, transform
3474 the call to `map' to a more efficient expression." 3569 the call to `map' to a more efficient expression."