1
0
forked from Alepha/Alepha

I added the lens-based comparison code.

The metaprogramming is still based upon the angle-bracket
type-form.  Now to rewrite it in terms of the constexpr systems.
This commit is contained in:
2021-10-25 02:02:12 -04:00
parent 3c11d6af74
commit f2ae99f648
4 changed files with 616 additions and 0 deletions

112
Capabilities.h Normal file
View File

@ -0,0 +1,112 @@
static_assert( __cplusplus > 201700, "C++17 Required" );
#pragma once
#include <Alepha/Alepha.h>
#include <Alepha/Meta/find.h>
#include <Alepha/Stud/type_traits.h>
namespace Alepha::Hydrogen
{
inline namespace exports { inline namespace capabilities {} }
namespace detail::capabilities
{
inline namespace exports
{
template< typename ... capabilities >
struct Capabilities;
template< typename T, typename cap >
struct has_capability; //: std::is_base_of< cap, T > {};
#if 0
template< template< typename ... > class Type, typename ... Caps, typename cap >
struct has_capability< Type< Capabilities< Caps... > >, cap >
{
using T= Type< Capabilities< Caps... > >;
static constexpr bool value= Meta::find_in_tuple_v< cap, std::tuple< Caps... > > or std::is_base_of_v< cap, T >;
using type= has_capability;
};
template< template< typename ... > class Type, typename ... Back, typename ... Caps, typename cap >
struct has_capability< Type< Capabilities< Caps... >, Back... >, cap >
{
using T= Type< Capabilities< Caps... >, Back... >;
static constexpr bool value= Meta::find_in_tuple_v< cap, std::tuple< Caps... > > or std::is_base_of_v< cap, T >;
using type= has_capability;
};
template< template< typename ... > class Type, typename ... Front, typename ... Caps, typename cap >
struct has_capability< Type< Front..., Capabilities< Caps... > >, cap >
{
using T= Type< Front..., Capabilities< Caps... > >;
static constexpr bool value= Meta::find_in_tuple_v< cap, std::tuple< Caps... > > or std::is_base_of_v< cap, T >;
using type= has_capability;
};
#endif
}
template< typename T >
struct is_capability_list : std::false_type {};
template< typename ... Args >
struct is_capability_list< Capabilities< Args... > > : std::true_type {};
template< typename T >
constexpr bool is_capability_list_v= is_capability_list< T >::value;
template< template< typename ... > class ... HigherKinds >
struct higher_kind_tuple {};
template< typename cap, typename ... Caps >
constexpr auto
has_cap( const Stud::type_identity< Capabilities< Caps... > > & )
{
return Meta::find_if< Meta::bind1st< std::is_base_of, cap >, Meta::list< Caps... > >{};
}
template< typename cap >
constexpr std::false_type has_cap( const Meta::list<> & ) { return {}; }
template< typename cap, typename First, typename ... TParams >
constexpr auto
has_cap( const Meta::list< First, TParams... > & )
{
using depth_type= decltype( has_cap< cap >( Meta::list< TParams... >{} ) );
if constexpr( is_capability_list_v< First > )
{
using bool_type= decltype( has_cap< cap >( Stud::type_identity< First >() ) );
if constexpr( bool_type::value )
{
return std::bool_constant< bool_type::value >{};
}
else return depth_type{};
}
else return depth_type{};
}
template< typename cap, template< typename ... > class Class, typename ... TParams >
constexpr auto
has_cap( const Class< TParams... > & )
{
return has_cap< cap >( Meta::list< TParams... >{} );
}
namespace exports
{
template< typename T, typename cap >
constexpr bool has_capability_v= std::is_base_of_v< cap, T > or decltype( has_cap< cap >( std::declval< T >() ) )::value;
template< typename T, typename cap >
struct has_capability : std::bool_constant< has_capability_v< T, cap > > {};
}
}
namespace exports::capabilities
{
using namespace detail::capabilities::exports;
}
}

415
comparisons.h Normal file
View File

