Fix up `push-if-new` with setf/places macromancy
author |
Steve Losh <steve@stevelosh.com> |
date |
Thu, 14 Apr 2016 13:32:31 +0000 |
parents |
fdb771cc2b8c
|
children |
9376531b5089
|
branches/tags |
(none) |
files |
package.lisp src/make-quickutils.lisp src/quickutils.lisp src/utils.lisp |
Changes
--- a/package.lisp Wed Apr 13 17:38:57 2016 +0000
+++ b/package.lisp Thu Apr 14 13:32:31 2016 +0000
@@ -7,7 +7,6 @@
#:defstar
#:bones.quickutils)
(:export
- #:vector-push-extend-all
#:push-if-new))
(defpackage #:bones.wam
--- a/src/make-quickutils.lisp Wed Apr 13 17:38:57 2016 +0000
+++ b/src/make-quickutils.lisp Thu Apr 14 13:32:31 2016 +0000
@@ -12,6 +12,7 @@
:tree-member-p
:tree-collect
:with-gensyms
+ :zip
:map-tree
)
:package "BONES.QUICKUTILS")
--- a/src/quickutils.lisp Wed Apr 13 17:38:57 2016 +0000
+++ b/src/quickutils.lisp Thu Apr 14 13:32:31 2016 +0000
@@ -2,7 +2,7 @@
;;;; See http://quickutil.org for details.
;;;; To regenerate:
-;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:DEFINE-CONSTANT :SET-EQUAL :CURRY :SWITCH :ENSURE-BOOLEAN :WHILE :UNTIL :TREE-MEMBER-P :TREE-COLLECT :WITH-GENSYMS :MAP-TREE) :ensure-package T :package "BONES.QUICKUTILS")
+;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:DEFINE-CONSTANT :SET-EQUAL :CURRY :SWITCH :ENSURE-BOOLEAN :WHILE :UNTIL :TREE-MEMBER-P :TREE-COLLECT :WITH-GENSYMS :ZIP :MAP-TREE) :ensure-package T :package "BONES.QUICKUTILS")
(eval-when (:compile-toplevel :load-toplevel :execute)
(unless (find-package "BONES.QUICKUTILS")
@@ -18,7 +18,8 @@
:CURRY :STRING-DESIGNATOR
:WITH-GENSYMS :EXTRACT-FUNCTION-NAME
:SWITCH :ENSURE-BOOLEAN :UNTIL :WHILE
- :TREE-MEMBER-P :TREE-COLLECT :MAP-TREE))))
+ :TREE-MEMBER-P :TREE-COLLECT
+ :TRANSPOSE :ZIP :MAP-TREE))))
(defun %reevaluate-constant (name value test)
(if (not (boundp name))
@@ -254,6 +255,17 @@
:append (tree-collect predicate item)))))
+ (defun transpose (lists)
+ "Analog to matrix transpose for a list of lists given by `lists`."
+ (apply #'mapcar #'list lists))
+
+
+ (defun zip (&rest lists)
+ "Take a tuple of lists and turn them into a list of
+tuples. Equivalent to `unzip`."
+ (transpose lists))
+
+
(defun map-tree (function tree)
"Map `function` to each of the leave of `tree`."
(check-type tree cons)
@@ -269,6 +281,6 @@
(eval-when (:compile-toplevel :load-toplevel :execute)
(export '(define-constant set-equal curry switch eswitch cswitch
ensure-boolean while until tree-member-p tree-collect with-gensyms
- with-unique-names map-tree)))
+ with-unique-names zip map-tree)))
;;;; END OF quickutils.lisp ;;;;
--- a/src/utils.lisp Wed Apr 13 17:38:57 2016 +0000
+++ b/src/utils.lisp Thu Apr 14 13:32:31 2016 +0000
@@ -1,9 +1,19 @@
(in-package #:bones.utils)
-;; TODO: learn setf expanders and do this right.
-(defmacro push-if-new (thing list-place)
- `(not (eql ,list-place (pushnew ,thing ,list-place))))
+(defmacro push-if-new (thing place
+ &environment env
+ &key key (test 'eql))
+ "Push `thing` into the list at `place` if it's not already there.
+
+ Returns whether `thing` was actually pushed. This function is basically
+ `pushnew` except for the return value.
-(defun vector-push-extend-all (vector &rest things)
- (loop :for thing :in things :do
- (vector-push-extend thing vector)))
+ "
+ (multiple-value-bind (temps exprs stores store-expr access-expr)
+ (get-setf-expansion place env)
+ (declare (ignore stores store-expr))
+ (with-gensyms (current result)
+ `(let* (,@(zip temps exprs)
+ (,current ,access-expr)
+ (,result (pushnew ,thing ,place :key ,key :test ,test)))
+ (not (eql ,current ,result))))))