From 970cfa3b627e5ef6eccc4b2894169a95175414c2 Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Fri, 5 Jul 2024 12:18:18 -0400 Subject: [PATCH] Unify everything to `template_for` form. --- IOStreams/IStreamable.h | 2 +- IOStreams/OStreamable.h | 2 +- Testing/TableTest.h | 2 +- Testing/printDebugging.h | 2 +- template_for.h | 169 ++++++++++++++++++++------------------- 5 files changed, 91 insertions(+), 86 deletions(-) diff --git a/IOStreams/IStreamable.h b/IOStreams/IStreamable.h index 8799ad9..da2bb5b 100644 --- a/IOStreams/IStreamable.h +++ b/IOStreams/IStreamable.h @@ -51,7 +51,7 @@ namespace Alepha::Hydrogen::IOStreams ::detail:: IStreamable_m int index= 0; // 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... - tuple_for_each( decomposed ) <=[&]( auto &element ) + template_for( decomposed ) <=[&]( auto &element ) { std::istringstream iss{ tokens.at( index++ ) }; iss >> element; diff --git a/IOStreams/OStreamable.h b/IOStreams/OStreamable.h index 9b11696..b8e6e5b 100644 --- a/IOStreams/OStreamable.h +++ b/IOStreams/OStreamable.h @@ -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 // 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; }; diff --git a/Testing/TableTest.h b/Testing/TableTest.h index eb82680..3ddf878 100644 --- a/Testing/TableTest.h +++ b/Testing/TableTest.h @@ -206,7 +206,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m oss << std::endl << "Test inputs were: " << std::endl; 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? oss << "Argument " << index++ << ": " << streamAdaptValue< OutputMode::Relaxed >( param ) << std::endl; diff --git a/Testing/printDebugging.h b/Testing/printDebugging.h index 7e0229f..11786e6 100644 --- a/Testing/printDebugging.h +++ b/Testing/printDebugging.h @@ -108,7 +108,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: printDebugging_m else if constexpr( Meta::is_tuple_v< T > ) { 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 << ", "; first= false; diff --git a/template_for.h b/template_for.h index a3a30a7..a398107 100644 --- a/template_for.h +++ b/template_for.h @@ -14,98 +14,103 @@ namespace Alepha::Hydrogen ::detail:: template_for_each_m { 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 - tuple_for_each( const std::tuple< Args... > &tuple, Function body ) - noexcept - ( - ( ... and noexcept( body( std::declval< const Args & >() ) ) ) - ) + operator <= ( Function &&func ) noexcept( noexcept( template_for_impl( tuple, std::forward< Function >( func ) ) ) ) { - 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 ); + return template_for_impl( tuple, std::forward< Function >( func ) ); } - // Apply type_identity to all tuple elements - template< typename > struct type_identify_tuple; + constexpr operator decltype( std::ignore ) () const= delete; + }; - template< typename T > - using type_identify_tuple_t= typename type_identify_tuple< T >::type; + template< typename Tuple > + [[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< typename Tuple > - struct for_each_syntax_adaptor - { - Tuple &tuple; + template< Tuple Type > + [[nodiscard]] + constexpr auto + exports::template_for( Type &tuple ) noexcept + { + return template_for_impl( tuple ); + } - template< typename Function > - constexpr void - operator <= ( Function &&func ) noexcept( noexcept( tuple_for_each( tuple, std::forward< Function >( func ) ) ) ) - { - return tuple_for_each( tuple, std::forward< Function >( func ) ); - } - - 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 ); - } + template< Tuple Type > + [[nodiscard]] + constexpr auto + exports::template_for( const Type &tuple ) noexcept + { + return template_for_impl( tuple ); } }