ndshape
Simple, fast linearization of 2D, 3D, and 4D coordinates.
The canonical choice of linearization function is row-major, i.e. stepping linearly through an N dimensional array would
step by X first, then Y, then Z, etc, assuming that [T; N] coordinates are provided as [X, Y, Z, ...]. More explicitly:
linearize([x, y, z, ...]) = x + X_SIZE * y + X_SIZE * Y_SIZE * z + ...
To achieve a different layout, one only needs to choose a different permutation of coordinates. For example, column-major
layout would require coordinates specified as [..., Z, Y, X]. For a 3D layout where each Y level set is contiguous in
memory, either layout [X, Z, Y] or [Z, X, Y] would work.
Example: Indexing Multidimensional Arrays
use ;
// An arbitrary shape.
let shape = ;
let index = shape.linearize;
assert_eq!;
assert_eq!;
// A shape with power-of-two dimensions
// This allows us to use bit shifting and masking for linearization.
let shape = ; // These are number of bits per dimension.
let index = shape.linearize;
assert_eq!;
assert_eq!;
// A runtime shape.
let shape = new;
let index = shape.linearize;
assert_eq!;
assert_eq!;
// Use a shape for indexing an array in 4D.
// Step X, then Y, then Z, since that results in monotonic increasing indices.
// (Believe it or not, Rust's N-dimensional array (e.g. `[[T; N]; M]`)
// indexing is significantly slower than this).
let shape = ;
let data = ;
for w in 0..8
Example: Negative Strides with Modular Arithmetic
It is often beneficial to linearize a negative vector that results in a negative linear "stride." But when using unsigned
linear indices, a negative stride would require a modular arithmetic representation, where e.g. -1 maps to u32::MAX.
This works fine with any Shape. You just need to be sure to use modular arithmetic with the resulting
linear strides, e.g. u32::wrapping_add and u32::wrapping_mul. Also, it is not
possible to delinearize a negative stride with modular arithmetic. For that, you must use signed integer coordinates.
use ;
let shape = ;
let stride = shape.linearize;
assert_eq!;
// Delinearize does not work with unsigned coordinates!
assert_ne!;
assert_eq!;
let shape = ;
let stride = shape.linearize;
assert_eq!;
// Delinearize works with signed coordinates.
assert_eq!;
License: MIT OR Apache-2.0