#pragma once #include <util/stream/output.h> #include <utility> #include <util/generic/strbuf.h> template <class T> struct TDumper { template <class S> static inline void Dump(S& s, const T& t) { s.Stream() << t; } }; namespace NDumpPrivate { template <class T, class V> inline void Dump(T& t, const V& v) { ::TDumper<V>::Dump(t, v); } template <class T, class V> inline T&& operator<<(T&& t, V&& v) { Dump(t, v); return std::forward<T>(t); } struct TADLBase { }; } struct TDumpBase: public ::NDumpPrivate::TADLBase { inline TDumpBase(IOutputStream& out, bool indent) noexcept : Out(&out) , IndentLevel(0) , Indent(indent) { } inline IOutputStream& Stream() const noexcept { return *Out; } void Char(char ch); void Char(wchar16 ch); void String(const TStringBuf& s); void String(const TWtringBuf& s); void Raw(const TStringBuf& s); IOutputStream* Out; size_t IndentLevel; bool Indent; }; struct TIndentScope { inline TIndentScope(TDumpBase& d) : D(&d) { ++(D->IndentLevel); } inline ~TIndentScope() { --(D->IndentLevel); } TDumpBase* D; }; template <class TChar> struct TRawLiteral { const TBasicStringBuf<TChar> S; }; template <class TChar> static inline TRawLiteral<TChar> DumpRaw(const TBasicStringBuf<TChar>& s) noexcept { return {s}; } template <class TChar> static inline TRawLiteral<TChar> DumpRaw(const TChar* s) noexcept { return {s}; } template <class C> struct TDumper<TRawLiteral<C>> { template <class S> static inline void Dump(S& s, const TRawLiteral<C>& v) { s.Raw(v.S); } }; struct TIndentNewLine { }; static inline TIndentNewLine IndentNewLine() noexcept { return {}; } template <> struct TDumper<TIndentNewLine> { template <class S> static inline void Dump(S& s, const TIndentNewLine&) { if (s.Indent) { s << DumpRaw("\n") << DumpRaw(TString(s.IndentLevel * 4, ' ').data()); } } }; template <class P> struct TDumper<const P*> { template <class S> static inline void Dump(S& s, const P* p) { s.Pointer(p); } }; template <class P> struct TDumper<P*>: public TDumper<const P*> { }; struct TCharDumper { template <class S, class V> static inline void Dump(S& s, const V& v) { s.Char(v); } }; template <class S, class V> static inline void OutSequence(S& s, const V& v, const char* openTag, const char* closeTag) { s.ColorScheme.Markup(s); s << DumpRaw(openTag); { TIndentScope scope(s); size_t cnt = 0; for (const auto& x : v) { if (cnt) { s.ColorScheme.Markup(s); s << DumpRaw(", "); } s << IndentNewLine(); s.ColorScheme.Literal(s); s << x; ++cnt; } } s << IndentNewLine(); s.ColorScheme.Markup(s); s << DumpRaw(closeTag); s.ColorScheme.ResetType(s); } struct TAssocDumper { template <class S, class V> static inline void Dump(S& s, const V& v) { ::OutSequence(s, v, "{", "}"); } }; struct TSeqDumper { template <class S, class V> static inline void Dump(S& s, const V& v) { ::OutSequence(s, v, "[", "]"); } }; struct TStrDumper { template <class S, class V> static inline void Dump(S& s, const V& v) { s.ColorScheme.String(s); s.String(v); s.ColorScheme.ResetType(s); } };