diff --git a/Capabilities.h b/Capabilities.h index 09e3501..e2d896a 100644 --- a/Capabilities.h +++ b/Capabilities.h @@ -5,7 +5,7 @@ static_assert( __cplusplus > 201700, "C++17 Required" ); #include #include -#include +#include namespace Alepha::Hydrogen { @@ -19,7 +19,7 @@ namespace Alepha::Hydrogen struct Capabilities; template< typename T, typename cap > - struct has_capability; //: std::is_base_of< cap, T > {}; + struct has_capability_s; //: std::is_base_of< cap, T > {}; #if 0 @@ -50,58 +50,68 @@ namespace Alepha::Hydrogen } template< typename T > - struct is_capability_list : std::false_type {}; + struct is_capability_list_s : std::false_type {}; template< typename ... Args > - struct is_capability_list< Capabilities< Args... > > : std::true_type {}; + struct is_capability_list_s< Capabilities< Args... > > : std::true_type {}; + + inline constexpr Meta::trait< is_capability_list_s > is_capability_list; template< typename T > - constexpr bool is_capability_list_v= is_capability_list< T >::value; + constexpr bool is_capability_list_v= is_capability_list( Meta::type_value< T >{} ); + template< template< typename ... > class ... HigherKinds > struct higher_kind_tuple {}; - template< typename cap, typename ... Caps > - constexpr auto - has_cap( const Stud::type_identity< Capabilities< Caps... > > & ) + template< typename Cap, typename ... Caps > + constexpr bool + has_cap_in_capability_base( const Meta::type_value< Capabilities< Caps... > > &, Meta::type_value< Cap > cap ) { - return Meta::find_if< Meta::bind1st< std::is_base_of, cap >, Meta::Container::vector< Caps... > >{}; + Meta::Container::vector< Caps... > types; + using std::begin, std::end; + return Meta::find_if( begin( types ), end( types ), Meta::bind1st( Meta::is_base_of, cap ) ); } - template< typename cap > - constexpr std::false_type has_cap( const Meta::Container::vector<> & ) { return {}; } - - template< typename cap, typename First, typename ... TParams > - constexpr auto - has_cap( const Meta::Container::vector< First, TParams... > & ) + template< typename Left, typename Cap > + constexpr bool + has_cap_in_capability_base( const Left &, Meta::type_value< Cap > cap ) { - using depth_type= decltype( has_cap< cap >( Meta::Container::vector< TParams... >{} ) ); - if constexpr( is_capability_list_v< First > ) + throw "Unevaluated"; + } + + template< typename Cap, typename ... TParams > + constexpr bool + has_cap( const Meta::Container::vector< TParams... > &types, Meta::type_value< Cap > cap ) + { + bool rv= 0; + template_for( types ) <=[&] + ( const auto type ) { - 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{}; + if( is_capability_list( type ) and has_cap_in_capability_base( type, cap ) ) rv= true; + }; + return rv; } - template< typename cap, template< typename ... > class Class, typename ... TParams > - constexpr auto - has_cap( const Class< TParams... > & ) + template< typename Cap, template< typename ... > class Class, typename ... TParams > + constexpr bool + has_cap( const Meta::type_value< Class< TParams... > > &, Meta::type_value< Cap > cap ) { - return has_cap< cap >( Meta::Container::vector< TParams... >{} ); + return has_cap( Meta::Container::vector< TParams... >{}, cap ); } 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; + constexpr bool has_capability_v= + std::is_base_of_v< cap, T > + or + has_cap( Meta::type_value< T >{}, Meta::type_value< cap >{} ); template< typename T, typename cap > - struct has_capability : std::bool_constant< has_capability_v< T, cap > > {}; + struct has_capability_s : std::bool_constant< has_capability_v< T, cap > > {}; + + inline constexpr Meta::trait< has_capability_s > has_capability; } } diff --git a/Meta/Container/vector.h b/Meta/Container/vector.h index 1832dfa..f609d22 100644 --- a/Meta/Container/vector.h +++ b/Meta/Container/vector.h @@ -15,6 +15,29 @@ namespace Alepha::Hydrogen::Meta::Container inline namespace exports { template< typename ... Members > struct vector; + + template< typename ... Members > + constexpr auto + template_for( vector< Members... > ); + } + + template< typename ... Members > + struct template_for_binder + { + template< typename Body > + constexpr void + operator <=( Body b ) + { + auto wrapper= [&]( auto element ) { b( element ); return nullptr; }; + std::nullptr_t loop[]= { wrapper( type_value< Members >{} )... }; + } + }; + + template< typename ... Members > + constexpr auto + exports::template_for( vector< Members... > ) + { + return template_for_binder< Members... >{}; } template< typename Vector > @@ -44,6 +67,22 @@ namespace Alepha::Hydrogen::Meta::Container { vector_iterator< List > iter; }; + + template< typename MetaFunction, typename Arg1, typename First, typename ... Members > + constexpr decltype( auto ) + invoke_call( MetaFunction func, type_value< Arg1 > arg1, dereferenced_iterator< vector< First, Members... > > deref ) + { + if( deref.iter.offset == 0 ) return func( arg1, type_value< First >{} ); + else return invoke_call( func, arg1, dereferenced_iterator< vector< Members... > >{ deref.iter.offset - 1 } ); + } + + template< typename MetaFunction, typename Arg1, typename First > + constexpr decltype( auto ) + invoke_call( MetaFunction func, type_value< Arg1 > arg1, dereferenced_iterator< vector< First > > deref ) + { + if( deref.iter.offset == 0 ) return func( arg1, type_value< First >{} ); + else throw "Out of bounds iterator"; + } template< typename First, typename ... Members, typename Value > constexpr bool diff --git a/Meta/find.h b/Meta/find.h index 53f5f32..42f009f 100644 --- a/Meta/find.h +++ b/Meta/find.h @@ -4,7 +4,7 @@ static_assert( __cplusplus > 201700, "C++17 Required" ); #include -#include +#include #include #include @@ -17,29 +17,23 @@ namespace Alepha::Hydrogen::Meta { inline namespace exports { - template< typename Predicate, typename Tuple > - struct find_if; + template< typename Iter, typename Predicate > + constexpr bool + find_if( const Iter first, const Iter last, Predicate pred ) + { + for( Iter pos= first; pos != last; ++pos ) + { + if( pred( *pos ) ) return true; + } + return false; + } - template< typename Predicate, typename First, typename ... Elements > - struct find_if< Predicate, Container::vector< First, Elements... > > - : std::conditional_t - < - Meta::call< Predicate, First >::value, - std::true_type, - find_if< Predicate, Container::vector< Elements... > > - >::type {}; - - template< typename Predicate > - struct find_if< Predicate, Container::vector<> > : std::false_type {}; - - template< typename Predicate, typename List > - constexpr bool find_if_v= find_if< Predicate, List >::value; - } - - namespace exports - { - template< typename Key, typename Argument > - constexpr bool find_v= find_if_v< Meta::bind1st< std::is_same, Key >, Argument >; + template< typename Iter, typename Value > + constexpr bool + find( const Iter first, const Iter last, const Value value ) + { + return find_if( first, last, Meta::bind1st( std::equal_to{}, value ) ); + } } } diff --git a/Meta/functional.h b/Meta/functional.h index 82f3987..65ee1ea 100644 --- a/Meta/functional.h +++ b/Meta/functional.h @@ -14,24 +14,38 @@ namespace Alepha::Hydrogen::Meta { inline namespace exports { - template< template< typename, typename > class Function, typename First > - struct bind1st - { - using type= bind1st; - template< typename Arg > - struct call : Function< First, Arg >::type {}; - }; + template< typename MetaFunction, typename Arg > + constexpr auto bind1st( MetaFunction func, Arg arg ); + } - template< template< typename, typename > class Function, typename Second > - struct bind2nd - { - using type= bind2nd; - template< typename Arg > - struct call : Function< Arg, Second >::type {}; - }; + template< typename MetaFunction, typename Arg > struct binder1st; - template< typename Function, typename ... Args > - struct call : Function::template call< Args... > {}; + template< typename MetaFunction, typename Arg1, typename Arg2 > + constexpr decltype( auto ) + invoke_call( MetaFunction func, Meta::type_value< Arg1 > arg1, Meta::type_value< Arg2 > arg2 ) + { + return func( arg1, arg2 ); + } + + template< typename MetaFunction, typename Arg > + struct binder1st< MetaFunction, Meta::type_value< Arg > > + { + MetaFunction func; + Meta::type_value< Arg > arg; + + template< typename Second > + constexpr decltype( auto ) + operator () ( const Second &second ) + { + return invoke_call( func, arg, second ); + } + }; + + template< typename MetaFunction, typename Arg > + constexpr auto + exports::bind1st( MetaFunction func, Arg arg ) + { + return binder1st< MetaFunction, Arg >{ func, arg }; } } diff --git a/Meta/test.cc b/Meta/test.cc index 6107174..eecf0f9 100644 --- a/Meta/test.cc +++ b/Meta/test.cc @@ -1,8 +1,9 @@ static_assert( __cplusplus > 201700, "C++17 Required" ); #include - #include +#include +#include #include @@ -21,6 +22,8 @@ namespace using namespace Alepha::Utility::evaluation; using namespace Alepha::Testing::literals; + using std::begin, std::end; + // These tests never actually fail at runtime, but they provide a simple way to have them // as unit tests. There's no call to actually assert them at runtime. If this test built, // it passes. @@ -115,6 +118,25 @@ namespace static_assert( not Alepha::Meta::is_streamable_v< void > ); }; }; + + namespace MetaContainer= Alepha::Meta::Container::exports; + using Alepha::Meta::type_value; + constexpr MetaContainer::vector< int, float, char > my_list; + + template< typename First, typename Last, typename Type > + constexpr bool + containsChar( First first, Last last, type_value< Type > value ) + { + for( auto pos= first; pos != last; ++pos ) + { + if( *pos == value ) return true; + } + return false; + } + + static_assert( containsChar( begin( my_list ), end( my_list ), type_value< char >{} ) ); + static_assert( not containsChar( begin( my_list ), end( my_list ), type_value< long double >{} ) ); + static_assert( containsChar( begin( my_list ), end( my_list ), type_value< int >{} ) ); } diff --git a/Meta/type_value.h b/Meta/type_value.h index b9679d2..e7305ce 100644 --- a/Meta/type_value.h +++ b/Meta/type_value.h @@ -12,21 +12,35 @@ namespace Alepha::Hydrogen::Meta { inline namespace exports { - template< typename > - struct type_value {}; + template< typename Type > + struct type_value { using type= Type; }; + + template< template< typename > class Trait, typename Value > + constexpr bool + check_trait( type_value< Value > ) + { + return Trait< Value >::value; + } + + template< template< typename, typename > class Trait, typename A, typename B > + constexpr bool + check_trait( type_value< A >, type_value< B > ) + { + return Trait< A, B >::value; + } template< typename Lhs, typename Rhs > constexpr bool - operator == ( type_value< Lhs >, type_value< Rhs > ) + operator == ( type_value< Lhs > lhs, type_value< Rhs > rhs ) { - return false; + return check_trait< std::is_same >( lhs, rhs ); } - template< typename Value > + template< typename Lhs, typename Rhs > constexpr bool - operator == ( type_value< Value >, type_value< Value > ) + operator != ( type_value< Lhs > lhs, type_value< Rhs > rhs ) { - return true; + return not( lhs == rhs ); } template< typename T > @@ -35,6 +49,34 @@ namespace Alepha::Hydrogen::Meta { return type_value< std::decay_t< T > >{}; } + + template< template< typename ... > class Trait > struct trait; + + template< template< typename > class Trait > + struct trait< Trait > + { + template< typename Type > + constexpr bool + operator() ( type_value< Type > ) const + { + return Trait< Type >::value; + } + }; + + template< template< typename, typename > class Trait > + struct trait< Trait > + { + template< typename A, typename B > + constexpr bool + operator() ( type_value< A >, type_value< B > ) const + { + return Trait< A, B >::value; + } + }; + + inline constexpr trait< std::is_base_of > is_base_of; + inline constexpr trait< std::is_same > is_same; + inline constexpr trait< std::is_default_constructible > is_default_constructible; } } diff --git a/comparisons.h b/comparisons.h index b55b52e..d7f9097 100644 --- a/comparisons.h +++ b/comparisons.h @@ -25,9 +25,11 @@ namespace Alepha::Hydrogen struct comparable {}; + namespace exports { using detail::comparisons::comparable; + inline constexpr Meta::type_value< comparable > comparable_capability; } template< typename T > diff --git a/comparisons.test/0.cc b/comparisons.test/0.cc index 0c22a08..6f17ae1 100644 --- a/comparisons.test/0.cc +++ b/comparisons.test/0.cc @@ -24,7 +24,13 @@ namespace using namespace Alepha::exports::comparisons; using namespace Alepha::exports::capabilities; - template< typename= int, typename= Capabilities< comparable >, typename= float, typename= Capabilities< short > > + template + < + typename= int, + typename= Capabilities< comparable >, + typename= float, + typename= Capabilities< short > + > struct Date_core { int y; @@ -35,7 +41,19 @@ namespace }; using Date= Date_core<>; - static_assert( Alepha::has_capability_v< Date, comparable > ); + namespace detail= Alepha::detail::capabilities; + + namespace Meta= Alepha::Meta; + + constexpr Meta::Container::vector< short, long, int, int, std::string, std::vector< int >, long, void, void > vec; + constexpr Meta::type_value< int > val; + using std::begin, std::end; + + static_assert( Meta::find_if( begin( vec ), end( vec ), Meta::bind1st( Meta::is_same, Meta::type_value< int >{} ) ) ); + static_assert( not Meta::find_if( begin( vec ), end( vec ), Meta::bind1st( Meta::is_same, Meta::type_value< double >{} ) ) ); + + static_assert( detail::is_capability_list_v< Capabilities< comparable > > ); + static_assert( Alepha::has_capability( Meta::type_value< Date >{}, comparable_capability ) ); template< template< typename > class op, typename T > constexpr bool