Header file range/v3/utility/concepts.hpp

#include <meta/meta.hpp>

#include <range/v3/utility/swap.hpp>

#include <range/v3/utility/common_type.hpp>

#include <range/v3/utility/nullptr_v.hpp>

#define CONCEPT_PP_CAT_(X, Y) X ## Y

#define CONCEPT_PP_CAT(X, Y) CONCEPT_PP_CAT_(X, Y)

#define CONCEPT_REQUIRES_(...) int CONCEPT_PP_CAT(_concept_requires_, __LINE__) = 42,                              typename std::enable_if<                                                                (CONCEPT_PP_CAT(_concept_requires_, __LINE__) == 43) || (__VA_ARGS__),              int                                                                             >::type = 0

#define CONCEPT_REQUIRES(...) template<                                                                               int CONCEPT_PP_CAT(_concept_requires_, __LINE__) = 42,                              typename std::enable_if<                                                                (CONCEPT_PP_CAT(_concept_requires_, __LINE__) == 43) || (__VA_ARGS__),              int                                                                             >::type = 0>

#define CONCEPT_ASSERT(...) static_assert((__VA_ARGS__), "Concept check failed: " #__VA_ARGS__)

#define CONCEPT_ASSERT_MSG static_assert

namespace ranges
{
    inline namespace v3
    {
        namespace detail
        {
            struct void_tester{};
            
            constexpr void_tester{} void_;
            
            struct is_void_t
            {
                int operator()(detail::void_tester) const;
            };
            
            constexpr is_void_t{} is_void;
            
            struct valid_expr_t
            {
                template <typename ... T>
                void operator()(T&&...) const;
            };
            
            constexpr valid_expr_t{} valid_expr;
            
            struct same_type_t
            {
                template <typename T, typename U>
                meta::if_<std::is_same<T, U>, int> operator()(T&&, U&&) const;
            };
            
            constexpr same_type_t{} same_type;
            
            struct is_true_t
            {
                template <typename Bool>
                meta::if_c<Bool::value, int> operator()(Bool) const;
            };
            
            constexpr is_true_t{} is_true;
            
            struct is_false_t
            {
                template <typename Bool>
                meta::if_c<!Bool::value, int> operator()(Bool) const;
            };
            
            constexpr is_false_t{} is_false;
            
            template <typename Concept>
            struct base_concept
            {
                using type = Concept;
            };
            
            template <typename Concept, typename ... Args>
            struct base_concept<Concept(Args...)>
            {
                using type = Concept;
            };
            
            template <typename Concept>
            using base_concept_t = typename base_concept<Concept>::type;
            
            template <typename Concept, typename Enable = void>
            struct base_concepts_of
            {
                using type = meta::list<>;
            };
            
            template <typename Concept>
            struct base_concepts_of<Concept, meta::void_<typename Concept::base_concepts_t>>
            {
                using type = typename Concept::base_concepts_t;
            };
            
            template <typename Concept>
            using base_concepts_of_t = meta::_t<base_concepts_of<Concept>>;
            
            template <typename ... Ts>
            std::false_type models_(any);
            
            template <typename ... Ts, typename Concept, typename = decltype(std::declval<Concept&>().template requires_<Ts...>(std::declval<Ts>()...))>
            )>meta::apply<meta::quote<meta::lazy::strict_and>, meta::transform<base_concepts_of_t<Concept>, meta::bind_back<meta::quote<concepts::models>, Ts...>>> models_(Concept*);
            
            template <typename List>
            struct most_refined_{};
            
            template <typename Head, typename ... Tail>
            struct most_refined_<meta::list<Head, Tail...>>;
            
            template <typename T>
            struct avoid_empty_braces_
            : std::false_type
            {};
            
            template <typename T>
            struct avoid_empty_braces_<std::initializer_list<T>>;
            
            template <typename T>
            struct avoid_empty_braces_<T*>
            : std::true_type
            {};
            
            template <typename T>
            using avoid_empty_braces = meta::_t<avoid_empty_braces_<uncvref_t<T>>>;
        }
        
        namespace concepts
        {
            using detail::void_;
            
