From 8cca5db5a1deafed974c2f62392eef4c48e81e07 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 4 Feb 2026 10:31:42 -0500 Subject: [PATCH] xo-indentlog: presence flag for refrtag/xrefrtag --- .../include/xo/indentlog/print/pretty.hpp | 17 +++++++++++ .../include/xo/indentlog/print/tag.hpp | 28 +++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/xo-indentlog/include/xo/indentlog/print/pretty.hpp b/xo-indentlog/include/xo/indentlog/print/pretty.hpp index 3ae010eb..d215b8b3 100644 --- a/xo-indentlog/include/xo/indentlog/print/pretty.hpp +++ b/xo-indentlog/include/xo/indentlog/print/pretty.hpp @@ -256,6 +256,11 @@ namespace xo { Member && member, Rest&&... rest) { + if constexpr (has_present>) { + if (!member.present()) + return this->print_upto_struct_members(ppii, rest...); + } + if (this->print_upto(" ") && this->print_upto(member)) return this->print_upto_struct_members(ppii, rest...); @@ -268,6 +273,13 @@ namespace xo { Member && member, Rest&&... rest) { + if constexpr (has_present>) { + if (!member.present()) { + this->pretty_struct_members(ppii, rest...); + return; + } + } + newline_indent(ppii.ci1()); this->pretty(member); this->pretty_struct_members(ppii, rest...); @@ -381,6 +393,11 @@ namespace xo { static bool print_pretty(const ppindentinfo & ppii, const Tag & tag) { + if constexpr (has_present) { + if (!tag.present()) + return true; + } + if (ppii.upto()) { if (tag.prefix_space()) ppii.pps()->write(" "); diff --git a/xo-indentlog/include/xo/indentlog/print/tag.hpp b/xo-indentlog/include/xo/indentlog/print/tag.hpp index 026e8205..03a03223 100644 --- a/xo-indentlog/include/xo/indentlog/print/tag.hpp +++ b/xo-indentlog/include/xo/indentlog/print/tag.hpp @@ -6,6 +6,7 @@ #include "concat.hpp" #include "quoted.hpp" #include "color.hpp" +#include #include // STRINGIFY(xyz) -> "xyz" @@ -20,6 +21,12 @@ #define XTAG(x) xo::xtag(STRINGIFY(x), x) namespace xo { + /** concept: true if T has a .present() method returning something bool-like **/ + template + concept has_present = requires(const T& t) { + { t.present() } -> std::convertible_to; + }; + enum class tagstyle { /** print with automatic escapes for embedded special characters * (any of ' ','"','\','\n','\r','\t'). @@ -79,10 +86,13 @@ namespace xo { **/ template struct ref_tag_impl { - ref_tag_impl(Name const & n, Value const & v) : name_{n}, value_{v} {} - ref_tag_impl(Name && n, Value && v) : name_{std::forward(n)}, value_{std::forward(v)} {} + ref_tag_impl(Name const & n, Value const & v, bool present = true) + : name_{n}, value_{v}, present_{present} {} + ref_tag_impl(Name && n, Value && v, bool present = true) + : name_{std::forward(n)}, value_{std::forward(v)}, present_{present} {} constexpr bool prefix_space() const { return PrefixSpace; } + bool present() const { return present_; } Name const & name() const { return name_; } Value const & value() const { return value_; } @@ -90,6 +100,7 @@ namespace xo { private: Name name_; const Value& value_; + bool present_ = true; }; // ----- xtag ----- @@ -150,12 +161,14 @@ namespace xo { /** 'reference raw tag'. * 1. @p v must survive until refrtag is used (i.e. until tag inserted into some stream) * 2. don't escape whitespace when printing value (pretty-printing with parseable structure) + * + * Print nothing if @p present is false **/ template auto - refrtag(Name && n, Value && v) + refrtag(Name && n, Value && v, bool present = true) { - return ref_tag_impl, std::decay_t>(n, v); + return ref_tag_impl, std::decay_t>(n, v, present); } // ----- xrefrtag ----- @@ -164,9 +177,9 @@ namespace xo { **/ template auto - xrefrtag(Name && n, Value && v) + xrefrtag(Name && n, Value && v, bool present = true) { - return ref_tag_impl, std::decay_t>(n, v); + return ref_tag_impl, std::decay_t>(n, v, present); } // ----- operator<< on tag_impl ----- @@ -199,6 +212,9 @@ namespace xo { operator<<(std::ostream &s, ref_tag_impl const & tag) { + if (!tag.present()) + return s; + using xo::print::unq; if (PrefixSpace)