#include <ostream>
-/**
- * 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 Buffer>
+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());
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<Packable>;
+template <> inline void PackableStreamBuf::postInit() { buf_.buffer(); }
+template <> inline void PackableStreamBuf::postSync() { buf_.flush(); }
+
class PackableStream : public std::ostream
{
public:
#define SQUID_SBUFSTREAM_H
#include "sbuf/SBuf.h"
-
-#include <ostream>
-
-/** 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<char>(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.
*
* 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<SBuf> streamBuffer_;
};
/// slowly stream-prints all arguments into a freshly allocated SBuf