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

352 lines
8.4 KiB
C++

static_assert( __cplusplus > 2020'99 );
#pragma once
#include <Alepha/Alepha.h>
#include <type_traits>
#include <Alepha/Meta/dep_value.h>
#include <Alepha/Capabilities.h>
namespace Alepha::Hydrogen ::detail
{
namespace comparisons_m::inline exports
{
struct comparable {};
}
namespace comparisons_m
{
template< typename T >
concept LensComparable= HasCapability< T, comparable >;
// Spaceship lens support
template< typename T >
concept MemberSpaceshipLensed=
LensComparable< T >
and
requires( const T &lhs, const T &rhs )
{
{ lhs.spaceship_lens() <=> rhs.spaceship_lens() } -> SameAs< std::strong_ordering >;
};
constexpr decltype( auto )
spaceship_lens( const MemberSpaceshipLensed auto &t )
{
return t.spaceship_lens();
}
template< typename T >
concept SpaceshipLensed=
LensComparable< T >
and
requires( const T &lhs, const T &rhs )
{
{ spaceship_lens( lhs ) <=> rhs.spaceship_lens( rhs ) } -> SameAs< std::strong_ordering >;
};
template< typename T >
constexpr decltype( auto )
make_spaceship_lens( T &t )
{
if constexpr( SpaceshipLensed< T > ) return spaceship_lens( t );
//else if constexpr( supports_default_lens_v< T > ) return default_lens( t );
else static_assert( Meta::dep_value< false, T > );
}
// Value lens support
template< typename T >
concept MemberValueLensed=
LensComparable< T >
and
requires( const T &val )
{
{ val.value_lens() } -> Concepts::Comparable;
};
constexpr decltype( auto )
value_lens( const MemberValueLensed auto &t )
{
return t.value_lens();
}
constexpr decltype( auto )
value_lens( const SpaceshipLensed auto &t )
{
return spaceship_lens( t );
}
template< typename T >
concept ValueLensed=
LensComparable< T >
and
requires( const T &val )
{
{ value_lens( val ) } -> Concepts::Comparable;
};
template< typename T >
constexpr decltype( auto )
make_value_lens( T &t )
{
if constexpr( ValueLensed< T > ) return value_lens( t );
//else if constexpr( supports_default_lens_v< T > ) return default_lens( t );
else static_assert( Meta::dep_value< false, T > );
}
// Equality Lens support
template< typename T >
concept MemberEqualityLensed=
LensComparable< T >
and
requires( const T &val )
{
{ val.equality_lens() } -> Concepts::EqualityComparable;
};
constexpr decltype( auto )
equality_lens( const MemberEqualityLensed auto &t )
{
return t.equality_lens();
}
constexpr decltype( auto )
equality_lens( const ValueLensed auto &t )
{
return value_lens( t );
}
template< typename T >
concept EqualityLensed=
LensComparable< T >
and
requires( const T &val )
{
{ equality_lens( val ) } -> Concepts::EqualityComparable;
};
template< typename T >
constexpr decltype( auto )
make_equality_lens( T &t )
{
if constexpr( EqualityLensed< T > ) return equality_lens( t );
//else if constexpr( supports_default_lens_v< T > ) return default_lens( t );
else static_assert( Meta::dep_value< false, T > );
}
// Strict weak order lens support
template< typename T >
concept MemberStrictWeakOrderLensed=
LensComparable< T >
and
requires( const T &val )
{
{ val.strict_weak_order_lens() } -> Concepts::LessThanComparable;
};
constexpr decltype( auto )
strict_weak_order_lens( const MemberStrictWeakOrderLensed auto &t )
{
return t.strict_weak_order_lens();
}
constexpr decltype( auto )
strict_weak_order_lens( const ValueLensed auto &t )
{
return value_lens( t );
}
template< typename T >
concept StrictWeakOrderLensed=
LensComparable< T >
and
requires( const T &val )
{
{ strict_weak_order_lens( val ) } -> Concepts::LessThanComparable;
};
template< typename T >
constexpr decltype( auto )
make_strict_weak_order_lens( T &t )
{
if constexpr( StrictWeakOrderLensed< T > ) return strict_weak_order_lens( t );
//else if constexpr( supports_default_lens_v< T > ) return default_lens( t );
else static_assert( Meta::dep_value< false, T > );
}
// Operator support:
template< LensComparable T >
constexpr bool
operator == ( const T &lhs, const T &rhs )
{
return make_equality_lens( lhs ) == make_equality_lens( rhs );
}
template< LensComparable T >
constexpr bool
operator != ( const T &lhs, const T &rhs )
{
return make_equality_lens( lhs ) != make_equality_lens( rhs );
}
template< LensComparable T >
constexpr bool
operator < ( const T &lhs, const T &rhs )
{
return make_strict_weak_order_lens( lhs ) < make_strict_weak_order_lens( rhs );
}
template< LensComparable T >
constexpr bool
operator > ( const T &lhs, const T &rhs )
{
return make_strict_weak_order_lens( lhs ) > make_strict_weak_order_lens( rhs );
}
template< LensComparable T >
constexpr bool
operator <= ( const T &lhs, const T &rhs )
{
return make_strict_weak_order_lens( lhs ) <= make_strict_weak_order_lens( rhs );
}
template< LensComparable T >
constexpr bool
operator >= ( const T &lhs, const T &rhs )
{
return make_strict_weak_order_lens( lhs ) >= make_strict_weak_order_lens( rhs );
}
template< typename ... Args >
struct magma_hook
{
std::tuple< Args... > view;
};
namespace exports
{
template< typename ... Args >
constexpr auto
ordering_magma( Args && ... args )
{
return magma_hook< Args... >{ std::tie( std::forward< Args >( args )... ) };
}
}
// TODO: Sort out the linear-trichotomous problem.
template< typename comp, std::size_t index= 0, typename ... Args >
constexpr bool
compOp( const std::tuple< Args... > &lhs, const std::tuple< Args... > &rhs )
{
if constexpr( index == sizeof...( Args ) ) return false;
else
{
const auto &l= std::get< index >( lhs );
const auto &r= std::get< index >( rhs );
if( comp{}( l, r ) ) return true;
else if( comp{}( r, l ) ) return false;
return compOp< comp, index + 1 >( lhs, rhs );
}
}
template< typename ... Args >
constexpr bool
operator < ( const magma_hook< Args... > &lhs, const magma_hook< Args... > &rhs )
{
return compOp< std::less<> >( lhs.view, rhs.view );
}
template< typename ... Args >
constexpr bool
operator > ( const magma_hook< Args... > &lhs, const magma_hook< Args... > &rhs )
{
return compOp< std::greater<> >( lhs.view, rhs.view );
}
template< typename comp, std::size_t index= 0, typename ... Args >
constexpr bool
comp_eqOp( const std::tuple< Args... > &lhs, const std::tuple< Args... > &rhs )
{
if constexpr( index == sizeof...( Args ) ) return true;
else
{
const auto &l= std::get< index >( lhs );
const auto &r= std::get< index >( rhs );
const bool first_pass= comp{}( l, r );
if( first_pass and comp{}( r, l ) ) return comp_eqOp< comp, index + 1 >( lhs, rhs );
return first_pass;
}
}
template< typename ... Args >
constexpr bool
operator <= ( const magma_hook< Args... > &lhs, const magma_hook< Args... > &rhs )
{
return comp_eqOp< std::less_equal<> >( lhs.view, rhs.view );
}
template< typename ... Args >
constexpr bool
operator >= ( const magma_hook< Args... > &lhs, const magma_hook< Args... > &rhs )
{
return comp_eqOp< std::greater_equal<> >( lhs.view, rhs.view );
}
template< std::size_t index= 0, typename ... Args >
constexpr bool
eq( const std::tuple< Args... > &lhs, const std::tuple< Args... > &rhs )
{
if constexpr( index == sizeof...( Args ) ) return true;
else
{
const auto &l= std::get< index >( lhs );
const auto &r= std::get< index >( rhs );
return ( l == r ) and eq< index + 1 >( lhs, rhs );
}
}
template< typename ... Args >
constexpr bool
operator == ( const magma_hook< Args... > &lhs, const magma_hook< Args... > &rhs )
{
return eq( lhs.view, rhs.view );
}
template< std::size_t index= 0, typename ... Args >
constexpr bool
ne( const std::tuple< Args... > &lhs, const std::tuple< Args... > &rhs )
{
if constexpr( index == sizeof...( Args ) ) return false;
else
{
const auto &l= std::get< index >( lhs );
const auto &r= std::get< index >( rhs );
return l != r and ne< index + 1 >( lhs, rhs );
}
}
template< typename ... Args >
constexpr bool
operator != ( const magma_hook< Args... > &lhs, const magma_hook< Args... > &rhs )
{
return ne( lhs, rhs );
}
}
}
namespace Alepha::Hydrogen::inline exports::inline comparisons_m
{
using namespace detail::comparisons_m::exports;
}