Raymond Toy pushed to branch issue-240-subsetp-with-hash-table at cmucl / cmucl
Commits:
-
46f5352a
by Raymond Toy at 2023-08-20T15:17:51-07:00
2 changed files:
Changes:
... | ... | @@ -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 |
... | ... | @@ -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))) |