Skip to content

Instantly share code, notes, and snippets.

@kirkshoop
Last active October 26, 2018 00:10
Show Gist options
  • Save kirkshoop/0b77a52c725e3ee406aa6a2ca858fb4b to your computer and use it in GitHub Desktop.
Save kirkshoop/0b77a52c725e3ee406aa6a2ca858fb4b to your computer and use it in GitHub Desktop.
// 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...);
};
}
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;
}
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
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