@ -0,0 +1,415 @@
static_assert( __cplusplus > 201700, "C++17 Required" );
#pragma once
#include <Alepha/Alepha.h>
#include <type_traits>
#include <Alepha/Meta/overload.h>
#include <Alepha/Capabilities.h>
namespace Alepha::Hydrogen
{
inline namespace exports { inline namespace comparisons {} }
namespace detail::comparisons
{
inline namespace exports {}
using namespace Meta::exports::template_overload;
// Basic capability support
// TODO: non-base-type capability via ADL rules on templates.
struct comparable {};
namespace exports
{
using detail::comparisons::comparable;
}
template< typename T >
constexpr bool has_comparable_capability_v= has_capability_v< std::decay_t< T >, comparable >;
template< typename T >
struct has_comparable_capability : std::bool_constant< has_comparable_capability_v< T > > {};
// Spaceship lens support
template< typename T, typename= void >
struct has_spaceship_lens_member : std::false_type {};
template< typename T >
struct has_spaceship_lens_member< T, std::void_t< decltype( std::declval< const T & >().spaceship_lens() ) > > : std::true_type {};
template< typename T >
constexpr bool has_spaceship_lens_member_v= has_spaceship_lens_member< T >::value;
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< has_spaceship_lens_member_v< T > >,
overload< __LINE__ > = nullptr
>
decltype( auto )
spaceship_lens( T &t )
{
return t.spaceship_lens();
}
template< typename T, typename= void >
struct supports_spaceship_lens : std::false_type {};
template< typename T >
struct supports_spaceship_lens< T, std::void_t< decltype( spaceship_lens( std::declval< const T & >() ) ) > > : std::true_type {};
template< typename T >
constexpr bool supports_spaceship_lens_v= supports_spaceship_lens< T >::value;
// Value lens support
template< typename T, typename= void >
struct has_value_lens_member : std::false_type {};
template< typename T >
struct has_value_lens_member< T, std::void_t< decltype( std::declval< const T & >().value_lens() ) > > : std::true_type {};
template< typename T >
constexpr bool has_value_lens_member_v= has_value_lens_member< T >::value;
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< has_value_lens_member_v< T > >,
overload< __LINE__ > = nullptr
>
decltype( auto )
value_lens( T &t )
{
return t.value_lens();
}
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_spaceship_lens_v< T > >,
overload< __LINE__ > = nullptr
>
decltype( auto )
value_lens( T &t )
{
return spaceship_lens( t );
}
template< typename T, typename= void >
struct supports_value_lens : std::false_type {};
template< typename T >
struct supports_value_lens< T, std::void_t< decltype( value_lens( std::declval< const T & >() ) ) > > : std::true_type {};
template< typename T >
constexpr bool supports_value_lens_v= supports_value_lens< T >::value;
// Equality Lens support
template< typename T, typename= void >
struct has_equality_lens_member : std::false_type {};
template< typename T >
struct has_equality_lens_member< T, std::void_t< decltype( std::declval< const T & >().equality_lens() ) > > : std::true_type {};
template< typename T >
constexpr bool has_equality_lens_member_v= has_equality_lens_member< T >::value;
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< has_equality_lens_member_v< T > >,
overload< __LINE__ > = nullptr
>
decltype( auto )
equality_lens( T &t )
{
return t.equality_lens();
}
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_value_lens_v< T > >,
overload< __LINE__ > = nullptr
>
decltype( auto )
equality_lens( T &t )
{
return value_lens( t );
}
template< typename T, typename= void >
struct supports_equality_lens : std::false_type {};
template< typename T >
struct supports_equality_lens< T, std::void_t< decltype( equality_lens( std::declval< const T & >() ) ) > > : std::true_type {};
template< typename T >
constexpr bool supports_equality_lens_v= supports_equality_lens< T >::value;
// Strict weak order lens support
template< typename T, typename= void >
struct has_strict_weak_order_lens_member : std::false_type {};
template< typename T >
struct has_strict_weak_order_lens_member< T, std::void_t< decltype( std::declval< const T & >().strict_weak_order_lens() ) > > : std::true_type {};
template< typename T >
constexpr bool has_strict_weak_order_lens_member_v= has_strict_weak_order_lens_member< T >::value;
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< has_strict_weak_order_lens_member_v< T > >,
overload< __LINE__ > = nullptr
>
decltype( auto )
strict_weak_order_lens( T &t )
{
return t.strict_weak_order_lens();
}
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_value_lens_v< T > >,
overload< __LINE__ > = nullptr
>
decltype( auto )
strict_weak_order_lens( T &t )
{
return value_lens( t );
}
template< typename T, typename= void >
struct supports_strict_weak_order_lens : std::false_type {};
template< typename T >
struct supports_strict_weak_order_lens< T, std::void_t< decltype( strict_weak_order_lens( std::declval< const T & >() ) ) > > : std::true_type {};
template< typename T >
constexpr bool supports_strict_weak_order_lens_v= supports_strict_weak_order_lens< T >::value;
// Operator support:
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_equality_lens_v< T > >,
overload< __LINE__ > = nullptr
>
bool
operator == ( const T &lhs, const T &rhs )
{
return equality_lens( lhs ) == equality_lens( rhs );
}
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_equality_lens_v< T > >,
overload< __LINE__ > = nullptr
>
bool
operator != ( const T &lhs, const T &rhs )
{
return equality_lens( lhs ) != equality_lens( rhs );
}
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_strict_weak_order_lens_v< T > >,
overload< __LINE__ > = nullptr
>
bool
operator < ( const T &lhs, const T &rhs )
{
return strict_weak_order_lens( lhs ) < strict_weak_order_lens( rhs );
}
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_strict_weak_order_lens_v< T > >,
overload< __LINE__ > = nullptr
>
bool
operator > ( const T &lhs, const T &rhs )
{
return strict_weak_order_lens( lhs ) > strict_weak_order_lens( rhs );
}
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_strict_weak_order_lens_v< T > >,
overload< __LINE__ > = nullptr
>
bool
operator <= ( const T &lhs, const T &rhs )
{
return strict_weak_order_lens( lhs ) <= strict_weak_order_lens( rhs );
}
template
<
typename T,
typename= std::enable_if_t< has_comparable_capability_v< T > >,
typename= std::enable_if_t< supports_strict_weak_order_lens_v< T > >,
overload< __LINE__ > = nullptr
>
bool
operator >= ( const T &lhs, const T &rhs )
{
return strict_weak_order_lens( lhs ) >= strict_weak_order_lens( rhs );
}
template< typename ... Args >
struct magma_hook
{
std::tuple< Args... > view;
};
namespace exports
{
template< typename ... Args >
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 >
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 >
bool
operator < ( const magma_hook< Args... > &lhs, const magma_hook< Args... > &rhs )
{
return compOp< std::less<> >( lhs.view, rhs.view );
}
template< typename ... Args >
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 >
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 >
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 >
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 >
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 >
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 >
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 >
bool
operator != ( const magma_hook< Args... > &lhs, const magma_hook< Args... > &rhs )
{
return ne( lhs, rhs );
}
}
namespace exports::comparisons
{
using namespace detail::comparisons::exports;
}
}

85
comparisons.test/0.cc Normal file
View File

@ -0,0 +1,85 @@
static_assert( __cplusplus > 201700, "C++17 Required" );
#include <Alepha/comparisons.h>
#include <Alepha/Testing/test.h>
#include <Alepha/Testing/TableTest.h>
#include <Alepha/Utility/evaluation.h>
namespace
{
using Alepha::Testing::argcnt_t;
using Alepha::Testing::argvec_t;
}
int
main( const argcnt_t argcnt, const argvec_t argvec )
{
return Alepha::Testing::runAllTests( argcnt, argvec );
}
namespace
{
using namespace Alepha::Testing::exports;
using namespace Alepha::exports::comparisons;
using namespace Alepha::exports::capabilities;
template< typename= int, typename= Capabilities< comparable >, typename= float, typename= Capabilities< short > >
struct Date_core
{
int y;
int m;
int d;
auto value_lens() const { return std::tie( y, m, d ); }
};
using Date= Date_core<>;
static_assert( Alepha::has_capability_v< Date, comparable > );
template< template< typename > class op, typename T >
constexpr bool
comp( const T &lhs, const T &rhs )
{
return op< T >{}( lhs, rhs );
}
auto tests= Alepha::Utility::enroll <=[]
{
"smoke.lt"_test <=TableTest< comp< std::less, Date > >::Cases
{
{ "smoke1", { { 1982, 12, 21 }, { 2020, 12, 15 } }, true },
{ "smoke1", { { 2020, 12, 15 }, { 1982, 12, 21 } }, false },
};
"smoke.gt"_test <=TableTest< comp< std::greater, Date > >::Cases
{
{ "smoke1", { { 1982, 12, 21 }, { 2020, 12, 15 } }, false },
{ "smoke1", { { 2020, 12, 15 }, { 1982, 12, 21 } }, true },
};
"smoke.le"_test <=TableTest< comp< std::less_equal, Date > >::Cases
{
{ "smoke1", { { 1982, 12, 21 }, { 2020, 12, 15 } }, true },
{ "smoke1", { { 2020, 12, 15 }, { 1982, 12, 21 } }, false },
};
"smoke.ge"_test <=TableTest< comp< std::greater_equal, Date > >::Cases
{
{ "smoke1", { { 1982, 12, 21 }, { 2020, 12, 15 } }, false },
{ "smoke1", { { 2020, 12, 15 }, { 1982, 12, 21 } }, true },
};
"smoke.eq"_test <=TableTest< comp< std::equal_to, Date > >::Cases
{
{ "smoke1", { { 1982, 12, 21 }, { 2020, 12, 15 } }, false },
{ "smoke1", { { 2020, 12, 15 }, { 1982, 12, 21 } }, false },
};
"smoke.ne"_test <=TableTest< comp< std::not_equal_to, Date > >::Cases
{
{ "smoke1", { { 1982, 12, 21 }, { 2020, 12, 15 } }, true },
{ "smoke1", { { 2020, 12, 15 }, { 1982, 12, 21 } }, true },
};
};
}

View File

@ -0,0 +1,4 @@
CXXFLAGS+= -std=c++17 -I ../
CXXFLAGS+= -g -O0
all: 0