Superclass for implementations of multidimensional arrays. An Array has a
classType which gives the Class of its elements, and a
shape which describes the number of elements in each index. The
rank is the number of indices. A
scalar Array has rank = 0. An Array may have arbitrary rank. The Array
size is the total number of elements, which must be less than 2^31 (about 2x10^9).
Actual data storage is done with Java 1D arrays and stride index calculations. This makes our Arrays rectangular, i.e. no "ragged arrays" where different elements can have different lengths as in Java multidimensional arrays, which are arrays of arrays.
Each primitive Java type (boolean, byte, char, short, int, long, float, double) has a corresponding concrete implementation, e.g. ArrayBoolean, ArrayDouble. Reference types are all implemented using the ArrayObject class, with the exceptions of the reference types that correspond to the primitive types, eg Double.class is mapped to double.class.
For efficiency, each Array type implementation has concrete subclasses for ranks 0-7, eg ArrayDouble.D0 is a double array of rank 0, ArrayDouble.D1 is a double array of rank 1, etc. These type and rank specific classes are convenient to work with when you know the type and rank of the Array. Ranks greater than 7 are handled by the type-specific superclass e.g. ArrayDouble. The Array class itself is used for fully general handling of any type and rank array. Use the Array.factory() methods to create Arrays in a general way.
The stride index calculations allow
logical views to be efficiently implemented, eg subset, transpose, slice, etc. These views use the same data storage as the original Array they are derived from. The index stride calculations are equally efficient for any composition of logical views.
The type, shape and backing storage of an Array are immutable. The data itself is read or written using an Index or an IndexIterator, which stores any needed state information for efficient traversal. This makes use of Arrays thread-safe (as long as you dont share the Index or IndexIterator) except for the possibility of non-atomic read/write on long/doubles. If this is the case, you should probably synchronize your calls. Presumably 64-bit CPUs will make those operations atomic also.
@author caron
@see Index
@see IndexIterator