Raymond Toy pushed to branch issue-240-clean-up-hashtable-for-sets-impl at cmucl / cmucl
Commits:
702fe16a by Raymond Toy at 2023-08-27T12:03:05-07:00
Rename/refactor nprocess-set
Do the same for nprocess-set as we did for process-set, renaming it to
do-destructive-set-operation.
- - - - -
2a02ec67 by Raymond Toy at 2023-08-27T14:27:53-07:00
Move the process-set-body macro into do-set-operation
Get rid the extra macro by moving inside the do-set-operation macro.
This makes it a little neater.
- - - - -
15ed5464 by Raymond Toy at 2023-08-27T14:55:27-07:00
Move the nprocess-set-body macro into do-destructive-set-operation
Get rid the extra macro by moving it inside the
do-destructive-set-operation macro. This makes it a little neater.
- - - - -
1 changed file:
- src/code/list.lisp
Changes:
=====================================
src/code/list.lisp
=====================================
@@ -753,17 +753,11 @@
union intersection set-difference
nunion nintersection nset-difference))
-;; Main code to process a set function. INIT-RES initializes the
-;; value of RES, which holds the result of the set function.
-;; TEST-FORM is a form that tests whether to add the item from LIST1
-;; to RES.
-(defmacro process-set-body (list1 init-res membership-test test-form)
- `(let ((res ,init-res))
- (dolist (item ,list1)
- (,membership-test ,test-form
- (push item res)))
- res))
-
+;; Handle a non-destructive set operation. LIST1 and LIST2 are the
+;; two arguments to the set function. INITIAL-RESULT is the value
+;; used to initialize the result list. IS specifies whether the test
+;; (or test-not) function implies an element of LIST1 should be
+;; included in the result.
(defmacro do-set-operation (list1 list2 &key initial-result is)
(let ((membership-test (ecase is
(:element-of-set
@@ -771,11 +765,19 @@
(:not-element-of-set
'unless))))
`(let ((hashtable (list-to-hashtable ,list2 key test test-not)))
- (if hashtable
- (process-set-body ,list1 ,initial-result ,membership-test
+ (macrolet
+ ((process-set-op (list1 init-res member-form test-form)
+ `(let ((res ,init-res))
+ (dolist (item ,list1)
+ (,member-form ,test-form
+ (push item res)))
+ res)))
+
+ (if hashtable
+ (process-set-op ,list1 ,initial-result ,membership-test
(nth-value 1 (gethash (apply-key key item) hashtable)))
- (process-set-body ,list1 ,initial-result ,membership-test
- (with-set-keys (member (apply-key key item) ,list2)))))))
+ (process-set-op ,list1 ,initial-result ,membership-test
+ (with-set-keys (member (apply-key key item) list2))))))))
;; Convert a list to a hashtable. The hashtable does not handle
;; duplicated values in the list. Returns the hashtable.
@@ -854,14 +856,14 @@
;;; the result list. INVERT-P is T if the result of the TEST-FORM
;;; should be inverted. TEST-FORM is the form used for determining
;;; how to update the result.
-(defmacro nprocess-set-body (init-res invert-p test-form)
+(defmacro nprocess-set-body (list1 init-res is-member-p test-form)
`(let ((res ,init-res)
- (list1 list1))
+ (list1 ,list1))
(do ()
((endp list1))
- (if ,(if invert-p
- `(not ,test-form)
- test-form)
+ (if ,(if is-member-p
+ test-form
+ `(not ,test-form))
(steve-splice list1 res)
(setq list1 (cdr list1))))
res))
@@ -870,13 +872,30 @@
;; initializes the value of the result list. INVERT-P indicates
;; whether to invert the test-form used to determine how the result
;; should be updated.
-(defmacro nprocess-set (init-res invert-p)
- `(let ((hashtable (list-to-hashtable list2 key test test-not)))
- (if hashtable
- (nprocess-set-body ,init-res ,invert-p
- (nth-value 1 (gethash (apply-key key (car list1)) hashtable)))
- (nprocess-set-body ,init-res ,invert-p
- (with-set-keys (member (apply-key key (car list1)) list2))))))
+(defmacro do-destructive-set-operation (list1 list2 &key initial-result is)
+ (let ((is-member-p (ecase is
+ (:element-of-set
+ t)
+ (:not-element-of-set
+ nil))))
+ `(let ((hashtable (list-to-hashtable ,list2 key test test-not)))
+ (macrolet
+ ((process-set-op (list1 init-res is-member-p test-form)
+ `(let ((res ,init-res)
+ (list1 ,list1))
+ (do ()
+ ((endp list1))
+ (if ,(if is-member-p
+ test-form
+ `(not ,test-form))
+ (steve-splice list1 res)
+ (setq list1 (cdr list1))))
+ res)))
+ (if hashtable
+ (process-set-op ,list1 ,initial-result ,is-member-p
+ (nth-value 1 (gethash (apply-key key (car ,list1)) hashtable)))
+ (process-set-op ,list1 ,initial-result ,is-member-p
+ (with-set-keys (member (apply-key key (car ,list1)) list2))))))))
(defun nunion (list1 list2 &key key (test #'eql testp) (test-not nil notp))
@@ -885,7 +904,7 @@
(if (and testp notp)
(error "Test and test-not both supplied."))
- (nprocess-set list2 t))
+ (do-destructive-set-operation list1 list2 :initial-result list2 :is :not-element-of-set))
(defun nintersection (list1 list2 &key key
(test #'eql testp) (test-not nil notp))
@@ -894,7 +913,7 @@
(if (and testp notp)
(error "Test and test-not both supplied."))
- (nprocess-set nil nil))
+ (do-destructive-set-operation list1 list2 :initial-result nil :is :element-of-set))
(defun nset-difference (list1 list2 &key key
(test #'eql testp) (test-not nil notp))
@@ -903,7 +922,7 @@
(if (and testp notp)
(error "Test and test-not both supplied."))
- (nprocess-set nil t))
+ (do-destructive-set-operation list1 list2 :initial-result nil :is :not-element-of-set))
(declaim (end-block))
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/bd928112a03960e68d419f…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/bd928112a03960e68d419f…
You're receiving this email because of your account on gitlab.common-lisp.net.
Raymond Toy pushed to branch issue-240-add-hashtable-set-exclusive-or at cmucl / cmucl
Commits:
8074203f by Raymond Toy at 2023-08-26T20:42:51-07:00
Add comments and fix docstring.
The docstring says set-exclusive-or produces elements appearing
exactly once in list1 and list2. But that's not right. The result
has elements appearing in either list1 or list2 but not both. Use the
text from the CLHS as the docstring.
Add some comments to the code.
- - - - -
1 changed file:
- src/code/list.lisp
Changes:
=====================================
src/code/list.lisp
=====================================
@@ -906,7 +906,7 @@
(defun set-exclusive-or (list1 list2 &key key
(test #'eql testp) (test-not nil notp))
- "Return new list of elements appearing exactly once in LIST1 and LIST2."
+ "Return new list of elements appearing exactly one of LIST1 and LIST2."
(declare (inline member))
(let ((result nil)
(key (when key (coerce key 'function)))
@@ -914,6 +914,8 @@
(test-not (if test-not (coerce test-not 'function) #'eql)))
(declare (type (or function null) key)
(type function test test-not))
+ ;; Find the elements in list1 that do not appear in list2 and add
+ ;; them to the result.
(let ((hashtable (list-to-hashtable list2 key test test-not)))
(cond
(hashtable
@@ -924,6 +926,8 @@
(dolist (elt list1)
(unless (with-set-keys (member (apply-key key elt) list2))
(setq result (cons elt result)))))))
+ ;; Now find the elements in list2 that do not appear in list1 and
+ ;; them to the result.
(let ((hashtable (list-to-hashtable list1 key test test-not)))
(cond
(hashtable
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/8074203fd56e40c38130f31…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/8074203fd56e40c38130f31…
You're receiving this email because of your account on gitlab.common-lisp.net.
Raymond Toy pushed to branch issue-240-add-hashtable-set-exclusive-or at cmucl / cmucl
Commits:
56ecb8cf by Raymond Toy at 2023-08-26T20:33:49-07:00
Fix another typo
Malformed flet is fixed now. Test runs correctly.
- - - - -
1 changed file:
- tests/sets.lisp
Changes:
=====================================
tests/sets.lisp
=====================================
@@ -283,20 +283,20 @@
(define-test set-exclusive-or.1
(:tag :issues)
(flet
- ((test min-length)
- ;; From CLHS
- (let ((lisp::*min-list-length-for-hashtable* min-length))
- (assert-equal '("b" "A" "b" "a")
- (set-exclusive-or '(1 "a" "b")
- '(1 "A" "b")))
- (assert-equal '("A" "a")
- (set-exclusive-or '(1 "a" "b")
- '(1 "A" "b")
- :test #'equal))
- (assert-equal nil
- (set-exclusive-or '(1 "a" "b")
- '(1 "A" "b")
- :test #'equalp))))
+ ((test (min-length)
+ ;; From CLHS
+ (let ((lisp::*min-list-length-for-hashtable* min-length))
+ (assert-equal '("b" "A" "b" "a")
+ (set-exclusive-or '(1 "a" "b")
+ '(1 "A" "b")))
+ (assert-equal '("A" "a")
+ (set-exclusive-or '(1 "a" "b")
+ '(1 "A" "b")
+ :test #'equal))
+ (assert-equal nil
+ (set-exclusive-or '(1 "a" "b")
+ '(1 "A" "b")
+ :test #'equalp)))))
;; Test the list impl by making the min length large. Then test
;; the hashtable impl with a very short min length
(test 100)
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/56ecb8cfbfd96a722cc710e…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/56ecb8cfbfd96a722cc710e…
You're receiving this email because of your account on gitlab.common-lisp.net.
Raymond Toy pushed to branch issue-240-add-hashtable-set-exclusive-or at cmucl / cmucl
Commits:
c8f2c87d by Raymond Toy at 2023-08-25T20:12:46-07:00
Fix typo.
Somehow a stray "g" got added to steve-splice. Remove it.
- - - - -
1 changed file:
- src/code/list.lisp
Changes:
=====================================
src/code/list.lisp
=====================================
@@ -842,7 +842,7 @@
;;; to the cdr, and "conses" the 1st elt of source to destination.
;;;
(defmacro steve-splice (source destination)
- `(let ((temp ,source))g
+ `(let ((temp ,source))
(setf ,source (cdr ,source)
(cdr temp) ,destination
,destination temp)))
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/c8f2c87db5e3ab95e5371e5…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/c8f2c87db5e3ab95e5371e5…
You're receiving this email because of your account on gitlab.common-lisp.net.