xo-umbrella2/xo-indentlog2/include/xo/indentlog2/print/PrettySink.hpp
Roland Conybeare ca846d00e3 xo-arena stack: backpointer to DArena from storage.
Refactor everything above DArena for less fragility
2026-09-19 15:25:10 -04:00

122 lines
4.6 KiB
C++

/** @file PrettySink.hpp
*
* @author Roland Conybeare, Jul 2026
**/
#pragma once
#include "PpState.hpp"
#include "PpTokenStreambuf.hpp"
#include <xo/ppsink/PpSink.hpp>
namespace xo {
namespace pp {
/**
* Use:
* @code
* PpConfig ppc;
* PrettySink pp(ppc, nullptr);
*
* @endcode
**/
class PrettySink : public PpSink {
public:
using MemorySizeVisitor = xo::mm::MemorySizeVisitor;
using uint32_t = std::uint32_t;
public:
/** @p cfg. pretty-printing configuration.
* @p out. if non-null, forward output to this streambuf.
**/
PrettySink(const PpConfig & cfg, std::streambuf * out);
/** move ctor.
* Needs special treatment for self-referencing pointers
* involving @ref sbuf_ and @ref pps_.
**/
PrettySink(PrettySink && rhs) noexcept;
/** move assignment disabled for now **/
PrettySink & operator=(PrettySink &&) = delete;
/** create pretty sink that writes to string **/
static PrettySink make2str(const PpConfig & cfg);
/** create pretty sink that writes to cout **/
static PrettySink make2cout(const PpConfig & cfg);
/** create temporary pretty sink, intended for a unit test **/
static PrettySink scratch_plain(std::string basename,
uint32_t logbuf_z,
uint32_t margin);
/** create temporary pretty sink **/
static PrettySink scratch_aux(std::string basename,
uint32_t logbuf_z,
uint32_t margin,
const PpStyle & style);
/** verify internal state appears consistent. **/
bool verify_ok(bool throw_flag = true) const;
/** attach (or detach, with nullptr) a streambuf that completed
* records are drained to (e.g. @c std::clog.rdbuf()).
* Forwards to the underlying @ref logbuf_.
**/
void set_dest_sbuf(std::streambuf * sb);
LogBuffer & logbuf() { return logbuf_; }
/** pretty-printed output flushed to @ref logbuf_ so far.
* Excludes content still buffered in @ref pps_.
* Valid until the next write or logbuf reset.
**/
std::string_view output() const {
auto s = logbuf_.char_used_span();
return std::string_view(s.lo(), s.hi());
}
/** visit mapped storage pools **/
void visit_pools(const MemorySizeVisitor & fn) const;
// inherited from PpSink
/* keep the inherited split()/split(spaces) and newline()
* convenience overloads visible alongside the overrides below
*/
using PpSink::split;
using PpSink::newline;
virtual std::pair<bool, std::string> copy_output() override final;
virtual PpSink & put(std::string_view x) override final;
virtual PpSink & put_with_escape(std::string_view x, bool quote_flag) override final;
virtual PpSink & begin() override final;
virtual PpSink & begin(std::int32_t offset) override final;
virtual PpSink & begin_here(std::int32_t offset) override final;
virtual PpSink & split(std::uint32_t spaces, std::int32_t offset) override final;
virtual PpSink & newline(std::int32_t offset) override final;
virtual PpSink & end() override final;
/** record boundary: emit the terminating newline, then drain the
* completed record to the attached streambuf and reclaim logbuf_.
**/
virtual PpSink & complete() override final;
/** current visible output column (enables right-aligned fields) **/
virtual std::optional<std::size_t> lpos() const override final {
return logbuf_.viz_lpos();
}
virtual PpSinkInserter stream_open(uint32_t min_z) override final;
virtual void stream_commit() override;
private:
/** Pretty printer state (+ driver) **/
PpState pps_;
/** stream buffer for writing into @ref pps_ (at the scan endpoint) **/
PpTokenStreambuf sbuf_;
/** Buffer for pretty-printed output **/
LogBuffer logbuf_;
};
} /*namespace pp*/
} /*namespace xo*/
/* end PrettySink.hpp */