1
0
forked from Alepha/Alepha

Make the underlying streambuf private in stacks.

This commit is contained in:
2024-04-03 15:01:52 -04:00
parent 8250680e6c
commit d8689b85e8
5 changed files with 55 additions and 24 deletions

View File

@ -4,6 +4,9 @@ static_assert( __cplusplus > 2020'99 );
#include <cassert> #include <cassert>
#include <istream>
#include <ostream>
namespace Alepha::Hydrogen::IOStreams::detail::StackableStreambuf_m namespace Alepha::Hydrogen::IOStreams::detail::StackableStreambuf_m
{ {
namespace namespace
@ -47,13 +50,26 @@ namespace Alepha::Hydrogen::IOStreams::detail::StackableStreambuf_m
const auto *const current= dynamic_cast< StackableStreambuf * >( os.rdbuf() ); const auto *const current= dynamic_cast< StackableStreambuf * >( os.rdbuf() );
if( not current ) return false; if( not current ) return false;
os.rdbuf( current->underlying ); current->unhook( os );
releaseTop( os, token ); releaseTop( os, token );
return true; return true;
} }
inline bool
releaseTop( std::istream &is )
{
const auto *const current= dynamic_cast< StackableStreambuf * >( is.rdbuf() );
if( not current ) return false;
current->unhook( is );
releaseTop( is, token );
return true;
}
inline void inline void
releaseStack( std::ios_base &ios ) releaseStack( std::ios_base &ios )
{ {
@ -84,6 +100,13 @@ namespace Alepha::Hydrogen::IOStreams::detail::StackableStreambuf_m
return os; return os;
} }
std::istream &
impl::operator >> ( std::istream &is, PopStack )
{
if( not releaseTop( is ) ) throw std::logic_error( "IStream has no stacked streambufs!" );
return is;
}
StackableStreambuf::~StackableStreambuf() {} StackableStreambuf::~StackableStreambuf() {}
StackableStreambuf::StackableStreambuf( std::ios &host ) StackableStreambuf::StackableStreambuf( std::ios &host )
@ -111,4 +134,9 @@ namespace Alepha::Hydrogen::IOStreams::detail::StackableStreambuf_m
for( std::streamsize i= 0; i< amt; ++i ) overflow( data[ i ] ); for( std::streamsize i= 0; i< amt; ++i ) overflow( data[ i ] );
return amt; return amt;
} }
void StackableStreambuf::unhook( std::ostream &os ) const { os.rdbuf( underlying ); }
void StackableStreambuf::unhook( std::istream &is ) const { is.rdbuf( underlying ); }
std::ostream &StackableStreambuf::out( std::ostream &&res ) const { res.rdbuf( underlying ); return *&res; }
} }

View File