            using detail::is_void;
            
            using detail::valid_expr;
            
            using detail::same_type;
            
            using detail::is_true;
            
            using detail::is_false;
            
            using ranges::uncvref_t;
            
            using _1 = std::integral_constant<int, 0>;
            
            using _2 = std::integral_constant<int, 1>;
            
            using _3 = std::integral_constant<int, 2>;
            
            using _4 = std::integral_constant<int, 3>;
            
            using _5 = std::integral_constant<int, 4>;
            
            using _6 = std::integral_constant<int, 5>;
            
            using _7 = std::integral_constant<int, 6>;
            
            using _8 = std::integral_constant<int, 7>;
            
            using _9 = std::integral_constant<int, 8>;
            
            template <typename T>
            using val_t = meta::if_<std::is_rvalue_reference<T>, T, T&>;
            
            template <typename T>
            val_t<T> val();
            
            template <typename Ret, typename T>
            Ret returns_(T const&);
            
            template <typename T, typename U>
            decltype(concepts::returns_<int>(static_cast<T>((U&&)u))) convertible_to(U&& u);
            
            template <typename T, typename U>
            meta::if_<std::is_same<T, U>, int> has_type(U&&);
            
            template <typename ... Concepts>
            struct refines;
            
            template <typename Concept, typename ... Ts>
            struct models;
            
            template <typename Concept, typename ... Args, typename ... Ts>
            struct models<Concept(Args...), Ts...>
            : models<Concept, meta::at<meta::list<Ts...>, Args>...>
            {};
            
            template <typename Concept, typename ... Ts>
            meta::if_c<concepts::models<Concept, Ts...>::value, int> model_of(Ts&&...);
            
            template <typename Concept, typename ... Ts>
            meta::if_c<concepts::models<Concept, Ts...>::value, int> model_of();
            
            template <typename Concepts, typename ... Ts>
            struct most_refined;
            
            template <typename Concepts, typename ... Ts>
            using most_refined_t = meta::_t<most_refined<Concepts, Ts...>>;
            
            struct Same
            {
                template <typename ... Ts>
                struct same
                : std::true_type
                {};
                
                template <typename T, typename ... Us>
                struct same<T, Us...>
                : meta::strict_and<std::is_same<T, Us>...>
                {};
                
                template <typename ... Ts>
                using same_t = meta::_t<same<Ts...>>;
                
                template <typename ... Ts>
                decltype(concepts::valid_expr(concepts::is_true(same_t<Ts...>{}))) requires_(Ts&&...);
            };
            
            struct ImplicitlyConvertibleTo;
            
            struct ExplicitlyConvertibleTo
            {
                template <typename T, typename U>
                decltype(concepts::valid_expr(static_cast<U>(std::forward<T>(t)))) requires_(T&& t, U&&);
            };
            
            struct ConvertibleTo
            : refines<struct ranges::v3::concepts::ImplicitlyConvertibleTo, struct ranges::v3::concepts::ExplicitlyConvertibleTo>
            {};
            
            struct DerivedFrom
            {
                template <typename T, typename U>
                decltype(concepts::valid_expr(concepts::is_true(std::is_base_of<U, T>{}))) requires_(T&&, U&&);
            };
            
            struct CommonReference
            {
                template <typename T, typename U, typename ... Rest>
                using reference_t = common_reference_t<T, U, Rest...>;
                
                template <typename T, typename U, typename C = reference_t<T, U>>
                decltype(concepts::valid_expr(concepts::model_of<Same, C, reference_t<U, T>>(), C(val<T>()), C(val<U>()))) requires_(T&&, U&&);
                
                template <typename T, typename U, typename ... Rest, typename CommonReference_ = CommonReference, typename C = reference_t<T, U>>
                decltype(concepts::valid_expr(concepts::model_of<CommonReference_, T, U>(), concepts::model_of<CommonReference_, C, Rest...>())) requires_(T&&, U&&, Rest&&...);
            };
            
            struct Common
            {
                template <typename T, typename U, typename ... Rest>
                using value_t = common_type_t<T, U, Rest...>;
                
