Raymond Toy pushed to branch issue-240-subsetp-with-hash-table at cmucl / cmucl

Commits:

2 changed files:

Changes:

  • src/code/list.lisp
    ... ... @@ -991,35 +991,6 @@
    991 991
     
    
    992 992
     (defvar *allow-hashtable-for-set-functions* t)
    
    993 993
     
    
    994
    -(declaim (start-block shorter-list-to-hashtable subsetp))
    
    995
    -
    
    996
    -(defun shorter-list-to-hashtable (list1 list2 key test test-not)
    
    997
    -  ;; Find the shorter list and return the length and the shorter list
    
    998
    -  (when test-not
    
    999
    -    (return-from shorter-list-to-hashtable nil))
    
    1000
    -  (let ((hash-test (let ((test-fn (if (and (symbolp test)
    
    1001
    -                                           (fboundp test))
    
    1002
    -                                      (fdefinition test)
    
    1003
    -                                      test)))
    
    1004
    -                     (cond ((eql test-fn #'eq) 'eq)
    
    1005
    -                           ((eql test-fn #'eql) 'eql)
    
    1006
    -                           ((eql test-fn #'equal) 'equal)
    
    1007
    -                           ((eql test-fn #'equalp) 'equalp)))))
    
    1008
    -    (unless hash-test
    
    1009
    -      (return-from shorter-list-to-hashtable nil))
    
    1010
    -    (multiple-value-bind (min-length shorter-list)
    
    1011
    -        (do ((len 0 (1+ len))
    
    1012
    -             (lst1 list1 (cdr lst1))
    
    1013
    -             (lst2 list2 (cdr lst2)))
    
    1014
    -            ((or (null lst1) (null lst2))
    
    1015
    -             (values len (if (null lst1) list1 list2))))
    
    1016
    -      (when (< min-length *min-list-length-for-hashtable*)
    
    1017
    -        (return-from shorter-list-to-hashtable nil))
    
    1018
    -      (let ((hashtable (make-hash-table :test hash-test :size min-length)))
    
    1019
    -        (dolist (item shorter-list)
    
    1020
    -          (setf (gethash (apply-key key item) hashtable) item))
    
    1021
    -        (values hashtable shorter-list)))))
    
    1022
    -
    
    1023 994
     (defun subsetp (list1 list2 &key key (test #'eql testp) (test-not nil notp))
    
    1024 995
       "Returns T if every element in list1 is also in list2."
    
    1025 996
       (declare (inline member))
    
    ... ... @@ -1029,28 +1000,21 @@
    1029 1000
       ;; SUBSETP is used early in TYPE-INIT where hash tables aren't
    
    1030 1001
       ;; available yet, so we can't use hashtables then.  LISPINIT will
    
    1031 1002
       ;; take care to disable this for the kernel.core.  SAVE will set
    
    1032
    -  ;; this to true it's safe to use hash tables for SUBSETP.
    
    1033
    -  (multiple-value-bind (hashtable shorter-list)
    
    1034
    -      (when *allow-hashtable-for-set-functions*
    
    1035
    -        (shorter-list-to-hashtable list1 list2 key test test-not))
    
    1003
    +  ;; this to true when it's safe to use hash tables for SUBSETP.
    
    1004
    +  (let ((hashtable
    
    1005
    +          (when *allow-hashtable-for-set-functions*
    
    1006
    +            (list-to-hashtable list2 key test test-not))))
    
    1036 1007
         (cond (hashtable
    
    1037
    -           (cond ((eq shorter-list list1)
    
    1038
    -                  (dolist (item list2)
    
    1039
    -	            (unless (nth-value 1 (gethash (apply-key key item) hashtable))
    
    1040
    -	              (return-from subsetp nil))))
    
    1041
    -                 ((eq shorter-list list2)
    
    1042
    -	          (dolist (item list1)
    
    1043
    -	            (unless (nth-value 1 (gethash (apply-key key item) hashtable))
    
    1044
    -	              (return-from subsetp nil)))))
    
    1008
    +	   (dolist (item list1)
    
    1009
    +	     (unless (nth-value 1 (gethash (apply-key key item) hashtable))
    
    1010
    +	       (return-from subsetp nil)))
    
    1045 1011
                t)
    
    1046
    -	  ((null hashtable)
    
    1012
    +	  (t
    
    1047 1013
     	   (dolist (item list1)
    
    1048 1014
     	     (unless (with-set-keys (member (apply-key key item) list2))
    
    1049 1015
     	       (return-from subsetp nil)))
    
    1050 1016
     	   T))))
    
    1051 1017
     
    
    1052
    -(declaim (end-block))
    
    1053
    -
    
    1054 1018
     
    
    1055 1019
     ;;; Functions that operate on association lists
    
    1056 1020
     
    

  • tests/sets.lisp
    ... ... @@ -172,3 +172,54 @@
    172 172
     		       '(3 4)
    
    173 173
     		       :test 'eql
    
    174 174
     		       :test-not 'eql)))
    
    175
    +
    
    176
    +
    
    177
    +(define-test subsetp.hash-eq
    
    178
    +    (:tag :issues)
    
    179
    +  (let ((lisp::*min-list-length-for-hashtable* 2))
    
    180
    +    (assert-true
    
    181
    +     (subsetp '(a b c a) '(a a d d c b) :test 'eq))
    
    182
    +    (assert-true
    
    183
    +     (subsetp '(a b c a b c a b c) '(a a d d c b) :test 'eq))
    
    184
    +    (assert-false
    
    185
    +     (subsetp '(a b c a z) '(a a d d c b) :test 'eq))
    
    186
    +    (assert-false
    
    187
    +     (subsetp '(a b c a b cz) '(a a d d c b) :test 'eq))))
    
    188
    +
    
    189
    +(define-test subsetp.hash-eql
    
    190
    +    (:tag :issues)
    
    191
    +  (let ((lisp::*min-list-length-for-hashtable* 2))
    
    192
    +    (assert-true
    
    193
    +     (subsetp '(a b c a) '(a a d d c b) :test 'eql))
    
    194
    +    (assert-false
    
    195
    +     (subsetp '(a b c a z) '(a a d d c b) :test 'eql))))
    
    196
    +
    
    197
    +(define-test subsetp.hash-equal
    
    198
    +    (:tag :issues)
    
    199
    +  (let ((lisp::*min-list-length-for-hashtable* 2))
    
    200
    +    (assert-true
    
    201
    +     (subsetp '("a" "b" "c" "a") '("a" "a" "d" "d" "c" "b") :test 'equal))
    
    202
    +    (assert-false
    
    203
    +     (subsetp '("a" "b" "c" "a" "z") '("a" "a" "d" "d" "c" "b") :test 'equal))))
    
    204
    +
    
    205
    +(define-test subsetp.hash-equalp
    
    206
    +    (:tag :issues)
    
    207
    +  (let ((lisp::*min-list-length-for-hashtable* 2))
    
    208
    +    (assert-true
    
    209
    +     (subsetp '("a" "b" "C" "A") '("a" "a" "d" "d" "c" "b") :test 'equalp))
    
    210
    +    (assert-false
    
    211
    +     (subsetp '("a" "b" "C" "A" "z") '("a" "a" "d" "d" "c" "b") :test 'equalp))))
    
    212
    +
    
    213
    +(define-test subsetp.hash-eql-with-key
    
    214
    +    (:tag :issues)
    
    215
    +  (assert-true (subsetp '((1 "a") (2 "b") (3 "c"))
    
    216
    +                        '((3 "c") (3 "c") (2 "b") (1 "a"))
    
    217
    +                        :test 'eql
    
    218
    +                        :key #'first)))
    
    219
    +
    
    220
    +(define-test subsetp.test-and-test-not
    
    221
    +  (assert-error 'simple-error
    
    222
    +                (subsetp '(1 2)
    
    223
    +                         '(3 4)
    
    224
    +                         :test 'eql
    
    225
    +                         :test-not 'equal)))