1
0
forked from Alepha/Alepha

Move string substitution to the StackableStreambuf framework.

This commit is contained in:
2023-10-21 05:08:48 -04:00
parent 5beca91dde
commit eee9c5362f
2 changed files with 18 additions and 87 deletions

View File

@ -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 &&params )
void
impl::build_streambuf( std::ostream &os, StartSubstitutions &&params )
{
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

View File

@ -18,6 +18,8 @@ static_assert( __cplusplus > 2020'00 );
#include <Alepha/Concepts.h>
#include <Alepha/Utility/StackableStreambuf.h>
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 && );
}
/*!