SIMD implementations of the standard algorithms.
Each algorithm keeps the name and the meaning of its std counterpart, takes ranges, and calls its operation on SIMD registers. A position comes back as an iterator into the range given, and a count or a reduction as a value. Where the standard uses one name for the in-place and the out-of-place forms, this module has two, eve::algo::transform_inplace and eve::algo::transform_to, because the two loops differ. Every algorithm takes options between brackets, see Options.
Classes | |
| struct | eve::algo::set_intersection_result< I1, I2, O > |
| Return type of eve::algo::set_intersection: where each input stopped, and the output. More... | |
Variables | |
| constexpr auto | eve::algo::max_element = function_with_traits<max_element_>[default_simple_algo_traits] |
| SIMD variation on std::max_element not exact match. | |
| constexpr auto | eve::algo::search = function_with_traits<search_>[eve::algo::unroll<4>] |
| SIMD version of std::search (subsequence in a sequence). | |
| constexpr auto | eve::algo::all_of = function_with_traits<all_of_>[default_simple_algo_traits] |
| a SIMD version of std::all_of | |
| constexpr auto | eve::algo::any_of = function_with_traits<any_of_>[default_simple_algo_traits] |
| a SIMD version of std::any_of | |
| constexpr auto | eve::algo::copy = function_with_traits<copy_>[default_simple_algo_traits] |
| SIMD optimized copy algorithm. | |
| constexpr auto | eve::algo::copy_backward = function_with_traits<copy_backward_>[default_simple_algo_traits] |
| SIMD optimized backward copy algorithm. | |
| constexpr auto | eve::algo::copy_if = function_with_traits<copy_if_> |
| SIMD variation on std::copy_if. | |
| constexpr auto | eve::algo::equal = function_with_traits<equal_>[all_of.get_traits()] |
| a SIMD version of std::equal | |
| constexpr auto | eve::algo::fill = function_with_traits<fill_>[default_simple_algo_traits] |
| a version of std::fill | |
| constexpr auto | eve::algo::find_if = function_with_traits<find_if_>[default_simple_algo_traits] |
| SIMD version of std::find_if. | |
| constexpr auto | eve::algo::find = function_with_traits<find_>[find_if.get_traits()] |
| a version of find_if with a value to find instead of a predicate to test. | |
| constexpr auto | eve::algo::find_if_not = function_with_traits<find_if_not_>[find_if.get_traits()] |
| a version of eve::algo::find_if where the preicate is negated | |
| constexpr auto | eve::algo::find_last_if = function_with_traits<find_last_if_>[default_simple_algo_traits] |
| SIMD version of std::ranges::find_last_if. | |
| constexpr auto | eve::algo::find_last = function_with_traits<find_last_>[find_last_if.get_traits()] |
| a version of find_last_if with a value to find instead of a predicate to test. | |
| constexpr auto | eve::algo::find_last_if_not = function_with_traits<find_last_if_not_>[find_last_if.get_traits()] |
| a version of find_last_if where the preicate is negated | |
| constexpr auto | eve::algo::for_each = function_with_traits<for_each_> |
| a basic for_each algorithm. | |
| struct { | |
| } | eve::algo::for_each_iteration_with_expensive_optional_part |
| low level util for writing algorithms. A variation on for_each_iteration that has a place for work we don't want duplicated in assembly. | |
| constexpr auto | eve::algo::for_each_selected = function_with_traits<for_each_selected_> |
| an algorithm to perform some scalar operation for every element, that matches a given SIMD predicate. Defined in Header | |
| constexpr auto | eve::algo::iota = function_with_traits<iota_>[copy.get_traits()] |
| SIMD version of std::iota For conversion/overflow behaviour, should follow the standard. | |
| constexpr auto | eve::algo::keep_if = function_with_traits<keep_if_>[no_traits] |
| In-place version of std::copy_if. | |
| constexpr auto | eve::algo::max_value = function_with_traits<max_value_>[default_simple_algo_traits] |
| SIMD algorithm that returns maximum value in the range. | |
| constexpr auto | eve::algo::min_element = function_with_traits<min_element_> |
| SIMD version of std::min_element. | |
| constexpr auto | eve::algo::min_value = function_with_traits<min_value_>[default_simple_algo_traits] |
| SIMD algorithm that returns minimum value in the range. | |
| constexpr auto | eve::algo::mismatch = function_with_traits<mismatch_>[find_if.get_traits()] |
| a SIMD version of std::mismatch | |
| constexpr auto | eve::algo::none_of = function_with_traits<none_of_> |
| a SIMD version of std::none_of | |
| constexpr auto | eve::algo::reduce = function_with_traits<reduce_>[default_simple_algo_traits] |
| SIMD optimized version of std::reduce. | |
| constexpr auto | eve::algo::remove_if = function_with_traits<remove_if_>[no_traits] |
| SIMD version of std::remove_if. | |
| constexpr auto | eve::algo::remove = function_with_traits<remove_>[no_traits] |
| SIMD version of std::remove. | |
| constexpr auto | eve::algo::reverse = function_with_traits<reverse_>[no_unrolling][no_aligning] |
| SIMD version of std::reverse. | |
| constexpr auto | eve::algo::reverse_copy = function_with_traits<reverse_copy_>[algo::unroll<1>] |
| SIMD version of std::reverse_copy. | |
| constexpr auto | eve::algo::set_intersection = function_with_traits<set_intersection_> |
| SIMD variation on std::set_intersection that HAS A SLIGHTLY DIFFERENT SEMANTICS. | |
| constexpr auto | eve::algo::swap_ranges = function_with_traits<swap_ranges_>[default_simple_algo_traits] |
| SIMD version of std::swap_ranges. | |
| constexpr auto | eve::algo::transform_inplace = function_with_traits<transform_inplace_>[default_simple_algo_traits] |
| same as; | |
| constexpr auto | eve::algo::transform_to = function_with_traits<transform_to_>[default_simple_algo_traits] |
| SIMD version of std::transform. | |
| constexpr auto | eve::algo::transform_copy_if = function_with_traits<eve_implementation_defined> |
| Similar to applying eve::transform_to and eve::copy_if at the same time. | |
| constexpr auto | eve::algo::transform_keep_if = function_with_traits<transform_keep_if_>[no_traits] |
| In-place version of eve::algo::transform_copy_if. | |
| constexpr auto | eve::algo::transform_reduce = function_with_traits<transform_reduce_>[default_simple_algo_traits] |
| SIMD version of std::transform_reduce for a single range. | |
|
inlineconstexpr |
a SIMD version of std::all_of
Tests if all of the elements in the range match the predicate. by default aligns and unrolls 4 times.
Alternative Header
Parameters
Return value
true if unary p returns true for all elements in the range, false otherwise. Returns true if the range is empty.
|
inlineconstexpr |
a SIMD version of std::any_of
Tests if any of the elements in the range match the predicate. by default aligns and unrolls 4 times.
Alternative Header
Parameters
Return value
true if p returns true for at least one element in the range, false otherwise. Returns false if the range is empty.
|
inlineconstexpr |
SIMD optimized copy algorithm.
Configurable Callable Object performing a SIMD optimized version of the copy. By default, the operation will be unrolled by a factor of 4, align memory accesses and perform conversions if needed.
Alternative Header
Parameters
|
inlineconstexpr |
SIMD optimized backward copy algorithm.
Configurable Callable Object performing backward copy between two ranges' or between a range and an iterator.
By default, eve::algo::copy_backward will be unrolled by a factor of 4, align memory accesses and perform conversions if needed.
Alternative Header
The elements are copied in reverse order (the last element is copied first), but their relative order is preserved. Due to the specificities of the SIMD algorithm, the second can not be an iterator. Use the zip based overload to do so.
Parameters
|
inlineconstexpr |
SIMD variation on std::copy_if.
Defined in Header
The main difference from std::copy_if is that it accepts output range and not an output iterator. If the output doesn't have enough space, algorithm will fill all of the available output and then stop. The interface difference allows eve to store more then just selected elements which is important for efficiency.
Tuning:
** Parameters **
** Return value **
relaxed_iterator past the last written element.
|
inlineconstexpr |
a SIMD version of std::equal
Tests whether two ranges are equal (accepts anything that zips together as a range of 2 things) By default aligns and unrolls 4 times.
Alternative Header
Parameters
Return value
bool whether any values matched the predicate
|
inlineconstexpr |
a version of find_if with a value to find instead of a predicate to test.
Alternative Header
Parameters
Return value
Iterator on the element found or past the end if not found (same as std)
|
inlineconstexpr |
SIMD version of std::find_if.
Configurable Callable Object performing a SIMD optimized version of the find_if By default, the operation will be unrolled by a factor of 4, and align memory accesses.
Alternative Header
Parameters
Return value
Iterator on the element found or past the end if not (same as std)
|
inlineconstexpr |
a version of eve::algo::find_if where the preicate is negated
Alternative Header
Parameters
Return value
Iterator on the element found or past the end if not found (same as std)
|
inlineconstexpr |
a version of find_last_if with a value to find instead of a predicate to test.
Parameters
Return value
Iterator on the element found or past the end if not found
|
inlineconstexpr |
SIMD version of std::ranges::find_last_if.
Configurable Callable Object performing a SIMD optimized version of the std::ranges::find_last_if By default, the operation will be unrolled by a factor of 4, and align memory accesses.
Parameters
Return value
Iterator on the element found or past the end if nothing was found.
|
inlineconstexpr |
a version of find_last_if where the preicate is negated
Parameters
Return value
Iterator on the element found or past the end if not found
|
inlineconstexpr |
a basic for_each algorithm.
If you have a more advanced unrolling, consider using the for_each_iteration.
Required header: #include <eve/module/algo/algo/for_each.hpp>
| struct { ... } eve::algo::for_each_iteration_with_expensive_optional_part |
low level util for writing algorithms. A variation on for_each_iteration that has a place for work we don't want duplicated in assembly.
Defined in Header
for_each_iteration, even if not unrolled, generates a few copies of the callback code. For some algorithms we want to move out a piece of callback code but we still don't want a function call. Think search: we want to move the more expensive part of validating match outside.
You can find example usage in the search implementation.
|
inlineconstexpr |
an algorithm to perform some scalar operation for every element, that matches a given SIMD predicate. Defined in Header
The scalar equivalent of this algorithm would be:
Parameters
Return value
returns true iff the iteration was interrupted.
|
inlineconstexpr |
SIMD version of std::iota For conversion/overflow behaviour, should follow the standard.
Required header: #include <eve/module/algo/algo/iota.hpp>
|
inlineconstexpr |
In-place version of std::copy_if.
Defined in Header
Takes values that pass the predicate, and copies them to the beginning of the range. Values past the returned sentinel are to be considered garbage.
Acts like an eager version of filter, or an in-place version of std::copy_if:
Tuning
::dense_output/::sparse_output: if you expect very sparse output (one or two trues per register), you can call ::keep_if[::sparse_output](...) to optimize for that scenario.
Parameters
Return value
Iterator past the last written element.
|
inlineconstexpr |
SIMD variation on std::max_element not exact match.
By default unrolls by 4 and aligned all memory accesses.
Alternative Header
Parameters
Return value
iterator to max element (end if the range is empty).
|
inlineconstexpr |
SIMD algorithm that returns maximum value in the range.
The standard only has _element versions of min/max algorithms. However, in SIMD finding the value is much faster then also finding the position - hence this algorithm.
Alternative Header
Parameters
Return value
maximum value from the range. If the input range was empty, it's std::nullopt.
|
inlineconstexpr |
SIMD version of std::min_element.
Alternative Header
Parameters
Return value
iterator to min element (end if the range is empty).
Can be one of two algorithms: one pass and two pass (default).
Two pass finds a value and then does a linear search for the value. This proves to be faster on smaller simpler arrays. By default unrolls by 4 and aligned all memory accesses.
The one pass version keeps track of index and is better suited for complicated predicates. You can opt in by using single_pass or expensive_callable traits. The single_pass opt-in will be aligning all data accesses
|
inlineconstexpr |
SIMD algorithm that returns minimum value in the range.
C++ standard only has std::min_element that returns iterator to the minimum element. We have that too (see: eve::algo::min_element) but it's slower then just getting the value. So we also provide min_value for when you don't care about the position. By default unrolls by 4 and aligned all memory accesses.
Alternative Header
Parameters
Return value
minimum value from the range. If the input range was empty, it's std::nullopt.
|
inlineconstexpr |
a SIMD version of std::mismatch
Finds the point where two ranges are different (accepts anything that zips together as a range of 2 things). By default aligns and unrolls 4 times.
Alternative Header
Parameters
Return value
eve::views::zip_iterator to the place where the mismatch happened. (if not found, will point past the end of both halves).
|
inlineconstexpr |
a SIMD version of std::none_of
Tests if none of the elements in the range match the predicate. by default aligns and unrolls 4 times.
Alternative Header
Parameters
Return value
true if p returns true for no elements in the range, false otherwise. Returns true if the range is empty.
|
inlineconstexpr |
SIMD optimized version of std::reduce.
Configurable Callable Object performing a SIMD optimized version of the reduce By default, the operation will be unrolled by a factor of 4, align memory accesses and perform conversions if needed.
Due to the nature of how SIMD algorithms work, the reduce operation has to be paired with its, neutral element. For example, for add you pass {add, zero} as zero is the identity for add. Instead of zero it can be beneficial to pass eve's constants like eve::zero, eve::one because sometimes the implementation can be improved
Alternative Header
Parameters
Return value
|
inlineconstexpr |
SIMD version of std::remove.
Defined in Header
TODO: docs
|
inlineconstexpr |
SIMD version of std::remove_if.
Defined in Header
TODO: docs
|
inlineconstexpr |
SIMD version of std::reverse.
Required header: #include <eve/module/algo/algo/reverse.hpp>
|
inlineconstexpr |
SIMD version of std::reverse_copy.
NOTE: reverese_copy(it, range) works but it's the same as reverse_copy(views::zip(it, range)), so it will be treated as first not last.
Required header: #include <eve/module/algo/algo/reverse.hpp>
|
inlineconstexpr |
SIMD version of std::search (subsequence in a sequence).
Defined in Header
Some ideas are taken from the previous work:
Tuning:
(2) calls (1) with eve::is_equal. In order to mimic the behaviour of std::search, it will also cast the types, so that you can search unrelated types.
Version (1) won't do implicit types conversions for you, you can either handle them in the predicate or use views::convert.
Parameters (1)
Return value
unaligned iterator pointing to where in haystack the sequence is.
If the needle is empty found == haystack.begin() is returned.
If the needle isn't found == haystack.end().
|
inlineconstexpr |
SIMD variation on std::set_intersection that HAS A SLIGHTLY DIFFERENT SEMANTICS.
Defined in Header
The main idea for the algorithm comes from "Faster-Than-Native Alternatives for x86 VP2INTERSECT Instructions" by Guillermo Diez-Canas. Link: https://arxiv.org/abs/2112.06342
Differences:
Other:
Tuning:
(2) calls (1) with eve::is_less, eve::is_equal and converting to common type.
Parameters (1)
Return value
set_intersection{ .in1, .in2, .out }.
|
inlineconstexpr |
SIMD version of std::swap_ranges.
Required header: #include <eve/module/algo/algo/swap_ranges.hpp>
|
inlineconstexpr |
Similar to applying eve::transform_to and eve::copy_if at the same time.
Defined in header
Conditionally copies values from an input range to an output range, transforming them in the process.
If the output range is too small, fills all the available space and then stops.
If the output range's element type is different from the type of the values returned by the transforming function, performs the appropriate conversions.
Parameters
Return value
Output iterator past the last written element.
|
inlineconstexpr |
same as;
but slightly more efficient
Required header: #include <eve/module/algo/algo/transform.hpp>
|
inlineconstexpr |
In-place version of eve::algo::transform_copy_if.
Defined in Header
Conditionally copies values that pass a predicate to the beginning of the range, transforming them in the process. Values past the returned sentinel are to be considered garbage.
Parameters
Return value
Iterator past the last written element.
|
inlineconstexpr |
SIMD version of std::transform_reduce for a single range.
Configurable Callable Object performing a SIMD optimized version of the transform_reduce By default, the operation will be unrolled by a factor of 4, align memory accesses and perform conversions if needed.
Due to the nature of how SIMD algorithms work, the reduce operation has to be paired with its, neutral element. For example, for add you pass {add, zero} as zero is the identity for add. Instead of zero it can be beneficial to pass eve's constants like eve::zero, eve::one because sometimes the implementation can be improved.
Supports fuse_operations trait => map_op starts to take an extra parameter: current sum. Allows to use fma. Note that add operations and zero are still used and have to be correct.
Alternative Header
Parameters
Return value
|
inlineconstexpr |
SIMD version of std::transform.
Required header: #include <eve/module/algo/algo/transform.hpp>