forked from Alepha/Alepha
Unify everything to template_for
form.
This commit is contained in:
@ -51,7 +51,7 @@ namespace Alepha::Hydrogen::IOStreams ::detail:: IStreamable_m
|
|||||||
int index= 0;
|
int index= 0;
|
||||||
// TODO: Consider the lens system here... but the basic use case seems to be for
|
// TODO: Consider the lens system here... but the basic use case seems to be for
|
||||||
// aggregates, so we'll go with this simple case for now...
|
// aggregates, so we'll go with this simple case for now...
|
||||||
tuple_for_each( decomposed ) <=[&]( auto &element )
|
template_for( decomposed ) <=[&]( auto &element )
|
||||||
{
|
{
|
||||||
std::istringstream iss{ tokens.at( index++ ) };
|
std::istringstream iss{ tokens.at( index++ ) };
|
||||||
iss >> element;
|
iss >> element;
|
||||||
|
@ -45,7 +45,7 @@ namespace Alepha::Hydrogen::IOStreams ::detail:: OStreamable_m
|
|||||||
|
|
||||||
// TODO: Consider the lens system here... but the basic use case seems to be for
|
// TODO: Consider the lens system here... but the basic use case seems to be for
|
||||||
// aggregates, so we'll go with this simple case for now...
|
// aggregates, so we'll go with this simple case for now...
|
||||||
tuple_for_each( decomposed ) <=[&]( const auto &element )
|
template_for( decomposed ) <=[&]( const auto &element )
|
||||||
{
|
{
|
||||||
os << NextItem << element;
|
os << NextItem << element;
|
||||||
};
|
};
|
||||||
|
@ -206,7 +206,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m
|
|||||||
|
|
||||||
oss << std::endl << "Test inputs were: " << std::endl;
|
oss << std::endl << "Test inputs were: " << std::endl;
|
||||||
int index= 0;
|
int index= 0;
|
||||||
tuple_for_each( params ) <=[&]( const auto ¶m )
|
template_for( params ) <=[&]( const auto ¶m )
|
||||||
{
|
{
|
||||||
// Debugging output for test inputs is relaxed, as it's not required they be streamable?
|
// Debugging output for test inputs is relaxed, as it's not required they be streamable?
|
||||||
oss << "Argument " << index++ << ": " << streamAdaptValue< OutputMode::Relaxed >( param ) << std::endl;
|
oss << "Argument " << index++ << ": " << streamAdaptValue< OutputMode::Relaxed >( param ) << std::endl;
|
||||||
|
@ -108,7 +108,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: printDebugging_m
|
|||||||
else if constexpr( Meta::is_tuple_v< T > )
|
else if constexpr( Meta::is_tuple_v< T > )
|
||||||
{
|
{
|
||||||
oss << '[';
|
oss << '[';
|
||||||
tuple_for_each( v ) <=[&oss, first= true]( const auto &elem ) mutable
|
template_for( v ) <=[&oss, first= true]( const auto &elem ) mutable
|
||||||
{
|
{
|
||||||
if( not first ) oss << ", ";
|
if( not first ) oss << ", ";
|
||||||
first= false;
|
first= false;
|
||||||
|
169
template_for.h
169
template_for.h
@ -14,98 +14,103 @@ namespace Alepha::Hydrogen ::detail:: template_for_each_m
|
|||||||
{
|
{
|
||||||
inline namespace exports
|
inline namespace exports
|
||||||
{
|
{
|
||||||
constexpr void tuple_for_each( const std::tuple<> &, const Functional auto ) noexcept {}
|
template< Tuple Type >
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto
|
||||||
|
template_for( Type &tuple ) noexcept;
|
||||||
|
|
||||||
template< typename ... Args, typename Function >
|
template< Tuple Type >
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto
|
||||||
|
template_for( const Type &tuple ) noexcept;
|
||||||
|
|
||||||
|
template< Aggregate Type >
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto
|
||||||
|
template_for( Type &agg, std::optional< Reflection::aggregate_tuple_t< Type > > &&tupled= {} ) noexcept
|
||||||
|
{
|
||||||
|
tupled= Reflection::tuplizeAggregate( agg );
|
||||||
|
return template_for( *tupled );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< Aggregate Type >
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto
|
||||||
|
template_for( const Type &agg, std::optional< Reflection::aggregate_tuple_t< Type > > &&tupled= {} ) noexcept
|
||||||
|
{
|
||||||
|
tupled= Reflection::tuplizeAggregate( agg );
|
||||||
|
return template_for( *tupled );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename ... Args, typename Function >
|
||||||
|
constexpr void
|
||||||
|
template_for_impl( const std::tuple< Args... > &tuple, Function body )
|
||||||
|
noexcept
|
||||||
|
(
|
||||||
|
( ... and noexcept( body( std::declval< const Args & >() ) ) )
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const auto callWrapper= [&body]( auto &&element ) { body( element ); return nullptr; };
|
||||||
|
|
||||||
|
auto loop_body_handler= [&]( auto &&... tuple_elements )
|
||||||
|
{
|
||||||
|
std::nullptr_t expansion[]= { callWrapper( tuple_elements )... };
|
||||||
|
|
||||||
|
std::ignore= expansion;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::apply( loop_body_handler, tuple );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Nicer for-each syntax helper:
|
||||||
|
template< typename Tuple >
|
||||||
|
struct [[nodiscard]] syntax_adaptor
|
||||||
|
{
|
||||||
|
Tuple &tuple;
|
||||||
|
|
||||||
|
template< typename Function >
|
||||||
constexpr void
|
constexpr void
|
||||||
tuple_for_each( const std::tuple< Args... > &tuple, Function body )
|
operator <= ( Function &&func ) noexcept( noexcept( template_for_impl( tuple, std::forward< Function >( func ) ) ) )
|
||||||
noexcept
|
|
||||||
(
|
|
||||||
( ... and noexcept( body( std::declval< const Args & >() ) ) )
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
const auto callWrapper= [&body]( auto &&element ) { body( element ); return nullptr; };
|
return template_for_impl( tuple, std::forward< Function >( func ) );
|
||||||
|
|
||||||
auto loop_body_handler= [&]( auto &&... tuple_elements )
|
|
||||||
{
|
|
||||||
std::nullptr_t expansion[]= { callWrapper( tuple_elements )... };
|
|
||||||
|
|
||||||
std::ignore= expansion;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::apply( loop_body_handler, tuple );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply type_identity to all tuple elements
|
constexpr operator decltype( std::ignore ) () const= delete;
|
||||||
template< typename > struct type_identify_tuple;
|
};
|
||||||
|
|
||||||
template< typename T >
|
template< typename Tuple >
|
||||||
using type_identify_tuple_t= typename type_identify_tuple< T >::type;
|
[[nodiscard]]
|
||||||
|
constexpr auto
|
||||||
|
template_for_impl( Tuple &tuple ) noexcept
|
||||||
|
{
|
||||||
|
return syntax_adaptor< Tuple >{ tuple };
|
||||||
|
}
|
||||||
|
|
||||||
template<> struct type_identify_tuple< std::tuple<> > { using type= std::tuple<>; };
|
template< typename Tuple >
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto
|
||||||
|
template_for_impl( const Tuple &tuple ) noexcept
|
||||||
|
{
|
||||||
|
return syntax_adaptor< const Tuple >{ tuple };
|
||||||
|
}
|
||||||
|
|
||||||
template< typename ... Args >
|
|
||||||
struct type_identify_tuple< std::tuple< Args... > >
|
|
||||||
{
|
|
||||||
using type= std::tuple< std::type_identity< Args >... >;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Nicer for-each syntax helper:
|
template< Tuple Type >
|
||||||
template< typename Tuple >
|
[[nodiscard]]
|
||||||
struct for_each_syntax_adaptor
|
constexpr auto
|
||||||
{
|
exports::template_for( Type &tuple ) noexcept
|
||||||
Tuple &tuple;
|
{
|
||||||
|
return template_for_impl( tuple );
|
||||||
|
}
|
||||||
|
|
||||||
template< typename Function >
|
template< Tuple Type >
|
||||||
constexpr void
|
[[nodiscard]]
|
||||||
operator <= ( Function &&func ) noexcept( noexcept( tuple_for_each( tuple, std::forward< Function >( func ) ) ) )
|
constexpr auto
|
||||||
{
|
exports::template_for( const Type &tuple ) noexcept
|
||||||
return tuple_for_each( tuple, std::forward< Function >( func ) );
|
{
|
||||||
}
|
return template_for_impl( tuple );
|
||||||
|
|
||||||
constexpr operator decltype( std::ignore ) () const= delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename Tuple >
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr auto
|
|
||||||
tuple_for_each( Tuple &tuple ) noexcept
|
|
||||||
{
|
|
||||||
return for_each_syntax_adaptor< Tuple >{ tuple };
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename Tuple >
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr auto
|
|
||||||
tuple_for_each( const Tuple &tuple ) noexcept
|
|
||||||
{
|
|
||||||
return for_each_syntax_adaptor< const Tuple >{ tuple };
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename Type >
|
|
||||||
concept TemplateLoopable= false
|
|
||||||
or Tuple< Type >
|
|
||||||
or Aggregate< Type >
|
|
||||||
// or Array< T > // Do we need array support? Does it matter?
|
|
||||||
;
|
|
||||||
|
|
||||||
template< TemplateLoopable Type >
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr auto
|
|
||||||
template_for( Type &tuple, std::optional< Reflection::aggregate_tuple_t< Type > > &&tupled= {} ) noexcept
|
|
||||||
{
|
|
||||||
tupled= Reflection::tuplizeAggregate( tuple );
|
|
||||||
return tuple_for_each( *tupled );
|
|
||||||
}
|
|
||||||
|
|
||||||
template< TemplateLoopable Type >
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr auto
|
|
||||||
template_for( const Type &tuple, std::optional< Reflection::aggregate_tuple_t< Type > > &&tupled= {} ) noexcept
|
|
||||||
{
|
|
||||||
tupled= Reflection::tuplizeAggregate( tuple );
|
|
||||||
return tuple_for_each( *tupled );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user