(values array index)))
\f
;;;; MAKE-ARRAY
-(eval-when (:compile-toplevel :execute)
- (sb!xc:defmacro pick-vector-type (type &rest specs)
- `(cond ,@(mapcar (lambda (spec)
- `(,(if (eq (car spec) t)
- t
- `(subtypep ,type ',(car spec)))
- ,@(cdr spec)))
- specs))))
-
-;;; These functions are used in the implementation of MAKE-ARRAY for
-;;; complex arrays. There are lots of transforms to simplify
-;;; MAKE-ARRAY for various easy cases, but not for all reasonable
-;;; cases, so e.g. as of sbcl-0.6.6 we still make full calls to
-;;; MAKE-ARRAY for any non-simple array. Thus, there's some value to
-;;; making this somewhat efficient, at least not doing full calls to
-;;; SUBTYPEP in the easy cases.
+(defun %integer-vector-widetag-and-n-bits (signed high)
+ (let ((unsigned-table
+ #.(let ((map (make-array (1+ sb!vm:n-word-bits))))
+ (loop for saetp across
+ (reverse sb!vm:*specialized-array-element-type-properties*)
+ for ctype = (sb!vm:saetp-ctype saetp)
+ when (and (numeric-type-p ctype)
+ (eq (numeric-type-class ctype) 'integer)
+ (zerop (numeric-type-low ctype)))
+ do (fill map (cons (sb!vm:saetp-typecode saetp)
+ (sb!vm:saetp-n-bits saetp))
+ :end (1+ (integer-length (numeric-type-high ctype)))))
+ map))
+ (signed-table
+ #.(let ((map (make-array (1+ sb!vm:n-word-bits))))
+ (loop for saetp across
+ (reverse sb!vm:*specialized-array-element-type-properties*)
+ for ctype = (sb!vm:saetp-ctype saetp)
+ when (and (numeric-type-p ctype)
+ (eq (numeric-type-class ctype) 'integer)
+ (minusp (numeric-type-low ctype)))
+ do (fill map (cons (sb!vm:saetp-typecode saetp)
+ (sb!vm:saetp-n-bits saetp))
+ :end (+ (integer-length (numeric-type-high ctype)) 2)))
+ map)))
+ (cond ((> high sb!vm:n-word-bits)
+ (values #.sb!vm:simple-vector-widetag #.sb!vm:n-word-bits))
+ (signed
+ (let ((x (aref signed-table high)))
+ (values (car x) (cdr x))))
+ (t
+ (let ((x (aref unsigned-table high)))
+ (values (car x) (cdr x)))))))
+
+;;; This is a bit complicated, but calling subtypep over all
+;;; specialized types is exceedingly slow
(defun %vector-widetag-and-n-bits (type)
- (case type
- ;; Pick off some easy common cases.
- ;;
- ;; (Perhaps we should make a much more exhaustive table of easy
- ;; common cases here. Or perhaps the effort would be better spent
- ;; on smarter compiler transforms which do the calculation once
- ;; and for all in any reasonable user programs.)
- ((t)
- (values #.sb!vm:simple-vector-widetag #.sb!vm:n-word-bits))
- ((base-char standard-char #!-sb-unicode character)
- (values #.sb!vm:simple-base-string-widetag #.sb!vm:n-byte-bits))
- #!+sb-unicode
- ((character)
- (values #.sb!vm:simple-character-string-widetag #.sb!vm:n-word-bits))
- ((bit)
- (values #.sb!vm:simple-bit-vector-widetag 1))
- ;; OK, we have to wade into SUBTYPEPing after all.
- (t
- (unless *type-system-initialized*
- (bug "SUBTYPEP dispatch for MAKE-ARRAY before the type system is ready"))
- #.`(pick-vector-type type
- ,@(map 'list
- (lambda (saetp)
- `(,(sb!vm:saetp-specifier saetp)
- (values ,(sb!vm:saetp-typecode saetp)
- ,(sb!vm:saetp-n-bits saetp))))
- sb!vm:*specialized-array-element-type-properties*)))))
-
-(defun %complex-vector-widetag (type)
- (case type
- ;; Pick off some easy common cases.
- ((t)
- #.sb!vm:complex-vector-widetag)
- ((base-char #!-sb-unicode character)
- #.sb!vm:complex-base-string-widetag)
- #!+sb-unicode
- ((character)
- #.sb!vm:complex-character-string-widetag)
- ((nil)
- #.sb!vm:complex-vector-nil-widetag)
- ((bit)
- #.sb!vm:complex-bit-vector-widetag)
- ;; OK, we have to wade into SUBTYPEPing after all.
- (t
- (pick-vector-type type
- (nil #.sb!vm:complex-vector-nil-widetag)
- #!-sb-unicode
- (character #.sb!vm:complex-base-string-widetag)
- #!+sb-unicode
- (base-char #.sb!vm:complex-base-string-widetag)
- #!+sb-unicode
- (character #.sb!vm:complex-character-string-widetag)
- (bit #.sb!vm:complex-bit-vector-widetag)
- (t #.sb!vm:complex-vector-widetag)))))
+ (macrolet ((with-parameters ((arg-type &key intervals)
+ (&rest args) &body body)
+ (let ((type-sym (gensym)))
+ `(let (,@(loop for arg in args
+ collect `(,arg '*)))
+ (declare (ignorable ,@args))
+ (when (consp type)
+ (let ((,type-sym (cdr type)))
+ (block nil
+ ,@(loop for arg in args
+ collect
+ `(cond ((consp ,type-sym)
+ (let ((value (pop ,type-sym)))
+ (if (or (eq value '*)
+ (typep value ',arg-type)
+ ,(if intervals
+ `(and (consp value)
+ (null (cdr value))
+ (typep (car value)
+ ',arg-type))))
+ (setf ,arg value)
+ (ill-type))))
+ ((null ,type-sym)
+ (return))
+ (t
+ (ill-type)))))
+ (when ,type-sym
+ (ill-type))))
+ ,@body)))
+ (result (widetag)
+ (let ((value (symbol-value widetag)))
+ `(values ,value
+ ,(sb!vm:saetp-n-bits
+ (find value
+ sb!vm:*specialized-array-element-type-properties*
+ :key #'sb!vm:saetp-typecode))))))
+ (flet ((ill-type ()
+ (error "Invalid type specifier: ~s" type))
+ (integer-interval-widetag (low high)
+ (if (minusp low)
+ (%integer-vector-widetag-and-n-bits
+ t
+ (1+ (max (integer-length low) (integer-length high))))
+ (%integer-vector-widetag-and-n-bits
+ nil
+ (max (integer-length low) (integer-length high))))))
+ (let* ((consp (consp type))
+ (type-name (if consp
+ (car type)
+ type)))
+ (case type-name
+ ((t)
+ (when consp
+ (ill-type))
+ (result sb!vm:simple-vector-widetag))
+ ((base-char standard-char #!-sb-unicode character)
+ (when consp
+ (ill-type))
+ (result sb!vm:simple-base-string-widetag))
+ #!+sb-unicode
+ ((character extended-char)
+ (when consp
+ (ill-type))
+ (result sb!vm:simple-character-string-widetag))
+ (bit
+ (when consp
+ (ill-type))
+ (result sb!vm:simple-bit-vector-widetag))
+ (fixnum
+ (when consp
+ (ill-type))
+ (result sb!vm:simple-array-fixnum-widetag))
+ (unsigned-byte
+ (with-parameters ((integer 1)) (high)
+ (if (eq high '*)
+ (result sb!vm:simple-vector-widetag)
+ (%integer-vector-widetag-and-n-bits nil high))))
+ (signed-byte
+ (with-parameters ((integer 1)) (high)
+ (if (eq high '*)
+ (result sb!vm:simple-vector-widetag)
+ (%integer-vector-widetag-and-n-bits t high))))
+ (double-float
+ (with-parameters (double-float :intervals t) (low high)
+ (if (and (not (eq low '*))
+ (not (eq high '*))
+ (if (or (consp low) (consp high))
+ (>= (type-bound-number low) (type-bound-number high))
+ (> low high)))
+ (result sb!vm:simple-array-nil-widetag)
+ (result sb!vm:simple-array-double-float-widetag))))
+ (single-float
+ (with-parameters (single-float :intervals t) (low high)
+ (if (and (not (eq low '*))
+ (not (eq high '*))
+ (if (or (consp low) (consp high))
+ (>= (type-bound-number low) (type-bound-number high))
+ (> low high)))
+ (result sb!vm:simple-array-nil-widetag)
+ (result sb!vm:simple-array-single-float-widetag))))
+ (mod
+ (if (and (consp type)
+ (consp (cdr type))
+ (null (cddr type))
+ (typep (cadr type) '(integer 1)))
+ (%integer-vector-widetag-and-n-bits
+ nil (integer-length (1- (cadr type))))
+ (ill-type)))
+ #!+long-float
+ (long-float
+ (with-parameters (long-float :intervals t) (low high)
+ (if (and (not (eq low '*))
+ (not (eq high '*))
+ (if (or (consp low) (consp high))
+ (>= (type-bound-number low) (type-bound-number high))
+ (> low high)))
+ (result sb!vm:simple-array-nil-widetag)
+ (result sb!vm:simple-array-long-float-widetag))))
+ (integer
+ (with-parameters (integer :intervals t) (low high)
+ (let ((low (if (consp low)
+ (1+ (car low))
+ low))
+ (high (if (consp high)
+ (1- (car high))
+ high)))
+ (cond ((or (eq high '*)
+ (eq low '*))
+ (result sb!vm:simple-vector-widetag))
+ ((> low high)
+ (result sb!vm:simple-array-nil-widetag))
+ (t
+ (integer-interval-widetag low high))))))
+ (complex
+ (with-parameters (t) (subtype)
+ (if (eq subtype '*)
+ (result sb!vm:simple-vector-widetag)
+ (let ((ctype (specifier-type type)))
+ (cond ((eq ctype *empty-type*)
+ (result sb!vm:simple-array-nil-widetag))
+ ((union-type-p ctype)
+ (cond ((csubtypep ctype (specifier-type '(complex double-float)))
+ (result
+ sb!vm:simple-array-complex-double-float-widetag))
+ ((csubtypep ctype (specifier-type '(complex single-float)))
+ (result
+ sb!vm:simple-array-complex-single-float-widetag))
+ #!+long-float
+ ((csubtypep ctype (specifier-type '(complex long-float)))
+ (result
+ sb!vm:simple-array-complex-long-float-widetag))
+ (t
+ (result sb!vm:simple-vector-widetag))))
+ (t
+ (case (numeric-type-format ctype)
+ (double-float
+ (result
+ sb!vm:simple-array-complex-double-float-widetag))
+ (single-float
+ (result
+ sb!vm:simple-array-complex-single-float-widetag))
+ #!+long-float
+ (long-float
+ (result
+ sb!vm:simple-array-complex-long-float-widetag))
+ (t
+ (result sb!vm:simple-vector-widetag)))))))))
+ ((nil)
+ (result sb!vm:simple-array-nil-widetag))
+ (t
+ (block nil
+ (let ((ctype
+ (handler-case (specifier-type type)
+ (parse-unknown-type ()
+ (return (result sb!vm:simple-vector-widetag))))))
+ (if (union-type-p ctype)
+ (let ((types (union-type-types ctype)))
+ (cond ((not (every #'numeric-type-p types))
+ (result sb!vm:simple-vector-widetag))
+ ((csubtypep ctype (specifier-type 'integer))
+ (integer-interval-widetag
+ (reduce #'min types :key #'numeric-type-low)
+ (reduce #'max types :key #'numeric-type-high)))
+ ((csubtypep ctype (specifier-type 'double-float))
+ (result sb!vm:simple-array-double-float-widetag))
+ ((csubtypep ctype (specifier-type 'single-float))
+ (result sb!vm:simple-array-single-float-widetag))
+ #!+long-float
+ ((csubtypep ctype (specifier-type 'long-float))
+ (result sb!vm:simple-array-long-float-widetag))
+ (t
+ (result sb!vm:simple-vector-widetag))))
+ (let ((expansion (type-specifier ctype)))
+ (if (equal expansion type)
+ (result sb!vm:simple-vector-widetag)
+ (%vector-widetag-and-n-bits expansion))))))))))))
+
+(defun %complex-vector-widetag (widetag)
+ (macrolet ((make-case ()
+ `(case widetag
+ ,@(loop for saetp across sb!vm:*specialized-array-element-type-properties*
+ for complex = (sb!vm:saetp-complex-typecode saetp)
+ when complex
+ collect (list (sb!vm:saetp-typecode saetp) complex))
+ (t
+ #.sb!vm:complex-vector-widetag))))
+ (make-case)))
(defglobal %%simple-array-n-bits%% (make-array (1+ sb!vm:widetag-mask)))
#.(loop for info across sb!vm:*specialized-array-element-type-properties*
n-bits)
sb!vm:n-word-bits))))
-(defun make-array (dimensions &key
- (element-type t)
- (initial-element nil initial-element-p)
- (initial-contents nil initial-contents-p)
- adjustable fill-pointer
- displaced-to displaced-index-offset)
+(defun array-underlying-widetag (array)
+ (macrolet ((make-case ()
+ `(case widetag
+ ,@(loop for saetp across sb!vm:*specialized-array-element-type-properties*
+ for complex = (sb!vm:saetp-complex-typecode saetp)
+ when complex
+ collect (list complex (sb!vm:saetp-typecode saetp)))
+ ((,sb!vm:simple-array-widetag
+ ,sb!vm:complex-vector-widetag
+ ,sb!vm:complex-array-widetag)
+ (with-array-data ((array array) (start) (end))
+ (declare (ignore start end))
+ (widetag-of array)))
+ (t
+ widetag))))
+ (let ((widetag (widetag-of array)))
+ (make-case))))
+
+;;; Widetag is the widetag of the underlying vector,
+;;; it'll be the same as the resulting array widetag only for simple vectors
+(defun %make-array (dimensions widetag n-bits
+ &key
+ element-type
+ (initial-element nil initial-element-p)
+ (initial-contents nil initial-contents-p)
+ adjustable fill-pointer
+ displaced-to displaced-index-offset)
+ (declare (ignore element-type))
(let* ((dimensions (if (listp dimensions) dimensions (list dimensions)))
(array-rank (length (the list dimensions)))
(simple (and (null fill-pointer)
(not adjustable)
(null displaced-to))))
(declare (fixnum array-rank))
- (when (and displaced-index-offset (null displaced-to))
- (error "can't specify :DISPLACED-INDEX-OFFSET without :DISPLACED-TO"))
- (when (and displaced-to
- (arrayp displaced-to)
- (not (equal (array-element-type displaced-to)
- (upgraded-array-element-type element-type))))
- (error "Array element type of :DISPLACED-TO array does not match specified element type"))
- (if (and simple (= array-rank 1))
- ;; 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 0 256) n-bits))
- (let* ((length (car dimensions))
- (array (allocate-vector-with-widetag type length n-bits)))
- (declare (type index length))
- (when initial-element-p
- (fill array initial-element))
- (when initial-contents-p
- (when initial-element-p
- (error "can't specify both :INITIAL-ELEMENT and ~
+ (cond ((and displaced-index-offset (null displaced-to))
+ (error "can't specify :DISPLACED-INDEX-OFFSET without :DISPLACED-TO"))
+ ((and simple (= array-rank 1))
+ ;; it's a (SIMPLE-ARRAY * (*))
+ (let* ((length (car dimensions))
+ (array (allocate-vector-with-widetag widetag length n-bits)))
+ (declare (type index length))
+ (when initial-element-p
+ (fill array initial-element))
+ (when initial-contents-p
+ (when initial-element-p
+ (error "can't specify both :INITIAL-ELEMENT and ~
:INITIAL-CONTENTS"))
- (unless (= length (length initial-contents))
- (error "There are ~W elements in the :INITIAL-CONTENTS, but ~
+ (unless (= length (length initial-contents))
+ (error "There are ~W elements in the :INITIAL-CONTENTS, but ~
the vector length is ~W."
- (length initial-contents)
- length))
- (replace array initial-contents))
- array))
- ;; it's either a complex array or a multidimensional array.
- (let* ((total-size (reduce #'* dimensions))
- (data (or displaced-to
- (data-vector-from-inits
- dimensions total-size element-type nil
- initial-contents initial-contents-p
- initial-element initial-element-p)))
- (array (make-array-header
- (cond ((= array-rank 1)
- (%complex-vector-widetag element-type))
- (simple sb!vm:simple-array-widetag)
- (t sb!vm:complex-array-widetag))
- array-rank)))
- (cond (fill-pointer
- (unless (= array-rank 1)
- (error "Only vectors can have fill pointers."))
- (let ((length (car dimensions)))
- (declare (fixnum length))
- (setf (%array-fill-pointer array)
- (cond ((eq fill-pointer t)
- length)
- (t
- (unless (and (fixnump fill-pointer)
- (>= fill-pointer 0)
- (<= fill-pointer length))
- ;; FIXME: should be TYPE-ERROR?
- (error "invalid fill-pointer ~W"
- fill-pointer))
- fill-pointer))))
- (setf (%array-fill-pointer-p array) t))
- (t
- (setf (%array-fill-pointer array) total-size)
- (setf (%array-fill-pointer-p array) nil)))
- (setf (%array-available-elements array) total-size)
- (setf (%array-data-vector array) data)
- (setf (%array-displaced-from array) nil)
- (cond (displaced-to
- (when (or initial-element-p initial-contents-p)
- (error "Neither :INITIAL-ELEMENT nor :INITIAL-CONTENTS ~
+ (length initial-contents)
+ length))
+ (replace array initial-contents))
+ array))
+ ((and (arrayp displaced-to)
+ (/= (array-underlying-widetag displaced-to) widetag))
+ (error "Array element type of :DISPLACED-TO array does not match specified element type"))
+ (t
+ ;; it's either a complex array or a multidimensional array.
+ (let* ((total-size (reduce #'* dimensions))
+ (data (or displaced-to
+ (data-vector-from-inits
+ dimensions total-size nil widetag n-bits
+ initial-contents initial-contents-p
+ initial-element initial-element-p)))
+ (array (make-array-header
+ (cond ((= array-rank 1)
+ (%complex-vector-widetag widetag))
+ (simple sb!vm:simple-array-widetag)
+ (t sb!vm:complex-array-widetag))
+ array-rank)))
+ (cond (fill-pointer
+ (unless (= array-rank 1)
+ (error "Only vectors can have fill pointers."))
+ (let ((length (car dimensions)))
+ (declare (fixnum length))
+ (setf (%array-fill-pointer array)
+ (cond ((eq fill-pointer t)
+ length)
+ (t
+ (unless (and (fixnump fill-pointer)
+ (>= fill-pointer 0)
+ (<= fill-pointer length))
+ ;; FIXME: should be TYPE-ERROR?
+ (error "invalid fill-pointer ~W"
+ fill-pointer))
+ fill-pointer))))
+ (setf (%array-fill-pointer-p array) t))
+ (t
+ (setf (%array-fill-pointer array) total-size)
+ (setf (%array-fill-pointer-p array) nil)))
+ (setf (%array-available-elements array) total-size)
+ (setf (%array-data-vector array) data)
+ (setf (%array-displaced-from array) nil)
+ (cond (displaced-to
+ (when (or initial-element-p initial-contents-p)
+ (error "Neither :INITIAL-ELEMENT nor :INITIAL-CONTENTS ~
can be specified along with :DISPLACED-TO"))
- (let ((offset (or displaced-index-offset 0)))
- (when (> (+ offset total-size)
- (array-total-size displaced-to))
- (error "~S doesn't have enough elements." displaced-to))
- (setf (%array-displacement array) offset)
- (setf (%array-displaced-p array) t)
- (%save-displaced-array-backpointer array data)))
- (t
- (setf (%array-displaced-p array) nil)))
- (let ((axis 0))
- (dolist (dim dimensions)
- (setf (%array-dimension array axis) dim)
- (incf axis)))
- array))))
+ (let ((offset (or displaced-index-offset 0)))
+ (when (> (+ offset total-size)
+ (array-total-size displaced-to))
+ (error "~S doesn't have enough elements." displaced-to))
+ (setf (%array-displacement array) offset)
+ (setf (%array-displaced-p array) t)
+ (%save-displaced-array-backpointer array data)))
+ (t
+ (setf (%array-displaced-p array) nil)))
+ (let ((axis 0))
+ (dolist (dim dimensions)
+ (setf (%array-dimension array axis) dim)
+ (incf axis)))
+ array)))))
+
+(defun make-array (dimensions &rest args
+ &key (element-type t)
+ initial-element initial-contents
+ adjustable
+ fill-pointer
+ displaced-to
+ displaced-index-offset)
+ (declare (ignore initial-element
+ initial-contents adjustable
+ fill-pointer displaced-to displaced-index-offset))
+ (multiple-value-bind (widetag n-bits) (%vector-widetag-and-n-bits element-type)
+ (apply #'%make-array dimensions widetag n-bits args)))
(defun make-static-vector (length &key
(element-type '(unsigned-byte 8))
;;; to FILL-DATA-VECTOR for error checking on the structure of
;;; initial-contents.
(defun data-vector-from-inits (dimensions total-size
- element-type widetag
+ element-type widetag n-bits
initial-contents initial-contents-p
initial-element initial-element-p)
(when initial-element-p
(when initial-contents-p
(error "cannot supply both :INITIAL-CONTENTS and :INITIAL-ELEMENT to
either MAKE-ARRAY or ADJUST-ARRAY."))
- (unless (typep initial-element element-type)
- (error "~S cannot be used to initialize an array of type ~S."
- initial-element element-type)))
+ ;; FIXME: element-type can be NIL when widetag is non-nil,
+ ;; and FILL will check the type, although the error will be not as nice.
+ ;; (cond (typep initial-element element-type)
+ ;; (error "~S cannot be used to initialize an array of type ~S."
+ ;; initial-element element-type))
+ )
(let ((data (if widetag
- (allocate-vector-with-widetag widetag total-size)
+ (allocate-vector-with-widetag widetag total-size n-bits)
(make-array total-size :element-type element-type))))
(cond (initial-element-p
(fill (the vector data) initial-element))
the :INITIAL-ELEMENT or :DISPLACED-TO option."))
(let* ((array-size (apply #'* dimensions))
(array-data (data-vector-from-inits
- dimensions array-size element-type nil
+ dimensions array-size element-type nil nil
initial-contents initial-contents-p
initial-element initial-element-p)))
(if (adjustable-array-p array)
(setf new-data
(data-vector-from-inits
dimensions new-length element-type
- (widetag-of old-data)
+ (widetag-of old-data) nil
initial-contents initial-contents-p
initial-element initial-element-p))
;; Provide :END1 to avoid full call to LENGTH
(data-vector-from-inits
dimensions new-length
element-type
- (widetag-of old-data) () nil
+ (widetag-of old-data) nil
+ () nil
initial-element initial-element-p)
old-data)))
(if (or (zerop old-length) (zerop new-length))