Mercurial > hg > xemacs-beta
diff lisp/cl-macs.el @ 5085:1ee30d3f9dd0
Handle the :from-end argument correctly, #'delete-duplicates compiler macro.
2010-03-02 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (delete-dups): New compiler macro for this function,
expanding to inline byte codes.
(delete-duplicates): Handle the :from-end argument correctly in
this compiler macro.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Tue, 02 Mar 2010 13:02:36 +0000 |
parents | 6afe991b8135 |
children | a24f2ab0093b |
line wrap: on
line diff
--- a/lisp/cl-macs.el Mon Mar 01 21:05:33 2010 +0000 +++ b/lisp/cl-macs.el Tue Mar 02 13:02:36 2010 +0000 @@ -3292,50 +3292,113 @@ (list 'let (list (list temp val)) (subst temp val res))))) form)) -;; XEmacs; inline delete-duplicates if it's called with a literal -;; #'equal or #'eq and no other keywords, we want the speed in -;; font-lock.el. +(define-compiler-macro delete-dups (list) + `(delete-duplicates (the list ,list) :test #'equal :from-end t)) + +;; XEmacs; inline delete-duplicates if it's called with one of the +;; common compile-time constant tests and an optional :from-end +;; argument, we want the speed in font-lock.el. (define-compiler-macro delete-duplicates (&whole form cl-seq &rest cl-keys) (let ((listp-check - (if (memq (car-safe cl-seq) - ;; No need to check for a list at runtime with these. We - ;; could expand the list, but these are all the functions - ;; in the relevant context at the moment. - '(nreverse append nconc mapcan mapcar)) - t - '(listp begin)))) - (cond ((and (= 4 (length form)) - (eq :test (third form)) - (or (equal '(quote eq) (fourth form)) - (equal '(function eq) (fourth form)))) + (cond + ((memq (car-safe cl-seq) + ;; No need to check for a list at runtime with these. We + ;; could expand the list, but these are all the functions + ;; in the relevant context at the moment. + '(nreverse append nconc mapcan mapcar string-to-list)) + t) + ((and (listp cl-seq) (eq (first cl-seq) 'the) + (eq (second cl-seq) 'list)) + ;; Allow users to force this, if they really want to. + t) + (t + '(listp begin))))) + (cond ((loop + for relevant-key-values + in '((:test 'eq) + (:test #'eq) + (:test 'eq :from-end nil) + (:test #'eq :from-end nil)) + ;; One of the above corresponds exactly to CL-KEYS: + thereis (not (set-difference cl-keys relevant-key-values + :test #'equal))) + `(let* ((begin ,cl-seq) + cl-seq) + (if ,listp-check + (progn + (while (memq (car begin) (cdr begin)) + (setq begin (cdr begin))) + (setq cl-seq begin) + (while (cddr cl-seq) + (if (memq (cadr cl-seq) (cddr cl-seq)) + (setcdr (cdr cl-seq) (cddr cl-seq)) + (setq cl-seq (cdr cl-seq)))) + begin) + ;; Call cl-delete-duplicates explicitly, to avoid the form + ;; getting compiler-macroexpanded again: + (cl-delete-duplicates begin ',cl-keys nil)))) + ((loop + for relevant-key-values + in '((:test 'eq :from-end t) + (:test #'eq :from-end t)) + ;; One of the above corresponds exactly to CL-KEYS: + thereis (not (set-difference cl-keys relevant-key-values + :test #'equal))) + `(let* ((begin ,cl-seq) + (cl-seq begin)) + (if ,listp-check + (progn + (while cl-seq + (setq cl-seq (setcdr cl-seq + (delq (car cl-seq) (cdr cl-seq))))) + begin) + ;; Call cl-delete-duplicates explicitly, to avoid the form + ;; getting compiler-macroexpanded again: + (cl-delete-duplicates begin ',cl-keys nil)))) + + ((loop + for relevant-key-values + in '((:test 'equal) + (:test #'equal) + (:test 'equal :from-end nil) + (:test #'equal :from-end nil)) + ;; One of the above corresponds exactly to CL-KEYS: + thereis (not (set-difference cl-keys relevant-key-values + :test #'equal))) + `(let* ((begin ,cl-seq) + cl-seq) + (if ,listp-check + (progn + (while (member (car begin) (cdr begin)) + (setq begin (cdr begin))) + (setq cl-seq begin) + (while (cddr cl-seq) + (if (member (cadr cl-seq) (cddr cl-seq)) + (setcdr (cdr cl-seq) (cddr cl-seq))) + (setq cl-seq (cdr cl-seq))) + begin) + ;; Call cl-delete-duplicates explicitly, to avoid the form + ;; getting compiler-macroexpanded again: + (cl-delete-duplicates begin ',cl-keys nil)))) + ((loop + for relevant-key-values + in '((:test 'equal :from-end t) + (:test #'equal :from-end t)) + ;; One of the above corresponds exactly to CL-KEYS: + thereis (not (set-difference cl-keys relevant-key-values + :test #'equal))) `(let* ((begin ,cl-seq) (cl-seq begin)) (if ,listp-check (progn (while cl-seq - (setq cl-seq (setcdr cl-seq (delq (car cl-seq) - (cdr cl-seq))))) - begin) + (setq cl-seq + (setcdr cl-seq (delete (car cl-seq) (cdr cl-seq))))) + begin) ;; Call cl-delete-duplicates explicitly, to avoid the form ;; getting compiler-macroexpanded again: (cl-delete-duplicates begin ',cl-keys nil)))) - ((and (= 4 (length form)) - (eq :test (third form)) - (or (equal '(quote equal) (fourth form)) - (equal '(function equal) (fourth form)))) - `(let* ((begin ,cl-seq) - (cl-seq begin)) - (if ,listp-check - (progn - (while cl-seq - (setq cl-seq (setcdr cl-seq (delete (car cl-seq) - (cdr cl-seq))))) - begin) - ;; Call cl-delete-duplicates explicitly, to avoid the form - ;; getting compiler-macroexpanded again: - (cl-delete-duplicates begin ',cl-keys nil)))) - (t - form)))) + (t form)))) ;; XEmacs; it's perfectly reasonable, and often much clearer to those ;; reading the code, to call regexp-quote on a constant string, which is