This is a proposal for a simple numeric vector API. It provides what appear to be a set of specialized numeric-only vectors distinguished by their representation type. However, implementations may in fact use R7RS-small bytevectors to represent any or all of the vector types. It is recommended that implementations use bytevectors unless (as on the JVM and the CLR) it is impossible to efficiently coerce bytevectors to numeric vectors. Users can compel the creation of bytevectors rather than implementation-dependent numeric vectors. Numeric vectors containing unsigned 8-bit exact integers (u8vectors) must be represented as bytevectors.
This design subsumes SRFI 4, except that users cannot count on distinguishing different types of numeric vectors by predicates. It differs from related designs such as SRFI 63, SRFI 66, and R6RS in that each procedure listed below actually represents many procedures, one for each defined representation type. This makes for a lot of procedures, but many of them can be easily inlined by even a very dumb compiler, providing high efficiency. The procedures provided in the present proposal are the numeric-vector analogues of the R7RS-small vector API.
A <type> consists of a <principal type> followed by an <endianism>.
The <principal type> values are:
The <endianism> values are:
Endianism is not applicable to the u8 and s8 types. Thus there are 3 * 14 - 4, or 38, representation types altogether.
The number of bytes occupied by a representation type is the number of bits expressed in its name divided by 8. This value is designated by b in the descriptions of procedures.
(make-<type>vector k [ fill ])
Returns a newly allocated numeric vector of length k. If the implementation chooses to allocate a bytevector, it will be of size k * b. Fill is converted to a binary value according to `<type> and used to fill the vector; if fill is not specified, the values of the elements are unspecified. It is an error if fill cannot be accurately converted to <type>.
(<type>vector v ... )
Returns a newly allocated numeric vector of length k, where k is the number of arguments to the procedure. If the implementation chooses to allocate a bytevector, its length will be k * b. It is filled with the binary values resulting from encoding the v arguments according to <type>. It is an error if an argument cannot be accurately converted to <type>.
(<type>vector? obj)
Returns #t if obj can be treated as a <type>vector, and #f if it cannot. These predicates cannot be reliably used to discriminate between one numeric vector type and another, since any or all may share the same underlying types. In particular, bytevectors return #t to all of them.
(numeric-vector-empty? numvector)
Returns #t if numvector has length 0, and #f otherwise. This procedure is not specialized for different numeric types.
(<type>vector-ref numvector k)
Returns a Scheme number corresponding to the kth element of numvector. If numvector is a bytevector, this will be the binary value encoded according to <type> beginning at offset k * b in bytevector. This procedure treats bytevectors as uniformly typed vectors.
(bytevector-<type>-ref bytevector k)
Returns a Scheme number corresponding to the binary value encoded according to <type> beginning at offset k in bytevector. This procedure treats bytevector as potentially containing more than one type.
Note that bytevector-u8-ref is defined in the small language.
(<type>vector-set! numvector k v)
Converts v to a binary value encoded according to <type> and places it into the kth element of numvector. If numvector is a bytevector, the value is placed beginning at offset k * b. This procedure treats bytevectors as uniformly typed vectors. It is an error if v cannot be converted to <type>.
(bytevector-<type>-set! bytevector k v)
Converts v to a binary value encoded according to <type> and places it into bytevector beginning at offset k. This procedure treats bytevector as potentially containing more than one type. It is an error if v cannot be converted to <type>.
Note that bytevector-u8-set! is defined in the small language.
It is an error if a value being used to fill an element of a <type>vector cannot be converted to <type>.
(vector-><type>vector vector [start [ end ] ])
Returns a newly allocated <type>vector of length end - start, filled with the corresponding elements of vector.
(list-><type>vector list)
Returns a newly allocated <type>vector whose length is the length of list, filled with the elements of list.
(bytevector-><type>vector bytevector [ start [ end ] ])
Returns a <type>vector of length end / b - start / b, filled with the elements of bytevector taken b at a time. The result may share storage with bytevector.
(vector-><type>vector! numvector at vector [start [ end ] ])
Writes the elements of vector from start to end into numvector starting at at.
(list-><type>vector! list numvector at)
Writes the elements of list into numvector starting at at.
(bytevector-><type>vector! numvector at vector [start [ end ] ])
Writes the elements of bytevector from b * start to b * end taken b at a time into numvector starting at at.
(<type>vector->vector numvector [ start [ end ] ])
(<type>vector->list numvector [ start [ end ] ])
Returns a newly allocated vector or list of length end - start with the elements of numvector from start to end.
(<type>vector->bytevector numvector [ start [ end ] ])
Returns a newly allocated bytevector of length b * end - b * start with the elements of numvector from start to end. The result may share structure with numvector; in particular
(<type>vector->vector! vector at numvector [start [ end ] ])
(<type>vector->bytevector! bytevector at numvector [start [ end ] ])
Writes the elements of numvector from start to end into vector or bytevector starting at at.
(<type>vector-length numvector)
Returns the length of numvector. If numvector is a bytevector, returns its length divided by b and rounded toward zero.
(<type>vector-copy numvector [ [ start ] end ] )
Copies the elements of numvector from start to end into a newly allocated numeric vector of the same representation type. If numvector is a bytevector, this is equivalent to bytevector-copy, except that start and end are multiplied by b.
(<type>vector-copy! to at from [ [ start ] end ] )
Copies the elements of from from start to end into to starting at at. If numvector is a bytevector, the number of bytes copied is (end - start) * b.
<type>vector-append numvector ...)
Returns a newly allocated <type>vector whose elements are the concatenation of the elements in numvectors. It is an error if the numvectors are not all of the same type. If they are all bytevectors, <type>vector-append is equivalent to bytevector-append.
(<type>vector-fill! bytevector fill [ [ start ] end ] )
Stores fill in the elements of bytevector viewed as a <type>vector from start to end. An error is signaled if fill cannot be accurately converted to <type>.
(<type>vector-map proc numvector1 ...)
Returns a newly allocated <type>vector which contains the results of applying proc to the elements of the numvectors in an unspecified order.
(<type>vector-for-each proc numvector1 ...)
Applies proc to the elements of the numvectors in order from first to last. Returns an unspecified value.
See the procedures of VectorsCowan, with the exceptions of the ones defined here.
For mapping C structs onto bytevectors, see StructuresCowan or StructuresTaylan.
This syntax-rules macro by Ian Price will be helpful in implementing lots of similar but not identical procedures for the 38 types.