forked from Alepha/Alepha
Start implementing a unified stackable streambuf framework.
This commit is contained in:
115
Utility/StackableStreambuf.h
Normal file
115
Utility/StackableStreambuf.h
Normal file
@ -0,0 +1,115 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <ios>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Alepha::Hydrogen::Utility ::detail:: stackable_streambuf
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
struct StackableStreambuf;
|
||||
|
||||
template< typename > struct PushStack;
|
||||
|
||||
template< typename > struct PopStack;
|
||||
}
|
||||
|
||||
inline const auto index= std::ios::xalloc();
|
||||
|
||||
inline namespace impl
|
||||
{
|
||||
void releaseStack( std::ios_base &ios );
|
||||
|
||||
void iosCallback( const std::ios_base::event event, std::ios_base &ios, const int idx );
|
||||
}
|
||||
|
||||
struct exports::StackableStreambuf
|
||||
: virtual public std::streambuf
|
||||
{
|
||||
public:
|
||||
std::streambuf *underlying;
|
||||
|
||||
~StackableStreambuf() {}
|
||||
|
||||
explicit
|
||||
StackableStreambuf( std::ostream &host )
|
||||
: underlying( host.rdbuf( this ) )
|
||||
{
|
||||
// TODO: Atomicity for this:
|
||||
if( not host.iword( index ) ) host.register_callback( iosCallback, index );
|
||||
host.iword( index )= 1;
|
||||
}
|
||||
|
||||
std::ostream out() const { return std::ostream{ underlying }; }
|
||||
|
||||
virtual void writeChar( const char ch )= 0;
|
||||
virtual void drain()= 0;
|
||||
|
||||
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
|
||||
impl::releaseStack( std::ios_base &ios )
|
||||
{
|
||||
auto &os= dynamic_cast< std::ostream & >( ios );
|
||||
auto *streambuf= os.rdbuf();
|
||||
|
||||
while( auto *stacked= dynamic_cast< StackableStreambuf * >( streambuf ) )
|
||||
{
|
||||
streambuf= stacked->underlying;
|
||||
stacked->drain();
|
||||
os.rdbuf( stacked->underlying );
|
||||
delete stacked;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
impl::iosCallback( const std::ios_base::event event, std::ios_base &ios, const int idx )
|
||||
{
|
||||
if( index != idx ) throw std::logic_error{ "Wrong index." };
|
||||
|
||||
if( event == std::ios_base::erase_event ) releaseStack( ios );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
struct exports::PushStack : T {};
|
||||
|
||||
template< typename T >
|
||||
struct exports::PopStack {};
|
||||
|
||||
template< typename T >
|
||||
std::ostream &
|
||||
operator << ( std::ostream &os, PushStack< T > &¶ms )
|
||||
{
|
||||
build_streambuf( os, params );
|
||||
return os;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
std::ostream &
|
||||
operator << ( std::ostream &os, PopStack< T > )
|
||||
{
|
||||
releaseStack( os );
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
@ -10,6 +10,8 @@ static_assert( __cplusplus > 2020 );
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
|
||||
#include <Alepha/Utility/StackableStreambuf.h>
|
||||
|
||||
#include "evaluation_helpers.h"
|
||||
|
||||
namespace Alepha::Cavorite ::detail:: word_wrap
|
||||
|
Reference in New Issue
Block a user