From 8bd9852bd4b411f309bef2ab18f69f6f7c553a4d Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Wed, 3 Apr 2024 15:50:31 -0400 Subject: [PATCH] Fix forwarding the messages to the underlying functions. If you take the address of the overriding function, it cannot be converted to the base class. So for all the "forward to underlying" set I have to make a base class with no overrides which forwards. Then the main stackable class can make any overrides it wants. I believe that this is still safe, since the base class knows the name to be virtual. So we're not taking the address of the impl function, but instead taking the index of the virtual function. If I'm wrong... I'll need a whole different approach here. --- IOStreams/StackableStreambuf.h | 91 ++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/IOStreams/StackableStreambuf.h b/IOStreams/StackableStreambuf.h index 50ffc17..843d4d4 100644 --- a/IOStreams/StackableStreambuf.h +++ b/IOStreams/StackableStreambuf.h @@ -21,11 +21,63 @@ namespace Alepha::Hydrogen::IOStreams ::detail:: StackableStreambuf_m struct PopStack{}; } + struct StackableStreambufUnderlyingShim + : protected virtual std::streambuf + { + private: + virtual std::streambuf *getUnderlying() const= 0; + + protected: + // EEEW. But to sidestep/circumvent, all this below is necessary. + auto + forwardOverflow( const int ch ) const + { + int (std::streambuf::*ov)( int )= &StackableStreambufUnderlyingShim::overflow; + return ( getUnderlying()->*ov )( ch ); + } + + auto + forwardUnderflow() const + { + int (std::streambuf::*uf)()= &StackableStreambufUnderlyingShim::underflow; + return (getUnderlying()->*uf)(); + } + + auto + underlying_eback() const + { + char *(std::streambuf::*eb)() const= &StackableStreambufUnderlyingShim::eback; + return (getUnderlying()->*eb)(); + } + + auto + underlying_gptr() const + { + char *(std::streambuf::*gp)() const= &StackableStreambufUnderlyingShim::gptr; + return (getUnderlying()->*gp)(); + } + + auto + underlying_egptr() const + { + char *(std::streambuf::*egp)() const= &StackableStreambufUnderlyingShim::egptr; + return (getUnderlying()->*egp)(); + } + + void + underlying_setg( char *const b, char *const g, char *const e ) + { + void (std::streambuf::*sg)( char *, char *, char * )= &StackableStreambufUnderlyingShim::setg; + return (getUnderlying()->*sg)( b, g, e ); + } + }; + struct exports::StackableStreambuf - : virtual public std::streambuf + : virtual public std::streambuf, virtual protected StackableStreambufUnderlyingShim { private: std::streambuf *underlying; + std::streambuf *getUnderlying() const final { return underlying; } public: ~StackableStreambuf() override; @@ -81,43 +133,6 @@ namespace Alepha::Hydrogen::IOStreams ::detail:: StackableStreambuf_m // available. std::streamsize xsputn( const char *data, std::streamsize amt ) override; - - // EEEW. But to sidestep/circumvent, all this below is necessary. - auto - forwardUnderflow() const - { - int (std::streambuf::*uf)()= &StackableStreambuf::underflow; - return (underlying->*uf)(); - } - - auto - underlying_eback() const - { - char *(std::streambuf::*eb)() const= &StackableStreambuf::eback; - return (underlying->*eb)(); - } - - auto - underlying_gptr() const - { - char *(std::streambuf::*gp)() const= &StackableStreambuf::gptr; - return (underlying->*gp)(); - } - - auto - underlying_egptr() const - { - char *(std::streambuf::*egp)() const= &StackableStreambuf::egptr; - return (underlying->*egp)(); - } - - void - underlying_setg( char *const b, char *const g, char *const e ) - { - void (std::streambuf::*sg)( char *, char *, char * )= &StackableStreambuf::setg; - return (underlying->*sg)( b, g, e ); - } - void assume_underlying() {