Library: introduce compact textual representation for GenNode
This extension is required to use GenNode as data source for text-template instantiation. I am aware that such a function could counter the design intent for GenNode, because it could be (ab)used to "just get the damn value" and then parse back the results...
This commit is contained in:
parent
4c4ae0691c
commit
cfe54a5070
5 changed files with 113 additions and 3 deletions
|
|
@ -50,8 +50,10 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
|
||||
using util::join;
|
||||
using boost::lexical_cast;
|
||||
using lib::time::TimeValue;
|
||||
using lib::transformIterator;
|
||||
using util::almostEqual;
|
||||
using lib::hash::LuidH;
|
||||
|
||||
|
|
@ -290,4 +292,70 @@ namespace diff{
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** compact textual representation of a Record<GenNode> (»object«). */
|
||||
string renderCompact (Rec const& rec)
|
||||
{
|
||||
auto renderChild = [](diff::GenNode const& n){ return renderCompact(n); };
|
||||
auto renderAttrib = [](diff::GenNode const& n){
|
||||
return (n.isNamed()? n.idi.getSym()+"=" : "")
|
||||
+ renderCompact(n);
|
||||
};
|
||||
|
||||
return (Rec::TYPE_NIL==rec.getType()? "" : rec.getType())
|
||||
+ "{"
|
||||
+ join (transformIterator (rec.attribs(), renderAttrib))
|
||||
+ (isnil(rec.scope())? "" : "|")
|
||||
+ join (transformIterator (rec.scope() , renderChild))
|
||||
+ "}"
|
||||
;
|
||||
}
|
||||
|
||||
string
|
||||
renderCompact (RecRef const& ref)
|
||||
{
|
||||
return "Ref->" + (ref.empty()? util::BOTTOM_INDICATOR
|
||||
: renderCompact (*ref.get()));
|
||||
}
|
||||
|
||||
/** @remark presentation is oriented towards readability
|
||||
* - numbers are slightly rounded (see \ref util::showDouble() )
|
||||
* - time values are displayed timecode-like
|
||||
* - nested scopes are displayed recursively, enclosed in curly brackets
|
||||
* @see text-template-gen-node-binding.hpp
|
||||
*/
|
||||
string
|
||||
renderCompact (GenNode const& node)
|
||||
{
|
||||
class Renderer
|
||||
: public Variant<diff::DataValues>::Renderer
|
||||
{
|
||||
#define RENDER_CONTENT(_TY_) \
|
||||
virtual string handle (_TY_ const& val) override { return util::toString(val); }
|
||||
|
||||
RENDER_CONTENT (int)
|
||||
RENDER_CONTENT (int64_t)
|
||||
RENDER_CONTENT (short)
|
||||
RENDER_CONTENT (char)
|
||||
RENDER_CONTENT (double)
|
||||
RENDER_CONTENT (bool)
|
||||
RENDER_CONTENT (time::Time)
|
||||
RENDER_CONTENT (time::Offset)
|
||||
RENDER_CONTENT (time::Duration)
|
||||
RENDER_CONTENT (time::TimeSpan)
|
||||
#undef RENDER_CONTENT
|
||||
|
||||
virtual string handle (string const& val) override { return val; }
|
||||
virtual string handle (LuidH const& val) override { return util::showHash(val, 2);}
|
||||
virtual string handle (RecRef const& ref) override { return renderCompact(ref); }
|
||||
virtual string handle (Rec const& rec) override { return renderCompact(rec); }
|
||||
};
|
||||
|
||||
Renderer visitor;
|
||||
return node.data.accept (visitor);
|
||||
}
|
||||
|
||||
|
||||
}} // namespace lib::diff
|
||||
|
|
|
|||
|
|
@ -501,6 +501,15 @@ namespace diff{
|
|||
};
|
||||
|
||||
|
||||
/** compact textual representation of a GenNode tree */
|
||||
string renderCompact (GenNode const&);
|
||||
string renderCompact (RecRef const&);
|
||||
string renderCompact (Rec const&);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* metafunction to detect types able to be wrapped into a GenNode.
|
||||
|
|
|
|||
|
|
@ -683,6 +683,12 @@ namespace diff{
|
|||
return record_;
|
||||
}
|
||||
|
||||
operator string() const
|
||||
{
|
||||
return "Ref->" + (empty()? util::BOTTOM_INDICATOR
|
||||
: string(*record_));
|
||||
}
|
||||
|
||||
/** @note equality of references (instance pointers), not targets */
|
||||
friend bool
|
||||
operator== (RecordRef const& r1, RecordRef const& r2)
|
||||
|
|
|
|||
|
|
@ -252,6 +252,13 @@ namespace lib {
|
|||
virtual ~Predicate() { } ///< this is an interface
|
||||
};
|
||||
|
||||
class Renderer
|
||||
: public VisitorConstFunc<string>
|
||||
{
|
||||
public:
|
||||
virtual ~Renderer() { } ///< this is an interface
|
||||
}; ///////////////////////////////////TICKET #1361 : unable to make the Visitor fully generic
|
||||
|
||||
/**
|
||||
* Metafunction to pick the first of the variant's types,
|
||||
* which satisfies the given trait or predicate template
|
||||
|
|
@ -274,9 +281,10 @@ namespace lib {
|
|||
|
||||
virtual ~Buffer() {} ///< this is an ABC with VTable
|
||||
|
||||
virtual void dispatch (Visitor&) =0;
|
||||
virtual bool dispatch (Predicate&) const =0;
|
||||
virtual operator string() const =0;
|
||||
virtual void dispatch (Visitor&) =0;
|
||||
virtual bool dispatch (Predicate&) const =0;
|
||||
virtual string dispatch (Renderer&) const =0;
|
||||
virtual operator string() const =0;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -379,6 +387,15 @@ namespace lib {
|
|||
return typeDispatcher.handle (this->access());
|
||||
}
|
||||
|
||||
string
|
||||
dispatch (Renderer& visitor) const
|
||||
{
|
||||
using Dispatcher = variant::VFunc<string>::template ValueAcceptInterface<const TY>;
|
||||
|
||||
Dispatcher& typeDispatcher = visitor;
|
||||
return typeDispatcher.handle (this->access());
|
||||
}
|
||||
|
||||
/** diagnostic helper */
|
||||
operator string() const;
|
||||
};
|
||||
|
|
@ -536,6 +553,12 @@ namespace lib {
|
|||
{
|
||||
return buffer().dispatch (visitor);
|
||||
}
|
||||
|
||||
string
|
||||
accept (Renderer& visitor) const
|
||||
{
|
||||
return buffer().dispatch (visitor);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -147,6 +147,8 @@ namespace test{
|
|||
CHECK (!n3.isNamed());
|
||||
|
||||
cout << n3 <<endl; // diagnostic spam
|
||||
|
||||
CHECK (renderCompact(n3) == "spam{ham=eggs}"_expect);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -289,6 +291,8 @@ namespace test{
|
|||
for (auto & elm : n)
|
||||
cout << elm <<endl;
|
||||
|
||||
CHECK (renderCompact(n) == "{hasSpam=true|*, ★, 3.1415927, ham{|eggs, spam, spam}, 0:00:00.000≺920ms≻, 42}"_expect);
|
||||
|
||||
|
||||
auto iter = n.begin();
|
||||
CHECK (!isnil (iter));
|
||||
|
|
|
|||
Loading…
Reference in a new issue