Concepts and type traits

Asynchronous std concepts

template<typename F, typename ...Args>
concept invocable
#include <libfork/algorithm/constraints.hpp>

Test if “F” is async invocable xor normally invocable with Args....

template<typename F, typename ...Args>
concept regular_invocable
#include <libfork/algorithm/constraints.hpp>

Test if “F” is regularly async invocable xor normally invocable invocable with Args....

template<class F, class I>
concept indirectly_unary_invocable
#include <libfork/algorithm/constraints.hpp>

`std::indirectly_unary_invocable that accepts async and regular function.

This uses the relaxed version from P2997R0 and the further relaxation from P2609R3

template<class F, class I>
concept indirectly_regular_unary_invocable
#include <libfork/algorithm/constraints.hpp>

`std::indirectly_regular_unary_invocable that accepts async and regular function.

This uses the relaxed version from P2997R0 and the further relaxation from P2609R3

Hint: indirect_value_t<I> = invoke_result_t<proj &, std::iter_value_t<I> &> for 1-projected iterators.

Asynchronous std traits

template<typename F, typename ...Args>
using lf::invoke_result_t = typename detail::either_invocable_result<F, Args...>::type

The result of invoking a regular-or-async function.

If F is a regular function then this is the same as std::invoke_result<F, Args...>. Otherwise, if F is an async function then this is the same as lf::core::invoke_result_t<F, Args...>.

template<std::indirectly_readable I>
using lf::indirect_value_t = typename detail::indirect_value_impl<I>::type

From P2609R3, the referenced value type.

Relaxes some constraints for lf::core::indirectly_unary_invocable Specifically: indirect_value_t<I> must be std::iter_value_t<I> & for an iterator and invoke_result_t<Proj &, indirect_value_t<Iter>> for projected<Proj, Iter>.

template<class F, class ...Is>
using lf::indirect_result_t = invoke_result_t<F, std::iter_reference_t<Is>...>

A variation of std::indirect_result_t that accepts async and regular function.

template<std::indirectly_readable I, typename ...Proj>
using lf::projected = typename detail::compose_projection<I, Proj...>::type

A variation of std::projected that accepts async/regular functions and composes projections.

Groups

template<class Bop, class T, class U>
concept semigroup
#include <libfork/algorithm/constraints.hpp>

A semigroup is a set S and an associative binary operation ·, such that S is closed under ·.

Associativity means that for all a, b, c in S, (a · b) · c = a · (b · c).

Example: (Z, +) is a semigroup, since we can add any two integers and the result is also an integer.

Example: (Z, /) is not a semigroup, since 2/3 s not an integer.

Example: (Z, -) is not a semigroup, since (1 - 1) - 1 != 1 - (1 - 1).

Let t, u and bop be objects of types T, U and Bop respectively. Then the following expressions must be valid:

  1. bop(t, t)

  2. bop(u, u)

  3. bop(u, t)

  4. bop(t, u)

Additionally, the expressions must return the same type, R.

Note: A semigroup requires all invocations to be regular. This is a semantic requirement only.

Constraints

Foldability

template<class Bop, class T>
concept foldable
#include <libfork/algorithm/constraints.hpp>

Test if a binary operation supports a fold operation over a type.

The binary operation must be associative but not necessarily commutative.

This means a collection of one or more values of type T can be folded to a single value of type Acc equal to std::decay_t<semigroup_t<Bop, T>> using bop, an operator of type Bop.

For example using the infix notation a · b to mean bop(a, b):

  1. fold bop [a] = a

  2. fold bop [a, b] = a · b

  3. fold bop [a, b, c] = a · b · c

  4. fold bop [a, b, c, ...] = a · b · c · ...

The order of evaluation is unspecified but the elements will not be reordered.

tparam Bop:

Associative binary operator.

tparam I:

Input type

template<class Bop, class I>
concept indirectly_foldable
#include <libfork/algorithm/constraints.hpp>

An indirect version of lf::foldable.

tparam Bop:

Associative binary operator.

tparam I:

Input iterator.

template<class Bop, std::random_access_iterator I, class Proj>
using lf::indirect_fold_acc_t = std::decay_t<indirect_result_t<Bop&, projected<I, Proj>, projected<I, Proj>>>

Compute the accumulator/result type for a fold operation.

Scannability

template<class Bop, class O, class T>
concept scannable
#include <libfork/algorithm/constraints.hpp>

Test if a binary operation supports a scan operation over a type.

The binary operation must be associative but not necessarily commutative.

tparam Bop:

The binary operation.

tparam O:

The output iterator.

tparam T:

The value type to scan over.

template<class Bop, class O, class I>
concept indirectly_scannable
#include <libfork/algorithm/constraints.hpp>

An indirect version of lf::scannable over an iterator.

tparam Bop:

The binary operation.

tparam O:

The output iterator.

tparam T:

The input iterator.