1
0
forked from Alepha/Alepha
Files
Alepha/Concepts.h

292 lines
6.3 KiB
C++

static_assert( __cplusplus > 2020'99 );
#pragma once
#include <Alepha/Alepha.h>
#include <concepts>
#include <type_traits>
#include <iosfwd>
#include "meta.h"
#include "function_traits.h"
namespace Alepha::Hydrogen ::detail:: Concepts_m
{
inline namespace exports
{
// This section re-capitalizes the standard library concept constraints.
inline namespace wrap_std
{
template< typename T, typename U >
concept SameAs= std::same_as< T, U >;
template< typename T, typename ... Args >
concept ConstructibleFrom= std::constructible_from< T, Args... >;
template< typename T, typename U >
concept ConvertibleTo= std::convertible_to< T, U >;
template< typename T, typename Base >
concept DerivedFrom= std::derived_from< T, Base >;
template< typename T >
concept FloatingPoint= std::floating_point< T >;
template< typename T >
concept Integral= std::integral< T >;
}
template< typename T, typename U >
concept ConvertibleFrom= ConvertibleTo< U, T >;
template< typename T, typename NonBase >
concept NotDerivedFrom= not DerivedFrom< T, NonBase >;
// This is potentially useful since `std::is_base_of` can peer past privacy...
template< typename T, typename Base >
concept HasBase= std::is_base_of_v< Base, T >;
template< typename T, typename NonBase >
concept LacksBase= not HasBase< T, NonBase >;
template< typename T, typename Target >
concept ConvertibleToButNotSameAs= true
and not SameAs< T, Target >
and ConvertibleTo< T, Target >
;
template< typename T >
concept EmptyType= std::is_empty_v< T >;
// Stream related concepts...
template< typename T >
concept OStreamable=
requires( const T &t, std::ostream &os )
{
{ os << t } -> SameAs< std::ostream & >;
};
template< typename T >
concept IStreamable=
requires( const T &t, std::istream &is )
{
{ is >> t } -> SameAs< std::istream & >;
};
template< typename T >
concept Streamable= OStreamable< T > and IStreamable< T >;
template< typename T >
concept Enumeration= std::is_enum_v< T >;
// Various operator possible concepts:
template< typename T >
concept Addable=
requires( const T &x, const T &y )
{
{ x + y };
};
template< typename Lhs, typename Rhs >
concept LhsAddableTo=
requires( const Lhs &lhs, const Rhs &rhs )
{
{ lhs + rhs };
};
template< typename Rhs, typename Lhs >
concept RhsAddableTo=
requires( const Lhs &lhs, const Rhs &rhs )
{
{ lhs + rhs };
};
template< typename A, typename B >
concept AdditionAssignable=
requires( A &a, const B &b )
{
{ a+= b };
};
template< typename A, typename B >
concept SubtractionAssignable=
requires( A &a, const B &b )
{
{ a-= b };
};
template< typename T, typename I >
concept IndexibleBy=
requires( T &t, const I &i )
{
{ t[ i ] };
};
template< typename T >
concept Dereferencible=
requires( T &t )
{
{ *t };
};
// Relational operator concepts...
template< typename T >
concept LessThanComparable=
requires( const T &lhs, const T &rhs )
{
{ lhs < rhs } -> ConvertibleTo< bool >;
};
template< typename T >
concept GreaterThanComparable=
requires( const T &lhs, const T &rhs )
{
{ lhs > rhs } -> ConvertibleTo< bool >;
};
template< typename T >
concept LessEqualComparable=
requires( const T &lhs, const T &rhs )
{
{ lhs <= rhs } -> ConvertibleTo< bool >;
};
template< typename T >
concept GreaterEqualComparable=
requires( const T &lhs, const T &rhs )
{
{ lhs >= rhs } -> ConvertibleTo< bool >;
};
template< typename T >
concept EqualityComparable=
requires( const T &lhs, const T &rhs )
{
{ lhs == rhs } -> ConvertibleTo< bool >;
};
template< typename T >
concept InequalityComparable=
requires( const T &lhs, const T &rhs )
{
{ lhs != rhs } -> ConvertibleTo< bool >;
};
template< typename T >
concept TotalOrderComparable=
requires( const T &lhs, const T &rhs )
{
{ total_order( lhs, rhs ) } -> SameAs< std::strong_ordering >;
};
template< typename T >
concept Comparable= true
and LessThanComparable< T >
and GreaterThanComparable< T >
and LessEqualComparable< T >
and GreaterEqualComparable< T >
and EqualityComparable< T >
and InequalityComparable< T >
;
template< typename T >
concept Primitive= FloatingPoint< T > or Integral< T >;
template< typename T >
concept Aggregate= std::is_aggregate_v< T >;
template< typename T >
concept Functional=
requires( const T &t )
{
{ std::function{ t } };
};
template< typename T >
concept NotFunctional= not Functional< T >;
template< typename T >
concept UnaryFunction= Functional< T > and function_traits< T >::args_size == 1;
template< typename T >
concept StandardLayout= std::is_standard_layout_v< T >;
template< typename T >
concept StandardLayoutAggregate= StandardLayout< T > and Aggregate< T >;
template< typename T >
concept Array= is_array_v< T >;
template< typename T, template< typename ... > class Ref >
concept SpecializationOf= is_specialization_of_v< T, Ref >;
template< typename T, template< typename ... > class Ref >
concept NotSpecializationOf= not SpecializationOf< T, Ref >;
template< typename T >
concept Vector= SpecializationOf< T, std::vector >;
template< typename T >
concept List= SpecializationOf< T, std::list >;
template< typename T >
concept Deque= SpecializationOf< T, std::deque >;
template< typename T >
concept Sequence= false
or Array< T >
or Vector< T >
or List< T >
or Deque< T >
;
template< typename T, typename Member >
concept SpecializedOn= is_specialized_on_v< T, Member >;
template< typename Member, typename Seq >
concept SequenceOf= Sequence< Seq > and SpecializedOn< Seq, Member >;
template< typename T >
concept Beginable=
requires( const T &t )
{
{ begin( t ) };
}
or
requires( const T &t )
{
{ std::begin( t ) };
};
template< typename T >
concept Endable=
requires( const T &t )
{
{ end( t ) };
}
or
requires( const T &t )
{
{ std::end( t ) };
};
template< typename T >
concept Iterable= Beginable< T > and Endable< T >;
template< typename T >
concept Tuple= is_tuple_v< T >;
}
}
namespace Alepha::Hydrogen::inline exports::inline Concepts_m::inline Concepts
{
using namespace detail::Concepts_m::exports;
}