                template <typename T, typename U, meta::if_<std::is_same<uncvref_t<T>, uncvref_t<U>>, int>=0>
                void requires_(T&&, U&&);
                
                template <typename T, typename U, meta::if_c<!std::is_same<uncvref_t<T>, uncvref_t<U>>::value, int>=0, typename C = value_t<T, U>, typename R = CommonReference::reference_t<T const&, U const&>>
                decltype(concepts::valid_expr(concepts::model_of<Same, C, value_t<U, T>>(), C(val<T&&>()), C(val<U&&>()), concepts::model_of<CommonReference, T const&, U const&>(), concepts::model_of<CommonReference, C&, R&&>())) requires_(T&&, U&&);
                
                template <typename T, typename U, typename ... Rest, typename Common_ = Common, typename C = value_t<T, U>>
                decltype(concepts::valid_expr(concepts::model_of<Common_, T, U>(), concepts::model_of<Common_, C, Rest...>())) requires_(T&&, U&&, Rest&&...);
            };
            
            struct Integral
            {
                template <typename T>
                decltype(concepts::valid_expr(concepts::is_true(std::is_integral<T>{}))) requires_(T&&);
            };
            
            struct SignedIntegral
            : refines<struct ranges::v3::concepts::Integral>
            {
                template <typename T>
                decltype(concepts::valid_expr(concepts::is_true(std::is_signed<T>{}))) requires_(T&&);
            };
            
            struct UnsignedIntegral
            : refines<struct ranges::v3::concepts::Integral>
            {
                template <typename T>
                decltype(concepts::valid_expr(concepts::is_true(std::is_unsigned<T>{}))) requires_(T&&);
            };
            
            struct Assignable
            {
                template <typename T, typename U>
                decltype(concepts::valid_expr(concepts::has_type<T&>(static_cast<T&&>(t)=static_cast<U&&>(u)))) requires_(T&& t, U&& u);
            };
            
            struct Swappable
            {
                template <typename T>
                decltype(concepts::valid_expr(((void)swap(std::declval<T>(), std::declval<T>()), 42))) requires_(T&&);
                
                template <typename T, typename U>
                decltype(concepts::valid_expr(((void)swap(std::declval<T>(), std::declval<U>()), 42), ((void)swap(std::declval<U>(), std::declval<T>()), 42))) requires_(T&&, U&&);
            };
            
            struct WeaklyEqualityComparable;
            
            struct EqualityComparable
            {
                template <typename T>
                decltype(concepts::valid_expr(concepts::convertible_to<bool>(t==t), concepts::convertible_to<bool>(t!=t))) requires_(T&& t);
                
                template <typename T, typename U, meta::if_<std::is_same<T, U>, int>=0>
                decltype(concepts::valid_expr(concepts::model_of<EqualityComparable, T>())) requires_(T&&, U&&);
                
                template <typename T, typename U, meta::if_c<!std::is_same<T, U>::value, int>=0, typename C = CommonReference::reference_t<T const&, U const&>>
                decltype(concepts::valid_expr(concepts::model_of<EqualityComparable, T>(), concepts::model_of<EqualityComparable, U>(), concepts::model_of<WeaklyEqualityComparable, T, U>(), concepts::model_of<CommonReference, T const&, U const&>(), concepts::model_of<EqualityComparable, C>())) requires_(T&&, U&&);
            };
            
            struct WeaklyOrdered
            {
                template <typename T>
                decltype(concepts::valid_expr(concepts::convertible_to<bool>(t<t), concepts::convertible_to<bool>(t>t), concepts::convertible_to<bool>(t<=t), concepts::convertible_to<bool>(t>=t))) requires_(T&& t);
                
                template <typename T, typename U, typename C = CommonReference::reference_t<T const&, U const&>>
                decltype(concepts::valid_expr(concepts::model_of<WeaklyOrdered, T>(), concepts::model_of<WeaklyOrdered, U>(), concepts::model_of<CommonReference, T const&, U const&>(), concepts::model_of<WeaklyOrdered, C>(), concepts::convertible_to<bool>(t<u), concepts::convertible_to<bool>(u<t), concepts::convertible_to<bool>(t>u), concepts::convertible_to<bool>(u>t), concepts::convertible_to<bool>(t<=u), concepts::convertible_to<bool>(u<=t), concepts::convertible_to<bool>(t>=u), concepts::convertible_to<bool>(u>=t))) requires_(T&& t, U&& u);
            };
            
