diff --git a/Reflection/CMakeLists.txt b/Reflection/CMakeLists.txt index d124a33..e115a64 100644 --- a/Reflection/CMakeLists.txt +++ b/Reflection/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory( tuplizeAggregate.test ) +add_subdirectory( tagged_ctor_size.test ) diff --git a/Reflection/detail/config.h b/Reflection/detail/config.h index 3fb0a99..cf82900 100644 --- a/Reflection/detail/config.h +++ b/Reflection/detail/config.h @@ -6,3 +6,12 @@ static_assert( __cplusplus > 2020'99 ); // This file will eventually contain all of the constants that control how much generated code the // C++17 Reflection system will geeerate. + +// Note: not exported! +namespace Alepha::Hydrogen::Reflection ::detail:: config_m +{ + namespace C + { + const std::size_t max_ctor_size= 32; + } +} diff --git a/Reflection/tagged_ctor_size.h b/Reflection/tagged_ctor_size.h new file mode 100644 index 0000000..4a9e7ce --- /dev/null +++ b/Reflection/tagged_ctor_size.h @@ -0,0 +1,95 @@ +static_assert( __cplusplus > 2020'99 ); + +#pragma once + +#include + +#include +#include +#include + +#include + +#include + +namespace Alepha::Hydrogen::Reflection ::detail:: tagged_ctor_size_m +{ + inline namespace exports {} + + namespace C + { + using namespace Reflection::detail::config_m::C; + } + + // Basic methodology here: I probe the number of arguments that an object can be constructed with, given the tag. + // I don't care what they actually are, as there's no easy way to hoist out what they are. However, for an + // object ctor, we have to get the exact right number. + // Therefore we just wind up finding the smallest-ordinality ctor with that tag. + + // The basic adaptable argument. Because it pretends to be anything, it can be used as a parameter in invoking + // any initialization method. + template< typename Forbidden > + struct argument + { + template< typename T > + requires( not Concepts::SameAs< T, Forbidden > ) + constexpr operator T (); + }; + + template< typename T, typename ... Args > + requires Concepts::ConstructibleFrom< T, Args... > + constexpr void construct( const std::tuple< Args... > & ); + + template< typename T, typename Tuple > + concept ConstructibleWithTuple= + requires( Tuple tup ) + { + { construct< T >( tup ) }; + }; + + template< typename Forbidden, typename Seq > + struct expand; + + template< typename Forbidden, std::size_t ... Ints > + struct expand< Forbidden, std::index_sequence< Ints... > > + { + using type= decltype( std::make_tuple( ( Ints, argument< Forbidden >{} )... ) ); + }; + + template< typename Forbidden, std::size_t argcnt > + using expand_t= typename expand< Forbidden, std::make_index_sequence< argcnt > >::type; + + template< typename T, typename tag, std::size_t args > + concept ConstructibleWith= + ConstructibleWithTuple< T, decltype( std::tuple_cat( std::declval< expand_t< T, args > >(), std::declval< std::tuple< tag > >() ) ) >; + + // The first step is to just start it all off with a blank sequence and walk forward from there. + // The default arguments cause it to start with the blank sequence, even if it doesn't match this + // case in the specialization selection. + template< typename T, typename tag, std::size_t cnt= 0 > + struct has_tagged_ctor + : has_tagged_ctor< T, tag, cnt + 1 > {}; + + template< typename T, typename tag > + struct has_tagged_ctor< T, tag, C::max_ctor_size > + : std::false_type {}; + + template< typename T, typename tag, std::size_t depth > + requires ConstructibleWith< T, tag, depth > + struct has_tagged_ctor< T, tag, depth > + : std::true_type {}; + + namespace exports + { + template< typename T, typename tag > + constexpr std::size_t has_tagged_ctor_v= has_tagged_ctor< T, tag >::value; + + template< typename T, typename tag > + struct has_tagged_ctor : std::bool_constant< has_tagged_ctor_v< T, tag > > {}; + } +} + +namespace Alepha::Hydrogen::Reflection::inline exports::inline tagged_ctor_size_m +{ + using namespace detail::tagged_ctor_size_m::exports; +} diff --git a/Reflection/tagged_ctor_size.test/0.cc b/Reflection/tagged_ctor_size.test/0.cc new file mode 100644 index 0000000..67737ab --- /dev/null +++ b/Reflection/tagged_ctor_size.test/0.cc @@ -0,0 +1,23 @@ +static_assert( __cplusplus > 2020'99 ); + +#include + +#include +#include +#include + +namespace +{ + using namespace Alepha::Testing::literals; + + struct tag {}; + struct tag2 {}; + struct instance + { + explicit instance( int a, float b, char c, double d, tag t ); + }; + + using namespace Alepha::Reflection::exports::tagged_ctor_size_m; + static_assert( has_tagged_ctor_v< instance, tag > ); + static_assert( not has_tagged_ctor_v< instance, tag2 > ); +} diff --git a/Reflection/tagged_ctor_size.test/CMakeLists.txt b/Reflection/tagged_ctor_size.test/CMakeLists.txt new file mode 100644 index 0000000..b099603 --- /dev/null +++ b/Reflection/tagged_ctor_size.test/CMakeLists.txt @@ -0,0 +1 @@ +unit_test( 0 )