Created
June 28, 2017 20:16
-
-
Save vittorioromeo/4d0dd32cbf2e9fb187ed573fcc28f043 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
// generated with `unosolo` | |
// https://github.com/SuperV1234/unosolo | |
#pragma once | |
#include <utility> | |
#ifndef FWD | |
#define FWD(...) ::std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__) | |
#endif | |
#include <type_traits> | |
#define SCELTA_NOEXCEPT_AND_TRT_ENABLE_IF(m_condition, ...) \ | |
noexcept(noexcept(__VA_ARGS__)) \ | |
->::std::enable_if_t<m_condition, decltype(__VA_ARGS__)> | |
#define SCELTA_NOEXCEPT_AND_TRT(...) \ | |
noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) | |
#define SCELTA_RETURNS_ENABLE_IF(m_condition, ...) \ | |
SCELTA_NOEXCEPT_AND_TRT_ENABLE_IF(__VA_ARGS__) \ | |
{ \ | |
return __VA_ARGS__; \ | |
} | |
#define SCELTA_RETURNS(...) \ | |
SCELTA_NOEXCEPT_AND_TRT(__VA_ARGS__) \ | |
{ \ | |
return __VA_ARGS__; \ | |
} | |
#define SCELTA_NOEXCEPT_AND_RETURN_BODY(...) \ | |
noexcept(noexcept(__VA_ARGS__)) \ | |
{ \ | |
return __VA_ARGS__; \ | |
} | |
#include <type_traits> | |
namespace scelta | |
{ | |
namespace impl | |
{ | |
template <typename...> | |
struct linear_overloader | |
{ | |
}; | |
template <typename T, typename... Ts> | |
struct linear_overloader<T, Ts...> : T | |
{ | |
private: | |
using U = linear_overloader<Ts...>; | |
U _u; | |
#define DEFINE_SELECT(m_refq) \ | |
private: \ | |
template <typename... Args, typename = decltype(std::declval<T m_refq>()( \ | |
std::declval<Args>()...))> \ | |
constexpr T m_refq select(int) m_refq noexcept \ | |
{ \ | |
return static_cast<T m_refq>(*this); \ | |
} \ | |
\ | |
template <typename... Args> \ | |
constexpr U m_refq select(...) m_refq noexcept \ | |
{ \ | |
return _u; \ | |
} \ | |
\ | |
public: \ | |
template <typename... Args> \ | |
constexpr decltype(auto) operator()(Args&&... xs) m_refq \ | |
{ \ | |
return select<Args...>(0)(FWD(xs)...); \ | |
} | |
DEFINE_SELECT(&) | |
DEFINE_SELECT(const&) | |
DEFINE_SELECT(&&) | |
#undef DEFINE_SELECT | |
public: | |
template <typename TFwd, typename... TFwds> | |
constexpr linear_overloader(TFwd&& x, TFwds&&... xs) noexcept( | |
std::is_nothrow_constructible_v<T, TFwd&&>&& | |
std::is_nothrow_constructible_v<U, TFwds&&...>) | |
: T{FWD(x)}, _u{FWD(xs)...} | |
{ | |
} | |
}; | |
} | |
template <typename... Ts> | |
constexpr auto linear_overload(Ts&&... xs) SCELTA_RETURNS( | |
impl::linear_overloader<std::remove_reference_t<Ts>...>{FWD(xs)...}) | |
} | |
#include <cassert> | |
#include <utility> | |
#ifndef NDEBUG | |
#define SCELTA_CONSTEXPR_ASSERT(expr) \ | |
(__builtin_expect(expr, true) ? void(0) : [] { assert(!#expr); }()) | |
#else | |
#define SCELTA_CONSTEXPR_ASSERT(...) void(0) | |
#endif | |
#include <type_traits> | |
namespace scelta | |
{ | |
namespace impl | |
{ | |
template <typename... Ts> | |
struct overloader : Ts... | |
{ | |
template <typename... Args> | |
constexpr overloader(Args&&... xs) noexcept( | |
(noexcept(Ts{FWD(xs)}) && ...)) | |
: Ts{FWD(xs)}... | |
{ | |
} | |
using Ts::operator()...; | |
}; | |
} | |
template <typename... Ts> | |
constexpr auto overload(Ts&&... xs) SCELTA_RETURNS( | |
impl::overloader<std::remove_reference_t<Ts>...>{FWD(xs)...}) | |
} | |
#include <type_traits> | |
namespace scelta::meta | |
{ | |
template <typename Source, typename T> | |
using as_if_forwarded = std::conditional_t< // | |
std::is_lvalue_reference_v<Source>, // | |
std::remove_reference_t<T>&, // | |
std::remove_reference_t<T>&&>; | |
template <typename Source, typename T> | |
auto forward_like(T&& x) | |
SCELTA_RETURNS(static_cast<as_if_forwarded<Source, T&&>>(x)) | |
} | |
namespace scelta::traits::impl | |
{ | |
template <typename Trait> | |
struct dispatch | |
{ | |
template <typename... Ts> | |
constexpr auto operator()(Ts&&... xs) const | |
SCELTA_RETURNS( | |
Trait{}(FWD(xs)...) | |
) | |
}; | |
} | |
namespace scelta::traits::optional | |
{ | |
template <typename> | |
struct access | |
{ | |
template <typename Optional> | |
constexpr auto operator()(Optional&& o) | |
SCELTA_RETURNS( | |
*FWD(o) | |
) | |
}; | |
template <typename T> | |
inline constexpr traits::impl::dispatch<access<T>> access_v{}; | |
} | |
#include <type_traits> | |
namespace scelta::impl | |
{ | |
template <typename Optional> | |
constexpr auto access_optional(Optional&& o) | |
SCELTA_RETURNS( | |
::scelta::traits::optional::access_v<std::decay_t<Optional>>(FWD(o)) | |
) | |
} | |
namespace scelta::traits::adt | |
{ | |
template <typename> | |
struct valid | |
{ | |
template <typename... Variants> | |
constexpr auto operator()(Variants&&...) | |
{ | |
return true; | |
} | |
}; | |
template <typename T> | |
inline constexpr traits::impl::dispatch<valid<T>> valid_v{}; | |
} | |
namespace scelta | |
{ | |
struct nullopt_t | |
{ | |
}; | |
inline constexpr nullopt_t nullopt{}; | |
} | |
namespace scelta::impl | |
{ | |
template <typename... Ts> | |
constexpr auto to_nullopt(Ts&&...) | |
SCELTA_RETURNS( | |
::scelta::nullopt | |
) | |
template <typename Visitor> | |
constexpr auto visit_optional(Visitor&& visitor) | |
SCELTA_RETURNS( | |
FWD(visitor)() | |
) | |
template <typename F, typename Continuation, typename Optional> | |
constexpr auto call_with_optional(F&& f, Continuation&& c, Optional&& o) | |
SCELTA_RETURNS( | |
o ? FWD(c)(FWD(f)(meta::forward_like<Optional>(::scelta::impl::access_optional(o)))) | |
: FWD(c)(FWD(f)(to_nullopt())) | |
) | |
template <typename Visitor, typename Optional, typename... Optionals> | |
constexpr auto visit_optional( | |
Visitor&& visitor, Optional&& o, Optionals&&... os) ->decltype(auto) | |
{ | |
return | |
SCELTA_CONSTEXPR_ASSERT( | |
::scelta::traits::adt::valid_v<std::decay_t<Optional>>(o, os...) | |
), | |
call_with_optional( | |
[&](auto&& x) noexcept | |
{ | |
return [&](auto&&... xs) SCELTA_RETURNS( | |
FWD(visitor)(FWD(x), FWD(xs)...) | |
); | |
}, | |
[&](auto&& bound_visitor) SCELTA_RETURNS( | |
visit_optional(FWD(bound_visitor), FWD(os)...) | |
), | |
FWD(o) | |
); | |
} | |
} | |
#include <type_traits> | |
namespace scelta::meta | |
{ | |
template <typename T> | |
struct always_false | |
{ | |
using type = std::false_type; | |
}; | |
template <typename T> | |
using always_false_t = typename always_false<T>::type; | |
template <typename T> | |
inline constexpr always_false_t<T> always_false_v{}; | |
} | |
namespace scelta::traits::adt | |
{ | |
namespace impl | |
{ | |
struct visit_optional_t | |
{ | |
template <typename Tag, typename... Ts> | |
constexpr auto operator()(Tag, Ts&&... xs) | |
SCELTA_RETURNS( | |
::scelta::impl::visit_optional(FWD(xs)...) | |
) | |
}; | |
} | |
/*template <typename T> | |
struct visit | |
{ | |
static_assert(meta::always_false_v<T>, | |
};*/ | |
template <typename> | |
struct visit; | |
template <typename T> | |
inline constexpr traits::impl::dispatch<visit<T>> visit_v{}; | |
} | |
#include <type_traits> | |
namespace scelta::impl | |
{ | |
struct non_recursive_tag | |
{ | |
}; | |
template <typename Return> | |
struct recursive_tag | |
{ | |
using return_type = Return; | |
}; | |
template <typename Tag, typename Visitor, typename Variant, typename... Variants> | |
constexpr auto visit_homogenizer(Tag tag, | |
Visitor&& visitor, Variant&& variant, Variants&&... variants) | |
SCELTA_RETURNS( | |
::scelta::traits::adt::visit_v<std::decay_t<Variant>>(tag, | |
FWD(visitor), FWD(variant), FWD(variants)...) | |
) | |
} | |
#include <type_traits> | |
namespace scelta::meta | |
{ | |
template <typename T> | |
using remove_cv_ref_t = std::remove_cv_t<std::remove_reference_t<T>>; | |
template <typename T> | |
using remove_cv_ref_ptr_t = std::remove_pointer_t<remove_cv_ref_t<T>>; | |
template <typename Source, typename T> | |
using copy_lvalue_reference_t = | |
std::conditional_t<std::is_lvalue_reference_v<Source>, | |
std::add_lvalue_reference_t<T>, T>; | |
template <typename Source, typename T> | |
using copy_rvalue_reference_t = | |
std::conditional_t<std::is_rvalue_reference_v<Source>, | |
std::add_rvalue_reference_t<T>, T>; | |
template <typename Source, typename T> | |
using copy_reference_t = | |
copy_lvalue_reference_t<Source, copy_rvalue_reference_t<Source, T>>; | |
template <typename Source, typename T> | |
using copy_const_t = | |
std::conditional_t<std::is_const_v<Source>, std::add_const_t<T>, T>; | |
template <typename Source, typename T> | |
using copy_volatile_t = std::conditional_t<std::is_volatile_v<Source>, | |
std::add_volatile_t<T>, T>; | |
template <typename Source, typename T> | |
using copy_cv_t = copy_volatile_t<Source, copy_const_t<Source, T>>; | |
template <typename Source, typename T> | |
using copy_pointer_t = | |
std::conditional_t<std::is_pointer_v<Source>, std::add_pointer_t<T>, T>; | |
template <typename Source, typename Destination> | |
class copy_cv_ptr_ref | |
{ | |
private: | |
using S = std::remove_reference_t<Source>; | |
using D = remove_cv_ref_ptr_t<Destination>; | |
using U1 = copy_cv_t<S, D>; | |
using U2 = copy_pointer_t<S, U1>; | |
public: | |
using type = copy_reference_t<Source, U2>; | |
}; | |
template <typename Source, typename Destination> | |
using copy_cv_ptr_ref_t = | |
typename copy_cv_ptr_ref<Source, Destination>::type; | |
} | |
#include <type_traits> | |
namespace scelta::meta | |
{ | |
namespace impl | |
{ | |
template <typename T> | |
using identity_check = T; | |
template <typename, typename T> | |
using identity_replace = T; | |
template < // | |
template <typename> typename OnCheck, // | |
template <typename, typename> typename OnReplace, // | |
typename Before, typename After, // | |
typename T // | |
> | |
struct apply : std::conditional< // | |
std::is_same_v<OnCheck<T>, Before>, // | |
OnReplace<T, After>, // | |
T> | |
{ | |
}; | |
template < // | |
template <typename> typename OnCheck, // | |
template <typename, typename> typename OnReplace, // | |
typename Before, typename After, // | |
template <typename...> typename T, typename... Ts // | |
> | |
struct apply<OnCheck, OnReplace, Before, After, T<Ts...>> | |
{ | |
using type = T< | |
typename apply<OnCheck, OnReplace, Before, After, Ts>::type...>; | |
}; | |
template < // | |
template <typename> typename OnCheck, // | |
template <typename, typename> typename OnReplace // | |
> | |
struct replace_all_impl | |
{ | |
template <typename Before, typename After, typename T> | |
using apply_t = | |
typename apply<OnCheck, OnReplace, Before, After, T>::type; | |
}; | |
using identity_replacer = | |
replace_all_impl<identity_check, identity_replace>; | |
using copy_cv_ref_ptr_replacer = | |
replace_all_impl<remove_cv_ref_ptr_t, copy_cv_ptr_ref_t>; | |
} | |
template <typename Before, typename After, typename T> | |
using replace_all_t = impl::identity_replacer::apply_t<Before, After, T>; | |
template <typename Before, typename After, typename T> | |
using replace_all_copy_cv_ptr_ref_t = | |
impl::copy_cv_ref_ptr_replacer::apply_t<Before, After, T>; | |
} | |
#include <type_traits> | |
namespace scelta::meta | |
{ | |
namespace impl | |
{ | |
template <typename F> | |
struct fn_ref_wrapper | |
{ | |
static_assert(std::is_reference_v<F>); | |
F _f; | |
constexpr fn_ref_wrapper(F f) noexcept : _f{FWD(f)} | |
{ | |
} | |
template <typename... Ts> | |
constexpr auto operator()(Ts&&... xs) const | |
SCELTA_RETURNS( | |
FWD(_f)(FWD(xs)...) | |
) | |
}; | |
template <typename F> | |
struct y_combinator_wrapper : F | |
{ | |
template <typename FFwd> | |
constexpr y_combinator_wrapper(FFwd&& f) noexcept( | |
noexcept(F(FWD(f)))) | |
: F(FWD(f)) | |
{ | |
} | |
#define DEFINE_CALL_OPERATOR(m_refq) \ | |
template <typename... Ts> \ | |
constexpr auto operator()(Ts&&... xs) m_refq SCELTA_NOEXCEPT_AND_TRT( \ | |
std::declval<F m_refq>()( \ | |
std::declval<fn_ref_wrapper<y_combinator_wrapper m_refq>>(), \ | |
FWD(xs)...)) \ | |
{ \ | |
return static_cast<F m_refq>(*this)( \ | |
fn_ref_wrapper<y_combinator_wrapper m_refq>{ \ | |
static_cast<y_combinator_wrapper m_refq>(*this)}, \ | |
FWD(xs)...); \ | |
} | |
DEFINE_CALL_OPERATOR(&) | |
DEFINE_CALL_OPERATOR(const&) | |
DEFINE_CALL_OPERATOR(&&) | |
#undef DEFINE_CALL_OPERATOR | |
}; | |
} | |
template <typename F> | |
auto y_combinator(F&& f) | |
SCELTA_RETURNS( | |
impl::y_combinator_wrapper<std::decay_t<F>>(FWD(f)) | |
) | |
} | |
#include <tuple> | |
namespace scelta::traits::adt | |
{ | |
namespace impl | |
{ | |
template <typename... Ts> | |
struct alternative_tuple | |
{ | |
using type = std::tuple<Ts...>; | |
}; | |
} | |
template <typename> | |
struct alternatives; | |
template <template <typename...> class T, typename... Ts> | |
struct alternatives<T<Ts...>> : impl::alternative_tuple<Ts...> | |
{ | |
}; | |
template <typename T> | |
inline constexpr traits::impl::dispatch<alternatives<T>> alternatives_v{}; | |
template <typename T, std::size_t N> | |
using nth_alternative = | |
std::tuple_element_t<N, typename alternatives<T>::type>; | |
template <typename T> | |
using first_alternative = nth_alternative<T, 0>; | |
} | |
namespace scelta | |
{ | |
template <typename Visitor> | |
constexpr auto visit(Visitor&& visitor) | |
SCELTA_RETURNS(FWD(visitor)()) | |
namespace impl | |
{ | |
constexpr void visit_impl() noexcept { return; } | |
template <typename Tag, typename Visitor, typename Variant, typename... Variants> | |
constexpr auto visit_impl(Tag tag, | |
Visitor&& visitor, Variant&& v, Variants&&... vs) | |
SCELTA_NOEXCEPT_AND_TRT( | |
impl::visit_homogenizer(tag, FWD(visitor), FWD(v), FWD(vs)...) | |
) | |
{ | |
return | |
SCELTA_CONSTEXPR_ASSERT( | |
::scelta::traits::adt::valid_v<std::decay_t<Variant>>(v, vs...) | |
), | |
impl::visit_homogenizer(tag, FWD(visitor), FWD(v), FWD(vs)...); | |
} | |
} | |
template <typename... Ts> | |
constexpr auto visit(Ts&&... xs) | |
SCELTA_RETURNS(impl::visit_impl(impl::non_recursive_tag{}, FWD(xs)...)) | |
} | |
namespace scelta | |
{ | |
namespace impl | |
{ | |
template <typename Visitor> | |
struct bound_visitor : Visitor | |
{ | |
template <typename FwdVisitor> | |
constexpr bound_visitor(FwdVisitor&& visitor) noexcept( | |
noexcept(Visitor{FWD(visitor)})) | |
: Visitor{FWD(visitor)} | |
{ | |
} | |
#define DEFINE_BOUND_VISITOR_CALL(m_refq) \ | |
template <typename... Variants> \ | |
constexpr auto operator()(Variants&&... variants) m_refq \ | |
SCELTA_NOEXCEPT_AND_TRT( \ | |
::scelta::visit(std::declval<Visitor m_refq>(), FWD(variants)...)) \ | |
{ \ | |
return ::scelta::visit( \ | |
static_cast<Visitor m_refq>(*this), FWD(variants)...); \ | |
} | |
DEFINE_BOUND_VISITOR_CALL(&) | |
DEFINE_BOUND_VISITOR_CALL(const&) | |
DEFINE_BOUND_VISITOR_CALL(&&) | |
#undef DEFINE_BOUND_VISITOR_CALL | |
}; | |
template <typename Visitor> | |
constexpr auto make_bound_visitor(Visitor&& visitor) | |
SCELTA_RETURNS( | |
bound_visitor<std::decay_t<Visitor>>{FWD(visitor)} | |
) | |
} | |
template <typename... Fs> | |
constexpr auto match(Fs&&... fs) | |
SCELTA_RETURNS( | |
impl::make_bound_visitor(::scelta::overload(FWD(fs)...)) | |
) | |
} | |
#ifndef SCELTA_SUPPORT_VARIANT_MPARK_DISABLE | |
#if __has_include(<mpark/variant.hpp>) | |
#include <mpark/variant.hpp> | |
#define SCELTA_SUPPORT_VARIANT_MPARK 1 | |
namespace scelta::traits::adt | |
{ | |
template <typename... Alts> | |
struct visit<::mpark::variant<Alts...>> | |
{ | |
template <typename Tag, typename... Ts> | |
constexpr auto operator()(Tag, Ts&&... xs) | |
SCELTA_RETURNS( | |
::mpark::visit(FWD(xs)...) | |
) | |
}; | |
template <typename... Alts> | |
struct valid<::mpark::variant<Alts...>> | |
{ | |
template <typename... Ts> | |
constexpr auto operator()(Ts&&... xs) | |
SCELTA_RETURNS( | |
(!xs.valueless_by_exception() && ...) | |
) | |
}; | |
} | |
#endif | |
#endif | |
#ifndef SCELTA_SUPPORT_VARIANT_STD_DISABLE | |
#if __has_include(<variant>) | |
#include <variant> | |
#define SCELTA_SUPPORT_VARIANT_STD 1 | |
namespace scelta::traits::adt | |
{ | |
template <typename... Alts> | |
struct visit<::std::variant<Alts...>> | |
{ | |
template <typename Tag, typename... Ts> | |
constexpr auto operator()(Tag, Ts&&... xs) | |
SCELTA_RETURNS( | |
::std::visit(FWD(xs)...) | |
) | |
}; | |
template <typename... Alts> | |
struct valid<::std::variant<Alts...>> | |
{ | |
template <typename... Ts> | |
constexpr auto operator()(Ts&&... xs) | |
SCELTA_RETURNS( | |
(!xs.valueless_by_exception() && ...) | |
) | |
}; | |
} | |
#endif | |
#endif | |
#ifndef SCELTA_SUPPORT_VARIANT_BOOST_DISABLE | |
#if __has_include(<boost/variant.hpp>) | |
#include <boost/variant.hpp> | |
#define SCELTA_SUPPORT_VARIANT_BOOST 1 | |
namespace scelta::traits::adt | |
{ | |
template <typename... Alts> | |
struct visit<::boost::variant<Alts...>> | |
{ | |
template <typename Tag, typename... Ts> | |
constexpr auto operator()(Tag, Ts&&... xs) | |
SCELTA_RETURNS( | |
::boost::apply_visitor(FWD(xs)...) | |
) | |
}; | |
} | |
#endif | |
#endif | |
#ifndef SCELTA_SUPPORT_VARIANT_TYPE_SAFE_DISABLE | |
#if __has_include(<type_safe/variant.hpp>) && \ | |
__has_include(<type_safe/visitor.hpp>) | |
#include <cassert> | |
#include <type_safe/variant.hpp> | |
#include <type_safe/visitor.hpp> | |
#define SCELTA_SUPPORT_VARIANT_TYPE_SAFE 1 | |
namespace scelta::impl | |
{ | |
template <typename... Ts> | |
using any_is_nullvar = std::disjunction< | |
std::is_same<std::decay_t<Ts>, type_safe::nullvar_t>...>; | |
template <typename... Ts> | |
inline constexpr auto any_is_nullvar_v = any_is_nullvar<Ts...>::value; | |
template <typename T> | |
struct nullvar_ignorer | |
{ | |
T _visitor; | |
static_assert(std::is_reference_v<T>); | |
template <typename TFwd> | |
constexpr nullvar_ignorer(TFwd&& visitor) : _visitor{FWD(visitor)} | |
{ | |
} | |
template <typename... Ts, | |
std::enable_if_t<any_is_nullvar_v<Ts...>>* = nullptr> | |
constexpr void operator()(Ts&&...) const noexcept | |
{ | |
assert(false); | |
__builtin_unreachable(); | |
} | |
template <typename... Ts, | |
std::enable_if_t<!any_is_nullvar_v<Ts...>>* = nullptr> | |
constexpr auto operator()(Ts&&... xs) | |
SCELTA_RETURNS(FWD(_visitor)(FWD(xs)...)) | |
}; | |
template <typename T> | |
constexpr auto make_nullvar_ignorer(T&& x) | |
SCELTA_RETURNS(nullvar_ignorer<T&&>{FWD(x)}) | |
} | |
namespace scelta::traits::adt | |
{ | |
template <typename VariantPolicy, typename... Alternatives> | |
struct visit<::type_safe::basic_variant<VariantPolicy, Alternatives...>> | |
{ | |
template <typename Tag, typename Visitor, typename... Ts> | |
constexpr auto operator()(Tag, Visitor&& v, Ts&&... xs) | |
SCELTA_RETURNS( | |
::type_safe::visit( | |
::scelta::impl::make_nullvar_ignorer(FWD(v)), | |
FWD(xs)... | |
) | |
) | |
}; | |
template <typename VariantPolicy, typename... Alternatives> | |
struct valid<::type_safe::basic_variant<VariantPolicy, Alternatives...>> | |
{ | |
template <typename... Ts> | |
constexpr auto operator()(Ts&&...) | |
SCELTA_RETURNS( | |
true // TODO: depends on policy | |
) | |
}; | |
template <typename VariantPolicy, typename... Alternatives> | |
struct alternatives< | |
::type_safe::basic_variant<VariantPolicy, Alternatives...>> | |
: impl::alternative_tuple<Alternatives...> | |
{ | |
}; | |
} | |
#endif | |
#endif | |
#ifndef SCELTA_SUPPORT_VARIANT_EGGS_DISABLE | |
#if __has_include(<eggs/variant.hpp>) | |
#include <eggs/variant.hpp> | |
#define SCELTA_SUPPORT_VARIANT_EGGS 1 | |
namespace scelta::traits::adt | |
{ | |
template <typename... Alts> | |
struct visit<::eggs::variant<Alts...>> | |
{ | |
template <typename Tag, typename... Ts> | |
constexpr auto operator()(Tag, Ts&&... xs) | |
SCELTA_RETURNS( | |
::eggs::variants::apply(FWD(xs)...) | |
) | |
}; | |
} | |
#endif | |
#endif | |
#ifndef SCELTA_SUPPORT_OPTIONAL_BOOST_DISABLE | |
#if __has_include(<boost/optional.hpp>) && __has_include(<boost/none.hpp>) | |
#include <boost/optional.hpp> | |
#include <boost/none.hpp> | |
#define SCELTA_SUPPORT_OPTIONAL_BOOST 1 | |
namespace scelta::traits::adt | |
{ | |
template <typename T> | |
struct visit<::boost::optional<T>> : impl::visit_optional_t | |
{ | |
}; | |
} | |
#endif | |
#endif | |
#ifndef SCELTA_SUPPORT_OPTIONAL_TYPE_SAFE_DISABLE | |
#if __has_include(<type_safe/optional.hpp>) | |
#include <type_safe/optional.hpp> | |
#define SCELTA_SUPPORT_OPTIONAL_TYPE_SAFE 1 | |
namespace scelta::traits | |
{ | |
namespace adt | |
{ | |
template <typename T> | |
struct visit<::type_safe::basic_optional<T>> : impl::visit_optional_t | |
{ | |
}; | |
template <typename T> | |
struct alternatives<::type_safe::basic_optional<T>> | |
: impl::alternative_tuple<typename T::value_type> | |
{ | |
}; | |
} | |
namespace optional | |
{ | |
template <typename T> | |
struct access<::type_safe::basic_optional<T>> | |
{ | |
template <typename Optional> | |
constexpr auto operator()(Optional&& o) | |
SCELTA_RETURNS( | |
FWD(o).value() | |
) | |
}; | |
} | |
} | |
#endif | |
#endif | |
#ifndef SCELTA_SUPPORT_OPTIONAL_STD_DISABLE | |
#if __has_include(<optional>) | |
#include <optional> | |
#define SCELTA_SUPPORT_OPTIONAL_STD 1 | |
namespace scelta::traits::adt | |
{ | |
template <typename T> | |
struct visit<::std::optional<T>> : impl::visit_optional_t | |
{ | |
}; | |
} | |
#endif | |
#endif | |
namespace scelta::recursive | |
{ | |
struct placeholder | |
{ | |
placeholder() = delete; | |
placeholder(const placeholder&) = delete; | |
placeholder(placeholder&&) = delete; | |
placeholder& operator=(const placeholder&) = delete; | |
placeholder& operator=(placeholder&&) = delete; | |
}; | |
namespace impl | |
{ | |
template <typename After, typename T> | |
using replace_placeholders = // | |
meta::replace_all_copy_cv_ptr_ref_t<placeholder, After, T>; | |
} | |
} | |
#include <type_traits> | |
namespace scelta::recursive | |
{ | |
namespace impl | |
{ | |
template <typename T, typename = void> | |
struct original_type | |
{ | |
using type = T; | |
}; | |
template <typename T> | |
struct original_type<T, std::void_t<typename T::base_type>> | |
{ | |
using type = typename T::base_type; | |
}; | |
template <typename T> | |
using original_type_t = typename original_type<T>::type; | |
} | |
} | |
#include <type_traits> | |
namespace scelta::recursive | |
{ | |
template <typename Return, typename Visitor, typename... Variants> | |
constexpr Return visit(Visitor&& visitor, Variants&&... variants) | |
{ | |
return ::scelta::impl::visit_impl( | |
::scelta::impl::recursive_tag<Return>{}, FWD(visitor), | |
static_cast<meta::copy_cv_ptr_ref_t<Variants&&, | |
impl::original_type_t<std::decay_t<Variants>>>>(variants)...); | |
} | |
} | |
namespace scelta::recursive | |
{ | |
namespace impl | |
{ | |
template <typename Return, typename... Fs> | |
constexpr auto make_recursive_visitor(Fs&&... fs) | |
{ | |
return meta::y_combinator( | |
[o = overload(FWD(fs)...)](auto self, auto&&... xs) mutable | |
-> Return | |
{ | |
return o( | |
[&self](auto&&... vs) -> Return { | |
return ::scelta::recursive::visit<Return>( | |
self, FWD(vs)...); | |
}, | |
FWD(xs)...); | |
} | |
); | |
} | |
} | |
template <typename Return, typename... Fs> | |
constexpr auto match(Fs&&... fs) | |
{ | |
return [rv = impl::make_recursive_visitor<Return>(FWD(fs)...)]( | |
auto&&... vs) mutable->Return | |
{ | |
return ::scelta::recursive::visit<Return>(rv, FWD(vs)...); | |
}; | |
} | |
} | |
#include <type_traits> | |
namespace scelta::recursive | |
{ | |
template <typename> | |
class builder; | |
template <template <typename...> typename T, typename... Ts> | |
class builder<T<Ts...>> | |
{ | |
public: | |
struct type; | |
template <typename U> | |
using resolve = impl::replace_placeholders<type, U>; | |
private: | |
using resolved_type = resolve<T<Ts...>>; | |
public: | |
struct type : resolved_type | |
{ | |
using resolved_type::resolved_type; | |
using base_type = resolved_type; | |
}; | |
}; | |
template <typename Builder> | |
using type = typename Builder::type; | |
template <typename Builder, typename T> | |
using resolve = typename Builder::template resolve<T>; | |
} | |
namespace example | |
{ | |
// First available variant type. | |
template <typename... Ts> | |
using variant = | |
#if defined(SCELTA_SUPPORT_VARIANT_STD) | |
::std::variant | |
#elif defined(SCELTA_SUPPORT_VARIANT_BOOST) | |
::boost::variant | |
#elif defined(SCELTA_SUPPORT_VARIANT_EGGS) | |
::eggs::variant | |
#elif defined(SCELTA_SUPPORT_VARIANT_MPARK) | |
::mpark::variant | |
#elif defined(SCELTA_SUPPORT_VARIANT_TYPE_SAFE) | |
::type_safe::variant | |
#else | |
#error "No variant type available." | |
#endif | |
<Ts...>; | |
// First available optional type. | |
template <typename... Ts> | |
using optional = | |
#if defined(SCELTA_SUPPORT_OPTIONAL_STD) | |
::std::optional | |
#elif defined(SCELTA_SUPPORT_OPTIONAL_BOOST) | |
::boost::optional | |
#elif defined(SCELTA_SUPPORT_OPTIONAL_TYPE_SAFE) | |
::type_safe::optional | |
#else | |
#error "No optional type available." | |
#endif | |
<Ts...>; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment