0.8.1.9:
[sbcl.git] / src / code / array.lisp
index f2b646a..d8d04e9 100644 (file)
 
 ;;; These functions are only needed by the interpreter, 'cause the
 ;;; compiler inlines them.
-(macrolet ((def-frob (name)
+(macrolet ((def (name)
             `(progn
                (defun ,name (array)
                  (,name array))
                (defun (setf ,name) (value array)
                  (setf (,name array) value)))))
-  (def-frob %array-fill-pointer)
-  (def-frob %array-fill-pointer-p)
-  (def-frob %array-available-elements)
-  (def-frob %array-data-vector)
-  (def-frob %array-displacement)
-  (def-frob %array-displaced-p))
+  (def %array-fill-pointer)
+  (def %array-fill-pointer-p)
+  (def %array-available-elements)
+  (def %array-data-vector)
+  (def %array-displacement)
+  (def %array-displaced-p))
 
 (defun %array-rank (array)
   (%array-rank array))
 (defun %with-array-data (array start end)
   (%with-array-data-macro array start end :fail-inline? t))
 
+(defun %data-vector-and-index (array index)
+  (if (array-header-p array)
+      (multiple-value-bind (vector index)
+          (%with-array-data array index nil)
+        (values vector index))
+      (values array index)))
+
 ;;; It'd waste space to expand copies of error handling in every
 ;;; inline %WITH-ARRAY-DATA, so we have them call this function
 ;;; instead. This is just a wrapper which is known never to return.
 (defun failed-%with-array-data (array start end)
   (declare (notinline %with-array-data))
   (%with-array-data array start end)
-  (error "internal error: shouldn't be here with valid parameters"))
+  (bug "called FAILED-%WITH-ARRAY-DATA with valid array parameters?"))
 \f
 ;;;; MAKE-ARRAY
-
 (eval-when (:compile-toplevel :execute)
   (sb!xc:defmacro pick-vector-type (type &rest specs)
     `(cond ,@(mapcar (lambda (spec)
      ;; FIXME: The data here are redundant with
      ;; *SPECIALIZED-ARRAY-ELEMENT-TYPE-PROPERTIES*.
      (pick-vector-type type
+       (nil (values #.sb!vm:simple-array-nil-widetag 0))
        (base-char (values #.sb!vm:simple-string-widetag #.sb!vm:n-byte-bits))
        (bit (values #.sb!vm:simple-bit-vector-widetag 1))
        ((unsigned-byte 2)
     (when (and displaced-index-offset (null displaced-to))
       (error "can't specify :DISPLACED-INDEX-OFFSET without :DISPLACED-TO"))
     (if (and simple (= array-rank 1))
-       ;; Its a (simple-array * (*))
+       ;; it's a (SIMPLE-ARRAY * (*))
        (multiple-value-bind (type n-bits)
            (%vector-widetag-and-n-bits element-type)
          (declare (type (unsigned-byte 8) type)
-                  (type (integer 1 256) n-bits))
+                  (type (integer 0 256) n-bits))
          (let* ((length (car dimensions))
                 (array (allocate-vector
                         type
                       length))
              (replace array initial-contents))
            array))
-       ;; It's either a complex array or a multidimensional array.
+       ;; it's either a complex array or a multidimensional array.
        (let* ((total-size (reduce #'* dimensions))
               (data (or displaced-to
                         (data-vector-from-inits
              (setf (%array-dimension array axis) dim)
              (incf axis)))
          array))))
-       
+
 ;;; DATA-VECTOR-FROM-INITS returns a simple vector that has the
 ;;; specified array characteristics. Dimensions is only used to pass
 ;;; to FILL-DATA-VECTOR for error checking on the structure of
       #!+long-float long-float
       (complex single-float)
       (complex double-float)
-      #!+long-float (complex long-float))))
+      #!+long-float (complex long-float)
+      nil)))
     
 (defun hairy-data-vector-ref (array index)
   (with-array-data ((vector array) (index index) (end))
-    (declare (ignore end) (optimize (safety 3)))
+    (declare (ignore end))
     (etypecase vector .
               #.(mapcar (lambda (type)
                           (let ((atype `(simple-array ,type (*))))
                                                index))))
                         *specialized-array-element-types*))))
 
+;;; (Ordinary DATA-VECTOR-REF usage compiles into a vop, but
+;;; DATA-VECTOR-REF is also FOLDABLE, and this ordinary function
+;;; definition is needed for the compiler to use in constant folding.)
+(defun data-vector-ref (array index)
+  (hairy-data-vector-ref array index))
+
 (defun hairy-data-vector-set (array index new-value)
   (with-array-data ((vector array) (index index) (end))
-    (declare (ignore end) (optimize (safety 3)))
+    (declare (ignore end))
     (etypecase vector .
               #.(mapcar (lambda (type)
                           (let ((atype `(simple-array ,type (*))))
                               (data-vector-set (the ,atype vector)
                                                index
                                                (the ,type
-                                                 new-value)))))
+                                                 new-value))
+                              ;; For specialized arrays, the return
+                              ;; from data-vector-set would have to
+                              ;; be reboxed to be a (Lisp) return
+                              ;; value; instead, we use the
+                              ;; already-boxed value as the return.
+                              new-value)))
                         *specialized-array-element-types*))))
 
 (defun %array-row-major-index (array subscripts
          (declare (list subs) (fixnum axis chunk-size result))
          (let ((index (car subs))
                (dim (%array-dimension array axis)))
-           (declare (fixnum index dim))
-           (unless (< -1 index dim)
+           (declare (fixnum dim))
+           (unless (and (fixnump index) (< -1 index dim))
              (if invalid-index-error-p
-                 (error "invalid index ~W~[~;~:; on axis ~:*~W~] in ~S"
-                        index axis array)
+                 (error 'simple-type-error
+                        :format-control "invalid index ~W~[~;~:; on axis ~:*~W~] in ~S"
+                        :format-arguments (list index axis array)
+                        :datum index
+                        :expected-type `(integer 0 (,dim)))
                  (return-from %array-row-major-index nil)))
-           (incf result (* chunk-size index))
+           (incf result (* chunk-size (the fixnum index)))
            (setf chunk-size (* chunk-size dim))))
-       (let ((index (first subscripts)))
-         (unless (< -1 index (length (the (simple-array * (*)) array)))
+       (let ((index (first subscripts))
+             (length (length (the (simple-array * (*)) array))))
+         (unless (and (fixnump index) (< -1 index length))
            (if invalid-index-error-p
-               (error "invalid index ~W in ~S" index array)
+               ;; FIXME: perhaps this should share a format-string
+               ;; with INVALID-ARRAY-INDEX-ERROR or
+               ;; INDEX-TOO-LARGE-ERROR?
+               (error 'simple-type-error
+                      :format-control "invalid index ~W in ~S"
+                      :format-arguments (list index array)
+                      :datum index
+                      :expected-type `(integer 0 (,length)))
                (return-from %array-row-major-index nil)))
          index))))
 
 (defun array-in-bounds-p (array &rest subscripts)
   #!+sb-doc
-  "Return T if the Subscipts are in bounds for the Array, Nil otherwise."
+  "Return T if the SUBSCIPTS are in bounds for the ARRAY, NIL otherwise."
   (if (%array-row-major-index array subscripts nil)
       t))
 
 
 (defun aref (array &rest subscripts)
   #!+sb-doc
-  "Return the element of the Array specified by the Subscripts."
+  "Return the element of the ARRAY specified by the SUBSCRIPTS."
   (row-major-aref array (%array-row-major-index array subscripts)))
 
 (defun %aset (array &rest stuff)
 ;;;  ZOO
 ;;; But that doesn't seem to be what happens in CMU CL.
 ;;;
+;;; KLUDGE: this is probably because ANSI, in its wisdom (CLHS
+;;; 5.1.2.5) requires implementations to support
+;;;   (SETF (APPLY #'AREF ...) ...)
+;;; [and also #'BIT and #'SBIT].  Yes, this is terrifying, and it's
+;;; also terrifying that this sequence of definitions causes it to
+;;; work.
+;;;
 ;;; Also, it would be nice to make DESCRIBE FOO tell whether a symbol
 ;;; has a setf expansion and/or a setf function defined.
 
   "Return the type of the elements of the array"
   (let ((widetag (widetag-of array)))
     (macrolet ((pick-element-type (&rest stuff)
-                `(cond ,@(mapcar #'(lambda (stuff)
-                                     (cons
-                                      (let ((item (car stuff)))
-                                        (cond ((eq item t)
-                                               t)
-                                              ((listp item)
-                                               (cons 'or
-                                                     (mapcar (lambda (x)
-                                                               `(= widetag ,x))
-                                                             item)))
-                                              (t
-                                               `(= widetag ,item))))
-                                      (cdr stuff)))
-                                                  stuff))))
+                `(cond ,@(mapcar (lambda (stuff)
+                                   (cons
+                                    (let ((item (car stuff)))
+                                      (cond ((eq item t)
+                                             t)
+                                            ((listp item)
+                                             (cons 'or
+                                                   (mapcar (lambda (x)
+                                                             `(= widetag ,x))
+                                                           item)))
+                                            (t
+                                             `(= widetag ,item))))
+                                    (cdr stuff)))
+                                 stuff))))
       ;; FIXME: The data here are redundant with
       ;; *SPECIALIZED-ARRAY-ELEMENT-TYPE-PROPERTIES*.
       (pick-element-type
+       (sb!vm:simple-array-nil-widetag nil)
        ((sb!vm:simple-string-widetag sb!vm:complex-string-widetag) 'base-char)
        ((sb!vm:simple-bit-vector-widetag
         sb!vm:complex-bit-vector-widetag) 'bit)
          (declare (ignore start end))
          (array-element-type array)))
        (t
-       (error "~S is not an array." array))))))
+       (error 'type-error :datum array :expected-type 'array))))))
 
 (defun array-rank (array)
   #!+sb-doc
   (unless (array-header-p vector)
     (macrolet ((frob (name &rest things)
                 `(etypecase ,name
+                   ((simple-array nil (*)) (error 'cell-error
+                                            :name 'nil-array-element))
                    ,@(mapcar (lambda (thing)
                                (destructuring-bind (type-spec fill-value)
                                    thing
 
 (defun zap-array-data-aux (old-data old-dims offset new-data new-dims)
   (declare (fixnum offset))
-  (let ((limits (mapcar #'(lambda (x y)
-                           (declare (fixnum x y))
-                           (1- (the fixnum (min x y))))
+  (let ((limits (mapcar (lambda (x y)
+                         (declare (fixnum x y))
+                         (1- (the fixnum (min x y))))
                        old-dims new-dims)))
     (macrolet ((bump-index-list (index limits)
                 `(do ((subscripts ,index (cdr subscripts))