n_circular_array
N Circular Array
An n-dimensional circular array.
Features
- Fixed dimension arrays of any size.
- Element insertion to the front or back of any dimension.
- Indexing, range and slicing operations.
- Optimized for contiguous memory.
- Support for external types through
AsRef<[T]>andAsMut<[T]>. - Thorough testing for arrays of smaller dimensionality.
- No external dependencies.
Usage
The following example demonstrates the basic functionality offered by this crate.
// A 1-dimensional circular array of 6 elements.
let mut array = new;
array.push_front;
assert_eq!;
array.push_back;
assert_eq!;
// A 2-dimensional array of 3*3 elements.
let mut array = new;
// Push to the front of axis 0.
array.push_front;
assert_eq!;
// Push to the back of axis 1.
array.push_back;
assert_eq!;
// Iterate over index 1 of axis 0 (The second column).
assert_eq!;
Mutation
n_circular_array allows for mutating single elements, or inserting any number
of slices to an axis. Insertion operations expect elements of row-major
ordering. Operations accept either an array slice &[T], or an ExactSizeIterator
of &T elements for _iter suffixed methods.
// A 2-dimensional circular array of 3*2 elements.
let mut array = new;
// Push two columns to the front of axis 0.
array.push_front;
// Mutate the last element of the array (equivalent to `array.get_mut([2, 2])`).
assert_eq!;
array = 99;
assert_eq!;
// Push two rows of zero to the front of axis 1.
let axis_len = array.shape;
array.push_front_iter;
assert_eq!;
See [CircularArrayMut].
Indexing
n_circular_array allows for elements to be accessed by index or slice. Note
that indexing operations take a fixed size array of N indices/ranges where N
is the dimensionality of the array.
// A 3-dimensional array of 3*3*2 elements.
let mut array = new;
// Get the first element at index 1 of axis 2 (equivalent to `array.get([0, 0, 1])`).
assert_eq!;
// Get the second and third row.
assert_eq!;
// All columns of row 2, slice 1.
assert_eq!;
See [CircularArrayIndex] and [CircularArrayIndexMut].
Resizing/Reshaping
Resizing or reshaping can be achieved by iterating and collecting into a new
CircularArray. This functionality is not offered from within the crate to make the
performance implications explicit.
// A 3-dimensional array of 3*3*2 elements.
let mut array = new;
// Insert a row at index 0.
array.push_front;
assert_eq!;
assert_eq!;
// Iterate over index 1 of axis 2 into a 2-dimensional array of shape [3, 3].
let iter = array.iter_slice;
// Operations return `ExactSizeIterator` implementations.
assert_eq!;
let array_2 = from_iter;
assert_eq!;
assert_eq!;
Performance
Wrapping contigous slices over the bounds of an axis reduces cache locality,
especially for the innermost dimensions of any n > 1 array. Where possible,
an array should be oriented where the majority of operations are performed on the
outermost dimension(s). This will allow n_circular_array to take contiguous
slices of memory where possible, which can result in operations being reduced to
as little as a single iteration over a contiguous slice, or a single call to
copy_from_slice during mutation.
External types implementing AsRef<[T]> and AsMut<[T]> may also improve performance
over Vec<T> or Box<T>. If necessary, AsRef<[T]> and AsMut<[T]> can be delegated
to unsafe methods, although this is discouraged.
Finally, for smaller arrays, avoiding a circular array and simply copying (or cloning)
an array window may outperform n_circular_array. Benchmark if unsure whether
your use case benefits from n_circular_array.
License: MIT OR Apache-2.0