From eee9c5362f49e16e427b3648c226a9408bc11bd8 Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Sat, 21 Oct 2023 05:08:48 -0400 Subject: [PATCH] Move string substitution to the `StackableStreambuf` framework. --- string_algorithms.cpp | 91 +++++-------------------------------------- string_algorithms.h | 14 ++++--- 2 files changed, 18 insertions(+), 87 deletions(-) diff --git a/string_algorithms.cpp b/string_algorithms.cpp index db3c9d8..9cc3840 100644 --- a/string_algorithms.cpp +++ b/string_algorithms.cpp @@ -22,18 +22,22 @@ namespace Alepha::Hydrogen ::detail:: string_algorithms } struct VariableExpansionStreambuf - : public std::streambuf + : public Utility::StackableStreambuf { public: - std::streambuf *underlying= nullptr; VarMap substitutions; std::stringbuf varName; char sigil; enum { Symbol= 1, Normal= 0 } mode= Normal; int throws= 0; + explicit + VariableExpansionStreambuf( std::ostream &os, VarMap &&substitutions, const char sigil ) + : StackableStreambuf( os ), substitutions( std::move( substitutions ) ), sigil( sigil ) + {} + void - writeChar( const char ch ) + writeChar( const char ch ) override { std::ostream current{ underlying }; @@ -64,22 +68,6 @@ namespace Alepha::Hydrogen ::detail:: string_algorithms current << ch; } - int - overflow( const int ch ) override - { - if( ch == EOF ) throw std::logic_error{ "EOF!" }; - writeChar( ch ); - - return 1; - } - - std::streamsize - xsputn( const char *const data, const std::streamsize amt ) override - { - for( std::streamsize i= 0; i< amt; ++i ) overflow( data[ i ] ); - return amt; - } - void drain() { @@ -92,71 +80,12 @@ namespace Alepha::Hydrogen ::detail:: string_algorithms } } }; - - const auto wrapperIndex= std::ios::xalloc(); - - void - releaseWrapper( std::ostream &os ) - { - if( C::debugIOStreamLifecycle ) error() << "Release wrapper called on: " << &os << std::endl; - auto *const streambuf= static_cast< VariableExpansionStreambuf * >( os.pword( wrapperIndex ) ); - if( not streambuf ) throw std::logic_error{ "Attempt to remove a substitution context which doesn't exist." }; - - AutoRAII current - { - [&] { return os.rdbuf( streambuf->underlying ); }, - [&] ( std::streambuf *streambuf ) noexcept - { - if( C::debugIOStreamLifecycle ) error() << "Deletion actually happening, now." << std::endl; - delete streambuf; - os.pword( wrapperIndex )= nullptr; - } - }; - streambuf->drain(); - } - - void - wordwrapCallback( const std::ios_base::event event, std::ios_base &ios, const int idx ) noexcept - { - if( C::debugIOStreamLifecycle ) error() << "ios callback called on: " << &ios << std::endl; - if( wrapperIndex != idx ) throw std::logic_error{ "Wrong index." }; - - if( not ios.pword( wrapperIndex ) ) return; - - - if( const auto os_p= dynamic_cast< std::ostream * >( &ios ); os_p and event == std::ios_base::erase_event ) - { - releaseWrapper( *os_p ); - } - } } - std::ostream & - impl::operator << ( std::ostream &os, StartSubstitutions &¶ms ) + void + impl::build_streambuf( std::ostream &os, StartSubstitutions &¶ms ) { - auto streambuf= std::make_unique< VariableExpansionStreambuf >(); - streambuf->underlying= os.rdbuf( streambuf.get() ); - streambuf->substitutions= std::move( params.substitutions ); - streambuf->sigil= params.sigil; - auto &state= os.iword( wrapperIndex ); - if( not state ) - { - state= 1; - os.register_callback( wordwrapCallback, wrapperIndex ); - if( C::debugIOStreamLifecycle ) error() << "Adding callback to " << (void *) static_cast< std::ios * >( &os ) << std::endl; - } - - assert( os.pword( wrapperIndex ) == nullptr ); - os.pword( wrapperIndex )= streambuf.release(); - - return os; - } - - std::ostream & - impl::operator << ( std::ostream &os, EndSubstitutions_t ) - { - releaseWrapper( os ); - return os; + new VariableExpansionStreambuf{ os, std::move( params.substitutions ), params.sigil }; } std::string diff --git a/string_algorithms.h b/string_algorithms.h index 184fa3e..ff394d0 100644 --- a/string_algorithms.h +++ b/string_algorithms.h @@ -18,6 +18,8 @@ static_assert( __cplusplus > 2020'00 ); #include +#include + namespace Alepha::Hydrogen ::detail:: string_algorithms { inline namespace exports {} @@ -38,26 +40,26 @@ namespace Alepha::Hydrogen ::detail:: string_algorithms */ std::string expandVariables( const std::string &text, const VarMap &vars, const char sigil ); - struct StartSubstitutions + struct StartSubstitutions_params { const char sigil; VarMap substitutions; explicit - StartSubstitutions( const char sigil, VarMap substitutions ) + StartSubstitutions_params( const char sigil, VarMap substitutions ) : sigil( sigil ), substitutions( std::move( substitutions ) ) {} }; + using StartSubstitutions= Utility::PushStack< StartSubstitutions_params >; + // Note that these function as a stack -- so `EndSubstitutions` will // terminate the top of that stack. - constexpr struct EndSubstitutions_t {} EndSubstitutions; + constexpr Utility::PopStack EndSubstitutions; inline namespace impl { - std::ostream &operator << ( std::ostream &, StartSubstitutions && ); - - std::ostream &operator << ( std::ostream &, EndSubstitutions_t ); + void build_streambuf( std::ostream &, StartSubstitutions && ); } /*!