42#ifndef UFO_EXECUTION_ALGORITHM_HPP
43#define UFO_EXECUTION_ALGORITHM_HPP
46#include <ufo/execution/execution.hpp>
60using execution::ExecutionPolicy;
79template <std::
integral Index,
class UnaryFunc,
class Proj = std::
identity>
80constexpr UnaryFunc
for_each(Index first, Index last, UnaryFunc f, Proj proj = {})
82 for (; last != first; ++first) {
83 std::invoke(f, std::invoke(proj, first));
107 class Proj = std::identity>
108void for_each(T&& policy, Index first, Index last, UnaryFunc f, Proj proj = {})
110 if constexpr (execution::STLBackend<T>) {
111 auto r = std::views::iota(first, last) | std::views::transform(std::move(proj));
112 std::for_each(execution::toSTL(std::forward<T>(policy)), std::ranges::begin(r),
113 std::ranges::end(r), f);
115#if defined(UFO_PAR_GCD)
116 else if constexpr (execution::GCDBackend<T>) {
117 dispatch_apply(
static_cast<std::size_t
>(last - first),
118 dispatch_get_global_queue(0, 0), ^(std::size_t i) {
119 std::invoke(f, std::invoke(proj, first +
static_cast<Index
>(i)));
123#if defined(UFO_PAR_TBB)
124 else if constexpr (execution::TBBBackend<T>) {
125 oneapi::tbb::parallel_for(
126 first, last, [f, proj](Index i) { std::invoke(f, std::invoke(proj, i)); });
129 else if constexpr (execution::OMPBackend<T>) {
130 auto s_first =
static_cast<std::make_signed_t<Index>
>(first);
131 auto s_last =
static_cast<std::make_signed_t<Index>
>(last);
132#pragma omp parallel for
133 for (
auto i = s_first; i < s_last; ++i) {
134 std::invoke(f, std::invoke(proj,
static_cast<Index
>(i)));
152template <std::input_iterator InputIt,
class UnaryFunc,
class Proj = std::
identity>
153constexpr UnaryFunc
for_each(InputIt first, InputIt last, UnaryFunc f, Proj proj = {})
155 for (; first != last; ++first) {
156 std::invoke(f, std::invoke(proj, *first));
182 class UnaryFunc,
class Proj = std::identity>
183void for_each(T&& policy, RandomIt first, RandomIt last, UnaryFunc f, Proj proj = {})
185 if constexpr (execution::STLBackend<T>) {
187 std::forward<T>(policy), std::size_t{},
188 static_cast<std::size_t
>(std::distance(first, last)),
189 [first, f, proj](std::size_t i) { std::invoke(f, std::invoke(proj, first[i])); });
191#if defined(UFO_PAR_GCD)
192 else if constexpr (execution::GCDBackend<T>) {
193 std::size_t s =
static_cast<std::size_t
>(std::distance(first, last));
194 dispatch_apply(s, dispatch_get_global_queue(0, 0), ^(std::size_t i) {
195 std::invoke(f, std::invoke(proj, first[i]));
199#if defined(UFO_PAR_TBB)
200 else if constexpr (execution::TBBBackend<T>) {
202 std::size_t s =
static_cast<std::size_t
>(std::distance(first, last));
203 oneapi::tbb::parallel_for(std::size_t{}, s, [first, f, proj](std::size_t i) {
204 std::invoke(f, std::invoke(proj, first[i]));
208 else if constexpr (execution::OMPBackend<T>) {
209 auto s =
static_cast<std::make_signed_t<std::size_t>
>(std::distance(first, last));
210#pragma omp parallel for
211 for (
auto i =
static_cast<decltype(s)
>(0); i < s; ++i) {
212 std::invoke(f, std::invoke(proj, first[i]));
228template <std::ranges::input_range Range,
class UnaryFunc,
class Proj = std::
identity>
230constexpr std::ranges::for_each_result<std::ranges::iterator_t<Range>, UnaryFunc>
233 return std::ranges::for_each(std::forward<Range>(r), std::move(f), std::move(proj));
247 class UnaryFunc,
class Proj = std::identity>
250 ufo::for_each(std::forward<T>(policy), std::ranges::begin(r), std::ranges::end(r),
251 std::move(f), std::move(proj));
273template <std::input_iterator InputIt,
class OutputIt,
class UnaryOp,
274 class Proj = std::identity>
275constexpr OutputIt
transform(InputIt first1, InputIt last1, OutputIt d_first,
276 UnaryOp unary_op, Proj proj = {})
278 for (; first1 != last1; ++first1, ++d_first) {
279 *d_first = std::invoke(unary_op, std::invoke(proj, *first1));
300 std::random_access_iterator RandomIt2,
class UnaryOp,
301 class Proj = std::identity>
302 requires(!std::input_or_output_iterator<UnaryOp>)
304RandomIt2
transform(T&& policy, RandomIt1 first1, RandomIt1 last1, RandomIt2 d_first,
305 UnaryOp unary_op, Proj proj = {})
307 if constexpr (execution::STLBackend<T>) {
308 std::transform(execution::toSTL(std::forward<T>(policy)), first1, last1, d_first,
309 [&unary_op, &proj](
auto&& x) {
310 return std::invoke(unary_op,
311 std::invoke(proj, std::forward<
decltype(x)>(x)));
313 return d_first + std::distance(first1, last1);
315 std::size_t s =
static_cast<std::size_t
>(std::distance(first1, last1));
316 for_each(std::forward<T>(policy), std::size_t{}, s,
317 [first1, d_first, unary_op, proj](std::size_t i) {
318 d_first[i] = std::invoke(unary_op, std::invoke(proj, first1[i]));
337template <std::ranges::input_range Range1, std::weakly_incrementable OutputIt,
338 class UnaryOp,
class Proj = std::identity>
341 std::indirectly_writable<
342 OutputIt, std::indirect_result_t<
343 UnaryOp, std::projected<std::ranges::iterator_t<Range1>, Proj>>>)
344constexpr std::ranges::unary_transform_result<std::ranges::iterator_t<Range1>, OutputIt>
345transform(Range1&& r1, OutputIt d_first, UnaryOp unary_op, Proj proj = {})
347 return std::ranges::transform(std::forward<Range1>(r1), d_first, unary_op,
366 std::random_access_iterator RandomIt2,
class UnaryOp,
367 class Proj = std::identity>
369 std::indirectly_writable<
370 RandomIt2, std::indirect_result_t<
371 UnaryOp, std::projected<std::ranges::iterator_t<Range1>, Proj>>>)
372RandomIt2
transform(T&& policy, Range1&& r1, RandomIt2 d_first, UnaryOp unary_op,
375 return ufo::transform(std::forward<T>(policy), std::ranges::begin(r1),
376 std::ranges::end(r1), d_first, std::move(unary_op),
396template <std::input_iterator InputIt1, std::input_iterator InputIt2,
class OutputIt,
397 class BinaryOp,
class Proj1 = std::identity,
class Proj2 = std::identity>
398constexpr OutputIt
transform(InputIt1 first1, InputIt1 last1, InputIt2 first2,
399 OutputIt d_first, BinaryOp binary_op, Proj1 proj1 = {},
402 for (; first1 != last1; ++first1, ++first2, ++d_first) {
404 std::invoke(binary_op, std::invoke(proj1, *first1), std::invoke(proj2, *first2));
429 std::random_access_iterator RandomIt2, std::random_access_iterator RandomIt3,
430 class BinaryOp,
class Proj1 = std::identity,
class Proj2 = std::identity>
431RandomIt3
transform(T&& policy, RandomIt1 first1, RandomIt1 last1, RandomIt2 first2,
432 RandomIt3 d_first, BinaryOp binary_op, Proj1 proj1 = {},
435 if constexpr (execution::STLBackend<T>) {
436 std::transform(execution::toSTL(std::forward<T>(policy)), first1, last1, first2,
437 d_first, [&binary_op, &proj1, &proj2](
auto&& x,
auto&& y) {
438 return std::invoke(binary_op,
439 std::invoke(proj1, std::forward<
decltype(x)>(x)),
440 std::invoke(proj2, std::forward<
decltype(y)>(y)));
442 return d_first + std::distance(first1, last1);
444 std::size_t s =
static_cast<std::size_t
>(std::distance(first1, last1));
445 for_each(std::forward<T>(policy), std::size_t{}, s,
446 [first1, first2, d_first, binary_op, proj1, proj2](std::size_t i) {
447 d_first[i] = std::invoke(binary_op, std::invoke(proj1, first1[i]),
448 std::invoke(proj2, first2[i]));
470template <std::ranges::input_range Range1, std::input_iterator InputIt2,
471 std::weakly_incrementable OutputIt,
class BinaryOp,
class Proj1 = std::identity,
472 class Proj2 = std::identity>
475 std::indirectly_writable<
476 OutputIt, std::indirect_result_t<
477 BinaryOp, std::projected<std::ranges::iterator_t<Range1>, Proj1>,
478 std::projected<InputIt2, Proj2>>>)
479constexpr std::ranges::binary_transform_result<std::ranges::iterator_t<Range1>, InputIt2,
481transform(Range1&& r1, InputIt2 first2, OutputIt d_first, BinaryOp binary_op,
482 Proj1 proj1 = {}, Proj2 proj2 = {})
489 auto first1 = std::ranges::begin(r1);
490 auto last1 = std::ranges::end(r1);
491 for (; first1 != last1; ++first1, ++first2, ++d_first) {
493 std::invoke(binary_op, std::invoke(proj1, *first1), std::invoke(proj2, *first2));
495 return {std::move(first1), std::move(first2), std::move(d_first)};
516 std::random_access_iterator RandomIt2, std::random_access_iterator RandomIt3,
517 class BinaryOp,
class Proj1 = std::identity,
class Proj2 = std::identity>
519 std::indirectly_writable<
520 RandomIt3, std::indirect_result_t<
521 BinaryOp, std::projected<std::ranges::iterator_t<Range1>, Proj1>,
522 std::projected<RandomIt2, Proj2>>>)
523RandomIt3
transform(T&& policy, Range1&& r1, RandomIt2 first2, RandomIt3 d_first,
524 BinaryOp binary_op, Proj1 proj1 = {}, Proj2 proj2 = {})
526 return ufo::transform(std::forward<T>(policy), std::ranges::begin(r1),
527 std::ranges::end(r1), first2, d_first, std::move(binary_op),
528 std::move(proj1), std::move(proj2));
548template <ufo::execution::ExecutionPolicy P, std::input_iterator InputIt,
class T>
549[[nodiscard]] T
reduce(P&& policy, InputIt first, InputIt last, T init)
552 return std::reduce(execution::toSTL(std::forward<P>(policy)), first, last, init);
558 for_each(std::forward<P>(policy), first, last, [&](
auto const& x) {
559 std::lock_guard lock(m);
576template <ufo::execution::ExecutionPolicy P, std::ranges::input_range Range,
class T>
579 return reduce(std::forward<P>(policy), std::ranges::begin(r), std::ranges::end(r),
601template <ufo::execution::ExecutionPolicy P, std::input_iterator InputIt,
class UnaryPred>
602[[nodiscard]]
bool any_of(P&& policy, InputIt first, InputIt last, UnaryPred p)
605 return std::any_of(execution::toSTL(std::forward<P>(policy)), first, last, p);
607 std::atomic<bool> found =
false;
608 for_each(std::forward<P>(policy), first, last, [&](
auto const& x) {
632 return any_of(std::forward<P>(policy), std::ranges::begin(r), std::ranges::end(r),
648template <ufo::execution::ExecutionPolicy P, std::input_iterator InputIt,
class UnaryPred>
649[[nodiscard]]
bool all_of(P&& policy, InputIt first, InputIt last, UnaryPred p)
651 return !
any_of(std::forward<P>(policy), first, last,
652 [&p](
auto const& x) {
return !p(x); });
670 return all_of(std::forward<P>(policy), std::ranges::begin(r), std::ranges::end(r),
695[[nodiscard]] RandomIt
find_if(P&& policy, RandomIt first, RandomIt last, UnaryPred p)
698 return std::find_if(execution::toSTL(std::forward<P>(policy)), first, last, p);
700 std::atomic<std::size_t> min_idx =
701 static_cast<std::size_t
>(std::distance(first, last));
702 for_each(std::forward<P>(policy), std::size_t{}, min_idx.load(), [&](std::size_t i) {
704 std::size_t expected = min_idx.load();
705 while (i < expected && !min_idx.compare_exchange_weak(expected, i)) {
710 return first + min_idx.load();
730 return find_if(std::forward<P>(policy), std::ranges::begin(r), std::ranges::end(r),
752template <ufo::execution::ExecutionPolicy P, std::input_iterator InputIt,
class UnaryPred>
753[[nodiscard]] std::size_t
count_if(P&& policy, InputIt first, InputIt last, UnaryPred p)
756 return std::count_if(execution::toSTL(std::forward<P>(policy)), first, last, p);
758 std::atomic<std::size_t> count = 0;
759 for_each(std::forward<P>(policy), first, last, [&](
auto const& x) {
783 return count_if(std::forward<P>(policy), std::ranges::begin(r), std::ranges::end(r),
All vision-related classes and functions.
constexpr UnaryFunc for_each(Index first, Index last, UnaryFunc f, Proj proj={})
Applies f to each integer index in [first, last) sequentially.
bool all_of(P &&policy, InputIt first, InputIt last, UnaryPred p)
Checks if all elements in [first, last) satisfy p using the given execution policy.
RandomIt find_if(P &&policy, RandomIt first, RandomIt last, UnaryPred p)
Finds the first element in [first, last) satisfying p using the given execution policy.
bool any_of(P &&policy, InputIt first, InputIt last, UnaryPred p)
Checks if any element in [first, last) satisfies p using the given execution policy.
T reduce(P &&policy, InputIt first, InputIt last, T init)
Reduces the range [first, last) using init and the given execution policy.
std::size_t count_if(P &&policy, InputIt first, InputIt last, UnaryPred p)
Counts elements in [first, last) satisfying p using the given execution policy.
PointCloud< Dim, T, Rest... > transform(Transform< Dim, T > const &t, PointCloud< Dim, T, Rest... > pc)
Applies a rigid transform to every point position and returns the result.
Represents a closed interval [lower, upper] of a scalar type.