Trait slipstream::iterators::Vectorizable
source · pub trait Vectorizable<V>: Sized {
type Padding;
type Vectorizer: Vectorizer<V>;
// Required method
fn create(
self,
pad: Option<Self::Padding>
) -> (Self::Vectorizer, usize, Option<V>);
// Provided methods
fn vectorize(self) -> VectorizedIter<Self::Vectorizer, (), V> ⓘ { ... }
fn vectorize_pad(
self,
pad: Self::Padding
) -> VectorizedIter<Self::Vectorizer, Option<V>, V> ⓘ { ... }
}
Expand description
A trait describing things with direct support for splitting into vectors.
This supports vectorized iteration over shared and mutable slices as well as types composed of them (tuples and short fixed-sized arrays).
Note that, unlike normal iterators, shared slices return owned values (vectors) and mutable slices return proxy objects that allow writing the data back. It is not possible to directly borrow from the slice because of alignment. The tuples and arrays return tuples and arrays of the inner values.
Already pre-vectorized inputs are also supported (this is useful in combination with other not vectorized inputs).
Type hints
Oftentimes, the compiler can infer the type of the base type, but not the length of the vector. It is therefore needed to provide a type hint.
Furthermore, for tuples and arrays, the inner type really needs to be the slice, not something that can coerce into it (eg. vec or array).
Alternatively, you can use the free-standing functions vectorize
and
vectorize_pad
. It allows using the turbofish to provide the hint.
Examples
let data = [1, 2, 3, 4];
let v = data.vectorize().collect::<Vec<u32x2>>();
assert_eq!(vec![u32x2::new([1, 2]), u32x2::new([3, 4])], v);
let data = [1, 2, 3, 4];
for v in data.vectorize() {
let v: u32x2 = v; // Type hint
println!("{:?}", v);
}
let input = [1, 2, 3, 4];
let mut output = [0; 4];
let mul = u32x2::splat(2);
// We have to force the coercion to slice by [..]
for (i, mut o) in (&input[..], &mut output[..]).vectorize() {
*o = mul * i;
}
assert_eq!(output, [2, 4, 6, 8]);
let vectorized = [u32x2::new([1, 2]), u32x2::new([3, 4])];
let not_vectorized = [1, 2, 3, 4];
for (v, n) in (&vectorized[..], ¬_vectorized[..]).vectorize() {
assert_eq!(v, n);
}
Required Associated Types§
sourcetype Padding
type Padding
The input type provided by user to fill in the padding/uneven end.
Note that this doesn’t necessarily have to be the same type as the type returned by the
resulting iterator. For example, in case of mutable slices, the input is the vector, while
the output is MutProxy
.
sourcetype Vectorizer: Vectorizer<V>
type Vectorizer: Vectorizer<V>
An internal type managing the splitting into vectors.
Not of direct interest of the users of this crate.
Required Methods§
Provided Methods§
sourcefn vectorize(self) -> VectorizedIter<Self::Vectorizer, (), V> ⓘ
fn vectorize(self) -> VectorizedIter<Self::Vectorizer, (), V> ⓘ
Vectorize a slice or composite of slices
This variant assumes the input is divisible by the size of the vector. Prefer this if
possible over vectorize_pad
, as it is usually
significantly faster.
Panics
- If the slice length isn’t divisible by the vector size.
- If the parts of the composite produce different number of vectors. It is not mandated for the slices to be of equal length, only to produce the same number of vectors.
Examples
let longer = [1, 2, 3, 4, 5, 6, 7, 8];
let shorter = [1, 2, 3, 4];
for i in (&shorter[..], &longer[..]).vectorize() {
let (s, l): (u32x2, u32x4) = i;
println!("s: {:?}, l: {:?})", s, l);
}
sourcefn vectorize_pad(
self,
pad: Self::Padding
) -> VectorizedIter<Self::Vectorizer, Option<V>, V> ⓘ
fn vectorize_pad( self, pad: Self::Padding ) -> VectorizedIter<Self::Vectorizer, Option<V>, V> ⓘ
Vectorizes a slice or composite of slices, padding the odd end if needed.
While the vectorize
assumes the input can be split into
vectors without leftover, this version deals with the uneven rest by producing a padding
vector (if needed). The unused lanes are taken from the pad
parameter. This is at the
cost of some performance (TODO: figure out why it is so much slower).
For mutable slices, padding is used as usual, but the added lanes are not stored anywhere.
The padding is produced at the end.
In case of composites, this still assumes they produce the same number of full vectors and that they all either do or don’t need a padding.
Panics
If the above assumption about number of vectors and same padding behaviour is violated.
let data = [1, 2, 3, 4, 5, 6];
let v = data.vectorize_pad(i32x4::splat(-1)).collect::<Vec<_>>();
assert_eq!(v, vec![i32x4::new([1, 2, 3, 4]), i32x4::new([5, 6, -1, -1])]);