            struct TotallyOrdered
            : refines<struct ranges::v3::concepts::EqualityComparable, struct ranges::v3::concepts::WeaklyOrdered>
            {
                template <typename T>
                void requires_(T&&);
                
                template <typename T, typename U>
                decltype(concepts::valid_expr(concepts::model_of<TotallyOrdered>(val<T>()), concepts::model_of<TotallyOrdered>(val<U>()))) requires_(T&&, U&&);
            };
            
            struct Destructible
            {
                template <typename T, meta::if_<std::is_object<T>, int>=0>
                decltype(concepts::valid_expr(((void)t.~T(), 42), concepts::is_true(std::is_nothrow_destructible<T>()), concepts::has_type<T*>(&t), concepts::has_type<const T*>(&std::declval<const T&>()), ((void)delete p, 42), ((void)delete[]p, 42))) requires_(T&& t, T*const p = nullptr);
            };
            
            struct ConstructibleObject;
            
            struct BindableReference
            {
                template <typename T, typename ... Args, meta::if_<std::is_reference<T>, int>=0>
                decltype(concepts::valid_expr(concepts::is_true(std::is_constructible<T, Args...>()))) requires_(T&&, meta::id_t<Args>&&...);
            };
            
            struct Constructible
            {
                template <typename T, typename ... Args, meta::if_c<!std::is_reference<T>::value, int>=0>
                decltype(concepts::valid_expr(concepts::model_of<ConstructibleObject, T, Args...>())) requires_(T&&, meta::id_t<Args>&&...);
                
                template <typename T, typename ... Args, meta::if_<std::is_reference<T>, int>=0>
                decltype(concepts::valid_expr(concepts::model_of<BindableReference, T, Args...>())) requires_(T&&, meta::id_t<Args>&&...);
            };
            
            struct DefaultConstructible
            : refines<struct ranges::v3::concepts::Constructible>
            {
                template <typename T, meta::if_c<!detail::avoid_empty_braces<T>::value, int>=0>
                decltype(concepts::valid_expr(new T[n]{})) requires_(T&&, const std::size_t n = 42);
                
                template <typename T, meta::if_<detail::avoid_empty_braces<T>, int>=0>
                decltype(concepts::valid_expr(new T[n]())) requires_(T&&, const std::size_t n = 42);
            };
            
            struct MoveConstructible
            {
                template <typename T, typename UnCvT = meta::_t<std::remove_cv<T>>>
                decltype(concepts::valid_expr(concepts::model_of<Constructible, T, UnCvT&&>(), concepts::model_of<ImplicitlyConvertibleTo, UnCvT&&, T>())) requires_(T&&);
            };
            
            struct CopyConstructible
            : refines<struct ranges::v3::concepts::MoveConstructible>
            {
                template <typename T, typename UnCvT = meta::_t<std::remove_cv<T>>>
                decltype(concepts::valid_expr(concepts::model_of<Constructible, T, UnCvT const&>(), concepts::model_of<ImplicitlyConvertibleTo, UnCvT const&, T>(), concepts::model_of<Constructible, T, UnCvT&>(), concepts::model_of<ImplicitlyConvertibleTo, UnCvT&, T>(), concepts::model_of<Constructible, T, UnCvT const&&>(), concepts::model_of<ImplicitlyConvertibleTo, UnCvT const&&, T>())) requires_(T&&);
            };
            
            struct Movable
            : refines<struct ranges::v3::concepts::MoveConstructible>
            {
                template <typename T>
                decltype(concepts::valid_expr(concepts::model_of<Assignable, T&, T&&>(), concepts::model_of<Swappable, T&>())) requires_(T&&);
            };
            
