Last active
October 26, 2018 00:10
-
-
Save kirkshoop/0b77a52c725e3ee406aa6a2ca858fb4b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Eric Niebler 2015 | |
// Copyright Casey Carter 2015 | |
// | |
// Use, modification and distribution is subject to the | |
// Boost Software License, Version 1.0. (See accompanying | |
// file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
// | |
// Project home: https://github.com/caseycarter/cmcstl2 | |
#include <type_traits> | |
#include <functional> | |
namespace std | |
{ | |
template<typename T> | |
using __t = typename T::type; | |
template<template<class...> class T, class... U> | |
concept _Valid = requires { typename T<U...>; }; | |
template<class U, template<class...> class T, class... V> | |
concept _Is = _Valid<T, U, V...> && T<U, V...>::value; | |
template<class U, template<class...> class T, class... V> | |
concept _IsNot = _Valid<T, U, V...> && !T<U, V...>::value; | |
template<typename T, typename U> | |
concept Same = __is_same(T, U) && __is_same(U, T); | |
template<class From, class To> | |
concept ConvertibleTo = | |
is_convertible_v<From, To> && requires(From (&f)()) { | |
static_cast<To>(f()); | |
}; | |
// Axiom: implicit and explicit conversion have equal results. | |
template<class U> | |
concept _Decayed = Same<decay_t<U>, U>; | |
template<template<class...> class, class...> | |
struct __defer {}; | |
template<template<class...> class T, class... A> | |
requires _Valid<T, A...> | |
struct __defer<T, A...> { | |
using type = T<A...>; | |
}; | |
template<class T> | |
using __ref = add_lvalue_reference_t<T>; | |
template<class T, class X = remove_reference_t<T>> | |
using __cref = __ref<add_const_t<X>>; | |
template<class T, class U> | |
using __cond = decltype(true ? static_cast<T(*)()>(nullptr)() : static_cast<U(*)()>(nullptr)()); | |
template<class From, class To> | |
struct __copy_cv_ : type_identity<To> {}; | |
template<class From, class To> | |
struct __copy_cv_<From const, To> : add_const<To> {}; | |
template<class From, class To> | |
struct __copy_cv_<From volatile, To> : add_volatile<To> {}; | |
template<class From, class To> | |
struct __copy_cv_<From const volatile, To> : add_cv<To> {}; | |
template<class From, class To> | |
using __copy_cv = __t<__copy_cv_<From, To>>; | |
template<class T, class U> | |
struct __builtin_common {}; | |
template<class T, class U> | |
using __builtin_common_t = __t<__builtin_common<T, U>>; | |
template<class T, class U> | |
requires _Valid<__cond, __cref<T>, __cref<U>> | |
struct __builtin_common<T, U> : decay<__cond<__cref<T>, __cref<U>>> {}; | |
template<class T, class U, class R = __builtin_common_t<T &, U &>> | |
using __rref_res = conditional_t<is_reference_v<R>, | |
remove_reference_t<R> &&, R>; | |
template<class T, class U> | |
requires | |
_Valid<__builtin_common_t, T &, U &> && | |
ConvertibleTo<T &&, __rref_res<T, U>> && | |
ConvertibleTo<U &&, __rref_res<T, U>> | |
struct __builtin_common<T &&, U &&> : type_identity<__rref_res<T, U>> {}; | |
template<class T, class U> | |
using __lref_res = __cond<__copy_cv<T, U> &, __copy_cv<U, T> &>; | |
template<class T, class U> | |
struct __builtin_common<T &, U &> : __defer<__lref_res, T, U> {}; | |
template<class T, class U> | |
requires | |
_Valid<__builtin_common_t, T &, U const &> && | |
ConvertibleTo<U &&, __builtin_common_t<T &, U const &>> | |
struct __builtin_common<T &, U &&> : __builtin_common<T &, U const &> {}; | |
template<class T, class U> | |
struct __builtin_common<T &&, U &> : __builtin_common<U &, T &&> {}; | |
namespace __2 { | |
// common_type | |
template<class...> | |
struct common_type {}; | |
template<class... Ts> | |
using common_type_t = __t<common_type<Ts...>>; | |
template<class T> | |
struct common_type<T> : decay<T> {}; | |
template<class T, class U> | |
struct __common_type2 : common_type<decay_t<T>, decay_t<U>> {}; | |
template<_Decayed T, _Decayed U> | |
struct __common_type2<T, U> : __builtin_common<T, U> {}; | |
template<_Decayed T, _Decayed U> | |
requires requires { typename common_type_t<T, U>; } | |
struct __common_type2<T, U> : common_type<T, U> {}; | |
template<class T, class U> | |
struct common_type<T, U> : __common_type2<T, U> {}; | |
template<class T, class U, class V, class... W> | |
requires _Valid<common_type_t, T, U> | |
struct common_type<T, U, V, W...> | |
: common_type<common_type_t<T, U>, V, W...> {}; | |
namespace __qual { | |
template<class> | |
struct __xref { | |
template<class T> | |
using apply = T; | |
}; | |
template<class T> | |
struct __xref<T&> { | |
template<class U> | |
using apply = typename __xref<T>::template apply<U>&; | |
}; | |
template<class T> | |
struct __xref<T&&> { | |
template<class U> | |
using apply = typename __xref<T>::template apply<U>&&; | |
}; | |
template<class T> | |
struct __xref<const T> { | |
template<class U> | |
using apply = const U; | |
}; | |
template<class T> | |
struct __xref<volatile T> { | |
template<class U> | |
using apply = volatile U; | |
}; | |
template<class T> | |
struct __xref<const volatile T> { | |
template<class U> | |
using apply = const volatile U; | |
}; | |
} | |
template<class T, class U, template<class> class TQual, template<class> class UQual> | |
struct basic_common_reference {}; | |
template<class T, class U> | |
using __basic_common_reference = | |
basic_common_reference<remove_cvref_t<T>, remove_cvref_t<U>, | |
__qual::__xref<T>::template apply, | |
__qual::__xref<U>::template apply>; | |
// common_reference | |
template<class...> | |
struct common_reference {}; | |
template<class... Ts> | |
using common_reference_t = __t<common_reference<Ts...>>; | |
template<class T> | |
struct common_reference<T> : type_identity<T> {}; | |
template<class T, class U> | |
struct __common_reference2_2_ : common_type<T, U> {}; | |
template<class T, class U> | |
requires _Valid<__cond, T, U> | |
struct __common_reference2_2_<T, U> : type_identity<__cond<T, U>> {}; | |
template<class T, class U> | |
struct __common_reference2_1_ : __common_reference2_2_<T, U> {}; | |
template<class T, class U> | |
requires _Valid<__t, __basic_common_reference<T, U>> | |
struct __common_reference2_1_<T, U> : __basic_common_reference<T, U> {}; | |
template<class T, class U> | |
struct __common_reference2 : __common_reference2_1_<T, U> {}; | |
template<_Is<is_reference> T, _Is<is_reference> U> | |
requires | |
_Valid<__builtin_common_t, T, U> && | |
_Is<__builtin_common_t<T, U>, is_reference> | |
struct __common_reference2<T, U> : __builtin_common<T, U> {}; | |
template<class T, class U> | |
struct common_reference<T, U> : __common_reference2<T, U> {}; | |
template<class T, class U, class V, class... W> | |
requires _Valid<common_reference_t, T, U> | |
struct common_reference<T, U, V, W...> | |
: common_reference<common_reference_t<T, U>, V, W...> {}; | |
} // namespace __2 | |
template<class T, class U> | |
concept CommonReference = | |
requires { | |
typename __2::common_reference_t<T, U>; | |
typename __2::common_reference_t<U, T>; | |
} && | |
Same<__2::common_reference_t<T, U>, __2::common_reference_t<U, T>> && | |
ConvertibleTo<T, __2::common_reference_t<T, U>> && | |
ConvertibleTo<U, __2::common_reference_t<T, U>>; | |
template<class T, class U> | |
concept Common = | |
requires { | |
typename __2::common_type_t<T, U>; | |
typename __2::common_type_t<U, T>; | |
} && | |
Same<__2::common_type_t<T, U>, __2::common_type_t<U, T>> && | |
ConvertibleTo<T, __2::common_type_t<T, U>> && | |
ConvertibleTo<U, __2::common_type_t<T, U>> && | |
CommonReference<add_lvalue_reference_t<const T>, | |
add_lvalue_reference_t<const U>> && | |
CommonReference<add_lvalue_reference_t<common_type_t<T, U>>, | |
__2::common_reference_t<add_lvalue_reference_t<const T>, | |
add_lvalue_reference_t<const U>>>; | |
} // namespace std | |
namespace std | |
{ | |
template<class U> | |
concept _Object = | |
requires (U *u) { | |
{u} -> const volatile void*; | |
*u; | |
}; | |
template<class T, class U> | |
concept DerivedFrom = | |
__is_base_of(U, T) && | |
_Is<const volatile T*, is_convertible, const volatile U*>; | |
template<class T> | |
concept Destructible = _Is<T, is_nothrow_destructible>; | |
template<class T, class... Args> | |
concept Constructible = | |
Destructible<T> && _Is<T, is_constructible, Args...>; | |
template<class T> | |
concept DefaultConstructible = Constructible<T>; | |
template<class T> | |
concept MoveConstructible = Constructible<T, T> && ConvertibleTo<T, T>; | |
template<class T, class U> | |
concept Assignable = | |
_Is<T, is_lvalue_reference> && | |
CommonReference< | |
const remove_reference_t<T>&, | |
const remove_reference_t<U>&> && | |
requires(T t, U&& u) { | |
{ t = (U&&)u } -> Same<T>&&; | |
}; | |
namespace __cpo { | |
inline constexpr struct __swap { | |
template<class A, class B> | |
constexpr void operator()(A&& a, B&& b) const | |
noexcept(noexcept(swap((A&&) a, (B&&) b))) | |
requires requires { swap((A&&) a, (B&&) b); } | |
{ | |
swap((A&&) a, (B&&) b); | |
} | |
} swap {}; | |
} | |
template<class T> | |
concept Swappable = | |
requires(T& a, T& b) { | |
__cpo::swap(a, b); | |
}; | |
template<class T, class U> | |
concept SwappableWith = | |
CommonReference< | |
const remove_reference_t<T>&, | |
const remove_reference_t<U>&> && | |
requires(T&& t, U&& u) { | |
__cpo::swap((T&&)t, (T&&)t); | |
__cpo::swap((U&&)u, (U&&)u); | |
__cpo::swap((T&&)t, (U&&)u); | |
__cpo::swap((U&&)u, (T&&)t); | |
}; | |
template<class T> | |
concept Movable = | |
_Object<T> && | |
MoveConstructible<T> && | |
Assignable<T&, T> && | |
Swappable<T>; | |
template<class T> | |
concept CopyConstructible = | |
MoveConstructible<T> && | |
Constructible<T, T&> && | |
Constructible<T, const T&> && | |
Constructible<T, const T> && | |
ConvertibleTo<T&, T> && | |
ConvertibleTo<const T&, T> && | |
ConvertibleTo<const T, T>; | |
template<class T> | |
concept Copyable = | |
CopyConstructible<T> && | |
Movable<T> && | |
Assignable<T&, const T&>; | |
template<class T> | |
concept Semiregular = | |
Copyable<T> && DefaultConstructible<T>; | |
template<class F, class... Args> | |
concept Invocable = | |
requires(F&& f, Args&&... args) { | |
std::invoke((F&&)f, (Args&&)args...); | |
}; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace std::experimental | |
{ | |
template<typename _Tp> | |
struct __is_valid_await_suspend_return_type : false_type {}; | |
template<> | |
struct __is_valid_await_suspend_return_type<bool> : true_type {}; | |
template<> | |
struct __is_valid_await_suspend_return_type<void> : true_type {}; | |
template<typename _Promise> | |
struct __is_valid_await_suspend_return_type<coroutine_handle<_Promise>> | |
: true_type {}; | |
template<typename _Tp> | |
concept _AwaitSuspendReturnType = | |
__is_valid_await_suspend_return_type<_Tp>::value; | |
template<typename _Tp> | |
concept Awaiter = | |
requires(_Tp&& __awaiter, coroutine_handle<void> __h) | |
{ | |
// await_ready() result must be contextually convertible to bool. | |
__awaiter.await_ready() ? void() : void(); | |
__awaiter.await_suspend(__h); | |
requires _AwaitSuspendReturnType<decltype( | |
__awaiter.await_suspend(__h))>; | |
__awaiter.await_resume(); | |
}; | |
template<typename _Tp, typename _Result> | |
concept AwaiterOf = | |
Awaiter<_Tp> && | |
requires(_Tp&& __awaiter) | |
{ | |
{ __awaiter.await_resume() } -> _Result; | |
}; | |
template<typename _Tp> | |
concept _WeakHasMemberCoAwait = | |
requires(_Tp&& __awaitable) | |
{ | |
static_cast<_Tp&&>(__awaitable).operator co_await(); | |
}; | |
template<typename _Tp> | |
concept _WeakHasNonMemberCoAwait = | |
requires(_Tp&& __awaitable) | |
{ | |
operator co_await(static_cast<_Tp&&>(__awaitable)); | |
}; | |
inline namespace __cpo | |
{ | |
inline constexpr struct __get_awaiter | |
{ | |
template<_WeakHasMemberCoAwait _Tp> | |
constexpr decltype(auto) operator()(_Tp&& __awaitable) const | |
noexcept(noexcept(static_cast<_Tp&&>(__awaitable).operator co_await())) | |
{ | |
return static_cast<_Tp&&>(__awaitable).operator co_await(); | |
} | |
template<_WeakHasNonMemberCoAwait _Tp> | |
requires !_WeakHasMemberCoAwait<_Tp> | |
constexpr decltype(auto) operator()(_Tp&& __awaitable) const | |
noexcept(noexcept(operator co_await(static_cast<_Tp&&>(__awaitable)))) | |
{ | |
return operator co_await(static_cast<_Tp&&>(__awaitable)); | |
} | |
template<typename _Tp> | |
requires !_WeakHasNonMemberCoAwait<_Tp> && !_WeakHasMemberCoAwait<_Tp> | |
constexpr _Tp&& operator()(_Tp&& __awaitable) const noexcept | |
{ | |
return static_cast<_Tp&&>(__awaitable); | |
} | |
} get_awaiter{}; | |
} | |
template<typename _Tp> | |
concept Awaitable = | |
std::MoveConstructible<_Tp> && | |
requires(_Tp&& __awaitable) | |
{ | |
{ get_awaiter(static_cast<_Tp&&>(__awaitable)) } -> Awaiter; | |
}; | |
template<typename _Tp, typename _Result> | |
concept AwaitableOf = | |
Awaitable<_Tp> && | |
requires(_Tp&& __awaitable) | |
{ | |
{ get_awaiter(static_cast<_Tp&&>(__awaitable)) } -> AwaiterOf<_Result>; | |
}; | |
template<typename _Tp> | |
struct awaiter_type | |
{}; | |
template<Awaitable _Tp> | |
struct awaiter_type<_Tp> | |
{ | |
using type = decltype( | |
std::experimental::get_awaiter(std::declval<_Tp>())); | |
}; | |
template<Awaitable _Tp> | |
using awaiter_type_t = typename awaiter_type<_Tp>::type; | |
template<typename _Tp> | |
struct await_result {}; | |
template<Awaitable _Tp> | |
struct await_result<_Tp> | |
{ | |
using type = decltype( | |
std::declval<awaiter_type_t<_Tp>&>().await_resume()); | |
}; | |
template<typename _Tp> | |
using await_result_t = typename await_result<_Tp>::type; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace unifex | |
{ | |
struct visitee_tag; | |
using visitee = visitee_tag; | |
template<typename S> | |
struct visitee_traits; | |
// Awaitables are visitees: | |
template<std::experimental::Awaitable A> | |
struct visitee_traits<A> { | |
using visitee_concept = visitee_tag; | |
using error_type = std::exception_ptr; | |
template<template<class...> class Tuple, template<class...> class Variant = std::type_identity_t> | |
using value_types = Variant<Tuple<std::experimental::await_result_t<A>>>; | |
}; | |
} | |
namespace unifex | |
{ | |
namespace __adl | |
{ | |
// Visitee customisation points | |
template<class T, class... V> | |
auto __call_visit_by_ref(T&& t, V&&... v) -> decltype(static_cast<T&&>(t).visit(static_cast<V&&>(v)...)); | |
template<typename S, typename R> | |
requires requires(S&& visitee, R&& visitor) | |
{ | |
{ static_cast<S&&>(visitee).visit(static_cast<R&&>(visitor)) } -> void; | |
{ __call_visit_by_ref(static_cast<S&&>(visitee), static_cast<R&&>(visitor)) } -> void; | |
noexcept(static_cast<S&&>(visitee).visit(static_cast<R&&>(visitor))); | |
} | |
void visit(S&& visitee, R&& visitor) noexcept | |
{ | |
static_cast<S&&>(visitee).visit(static_cast<R&&>(visitor)); | |
} | |
template<typename S, typename R> | |
requires requires(S& visitee, R&& visitor) | |
{ | |
{ visit(visitee, static_cast<R&&>(visitor)) } -> void; | |
noexcept(visit(visitee, static_cast<R&&>(visitor))); | |
} | |
void visit(std::reference_wrapper<S> visitee, R&& visitor) noexcept | |
{ | |
visit(visitee.get(), static_cast<R&&>(visitor)); | |
} | |
template<typename S, typename R> | |
requires requires(S&& visitee, R&& visitor) | |
{ | |
{ visit(*static_cast<S&&>(visitee), static_cast<R&&>(visitor)) } -> void; | |
noexcept(visit(*static_cast<S&&>(visitee), static_cast<R&&>(visitor))); | |
} | |
void visit(S&& visitee, R&& visitor) noexcept | |
{ | |
visit(*static_cast<S&&>(visitee), static_cast<R&&>(visitor)); | |
} | |
template<typename A, typename R> | |
requires std::experimental::Awaitable<A> && | |
ValueVisitor<R, std::experimental::await_result_t<A>> && | |
ErrorVisitor<R, std::exception_ptr> | |
void visit(A awaitable, R visitor); | |
struct visit_fn | |
{ | |
template<typename Visitee, typename Visitor> | |
// requires requires (Visitee&& visitee, Visitor&& visitor) | |
// { | |
// { visit(static_cast<Visitee&&>(visitee), static_cast<Visitor&&>(visitor)) } -> void; | |
// noexcept(visit(static_cast<Visitee&&>(visitee), static_cast<Visitor&&>(visitor))); | |
// } | |
constexpr auto operator()(Visitee&& visitee, Visitor&& visitor) const noexcept | |
{ | |
visit(static_cast<Visitee&&>(visitee), static_cast<Visitor&&>(visitor)); | |
} | |
}; | |
} // namespace __adl | |
namespace op | |
{ | |
inline constexpr __adl::visit_fn visit{}; | |
} | |
namespace awaitable_visitees | |
{ | |
struct __visitee_adl_hook {}; | |
} | |
struct visitee_tag : private awaitable_visitees::__visitee_adl_hook { | |
using visitee_concept = visitee_tag; | |
}; | |
using visitee = visitee_tag; | |
// A visitee inherits from visitee_of<Error, Values...> to become a TypedVisitee. | |
// If a visitee can pass values As... or Bs... to a visitor, then the visitee | |
// can inherit from visitee_of<Error, As...>::or_<Bs...>. More sets of alternate | |
// values can be adde3d by tacking on more additional ::or_<...> instantiations; | |
// e.g., visitee_of<Error, As...>::or_<Bs...>::or_<Cs...> | |
template<class Error, class... Values> | |
requires sizeof...(Values) < 2 | |
struct visitee_of : visitee { | |
using error_type = Error; | |
template<template<class...> class Tuple> | |
using value_types = Tuple<Values...>; | |
}; | |
namespace __detail | |
{ | |
template<class S> | |
concept _VisiteeLike = requires { | |
typename S::visitee_concept; | |
}; | |
template<template<template<class...> class, template<class...> class> class> | |
struct __has_template; | |
template<typename> | |
struct __basic_visitee_traits { | |
}; | |
template<_VisiteeLike S> | |
struct __basic_visitee_traits<S> { | |
using visitee_concept = typename S::visitee_concept; | |
}; | |
template<_VisiteeLike S> | |
requires requires { | |
typename __has_template<S::template value_types>; | |
typename S::error_type; | |
} | |
struct __basic_visitee_traits<S> { | |
using visitee_concept = typename S::visitee_concept; | |
template<template<class...> class Tuple> | |
using value_types = typename S::template value_types<Tuple>; | |
using error_type = typename S::error_type; | |
}; | |
} | |
template<typename S> | |
struct visitee_traits | |
: std::conditional_t< | |
std::is_same_v<std::decay_t<S>, S>, | |
__detail::__basic_visitee_traits<S>, | |
visitee_traits<std::decay_t<S>>> { | |
using __not_specialized = void; | |
}; | |
template<typename S> | |
concept Visitee = | |
std::MoveConstructible<std::remove_cvref_t<S>> && | |
requires { typename visitee_traits<S>::visitee_concept; } && | |
std::DerivedFrom<typename visitee_traits<S>::visitee_concept, visitee>; | |
template<typename S> | |
concept TypedVisitee = | |
Visitee<S> && | |
requires { | |
typename __detail::__has_template< | |
visitee_traits<S>::template value_types>; | |
typename visitee_traits<S>::error_type; | |
}; | |
template<typename S, typename R> | |
concept VisiteeTo = | |
Visitee<S> && | |
Visitor<R> && | |
requires (S& from, R&& to) { | |
op::visit(from, (R&&) to); | |
}; | |
template< | |
TypedVisitee From, | |
template<class...> class Tuple> | |
using visitee_values_t = typename visitee_traits<std::remove_cvref_t<From>>::template value_types<Tuple>; | |
template<TypedVisitee From> | |
using visitee_error_t = typename visitee_traits<From>::error_type; | |
/// \cond | |
template<class Fun> | |
struct __invoke_with { | |
template<typename...Args> | |
using result_t = std::invoke_result_t<Fun, Args...>; | |
template<template<class...> class Tuple> | |
struct as { | |
template<typename...Args> | |
using result_t = | |
std::conditional_t< | |
std::is_void_v<result_t<Args...>>, | |
Tuple<>, | |
Tuple<result_t<Args...>>>; | |
}; | |
}; | |
template<class...> | |
struct __types; | |
/// \endcond | |
template<class Fun, TypedVisitee From> | |
requires requires { | |
typename visitee_traits<From>::template value_types< | |
__invoke_with<Fun>::template result_t, __types>; | |
} | |
struct transformed_visitee_of : visitee { | |
using error_type = typename visitee_traits<From>::error_type; | |
template<template<class...> class Tuple> | |
using value_types = | |
visitee_values_t< | |
From, | |
__invoke_with<Fun>::template as<Tuple>::template result_t>; | |
}; | |
} // namespace unifex |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace unifex | |
{ | |
template<typename S> | |
struct visitor_traits; | |
} | |
namespace unifex | |
{ | |
namespace __adl | |
{ | |
//////////////////////////// | |
// Default Visitor implementations | |
template<class T, class... V> | |
auto __call_value_by_ref(T& t, V&&... v) -> decltype(t.value(static_cast<V&&>(v)...)); | |
template<typename R, typename... Values> | |
requires requires(R& r, Values&&... values) | |
{ | |
{ r.value(static_cast<Values&&>(values)...) } -> void; | |
{ __call_value_by_ref(r, static_cast<Values&&>(values)...) } -> void; | |
} | |
void set_value(R& r, Values&&... values) | |
noexcept(noexcept(r.value(static_cast<Values&&>(values)...))) | |
{ | |
r.value(static_cast<Values&&>(values)...); | |
} | |
template<class T, class... V> | |
auto __call_error_by_ref(T& t, V&&... v) -> decltype(t.error(static_cast<V&&>(v)...)); | |
template<typename R, typename Error> | |
requires requires(R& r, Error&& error) | |
{ | |
{ r.error(static_cast<Error&&>(error)) } -> void; | |
{ __call_error_by_ref(r, static_cast<Error&&>(error)) } -> void; | |
noexcept(r.error(static_cast<Error&&>(error))); | |
} | |
auto set_error(R& r, Error&& error) noexcept | |
{ | |
r.error(static_cast<Error&&>(error)); | |
} | |
template<typename R, typename... Values> | |
requires requires(R& r, Values&&... values) | |
{ | |
{ set_value(*r, static_cast<Values&&>(values)...) } -> void; | |
} | |
void set_value(R& r, Values&&... values) | |
noexcept(noexcept(set_value(*r, static_cast<Values&&>(values)...))) | |
{ | |
set_value(*r, static_cast<Values&&>(values)...); | |
} | |
template<typename R, typename Error> | |
requires requires(R& r, Error&& error) | |
{ | |
{ set_error(*r, static_cast<Error&&>(error)) } -> void; | |
noexcept(set_error(*r, static_cast<Error&&>(error))); | |
} | |
auto set_error(R& r, Error&& error) noexcept | |
{ | |
set_error(*r, static_cast<Error&&>(error)); | |
} | |
///////////////////////////// | |
// std::reference_wrapper<R> specialisations | |
template<typename R, typename... Values> | |
requires requires(R& r, Values&&... values) | |
{ | |
set_value(r, static_cast<Values&&>(values)...); | |
} | |
void set_value(std::reference_wrapper<R> r, Values&&... values) | |
noexcept(noexcept(set_value(r.get(), static_cast<Values&&>(values)...))) | |
{ | |
set_value(r.get(), static_cast<Values&&>(values)...); | |
} | |
template<typename R, typename Error> | |
requires requires(R& r, Error&& error) | |
{ | |
{ set_error(r, static_cast<Error&&>(error)) } -> void; | |
noexcept(set_error(r, static_cast<Error&&>(error))); | |
} | |
void set_error(std::reference_wrapper<R> r, Error&& error) noexcept | |
{ | |
set_error(r.get(), static_cast<Error&&>(error)); | |
} | |
///////////////////////// | |
// Function object types | |
struct set_value_fn | |
{ | |
template<typename R, typename... Values> | |
requires requires(R&& r, Values&&... values) | |
{ | |
{ set_value(static_cast<R&&>(r), static_cast<Values&&>(values)...) } -> void; | |
} && sizeof...(Values) < 2 | |
void operator()(R&& r, Values&&... values) const | |
noexcept(noexcept(set_value(static_cast<R&&>(r), static_cast<Values&&>(values)...))) | |
{ | |
set_value(static_cast<R&&>(r), static_cast<Values&&>(values)...); | |
} | |
}; | |
struct set_error_fn | |
{ | |
template<typename R, typename Error> | |
requires requires(R&& r, Error&& error) | |
{ | |
{ set_error(static_cast<R&&>(r), static_cast<Error&&>(error)) } -> void; | |
noexcept(set_error(static_cast<R&&>(r), static_cast<Error&&>(error))); | |
} | |
void operator()(R&& r, Error&& error) const noexcept | |
{ | |
set_error(static_cast<R&&>(r), static_cast<Error&&>(error)); | |
} | |
}; | |
} // namespace __adl | |
namespace op | |
{ | |
inline constexpr __adl::set_error_fn set_error{}; | |
inline constexpr __adl::set_value_fn set_value{}; | |
} | |
namespace detail | |
{ | |
struct set_final_value_fn | |
{ | |
template<typename Visitor, typename... Values> | |
requires requires(Visitor&& r, Values&&... values) | |
{ | |
op::set_value(static_cast<Visitor&&>(r), static_cast<Values&&>(values)...); | |
op::set_error(static_cast<Visitor&&>(r), std::current_exception()); | |
} && sizeof...(Values) < 2 | |
void operator()(Visitor&& r, Values&&... values) const noexcept | |
{ | |
if constexpr ( | |
noexcept(op::set_value(static_cast<Visitor&&>(r), static_cast<Values&&>(values)...))) | |
{ | |
// Specialisation for noexcept set_value/set_done that avoids try/catch | |
// and avoids instantiating set_error() code-path. | |
op::set_value(static_cast<Visitor&&>(r), static_cast<Values&&>(values)...); | |
} | |
else | |
{ | |
try | |
{ | |
op::set_value(static_cast<Visitor&&>(r), static_cast<Values&&>(values)...); | |
} | |
catch (...) | |
{ | |
op::set_error(static_cast<Visitor&&>(r), std::current_exception()); | |
} | |
} | |
} | |
}; | |
} | |
namespace op | |
{ | |
inline constexpr detail::set_final_value_fn set_final_value{}; | |
} | |
struct visitor_tag { | |
using visitor_concept = visitor_tag; | |
}; | |
using visitor = visitor_tag; | |
namespace __detail | |
{ | |
template<class S> | |
concept _VisitorLike = requires { | |
typename S::visitor_concept; | |
}; | |
template<template<template<class...> class, template<class...> class> class> | |
struct __has_template; | |
template<typename> | |
struct __basic_visitor_traits { | |
}; | |
template<_VisitorLike S> | |
struct __basic_visitor_traits<S> { | |
using visitor_concept = typename S::visitor_concept; | |
}; | |
} | |
template<typename S> | |
struct visitor_traits | |
: std::conditional_t< | |
std::is_same_v<std::decay_t<S>, S>, | |
__detail::__basic_visitor_traits<S>, | |
visitor_traits<std::decay_t<S>>> { | |
using __not_specialized = void; | |
}; | |
template<typename S> | |
struct visitor_traits<S*> : | |
visitor_traits<std::decay_t<S>> { | |
}; | |
template<typename T> | |
concept Visitor = | |
std::MoveConstructible<T> && | |
requires { typename visitor_traits<T>::visitor_concept; } && | |
std::is_nothrow_move_constructible_v<T>; | |
template<class...> struct __types; | |
template<typename T, typename... Values> | |
concept _ValueVisitor = | |
requires(T&& visitor, Values&&... values) | |
{ | |
// set_final_value() also checks that set_error(visitor, std::current_exception()) | |
// is valid if either of set_value() or set_done() can throw. | |
op::set_final_value(static_cast<T&&>(visitor), static_cast<Values&&>(values)...); | |
}; | |
template<class T, class... Values> | |
inline constexpr bool _value_visitor_v = false; | |
template<class T, class... Values> | |
requires _ValueVisitor<T, Values...> | |
inline constexpr bool _value_visitor_v<T, Values...> = true; | |
template<class T> | |
requires _ValueVisitor<T> | |
inline constexpr bool _value_visitor_v<T, void> = true; | |
template<typename T, typename... Values> | |
concept ValueVisitor = | |
Visitor<T> && | |
_value_visitor_v<T, Values...>; | |
template<typename T, typename Error> | |
concept ErrorVisitor = | |
Visitor<T> && | |
requires(T&& visitor, Error&& error) | |
{ | |
op::set_error(static_cast<T&&>(visitor), static_cast<Error&&>(error)); | |
}; | |
} // namespace unifex |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment