Raymond Toy pushed to branch issue-240-add-hashtable-for-destructive-set-ops at cmucl / cmucl

Commits:

4 changed files:

Changes:

  • src/code/list.lisp
    ... ... @@ -1022,14 +1022,69 @@
    1022 1022
     	      (rplacd splicex (cdr x)))
    
    1023 1023
     	  (setq splicex x)))))
    
    1024 1024
     
    
    1025
    +(declaim (start-block shorter-list-to-hashtable subsetp))
    
    1026
    +
    
    1027
    +(defun shorter-list-to-hashtable (list1 list2 key test test-not)
    
    1028
    +  ;; Find the shorter list and return the length and the shorter list
    
    1029
    +  (when test-not
    
    1030
    +    (return-from shorter-list-to-hashtable nil))
    
    1031
    +  (let ((hash-test (let ((test-fn (if (and (symbolp test)
    
    1032
    +                                           (fboundp test))
    
    1033
    +                                      (fdefinition test)
    
    1034
    +                                      test)))
    
    1035
    +                     (cond ((eql test-fn #'eq) 'eq)
    
    1036
    +                           ((eql test-fn #'eql) 'eql)
    
    1037
    +                           ((eql test-fn #'equal) 'equal)
    
    1038
    +                           ((eql test-fn #'equalp) 'equalp)))))
    
    1039
    +    (unless hash-test
    
    1040
    +      (return-from shorter-list-to-hashtable nil))
    
    1041
    +    (multiple-value-bind (min-length shorter-list)
    
    1042
    +        (do ((len 0 (1+ len))
    
    1043
    +             (lst1 list1 (cdr lst1))
    
    1044
    +             (lst2 list2 (cdr lst2)))
    
    1045
    +            ((or (null lst1) (null lst2))
    
    1046
    +             (values len (if (null lst1) list1 list2))))
    
    1047
    +      (when (< min-length kernel::*min-list-length-for-subsetp-hashtable*)
    
    1048
    +        (return-from shorter-list-to-hashtable nil))
    
    1049
    +      (let ((hashtable (make-hash-table :test hash-test :size min-length)))
    
    1050
    +        (dolist (item shorter-list)
    
    1051
    +          (setf (gethash (apply-key key item) hashtable) item))
    
    1052
    +        (values hashtable shorter-list)))))
    
    1053
    +        
    
    1025 1054
     (defun subsetp (list1 list2 &key key (test #'eql testp) (test-not nil notp))
    
    1026 1055
       "Returns T if every element in list1 is also in list2."
    
    1027 1056
       (declare (inline member))
    
    1028
    -  (dolist (elt list1)
    
    1029
    -    (unless (with-set-keys (member (apply-key key elt) list2))
    
    1030
    -      (return-from subsetp nil)))
    
    1031
    -  T)
    
    1057
    +  (when (and testp notp)
    
    1058
    +    (error "Test and test-not both supplied."))
    
    1059
    +
    
    1060
    +  ;; SUBSETP is used early in TYPE-INIT where hash tables aren't
    
    1061
    +  ;; available yet, so we can't use hashtables then.  LISPINIT will
    
    1062
    +  ;; take care to disable this for the kernel.core.  SAVE will set
    
    1063
    +  ;; this to true when it's safe to use hash tables for SUBSETP.
    
    1064
    +  (multiple-value-bind (hashtable shorter-list)
    
    1065
    +      (when t
    
    1066
    +        (shorter-list-to-hashtable list1 list2 key test test-not))
    
    1067
    +    (cond (hashtable
    
    1068
    +           (cond ((eq shorter-list list1)
    
    1069
    +                  ;; Remove any item from list2 from the hashtable containing list1.
    
    1070
    +                  (dolist (item list2)
    
    1071
    +                    (remhash (apply-key key item) hashtable))
    
    1072
    +                  ;; If the hash table is now empty, then every
    
    1073
    +                  ;; element in list1 appeared in list2, so list1 is a
    
    1074
    +                  ;; subset of list2.
    
    1075
    +                  (zerop (hash-table-count hashtable)))
    
    1076
    +                 ((eq shorter-list list2)
    
    1077
    +                  (dolist (item list1)
    
    1078
    +                    (unless (nth-value 1 (gethash (apply-key key item) hashtable))
    
    1079
    +                      (return-from subsetp nil)))
    
    1080
    +                  t)))
    
    1081
    +	  (t
    
    1082
    +	   (dolist (item list1)
    
    1083
    +	     (unless (with-set-keys (member (apply-key key item) list2))
    
    1084
    +	       (return-from subsetp nil)))
    
    1085
    +	   T))))
    
    1032 1086
     
    
    1087
    +(declaim (end-block))
    
    1033 1088
     
    
    1034 1089
     
    
    1035 1090
     ;;; Functions that operate on association lists
    

  • src/code/type.lisp
    ... ... @@ -377,6 +377,14 @@
    377 377
     (cold-load-init (setq *use-implementation-types* t))
    
    378 378
     (declaim (type boolean *use-implementation-types*))
    
    379 379
     
    
    380
    +(defvar *min-list-length-for-subsetp-hashtable* 150
    
    381
    +  "The minimum length of either list argument for subsetp where a
    
    382
    +  hashtable is used to speed up processing instead of using a basic
    
    383
    +  list implementation.  This value was determined by experimentation.")
    
    384
    +
    
    385
    +(cold-load-init (setq *min-list-length-for-subsetp-hashtable* 150))
    
    386
    +(declaim (type fixnum *min-list-length-for-subsetp-hashtable*))
    
    387
    +
    
    380 388
     ;;; DELEGATE-COMPLEX-{SUBTYPEP-ARG2,INTERSECTION}  --  Interface
    
    381 389
     ;;;
    
    382 390
     ;;;    These functions are used as method for types which need a complex
    

  • src/i18n/locale/cmucl.pot
    ... ... @@ -1155,6 +1155,13 @@ msgid ""
    1155 1155
     "   affects array types."
    
    1156 1156
     msgstr ""
    
    1157 1157
     
    
    1158
    +#: src/code/type.lisp
    
    1159
    +msgid ""
    
    1160
    +"The minimum length of either list argument for subsetp where a\n"
    
    1161
    +"  hashtable is used to speed up processing instead of using a basic\n"
    
    1162
    +"  list implementation.  This value was determined by experimentation."
    
    1163
    +msgstr ""
    
    1164
    +
    
    1158 1165
     #: src/code/type.lisp
    
    1159 1166
     msgid "Subtypep is illegal on this type:~%  ~S"
    
    1160 1167
     msgstr ""
    

  • tests/sets.lisp
    ... ... @@ -280,4 +280,3 @@
    280 280
                              '(3 4)
    
    281 281
                              :test 'eql
    
    282 282
                              :test-not 'equal)))
    283
    ->>>>>>> Stashed changes