            struct Copyable
            : refines<struct ranges::v3::concepts::Movable, struct ranges::v3::concepts::CopyConstructible>
            {
                template <typename T>
                decltype(concepts::valid_expr(concepts::model_of<Assignable, T&, T const&>(), concepts::model_of<Assignable, T&, T&>(), concepts::model_of<Assignable, T&, T const&&>())) requires_(T&&);
            };
            
            struct SemiRegular
            : refines<struct ranges::v3::concepts::Copyable, struct ranges::v3::concepts::DefaultConstructible>
            {};
            
            struct Regular
            : refines<struct ranges::v3::concepts::SemiRegular, struct ranges::v3::concepts::EqualityComparable>
            {};
            
            struct Function
            {
                template <typename Fun, typename ... Args>
                using result_t = decltype(val<Fun>()(val<Args>()...));
                
                template <typename Fun, typename ... Args>
                decltype(concepts::valid_expr(concepts::model_of<CopyConstructible, uncvref_t<Fun>>(), ((void)val<Fun>()(val<Args>()...), 42))) requires_(Fun&& fun, Args&&... args);
            };
            
            struct RegularFunction
            : refines<struct ranges::v3::concepts::Function>
            {};
            
            struct Predicate
            : refines<struct ranges::v3::concepts::RegularFunction>
            {
                template <typename Fun, typename ... Args>
                decltype(concepts::valid_expr(concepts::convertible_to<bool>(val<Fun>()(val<Args>()...)))) requires_(Fun&& fun, Args&&... args);
            };
            
            struct Relation
            : refines<struct ranges::v3::concepts::RegularFunction>
            {
                template <typename Fun, typename T>
                decltype(concepts::valid_expr(concepts::model_of<Predicate>(val<Fun>(), val<T>(), val<T>()))) requires_(Fun&&, T&&);
                
                template <typename Fun, typename T, typename U, meta::if_<std::is_same<T, U>, int>=0>
                decltype(concepts::valid_expr(concepts::model_of<Predicate>(val<Fun>(), val<T>(), val<U>()))) requires_(Fun&&, T&&, T&&);
                
                template <typename Fun, typename T, typename U, meta::if_c<!std::is_same<T, U>::value, int>=0, typename C = CommonReference::reference_t<T const&, U const&>>
                decltype(concepts::valid_expr(concepts::model_of<Relation, Fun, T, T>(), concepts::model_of<Relation, Fun, U, U>(), concepts::model_of<CommonReference, T const&, U const&>(), concepts::model_of<Relation, Fun, C, C>(), concepts::model_of<Predicate, Fun, T, U>(), concepts::model_of<Predicate, Fun, U, T>())) requires_(Fun&&, T&&, U&&);
            };
        }
        
        template <typename ... Ts>
        using Same = concepts::Same::same_t<Ts...>;
        
        template <typename T, typename U>
        using ImplicitlyConvertibleTo = concepts::models<concepts::ImplicitlyConvertibleTo, T, U>;
        
        template <typename T, typename U>
        using ExplicitlyConvertibleTo = concepts::models<concepts::ExplicitlyConvertibleTo, T, U>;
        
        template <typename T, typename U>
        using ConvertibleTo = concepts::models<concepts::ConvertibleTo, T, U>;
        
        template <typename T, typename U>
        using DerivedFrom = concepts::models<concepts::DerivedFrom, T, U>;
        
        template <typename T, typename U, typename ... Rest>
        using CommonReference = meta::or_<meta::strict_and<std::is_void<T>, std::is_void<U>, std::is_void<Rest>...>, concepts::models<concepts::CommonReference, T, U, Rest...>>;
        
        template <typename T, typename U, typename ... Rest>
        using Common = meta::or_<meta::strict_and<std::is_void<T>, std::is_void<U>, std::is_void<Rest>...>, concepts::models<concepts::Common, T, U, Rest...>>;
        
        template <typename T>
        using Integral = concepts::models<concepts::Integral, T>;
        
        template <typename T>
        using SignedIntegral = concepts::models<concepts::SignedIntegral, T>;
        
        template <typename T>
        using UnsignedIntegral = concepts::models<concepts::UnsignedIntegral, T>;
        
        template <typename T>
        using Destructible = concepts::models<concepts::Destructible, T>;
        