@ -24,19 +24,24 @@ namespace Alepha::Hydrogen::IOStreams ::detail:: StackableStreambuf_m
struct exports::StackableStreambuf struct exports::StackableStreambuf
: virtual public std::streambuf : virtual public std::streambuf
{ {
public: private:
std::streambuf *underlying; std::streambuf *underlying;
public:
~StackableStreambuf() override; ~StackableStreambuf() override;
// Children must be created by `new`. // Children must be created by `new`.
explicit StackableStreambuf( std::ios &host ); explicit StackableStreambuf( std::ios &host );
auto out() const { return std::ostream{ underlying }; }
virtual void writeChar( char ch )= 0; virtual void writeChar( char ch )= 0;
virtual void drain()= 0; virtual void drain()= 0;
void unhook( std::ostream &os ) const;
void unhook( std::istream &is ) const;
protected:
std::ostream &out( std::ostream &&res= std::ostream{nullptr} ) const;
int overflow( const int ch ) override; int overflow( const int ch ) override;
// Underflow is not overridden. A read-oriented // Underflow is not overridden. A read-oriented

View File

@ -10,6 +10,7 @@ static_assert( __cplusplus > 2020'99 );
#include <Alepha/AutoRAII.h> #include <Alepha/AutoRAII.h>
#include <Alepha/error.h> #include <Alepha/error.h>
#include <Alepha/Utility/StaticValue.h> #include <Alepha/Utility/StaticValue.h>
#include <Alepha/System/programName.h> #include <Alepha/System/programName.h>
@ -132,13 +133,13 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m
namespace namespace
{ {
std::string void
buildIncompatibleHelpText( const std::string &name, const auto &domains, const auto &exclusivityMembers ) incompatibleHelpText( std::ostream &out, const std::string &name, const auto &domains, const auto &exclusivityMembers )
{ {
if( not domains.contains( typeid( ExclusivityDomain ) ) if( not domains.contains( typeid( ExclusivityDomain ) )
or domains.at( typeid( ExclusivityDomain ) ).empty() ) or domains.at( typeid( ExclusivityDomain ) ).empty() )
{ {
return ""; return;
} }
std::set< std::string > incompatibles; std::set< std::string > incompatibles;
@ -150,18 +151,17 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m
[]( const auto &item ) { return item.second; } ); []( const auto &item ) { return item.second; } );
} }
incompatibles.erase( name ); incompatibles.erase( name );
if( incompatibles.empty() ) return ""; if( incompatibles.empty() ) return;
std::ostringstream oss;
oss << "\nIncompatible with: \n\n"; out << "\nIncompatible with: \n\n";
bool first= true; bool first= true;
for( const auto &incompat: incompatibles ) for( const auto &incompat: incompatibles )
{ {
if( not first ) oss << ", "; if( not first ) out << ", ";
first= false; first= false;
oss << '`' << incompat << '`'; out << '`' << incompat << '`';
} }
oss << std::endl; out << std::endl;
return std::move( oss ).str();
} }
void void
@ -229,7 +229,7 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m
std::cout << name << ": " << std::string( padding, ' ' ) << helpText.str() << '\n'; std::cout << name << ": " << std::string( padding, ' ' ) << helpText.str() << '\n';
// Append the incompatibility text, when we see mutually-exclusive options. // Append the incompatibility text, when we see mutually-exclusive options.
std::cout << buildIncompatibleHelpText( name, domains, exclusivityMembers ); incompatibleHelpText( std::cout, name, domains, exclusivityMembers );
} }

View File

@ -42,7 +42,7 @@ namespace Alepha::Hydrogen ::detail:: string_algorithms_m
writeChar( const char ch ) override writeChar( const char ch ) override
{ {
if( C::debugExpansion ) error() << "Entry to write and got `" << ch << '`' << std::endl; if( C::debugExpansion ) error() << "Entry to write and got `" << ch << '`' << std::endl;
std::ostream current{ underlying }; std::ostream current{ out().rdbuf() };
if( mode == Normal and ch == sigil ) if( mode == Normal and ch == sigil )
{ {

View File

@ -64,28 +64,27 @@ namespace Alepha::Hydrogen ::detail:: word_wrap_m
void void
WordWrapStreambuf::writeChar( const char ch ) WordWrapStreambuf::writeChar( const char ch )
{ {
std::ostream outWrap{ underlying };
if( ch == '\n' ) if( ch == '\n' )
{ {
const auto prev= currentLineLength; const auto prev= currentLineLength;
const auto size= currentWord.size(); const auto size= currentWord.size();
currentLineLength= applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), outWrap ); currentLineLength= applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), out() );
currentWord.clear(); currentWord.clear();
outWrap << '\n'; out() << '\n';
if( currentLineLength == prev + size ) if( currentLineLength == prev + size )
{ {
std::fill_n( std::ostream_iterator< char >{ outWrap }, nextLineOffset, ' ' ); std::fill_n( std::ostream_iterator< char >{ out() }, nextLineOffset, ' ' );
currentLineLength= nextLineOffset; currentLineLength= nextLineOffset;
} }
else currentLineLength= 0; else currentLineLength= 0;
} }
else if( ch == ' ' ) else if( ch == ' ' )
{ {
currentLineLength= applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), outWrap ); currentLineLength= applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), out() );
currentWord.clear(); currentWord.clear();
if( currentLineLength < maximumWidth ) if( currentLineLength < maximumWidth )
{ {
outWrap << ' '; out() << ' ';
++currentLineLength; ++currentLineLength;
} }
} }
@ -96,8 +95,7 @@ namespace Alepha::Hydrogen ::detail:: word_wrap_m
WordWrapStreambuf::drain() WordWrapStreambuf::drain()
{ {
if( currentWord.empty() ) return; if( currentWord.empty() ) return;
std::ostream outWrap{ underlying }; applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), out() );
applyWordToLine( maximumWidth, nextLineOffset, currentLineLength, std::move( currentWord ), outWrap );
} }
std::string std::string