2746fc7667d9

Add `gathering-vector`
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Mon, 27 Feb 2017 13:52:44 +0000
parents 85823854b8cb
children 4d881c990060
branches/tags (none)
files losh.lisp package.lisp

Changes

--- a/losh.lisp	Wed Feb 22 11:19:29 2017 +0000
+++ b/losh.lisp	Mon Feb 27 13:52:44 2017 +0000
@@ -480,7 +480,7 @@
         ,else))))
 
 (defmacro gathering (&body body)
-  "Run `body` to gather some things and return them.
+  "Run `body` to gather some things and return a fresh list of them.
 
   `body` will be executed with the symbol `gather` bound to a function of one
   argument.  Once `body` has finished, a list of everything `gather` was called
@@ -516,6 +516,46 @@
         ,@body)
       (queue-contents ,result))))
 
+(defmacro gathering-vector (options &body body)
+  "Run `body` to gather some things and return a fresh vector of them.
+
+  `body` will be executed with the symbol `gather` bound to a function of one
+  argument.  Once `body` has finished, a vector of everything `gather` was
+  called on will be returned.  This vector will be adjustable and have a fill
+  pointer.
+
+  It's handy for pulling results out of code that executes procedurally and
+  doesn't return anything, like `maphash` or Alexandria's `map-permutations`.
+
+  The `gather` function can be passed to other functions, but should not be
+  retained once the `gathering` form has returned (it would be useless to do so
+  anyway).
+
+  Examples:
+
+    (gathering-vector ()
+      (dotimes (i 5)
+        (gather i))
+    =>
+    #(0 1 2 3 4)
+
+    (gathering-vector ()
+      (mapc #'gather '(1 2 3))
+      (mapc #'gather '(a b)))
+    =>
+    #(1 2 3 a b)
+
+  "
+  (destructuring-bind (&key (size 16))
+      options
+    (with-gensyms (result)
+      `(let ((,result (make-array ,size :adjustable t :fill-pointer 0)))
+         (flet ((gather (item)
+                  (vector-push-extend item ,result)))
+           (declare (dynamic-extent #'gather))
+           ,@body)
+         ,result))))
+
 (defmacro when-let* (binding-forms &body body)
   "Bind the forms in `binding-forms` in order, short-circuiting on `nil`.
 
--- a/package.lisp	Wed Feb 22 11:19:29 2017 +0000
+++ b/package.lisp	Mon Feb 27 13:52:44 2017 +0000
@@ -61,6 +61,7 @@
     :when-found
     :if-found
     :gathering
+    :gathering-vector
     :gather
     :when-let*
     :multiple-value-bind*))