        template <typename T, typename ... Args>
        using Constructible = concepts::models<concepts::Constructible, T, Args...>;
        
        template <typename T>
        using DefaultConstructible = concepts::models<concepts::DefaultConstructible, T>;
        
        template <typename T>
        using MoveConstructible = concepts::models<concepts::MoveConstructible, T>;
        
        template <typename T>
        using CopyConstructible = concepts::models<concepts::CopyConstructible, T>;
        
        template <typename T, typename U>
        using Assignable = concepts::models<concepts::Assignable, T, U>;
        
        template <typename T>
        using Movable = concepts::models<concepts::Movable, T>;
        
        template <typename T>
        using Copyable = concepts::models<concepts::Copyable, T>;
        
        template <typename T, typename U>
        using WeaklyEqualityComparable = concepts::models<concepts::WeaklyEqualityComparable, T, U>;
        
        template <typename T, typename U = T>
        using EqualityComparable = concepts::models<concepts::EqualityComparable, T, U>;
        
        template <typename T, typename U = T>
        using WeaklyOrdered = concepts::models<concepts::WeaklyOrdered, T, U>;
        
        template <typename T, typename U = T>
        using TotallyOrdered = concepts::models<concepts::TotallyOrdered, T, U>;
        
        template <typename T>
        using SemiRegular = concepts::models<concepts::SemiRegular, T>;
        
        template <typename T>
        using Regular = concepts::models<concepts::Regular, T>;
        
        template <typename T, typename U = T>
        using Swappable = concepts::models<concepts::Swappable, T, U>;
        
        template <typename Fun, typename ... Args>
        using Function = concepts::models<concepts::Function, Fun, Args...>;
        
        template <typename Fun, typename ... Args>
        using RegularFunction = concepts::models<concepts::RegularFunction, Fun, Args...>;
        
        template <typename Fun, typename ... Args>
        using Predicate = concepts::models<concepts::Predicate, Fun, Args...>;
        
        template <typename Fun, typename T, typename U = T>
        using Relation = concepts::models<concepts::Relation, Fun, T, U>;
    }
}

Macro CONCEPT_REQUIRES_

#define CONCEPT_REQUIRES_(...) int CONCEPT_PP_CAT(_concept_requires_, __LINE__) = 42,                              typename std::enable_if<                                                                (CONCEPT_PP_CAT(_concept_requires_, __LINE__) == 43) || (__VA_ARGS__),              int                                                                             >::type = 0

@{


Class template ranges::v3::concepts::refines<Concepts...>

template <typename ... Concepts>
struct refines
: detail::base_concept_t<Concepts>
{
    refines() = delete;
    
    using base_concepts_t = meta::list<Concepts...>;
    
    template <typename ... Ts>
    void requires_(Ts&&...);
};

/////////////////////////////////////////////////////////////////////////////////////////


Class template ranges::v3::concepts::models<Concept, Ts...>

template <typename Concept, typename ... Ts>
struct models
: meta::bool_<meta::_t<decltype(detail::models_<Ts...>(_nullptr_v<Concept>()))>::value>
{};

/////////////////////////////////////////////////////////////////////////////////////////


Function template ranges::v3::concepts::model_of<Concept, Ts...>

template <typename Concept, typename ... Ts>
meta::if_c<concepts::models<Concept, Ts...>::value, int> model_of(Ts&&...);

/////////////////////////////////////////////////////////////////////////////////////////


Class template ranges::v3::concepts::most_refined<Concepts, Ts...>

template <typename Concepts, typename ... Ts>
struct most_refined
: detail::most_refined_<meta::find_if<Concepts, meta::bind_back<meta::quote<models>, Ts...> > >
{};

/////////////////////////////////////////////////////////////////////////////////////////


Class ranges::v3::concepts::WeaklyEqualityComparable

struct WeaklyEqualityComparable
{
    template <typename T, typename U>
    decltype(concepts::valid_expr(concepts::convertible_to<bool>(t==u), concepts::convertible_to<bool>(t!=u), concepts::convertible_to<bool>(u==t), concepts::convertible_to<bool>(u!=t))) requires_(T&& t, U&& u);
};

///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////