forked from Alepha/Alepha
Move string substitution to the StackableStreambuf framework.
This commit is contained in:
@ -22,18 +22,22 @@ namespace Alepha::Hydrogen ::detail:: string_algorithms
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct VariableExpansionStreambuf
|
struct VariableExpansionStreambuf
|
||||||
: public std::streambuf
|
: public Utility::StackableStreambuf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::streambuf *underlying= nullptr;
|
|
||||||
VarMap substitutions;
|
VarMap substitutions;
|
||||||
std::stringbuf varName;
|
std::stringbuf varName;
|
||||||
char sigil;
|
char sigil;
|
||||||
enum { Symbol= 1, Normal= 0 } mode= Normal;
|
enum { Symbol= 1, Normal= 0 } mode= Normal;
|
||||||
int throws= 0;
|
int throws= 0;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
VariableExpansionStreambuf( std::ostream &os, VarMap &&substitutions, const char sigil )
|
||||||
|
: StackableStreambuf( os ), substitutions( std::move( substitutions ) ), sigil( sigil )
|
||||||
|
{}
|
||||||
|
|
||||||
void
|
void
|
||||||
writeChar( const char ch )
|
writeChar( const char ch ) override
|
||||||
{
|
{
|
||||||
std::ostream current{ underlying };
|
std::ostream current{ underlying };
|
||||||
|
|
||||||
@ -64,22 +68,6 @@ namespace Alepha::Hydrogen ::detail:: string_algorithms
|
|||||||
current << ch;
|
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
|
void
|
||||||
drain()
|
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 &
|
void
|
||||||
impl::operator << ( std::ostream &os, StartSubstitutions &¶ms )
|
impl::build_streambuf( std::ostream &os, StartSubstitutions &¶ms )
|
||||||
{
|
{
|
||||||
auto streambuf= std::make_unique< VariableExpansionStreambuf >();
|
new VariableExpansionStreambuf{ os, std::move( params.substitutions ), params.sigil };
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
|
|||||||
@ -18,6 +18,8 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
|
|
||||||
#include <Alepha/Concepts.h>
|
#include <Alepha/Concepts.h>
|
||||||
|
|
||||||
|
#include <Alepha/Utility/StackableStreambuf.h>
|
||||||
|
|
||||||
namespace Alepha::Hydrogen ::detail:: string_algorithms
|
namespace Alepha::Hydrogen ::detail:: string_algorithms
|
||||||
{
|
{
|
||||||
inline namespace exports {}
|
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 );
|
std::string expandVariables( const std::string &text, const VarMap &vars, const char sigil );
|
||||||
|
|
||||||
struct StartSubstitutions
|
struct StartSubstitutions_params
|
||||||
{
|
{
|
||||||
const char sigil;
|
const char sigil;
|
||||||
VarMap substitutions;
|
VarMap substitutions;
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
StartSubstitutions( const char sigil, VarMap substitutions )
|
StartSubstitutions_params( const char sigil, VarMap substitutions )
|
||||||
: sigil( sigil ), substitutions( std::move( substitutions ) )
|
: sigil( sigil ), substitutions( std::move( substitutions ) )
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using StartSubstitutions= Utility::PushStack< StartSubstitutions_params >;
|
||||||
|
|
||||||
// Note that these function as a stack -- so `EndSubstitutions` will
|
// Note that these function as a stack -- so `EndSubstitutions` will
|
||||||
// terminate the top of that stack.
|
// terminate the top of that stack.
|
||||||
constexpr struct EndSubstitutions_t {} EndSubstitutions;
|
constexpr Utility::PopStack EndSubstitutions;
|
||||||
|
|
||||||
inline namespace impl
|
inline namespace impl
|
||||||
{
|
{
|
||||||
std::ostream &operator << ( std::ostream &, StartSubstitutions && );
|
void build_streambuf( std::ostream &, StartSubstitutions && );
|
||||||
|
|
||||||
std::ostream &operator << ( std::ostream &, EndSubstitutions_t );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
Reference in New Issue
Block a user