Raymond Toy pushed to branch master at cmucl / cmucl

Commits:

2 changed files:

Changes:

  • src/code/list.lisp
    ... ... @@ -749,7 +749,9 @@
    749 749
     (defparameter *min-list-length-for-hashtable*
    
    750 750
       15)
    
    751 751
     
    
    752
    -(declaim (start-block list-to-hashtable union intersection set-difference))
    
    752
    +(declaim (start-block list-to-hashtable
    
    753
    +                      union intersection set-difference
    
    754
    +                      nunion nintersection nset-difference))
    
    753 755
     
    
    754 756
     ;; Main code to process a set function.  INIT-RES initializes the
    
    755 757
     ;; value of RES, which holds the result of the set function.
    
    ... ... @@ -836,8 +838,6 @@
    836 838
       (process-set nil t))
    
    837 839
     
    
    838 840
     
    
    839
    -(declaim (end-block))
    
    840
    -
    
    841 841
     ;;; Destination and source are setf-able and many-evaluable.  Sets the source
    
    842 842
     ;;; to the cdr, and "conses" the 1st elt of source to destination.
    
    843 843
     ;;;
    
    ... ... @@ -847,19 +847,42 @@
    847 847
     	   (cdr temp) ,destination
    
    848 848
     	   ,destination temp)))
    
    849 849
     
    
    850
    +;;; Main body for destructive set operations.  INIT-RES initializes
    
    851
    +;;; the result list.  INVERT-P is T if the result of the TEST-FORM
    
    852
    +;;; should be inverted.  TEST-FORM is the form used for determining
    
    853
    +;;; how to update the result.
    
    854
    +(defmacro nprocess-set-body (init-res invert-p test-form)
    
    855
    +  `(let ((res ,init-res)
    
    856
    +         (list1 list1))
    
    857
    +     (do ()
    
    858
    +         ((endp list1))
    
    859
    +       (if ,(if invert-p
    
    860
    +                `(not ,test-form)
    
    861
    +                test-form)
    
    862
    +           (steve-splice list1 res)
    
    863
    +           (setq list1 (cdr list1))))
    
    864
    +     res))
    
    865
    +
    
    866
    +;; Implementation of the destructive set operations.  INIT-RES
    
    867
    +;; initializes the value of the result list.  INVERT-P indicates
    
    868
    +;; whether to invert the test-form used to determine how the result
    
    869
    +;; should be updated.
    
    870
    +(defmacro nprocess-set (init-res invert-p)
    
    871
    +  `(let ((hashtable (list-to-hashtable list2 key test test-not)))
    
    872
    +     (if hashtable
    
    873
    +         (nprocess-set-body ,init-res ,invert-p
    
    874
    +                            (nth-value 1 (gethash (apply-key key (car list1)) hashtable)))
    
    875
    +         (nprocess-set-body ,init-res ,invert-p
    
    876
    +                            (with-set-keys (member (apply-key key (car list1)) list2))))))
    
    877
    +
    
    878
    +
    
    850 879
     (defun nunion (list1 list2 &key key (test #'eql testp) (test-not nil notp))
    
    851 880
       "Destructively returns the union list1 and list2."
    
    852 881
       (declare (inline member))
    
    853 882
       (if (and testp notp)
    
    854 883
           (error "Test and test-not both supplied."))
    
    855
    -  (let ((res list2)
    
    856
    -	(list1 list1))
    
    857
    -    (do ()
    
    858
    -	((endp list1))
    
    859
    -      (if (not (with-set-keys (member (apply-key key (car list1)) list2)))
    
    860
    -	  (steve-splice list1 res)
    
    861
    -	  (setf list1 (cdr list1))))
    
    862
    -    res))
    
    884
    +
    
    885
    +  (nprocess-set list2 t))
    
    863 886
       
    
    864 887
     (defun nintersection (list1 list2 &key key
    
    865 888
     			    (test #'eql testp) (test-not nil notp))
    
    ... ... @@ -867,13 +890,8 @@
    867 890
       (declare (inline member))
    
    868 891
       (if (and testp notp)
    
    869 892
           (error "Test and test-not both supplied."))
    
    870
    -  (let ((res nil)
    
    871
    -	(list1 list1))
    
    872
    -    (do () ((endp list1))
    
    873
    -      (if (with-set-keys (member (apply-key key (car list1)) list2))
    
    874
    -	  (steve-splice list1 res)
    
    875
    -	  (setq list1 (Cdr list1))))
    
    876
    -    res))
    
    893
    +
    
    894
    +  (nprocess-set nil nil))
    
    877 895
     
    
    878 896
     (defun nset-difference (list1 list2 &key key
    
    879 897
     			      (test #'eql testp) (test-not nil notp))
    
    ... ... @@ -881,14 +899,10 @@
    881 899
       (declare (inline member))
    
    882 900
       (if (and testp notp)
    
    883 901
           (error "Test and test-not both supplied."))
    
    884
    -  (let ((res nil)
    
    885
    -	(list1 list1))
    
    886
    -    (do () ((endp list1))
    
    887
    -      (if (not (with-set-keys (member (apply-key key (car list1)) list2)))
    
    888
    -	  (steve-splice list1 res)
    
    889
    -	  (setq list1 (cdr list1))))
    
    890
    -    res))
    
    891 902
     
    
    903
    +  (nprocess-set nil t))
    
    904
    +
    
    905
    +(declaim (end-block))
    
    892 906
     
    
    893 907
     (defun set-exclusive-or (list1 list2 &key key
    
    894 908
                              (test #'eql testp) (test-not nil notp))
    

  • tests/sets.lisp
    ... ... @@ -88,8 +88,37 @@
    88 88
     				:test 'eql
    
    89 89
     				:test-not 'eql)))
    
    90 90
     
    
    91
    -   
    
    92 91
     
    
    92
    +(define-test nset-diff.1
    
    93
    +    (:tag :issues)
    
    94
    +  ;; From CLHS
    
    95
    +  (flet 
    
    96
    +      ((test1 (min-length-limit)
    
    97
    +         (let ((lisp::*min-list-length-for-hashtable* min-length-limit)
    
    98
    +               (lst1 (list "A" "b" "C" "d"))
    
    99
    +               (lst2 (list "a" "B" "C" "d")))
    
    100
    +           (assert-equal '("b" "A")
    
    101
    +                         (nset-difference lst1 lst2 :test 'equal))
    
    102
    +           ;; This isn't specified by the CLHS, but it is what we do.
    
    103
    +           (assert-equal '("A") lst1))))
    
    104
    +    (test1 100)
    
    105
    +    (test1 1)))
    
    106
    +
    
    107
    +(define-test nset-diff.key
    
    108
    +    (:tag :issues)
    
    109
    +  (flet
    
    110
    +      ((test (min-length-limit)
    
    111
    +         ;; From CLHS
    
    112
    +         (let ((lisp::*min-list-length-for-hashtable* min-length-limit)
    
    113
    +               (lst1 (list '("a" . "b") '("c" . "d") '("e" . "f")))
    
    114
    +               (lst2 (list '("c" . "a") '("e" . "b") '("d" . "a"))))
    
    115
    +           (assert-equal '(("e" . "f") ("c" . "d"))
    
    116
    +                         (nset-difference lst1 lst2 :test 'equal :key #'cdr))
    
    117
    +           ;; This isn't specified by the CLHS, but it is what we do.
    
    118
    +           (assert-equal '(("a" . "b") ("c" . "d")) lst1))))
    
    119
    +    (test 100)
    
    120
    +    (test 1)))
    
    121
    +  
    
    93 122
     (define-test union.hash-eql
    
    94 123
         (:tag :issues)
    
    95 124
       ;; For union to use hashtables by making the threshold
    
    ... ... @@ -173,6 +202,33 @@
    173 202
     		       :test 'eql
    
    174 203
     		       :test-not 'eql)))
    
    175 204
     
    
    205
    +(define-test nunion.1
    
    206
    +    (:tag :issues)
    
    207
    +  (flet
    
    208
    +      ((test (min-list-length)
    
    209
    +         (let ((lisp::*min-list-length-for-hashtable* min-list-length)
    
    210
    +               (lst1 (list 1 2 '(1 2) "a" "b"))
    
    211
    +               (lst2 (list 2 3 '(2 3) "B" "C")))
    
    212
    +           (assert-equal '("b" "a" (1 2) 1 2 3 (2 3) "B" "C")
    
    213
    +                         (nunion lst1 lst2))
    
    214
    +           (assert-equal '(1 2 3 (2 3) "B" "C")
    
    215
    +                         lst1))))
    
    216
    +    (test 100)
    
    217
    +    (test 1)))
    
    218
    +
    
    219
    +(define-test nintersection.1
    
    220
    +    (:tag :issues)
    
    221
    +  (flet
    
    222
    +      ((test (min-list-length)
    
    223
    +         (let ((lisp::*min-list-length-for-hashtable* min-list-length)
    
    224
    +               (lst1 (list 1 1 2 3 4 'a 'b 'c "A" "B" "C" "d"))
    
    225
    +               (lst2 (list 1 4 5 'b 'c 'd "a" "B" "c" "D")))
    
    226
    +           (assert-equal '(c b 4 1 1)
    
    227
    +                         (nintersection lst1 lst2))
    
    228
    +           (assert-equal '(1) lst1))))
    
    229
    +    (test 100)
    
    230
    +    (test 1)))
    
    231
    +
    
    176 232
     
    
    177 233
     (define-test subsetp.hash-eq
    
    178 234
         (:tag :issues)