SIMD algorithms are complex to design, implement and tests as a lot of care has to be put into details like correct tail handling, alignment handling or unrolling.
EVE's algorithms and views module is designed to simplify such design while:
All those features are usable through generic interfaces to allow for reuse of similar loops structure at the cost of some idiosyncrasies.
For an in-depth discussion about those issues, you can take a look at the Algorithms section of our CppCon talk.
Many algorithms require some form of while(f != l)
loop. However, with SIMD, even this simple operation is non trivial. EVE algorithm building-blocks provide implementation for the most frequent loop structures. Those loops can then customized and reused without having to care about the actual range type used. For example, eve::mismatch is implemented as a customized call to eve::find.
Iterators are more fundamental than ranges. However, ranges can have some extra information like, for example, that instead of begin()
it has aligned_begin()
and the algorithm can use that. So the interfaces are range
based. We don't generally accept iterator
in interfaces just because it increases the maintenance. The eve::algo::as_range can be used to turn iterators pair into a EVE compatible range.
One case where it can be very awkward to use ranges instead of iterators is in multi-range algorithms , like transform_to
. In this case, unless we have some reason no to, we allow for passing anything that zips to range
, i.e. range
, iterator
or iterator
,range
. Exceptions are documented and have static_assert
s that will tell you it's not supported.
Many things that we want to accept in the interfaces as range
and/or iterator
are not ideal for writing code against. We also need to strip things like vector::iterator
to pointers. What also we want is to associate a cardinal
with iterator
.
This is why we have two layers: relaxed_range
/relaxed_iterator
and iterator
. There are a few things that relaxed_*
should be able to do but the main one is preprocess_range(traits, f, l)
which returns enhanced traits
and iterator
pair.
EVE allows to customize algorithms with traits. Traits are passed via []
and can be combined.
The more common ones are:
no_aliging
- stop aligning data accessesunroll<N>
- unroll N times (1 for no unrolling).force_cardinal<N>
- force how many elements in per step to process, needed for writing code dealing with intrinsics.The values used by default are documented by algorithm.