forked from Alepha/Alepha
Make the underlying streambuf private in stacks.
This commit is contained in:
@ -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; }
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 )
|
||||||
{
|
{
|
||||||
|
14
word_wrap.cc
14
word_wrap.cc
@ -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
|
||||||
|
Reference in New Issue
Block a user