Raymond Toy pushed to branch master at cmucl / cmucl

Commits:

3 changed files:

Changes:

  • src/code/list.lisp
    ... ... @@ -928,7 +928,7 @@
    928 928
     
    
    929 929
     (defun set-exclusive-or (list1 list2 &key key
    
    930 930
                              (test #'eql testp) (test-not nil notp))
    
    931
    -  "Return new list of elements appearing exactly once in LIST1 and LIST2."
    
    931
    +  "Return new list of elements appearing exactly one of LIST1 and LIST2."
    
    932 932
       (declare (inline member))
    
    933 933
       (let ((result nil)
    
    934 934
             (key (when key (coerce key 'function)))
    
    ... ... @@ -936,19 +936,38 @@
    936 936
             (test-not (if test-not (coerce test-not 'function) #'eql)))
    
    937 937
         (declare (type (or function null) key)
    
    938 938
                  (type function test test-not))
    
    939
    -    (dolist (elt list1)
    
    940
    -      (unless (with-set-keys (member (apply-key key elt) list2))
    
    941
    -	(setq result (cons elt result))))
    
    942
    -    (let ((test (if testp
    
    943
    -                    (lambda (x y) (funcall test y x))
    
    944
    -                    test))
    
    945
    -          (test-not (if notp
    
    946
    -                        (lambda (x y) (funcall test-not y x))
    
    947
    -                        test-not)))
    
    948
    -      (dolist (elt list2)
    
    949
    -        (unless (with-set-keys (member (apply-key key elt) list1))
    
    950
    -          (setq result (cons elt result)))))
    
    951
    -    result))
    
    939
    +    ;; Find the elements in list1 that do not appear in list2 and add
    
    940
    +    ;; them to the result.
    
    941
    +    (macrolet
    
    942
    +        ((compute-membership (item-list test-form)
    
    943
    +           `(dolist (elt ,item-list)
    
    944
    +              (unless ,test-form
    
    945
    +                (setq result (cons elt result))))))
    
    946
    +      (let ((hashtable (list-to-hashtable list2 key test test-not)))
    
    947
    +        (cond
    
    948
    +          (hashtable
    
    949
    +           (compute-membership list1
    
    950
    +                               (nth-value 1 (gethash (apply-key key elt) hashtable))))
    
    951
    +          (t
    
    952
    +           (compute-membership list1
    
    953
    +                               (with-set-keys (member (apply-key key elt) list2))))))
    
    954
    +      ;; Now find the elements in list2 that do not appear in list1 and
    
    955
    +      ;; them to the result.
    
    956
    +      (let ((hashtable (list-to-hashtable list1 key test test-not)))
    
    957
    +        (cond
    
    958
    +          (hashtable
    
    959
    +           (compute-membership list2
    
    960
    +                               (nth-value 1 (gethash (apply-key key elt) hashtable))))
    
    961
    +          (t
    
    962
    +           (let ((test (if testp
    
    963
    +                           (lambda (x y) (funcall test y x))
    
    964
    +                           test))
    
    965
    +                 (test-not (if notp
    
    966
    +                               (lambda (x y) (funcall test-not y x))
    
    967
    +                               test-not)))
    
    968
    +             (compute-membership list2
    
    969
    +                                 (with-set-keys (member (apply-key key elt) list1)))))))
    
    970
    +      result)))
    
    952 971
     
    
    953 972
     
    
    954 973
     ;;; The outer loop examines list1 while the inner loop examines list2. If an
    

  • src/i18n/locale/cmucl.pot
    ... ... @@ -3236,7 +3236,7 @@ msgid "Destructively returns the elements of list1 which are not in list2."
    3236 3236
     msgstr ""
    
    3237 3237
     
    
    3238 3238
     #: src/code/list.lisp
    
    3239
    -msgid "Return new list of elements appearing exactly once in LIST1 and LIST2."
    
    3239
    +msgid "Return new list of elements appearing exactly one of LIST1 and LIST2."
    
    3240 3240
     msgstr ""
    
    3241 3241
     
    
    3242 3242
     #: src/code/list.lisp
    

  • tests/sets.lisp
    ... ... @@ -279,3 +279,26 @@
    279 279
                              '(3 4)
    
    280 280
                              :test 'eql
    
    281 281
                              :test-not 'equal)))
    
    282
    +
    
    283
    +(define-test set-exclusive-or.1
    
    284
    +  (:tag :issues)
    
    285
    +  (flet
    
    286
    +      ((test (min-length)
    
    287
    +         ;; From CLHS
    
    288
    +         (let ((lisp::*min-list-length-for-hashtable* min-length))
    
    289
    +           (assert-equal '("b" "A" "b" "a")
    
    290
    +                         (set-exclusive-or '(1 "a" "b")
    
    291
    +                                           '(1 "A" "b")))
    
    292
    +           (assert-equal '("A" "a")
    
    293
    +                         (set-exclusive-or '(1 "a" "b")
    
    294
    +                                           '(1 "A" "b")
    
    295
    +                                           :test #'equal))
    
    296
    +           (assert-equal nil
    
    297
    +                         (set-exclusive-or '(1 "a" "b")
    
    298
    +                                           '(1 "A" "b")
    
    299
    +                                           :test #'equalp)))))
    
    300
    +    ;; Test the list impl by making the min length large.  Then test
    
    301
    +    ;; the hashtable impl with a very short min length
    
    302
    +    (test 100)
    
    303
    +    (test 2)))
    
    304
    +