146class CountingIterator
150 using iterator_concept = std::random_access_iterator_tag;
151 using iterator_category = std::random_access_iterator_tag;
152 using value_type = Eigen::Index;
153 using difference_type = Eigen::Index;
154 using pointer = void;
155 using reference = Eigen::Index;
157 CountingIterator() =
default;
160 explicit CountingIterator(Eigen::Index index)
165 [[nodiscard]] Eigen::Index
172 [[nodiscard]] Eigen::Index
173 operator[](difference_type n)
const
190 CountingIterator
const before = *
this;
207 CountingIterator
const before = *
this;
214 operator+=(difference_type n)
222 operator-=(difference_type n)
229 [[nodiscard]]
friend CountingIterator
230 operator+(CountingIterator it, difference_type n)
232 return CountingIterator{it.m_index + n};
236 [[nodiscard]]
friend CountingIterator
237 operator+(difference_type n, CountingIterator it)
239 return CountingIterator{it.m_index + n};
243 [[nodiscard]]
friend CountingIterator
244 operator-(CountingIterator it, difference_type n)
246 return CountingIterator{it.m_index - n};
250 [[nodiscard]]
friend difference_type
251 operator-(CountingIterator a, CountingIterator b)
253 return a.m_index - b.m_index;
257 [[nodiscard]]
friend auto
258 operator<=>(CountingIterator
const &, CountingIterator
const &) =
default;
262 Eigen::Index m_index = 0;
265static_assert(std::random_access_iterator<CountingIterator>);
275template <
typename Range>
280 using iterator_concept = std::random_access_iterator_tag;
281 using iterator_category = std::random_access_iterator_tag;
282 using value_type =
typename Range::value_type;
283 using difference_type = Eigen::Index;
284 using pointer = void;
285 using reference = value_type;
287 ElementIterator() =
default;
290 ElementIterator(Range
const & range, Eigen::Index index)
296 [[nodiscard]] value_type
299 return (*m_range)[m_index];
303 [[nodiscard]] value_type
304 operator[](difference_type n)
const
306 return (*m_range)[m_index + n];
321 ElementIterator
const before = *
this;
338 ElementIterator
const before = *
this;
345 operator+=(difference_type n)
353 operator-=(difference_type n)
360 [[nodiscard]]
friend ElementIterator
361 operator+(ElementIterator it, difference_type n)
367 [[nodiscard]]
friend ElementIterator
368 operator+(difference_type n, ElementIterator it)
374 [[nodiscard]]
friend ElementIterator
375 operator-(ElementIterator it, difference_type n)
381 [[nodiscard]]
friend difference_type
382 operator-(ElementIterator
const & a, ElementIterator
const & b)
384 return a.m_index - b.m_index;
388 [[nodiscard]]
friend bool
389 operator==(ElementIterator
const & a, ElementIterator
const & b)
391 return a.m_index == b.m_index;
395 [[nodiscard]]
friend auto
396 operator<=>(ElementIterator
const & a, ElementIterator
const & b)
398 return a.m_index <=> b.m_index;
403 Range
const * m_range =
nullptr;
404 Eigen::Index m_index = 0;
418concept StandardExecutionPolicy =
requires(P && policy, CountingIterator i, void (*f)(Eigen::Index)) {
419 std::for_each(std::forward<P>(policy), i, i, f);
429 operator()(Eigen::Index i)
const;
439concept UserExecutionPolicy =
requires(std::remove_cvref_t<P>
const & policy, IndexFunction
const & f) {
440 policy.forEachIndex(Eigen::Index{}, f);
447concept UserPolicyWithAllocator =
448 UserExecutionPolicy<P> &&
requires(std::remove_cvref_t<P>
const & policy) { policy.get_allocator(); };
460 || internal::UserExecutionPolicy<P> || internal::StandardExecutionPolicy<P>;
475template <
typename... Args>
476inline constexpr bool leadsWithPolicy =
false;
479template <
typename First,
typename... Rest>
487template <
typename T,
typename P>
489scratchVector(P
const & policy, std::size_t size)
491 if constexpr (UserPolicyWithAllocator<P>)
493 using Allocator = ReBound<std::remove_cvref_t<
decltype(policy.get_allocator())>, T>;
494 return std::vector<T, Allocator>(size, Allocator(policy.get_allocator()));
498 return std::vector<T>(size);
506inline constexpr Eigen::Index chunkSize = 1024;
509[[nodiscard]]
constexpr Eigen::Index
510chunkCount(Eigen::Index count)
512 return (count + chunkSize - 1) / chunkSize;
520template <ExecutionPolicy P,
typename F>
522forEachIndex([[maybe_unused]] P && policy, Eigen::Index count, F && f)
524 EMRYS_FILTER_ASSERT(count >= 0);
525 if constexpr (isSequential<P>)
527 for (Eigen::Index i = 0; i < count; ++i)
532 else if constexpr (UserExecutionPolicy<P>)
534 std::as_const(policy).forEachIndex(count, [&f](Eigen::Index i) {
540 std::for_each(std::forward<P>(policy), CountingIterator{0}, CountingIterator{count}, [&f](Eigen::Index i) {
550template <ExecutionPolicy P,
typename F>
552forEachChunk(P && policy, Eigen::Index count, F && f)
554 EMRYS_FILTER_ASSERT(count >= 0);
555 if constexpr (isSequential<P>)
559 f(Eigen::Index{0}, count);
564 forEachIndex(std::forward<P>(policy), chunkCount(count), [&](Eigen::Index chunk) {
565 Eigen::Index
const begin = chunk * chunkSize;
566 f(begin, std::min(chunkSize, count - begin));
582template <ExecutionPolicy P,
typename Partial,
typename Combine>
584reduceRanges(P && policy, Eigen::Index count, Partial
const & partial, Combine
const & combine)
586 using T = std::remove_cvref_t<std::invoke_result_t<Partial const &, Eigen::Index, Eigen::Index>>;
587 EMRYS_FILTER_ASSERT(count >= 0);
588 if constexpr (isSequential<P>)
590 return T{partial(Eigen::Index{0}, count)};
594 Eigen::Index
const chunks = chunkCount(count);
598 return T{partial(Eigen::Index{0}, count)};
600 auto partials = scratchVector<T>(policy,
static_cast<std::size_t
>(chunks));
601 forEachChunk(std::forward<P>(policy), count, [&](Eigen::Index begin, Eigen::Index length) {
602 partials[
static_cast<std::size_t
>(begin / chunkSize)] = partial(begin, length);
604 T result = std::move(partials[0]);
605 for (std::size_t c = 1; c < partials.size(); ++c)
607 result = combine(std::move(result), partials[c]);
617template <ExecutionPolicy P,
typename T,
typename Combine,
typename F>
619transformReduce(P && policy, Eigen::Index count, T
const & identity, Combine
const & combine, F
const & f)
622 std::forward<P>(policy),
624 [&](Eigen::Index begin, Eigen::Index length) {
626 for (Eigen::Index i = begin; i < begin + length; ++i)
628 result = combine(std::move(result), T(f(i)));
645template <ExecutionPolicy P,
typename T>
647cumulativeSum(P && policy, std::span<T const> in, std::span<T> out)
649 EMRYS_FILTER_ASSERT(in.size() == out.size() &&
"the scan writes one sum per element");
650 Eigen::Index
const count = Eigen::Index(in.size());
652 auto const scan = [&](Eigen::Index begin, Eigen::Index length, T
const * offset) {
653 auto const first = std::size_t(begin);
654 T sum = offset ? T(*offset + in[first]) : in[first];
656 for (std::size_t i = first + 1; i < std::size_t(begin + length); ++i)
666 if constexpr (isSequential<P>)
668 scan(0, count,
nullptr);
672 Eigen::Index
const chunks = chunkCount(count);
675 scan(0, count,
nullptr);
678 auto offsets = scratchVector<T>(policy,
static_cast<std::size_t
>(chunks));
679 forEachChunk(policy, count, [&](Eigen::Index begin, Eigen::Index length) {
680 auto const first = std::size_t(begin);
682 for (std::size_t i = first + 1; i < std::size_t(begin + length); ++i)
686 offsets[std::size_t(begin / chunkSize)] = total;
689 T carry = offsets[0];
690 for (std::size_t c = 1; c < offsets.size(); ++c)
692 T
const total = offsets[c];
696 forEachChunk(std::forward<P>(policy), count, [&](Eigen::Index begin, Eigen::Index length) {
697 std::size_t
const chunk = std::size_t(begin / chunkSize);
698 scan(begin, length, chunk == 0 ?
nullptr : &offsets[chunk]);
706template <ExecutionPolicy P,
typename FromDerived,
typename To>
708gather(P && policy, std::span<Eigen::Index const> indices, Eigen::MatrixBase<FromDerived>
const & from, To && to)
710 EMRYS_FILTER_ASSERT(to.cols() == Eigen::Index(indices.size()) &&
"gather one column per index");
711 forEachIndex(std::forward<P>(policy), Eigen::Index(indices.size()), [&](Eigen::Index j) {
712 Eigen::Index const source = indices[std::size_t(j)];
713 EMRYS_FILTER_ASSERT(source >= 0 && source < from.cols() &&
"a gathered index is out of range");
714 to.col(j) = from.col(source);
726template <ExecutionPolicy P,
typename Keep,
typename Move>
728copyIfIndex(P && policy, Eigen::Index count, Keep
const & keep, Move
const & move)
730 EMRYS_FILTER_ASSERT(count >= 0);
731 if constexpr (isSequential<P>)
733 Eigen::Index out = 0;
734 for (Eigen::Index i = 0; i < count; ++i)
749 auto positions = scratchVector<Eigen::Index>(policy,
static_cast<std::size_t
>(count));
750 forEachIndex(policy, count, [&](Eigen::Index i) {
751 positions[std::size_t(i)] = keep(i) ? 1 : 0;
753 cumulativeSum(policy, std::span<Eigen::Index const>{positions}, std::span<Eigen::Index>{positions});
754 forEachIndex(std::forward<P>(policy), count, [&](Eigen::Index i) {
755 Eigen::Index
const before = i == 0 ? 0 : positions[std::size_t(i - 1)];
756 if (positions[std::size_t(i)] != before)
761 return positions.back();
766template <ExecutionPolicy P,
typename T>
768fill(P && policy, std::span<T> out, T
const & value)
770 forEachChunk(std::forward<P>(policy), Eigen::Index(out.size()), [&](Eigen::Index begin, Eigen::Index length) {
771 std::fill_n(out.begin() + begin, length, value);
The allocator conventions of decisions.md [allocation]: DefaultAllocator, Capacity,...
The macros every header includes first.
An execution policy: execution::sequential, a policy of the standard library such as std::execution::...
Definition Execution.h:459
constexpr Sequential sequential
The default execution policy: plain loops on the calling thread, in index order (Sequential).
Definition Execution.h:128
The library's execution policies: the constant execution::sequential and its type.
Definition Execution.h:115
The type of execution::sequential, the default execution policy: plain loops on the calling thread,...
Definition Execution.h:123