From: Alex Rousskov Date: Thu, 13 Jan 2022 22:38:24 +0000 (+0000) Subject: Maintenance: De-duplicate PackableStreamBuf and SBufStreamBuf (#959) X-Git-Tag: SQUID_6_0_1~250 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f212d11018c298fd7a940dcecc7b4030ae790bc2;p=thirdparty%2Fsquid.git Maintenance: De-duplicate PackableStreamBuf and SBufStreamBuf (#959) SBufStreamBuf was almost identical to PackableStreamBuf. Both classes are pass-through write-only streambufs that lack their own put area. Now their common code lives in AppendingStreamBuf. No functionality changes intended. The removed std::streambuf method descriptions were imprecise and some were misleading. STL documentation describes this standard/parent API. While also similar, PackableStream and SBufStream have important differences in API and implementation. For example, unlike PackableStream, SBufStream owns the sink buffer and does not modify the buffer it was created with, providing a safe content extraction method instead. The two classes cannot be merged without changing their users, and it may be impossible to justify SBufStream users exposure to the dangers of forgetting to sync() the streambuf before accessing the sink. --- diff --git a/src/base/PackableStream.h b/src/base/PackableStream.h index 28e9e1506b..080768c55b 100644 --- a/src/base/PackableStream.h +++ b/src/base/PackableStream.h @@ -13,20 +13,18 @@ #include -/** - * Provides a streambuf interface for writing to Packable objects. - * Typical use is via a PackableStream rather than direct manipulation - */ -class PackableStreamBuf : public std::streambuf +// TODO: Move to src/base/AppendingStreamBuf.h +/// write-only std::streambuf that append()s all writes to a given Buffer +template +class AppendingStreamBuf : public std::streambuf { public: - explicit PackableStreamBuf(Packable &p) : buf_(p) { buf_.buffer(); } - virtual ~PackableStreamBuf() = default; + explicit AppendingStreamBuf(Buffer &p): buf_(p) { postInit(); } + virtual ~AppendingStreamBuf() = default; protected: - /** flush the current buffer and the character that is overflowing - * to the Packable. - */ + /* std::streambuf API */ + virtual int_type overflow(int_type aChar = traits_type::eof()) override { std::streamsize pending(pptr() - pbase()); @@ -42,28 +40,38 @@ protected: return aChar; } - /** push the buffer to the Packable */ virtual int sync() override { std::streamsize pending(pptr() - pbase()); lowAppend(pbase(), pending); - buf_.flush(); + postSync(); return 0; } - /** write multiple characters to the Packable - * - this is an optimisation method. - */ virtual std::streamsize xsputn(const char * chars, std::streamsize number) override { lowAppend(chars, number); return number; } private: + /// for specializations that must customize the last construction step + void postInit() {} + + /// for specializations that must customize the last sync() step + void postSync() {} + void lowAppend(const char *s, const std::streamsize n) {buf_.append(s,n);} - Packable &buf_; + Buffer &buf_; ///< the associated character sequence (a.k.a. the sink) }; +/** + * Provides a streambuf interface for writing to Packable objects. + * Typical use is via a PackableStream rather than direct manipulation + */ +using PackableStreamBuf = AppendingStreamBuf; +template <> inline void PackableStreamBuf::postInit() { buf_.buffer(); } +template <> inline void PackableStreamBuf::postSync() { buf_.flush(); } + class PackableStream : public std::ostream { public: diff --git a/src/sbuf/Stream.h b/src/sbuf/Stream.h index d910d480af..5359ba94f3 100644 --- a/src/sbuf/Stream.h +++ b/src/sbuf/Stream.h @@ -10,72 +10,7 @@ #define SQUID_SBUFSTREAM_H #include "sbuf/SBuf.h" - -#include - -/** streambuf class for a SBuf-backed stream interface. - * - * Auxiliary class to be able to leverage an ostream generating SBuf's - * analogous to std::ostrstream. - */ -class SBufStreamBuf : public std::streambuf -{ -public: - /// initialize streambuf; use supplied SBuf as backing store - explicit SBufStreamBuf(SBuf aBuf) : theBuf(aBuf) {} - - /// get a copy of the stream's contents - SBuf getBuf() { - return theBuf; - } - - /// clear the stream's store - void clearBuf() { - theBuf.clear(); - } - -protected: - virtual int_type overflow(int_type aChar = traits_type::eof()) { - std::streamsize pending(pptr() - pbase()); - - if (pending && sync()) - return traits_type::eof(); - - if (aChar != traits_type::eof()) { - char chars[1] = {static_cast(aChar)}; - - if (aChar != traits_type::eof()) - theBuf.append(chars, 1); - } - - pbump(-pending); // Reset pptr(). - return aChar; - } - - /// push the streambuf to the backing SBuf - virtual int sync() { - std::streamsize pending(pptr() - pbase()); - - if (pending) - theBuf.append(pbase(), pending); - - return 0; - } - - /** write multiple characters to the store entry - * \note this is an optimisation consistent with std::streambuf API - */ - virtual std::streamsize xsputn(const char * chars, std::streamsize number) { - if (number) - theBuf.append(chars, number); - - return number; - } - -private: - SBuf theBuf; - SBufStreamBuf(); // no default constructor -}; +#include "base/PackableStream.h" /** Stream interface to write to a SBuf. * @@ -90,32 +25,36 @@ public: * The supplied SBuf copied: in order to retrieve the written-to contents * they must be later fetched using the buf() class method. */ - SBufStream(SBuf aBuf): std::ostream(0), theBuffer(aBuf) { - rdbuf(&theBuffer); // set the buffer to now-initialized theBuffer - clear(); //clear badbit set by calling init(0) + SBufStream(const SBuf &aBuf): + std::ostream(nullptr), // initialize the parent; no stream buffer yet + sink_(aBuf), + streamBuffer_(sink_) // initialize the stream buffer + { + rdbuf(&streamBuffer_); // supply the now-initialized stream buffer + clear(); // clear the badbit that a nullptr stream buffer has triggered } /// Create an empty SBufStream - SBufStream(): std::ostream(0), theBuffer(SBuf()) { - rdbuf(&theBuffer); // set the buffer to now-initialized theBuffer - clear(); //clear badbit set by calling init(0) - } + SBufStream(): SBufStream(SBuf()) {} - /// Retrieve a copy of the current stream status + /// bytes written so far SBuf buf() { flush(); - return theBuffer.getBuf(); + return sink_; } /// Clear the stream's backing store SBufStream& clearBuf() { flush(); - theBuffer.clearBuf(); + sink_.clear(); return *this; } private: - SBufStreamBuf theBuffer; + /// buffer for (flushed) bytes written to the stream + SBuf sink_; + /// writes raw (post-formatting) bytes to the sink_ + AppendingStreamBuf streamBuffer_; }; /// slowly stream-prints all arguments into a freshly allocated SBuf