add DO-VECTOR-DATA, remove special case from VECTOR-MAP-INTO
authorNikodemus Siivola <nikodemus@random-state.net>
Sun, 27 May 2012 10:44:12 +0000 (13:44 +0300)
committerNikodemus Siivola <nikodemus@random-state.net>
Sun, 27 May 2012 12:41:53 +0000 (15:41 +0300)
  DO-VECTOR-DATA is like DOVECTOR, but uses WITH-ARRAY-DATA and grabs the
  right reffer function so there's no per-element dispatch.

  Since MAP used DOSEQUENCE for for-effect/arity-1 case, and DOSEQEUNCE in
  turn uses DOVECTOR, replacing DOVECTOR there with DO-VECTOR-DATA we get the
  a performance boost while being able to drop the special case in
  VECTOR-MAP-INTO.

  Add a test for which the special case was broken: mapping a list into a
  vector.

src/code/array.lisp
src/code/seq.lisp
tests/map-tests.impure.lisp

index 55c172d..0d44b09 100644 (file)
@@ -339,9 +339,30 @@ of specialized arrays is supported."
                        (svref ,',table-name tag)))))))
   (def !find-data-vector-setter %%data-vector-setters%%)
   (def !find-data-vector-setter/check-bounds %%data-vector-setters/check-bounds%%)
-  (def !find-data-vector-reffer %%data-vector-reffers%%)
+  ;; Used by DO-VECTOR-DATA -- which in turn appears in DOSEQUENCE expansion,
+  ;; meaning we can have post-build dependences on this.
+  (def %find-data-vector-reffer %%data-vector-reffers%%)
   (def !find-data-vector-reffer/check-bounds %%data-vector-reffers/check-bounds%%))
 
+;;; Like DOVECTOR, but more magical -- can't use this on host.
+(defmacro do-vector-data ((elt vector &optional result) &body body)
+  (multiple-value-bind (forms decls) (parse-body body :doc-string-allowed nil)
+    (with-unique-names (index vec start end ref)
+      `(with-array-data ((,vec ,vector)
+                         (,start)
+                         (,end)
+                         :check-fill-pointer t)
+         (let ((,ref (%find-data-vector-reffer ,vec)))
+           (do ((,index ,start (1+ ,index)))
+               ((>= ,index ,end)
+                (let ((,elt nil))
+                  ,@(filter-dolist-declarations decls)
+                  ,elt
+                  ,result))
+             (let ((,elt (funcall ,ref ,vec ,index)))
+               ,@decls
+               (tagbody ,@forms))))))))
+
 (macrolet ((%ref (accessor-getter extra-params)
              `(funcall (,accessor-getter array) array index ,@extra-params))
            (define (accessor-name slow-accessor-name accessor-getter
@@ -375,7 +396,7 @@ of specialized arrays is supported."
                         (declare (ignore end))
                         (,accessor-name vector index ,@extra-params)))))))
   (define hairy-data-vector-ref slow-hairy-data-vector-ref
-    !find-data-vector-reffer
+    %find-data-vector-reffer
     nil (progn))
   (define hairy-data-vector-set slow-hairy-data-vector-set
     !find-data-vector-setter
index 32d6c8d..bc678fd 100644 (file)
@@ -781,7 +781,7 @@ many elements are copied."
         (let ((,sequence ,s))
           (seq-dispatch ,sequence
             (dolist (,e ,sequence ,return) ,@body)
-            (dovector (,e ,sequence ,return) ,@body)
+            (do-vector-data (,e ,sequence ,return) ,@body)
             (multiple-value-bind (state limit from-end step endp elt)
                 (sb!sequence:make-sequence-iterator ,sequence)
               (do ((state state (funcall step ,sequence state from-end)))
@@ -1070,24 +1070,13 @@ many elements are copied."
            (type list sequences))
   (let ((index start))
     (declare (type index index))
-    (if (and sequences (null (rest sequences)))
-        ;; do it manually when there is 1 input sequence
-        (with-array-data ((src (first sequences)) (src-start) (src-end)
-                          :check-fill-pointer t)
-          (let ((src-index src-start))
-            (declare (type index src-index))
-            (loop until (or (eql src-index src-end)
-                            (eql index end))
-                  do (setf (aref data index) (funcall fun (aref src src-index)))
-                     (incf index)
-                     (incf src-index))))
-        (block mapping
-          (map-into-lambda sequences (&rest args)
-            (declare (truly-dynamic-extent args))
-            (when (eql index end)
-              (return-from mapping))
-            (setf (aref data index) (apply fun args))
-            (incf index))))
+    (block mapping
+      (map-into-lambda sequences (&rest args)
+        (declare (truly-dynamic-extent args))
+        (when (eql index end)
+          (return-from mapping))
+        (setf (aref data index) (apply fun args))
+        (incf index)))
     index))
 
 ;;; Uses the machinery of (MAP NIL ...). For non-vectors we avoid
index d8a11d4..ee984dd 100644 (file)
            :arg-seqs (*list-2* *list-2* *vector-30*)
            :arg-types (list list vector)))
 
+(test-util:with-test (:name :map-into-vector-from-list)
+  (map-into (eval (make-array 10))
+            #'list
+            (make-list 10)))
+
 ;;; success