Generic Record: settle type handling
initially, the intention was to inject the type as a magic attribute. But this turned out to make the implementation brittle, asymmetric and either quite demanding, or inefficient. The only sane approach would be to introduce a third collection, the metadata attributes. Then it would be possible to handle these automatically, but expose them through the iterator. In the end I decided against it, just the type attribute allone does not justify that effort. So now the type is an special magic field and kept apart from any object data.
This commit is contained in:
parent
0cde55a67f
commit
46bfc0638f
3 changed files with 32 additions and 22 deletions
|
|
@ -104,6 +104,7 @@ namespace diff{
|
|||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
using util::isnil;
|
||||
using std::string;
|
||||
|
||||
template<typename VAL>
|
||||
|
|
@ -141,13 +142,15 @@ namespace diff{
|
|||
Storage children_;
|
||||
|
||||
public:
|
||||
static const string TYPE_NIL;
|
||||
|
||||
Record()
|
||||
: type_("NIL")
|
||||
: type_(TYPE_NIL)
|
||||
{ }
|
||||
|
||||
template<typename A, typename C>
|
||||
Record(Symbol typeID, A&& att, C&& chi)
|
||||
: type_(typeID)
|
||||
: type_(isnil(typeID)? TYPE_NIL:string(typeID))
|
||||
, attribs_(std::forward<A> (att))
|
||||
, children_(std::forward<C> (chi))
|
||||
{ }
|
||||
|
|
@ -155,7 +158,7 @@ namespace diff{
|
|||
template<typename A, typename C>
|
||||
Record(Symbol typeID, std::initializer_list<A> const&& att
|
||||
, std::initializer_list<C> const&& chi)
|
||||
: type_(typeID)
|
||||
: type_(isnil(typeID)? TYPE_NIL:string(typeID))
|
||||
, attribs_(att)
|
||||
, children_(chi)
|
||||
{ }
|
||||
|
|
@ -163,7 +166,7 @@ namespace diff{
|
|||
template<typename SEQ>
|
||||
explicit
|
||||
Record (SEQ const& con)
|
||||
: type_("NIL")
|
||||
: type_(TYPE_NIL)
|
||||
{
|
||||
auto p = std::begin(con);
|
||||
auto e = std::end(con);
|
||||
|
|
@ -259,7 +262,7 @@ namespace diff{
|
|||
using valIter = TransformIter<scopeIter, Access>;
|
||||
|
||||
/** default iteration exposes all data within this "object", starting with the attributes */
|
||||
iterator begin () const { return iterator(this, attribs_.begin()); }
|
||||
iterator begin () const { return iterator(this, attribs_.empty()? children_.begin() : attribs_.begin()); }
|
||||
iterator end () const { return iterator(); }
|
||||
|
||||
scopeIter attribs() const { return iter_stl::eachElm(attribs_); }
|
||||
|
|
@ -271,9 +274,8 @@ namespace diff{
|
|||
protected: /* ==== API for the IterAdapter ==== */
|
||||
|
||||
/** Implementation of Iteration-logic: pull next element. */
|
||||
template<class ITER>
|
||||
friend void
|
||||
iterNext (const Record* src, ITER& pos)
|
||||
iterNext (const Record* src, ElmIter& pos)
|
||||
{
|
||||
++pos;
|
||||
checkPoint (src,pos);
|
||||
|
|
@ -284,22 +286,22 @@ namespace diff{
|
|||
* the end of the attribute collection. In this implementation,
|
||||
* we use the default constructed \c ITER() to mark iteration end.
|
||||
*/
|
||||
template<class ITER>
|
||||
friend bool
|
||||
checkPoint (const Record* src, ITER& pos)
|
||||
checkPoint (const Record* src, ElmIter& pos)
|
||||
{
|
||||
REQUIRE (src);
|
||||
if ((pos != ITER()) && (pos == src->attribs_.end()) && !src->children_.empty())
|
||||
static const ElmIter END;
|
||||
if (pos != END && pos == src->attribs_.end() && !src->children_.empty())
|
||||
{
|
||||
pos = src->children_.begin();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if (pos != ITER() && (pos != src->children_.end()))
|
||||
if (pos != END && (pos != src->children_.end()))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
pos = ITER();
|
||||
pos = END;
|
||||
return false;
|
||||
} }
|
||||
|
||||
|
|
@ -340,6 +342,9 @@ namespace diff{
|
|||
}
|
||||
};
|
||||
|
||||
template<typename VAL>
|
||||
const string Record<VAL>::TYPE_NIL = "NIL";
|
||||
|
||||
|
||||
|
||||
template<typename VAL>
|
||||
|
|
@ -620,6 +625,7 @@ namespace diff{
|
|||
using lib::transformIterator;
|
||||
|
||||
return "Rec("
|
||||
+ (TYPE_NIL==type_? "" : type_+"| ")
|
||||
+ join (transformIterator (this->attribs(), renderAttribute))
|
||||
+ " |{"
|
||||
+ join (this->scope())
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ END
|
|||
|
||||
|
||||
TEST "Generic Object Record" GenericRecordRepresentation_test <<END
|
||||
out-lit: enterprise = Rec(Name = USS Enterprise, Registry = NCC-1701-D, Class = Galaxy, Owner = United Federation of Planets, Operator = Starfleet, built = 2363 |{Picard, Riker, Data, Troi, Worf, Crusher, La Forge})
|
||||
out-lit: enterprise = Rec(starship| Name = USS Enterprise, Registry = NCC-1701-D, Class = Galaxy, Owner = United Federation of Planets, Operator = Starfleet, built = 2363 |{Picard, Riker, Data, Troi, Worf, Crusher, La Forge})
|
||||
out-lit: Name = USS Enterprise
|
||||
out-lit: Registry = NCC-1701-D
|
||||
out-lit: Class = Galaxy
|
||||
|
|
|
|||
|
|
@ -139,10 +139,13 @@ namespace test{
|
|||
|
||||
VERIFY_ERROR (INVALID, enterprise.get("warp10"));
|
||||
|
||||
cout << "enterprise = " << string(enterprise)<<endl;
|
||||
for (string elm : enterprise) cout << elm<<endl;
|
||||
cout << "enterprise = "
|
||||
<< string(enterprise)<<endl;
|
||||
for (string elm : enterprise)
|
||||
cout << elm<<endl;
|
||||
cout << "--Attributes--"<<endl;
|
||||
for (string att : enterprise.attribs()) cout << att<<endl;
|
||||
for (string att : enterprise.attribs())
|
||||
cout << att<<endl;
|
||||
cout << "--Keys--->" << join (enterprise.keys(), "<->")<<endl;
|
||||
cout << "--Vals--->" << join (enterprise.vals(), "<->")<<endl;
|
||||
cout << "--Crew--->" << join (enterprise.scope()," | ")<<endl;
|
||||
|
|
@ -155,6 +158,7 @@ namespace test{
|
|||
RecS nil;
|
||||
CHECK (isnil(nil));
|
||||
CHECK ("NIL" == nil.getType());
|
||||
CHECK (RecS::TYPE_NIL == nil.getType());
|
||||
|
||||
CHECK (!nil.begin());
|
||||
CHECK (nil.begin() == nil.end());
|
||||
|
|
@ -176,10 +180,10 @@ namespace test{
|
|||
CHECK (Seq{"z"} == contents (untyped2.scope()));
|
||||
|
||||
|
||||
RecS something({"type=thing", "a=1", "b=2", "c", "d"});
|
||||
RecS something({"a=1", "type=thing", "b=2", "c", "d"});
|
||||
CHECK (!isnil(something));
|
||||
CHECK ("thing" == something.getType());
|
||||
CHECK (Seq({"type=thing", "a=1", "b=2", "c", "d"}) == contents(something));
|
||||
CHECK (Seq({"a=1", "b=2", "c", "d"}) == contents(something));
|
||||
CHECK (Seq({"a", "b"}) == contents (something.keys()));
|
||||
CHECK (Seq({"1", "2"}) == contents (something.vals()));
|
||||
CHECK (Seq({"c", "d"}) == contents (something.scope()));
|
||||
|
|
@ -189,7 +193,7 @@ namespace test{
|
|||
void
|
||||
copy_and_move()
|
||||
{
|
||||
RecS a({"type=thing", "a=1", "b=2", "c", "d"});
|
||||
RecS a({"a=1", "b=2", "c", "d"});
|
||||
RecS b(a);
|
||||
CHECK (a.getType() == b.getType());
|
||||
CHECK (contents(a) == contents(b));
|
||||
|
|
@ -284,7 +288,7 @@ namespace test{
|
|||
RecS aa(mut);
|
||||
CHECK (a != aa);
|
||||
CHECK ("u" == aa.getType());
|
||||
CHECK (Seq({"type=u", "a=1", "a"}) == contents(aa));
|
||||
CHECK (Seq({"a=1", "a"}) == contents(aa));
|
||||
CHECK (Seq({"a"}) == contents (aa.keys()));
|
||||
CHECK (Seq({"1"}) == contents (aa.vals()));
|
||||
CHECK (Seq({"a"}) == contents (aa.scope()));
|
||||
|
|
@ -299,8 +303,8 @@ namespace test{
|
|||
|
||||
mut.replace(a);
|
||||
CHECK (isnil (mut));
|
||||
CHECK (Seq({"type=u", "a=α", "a=β", "⟂", "a"}) == contents(a));
|
||||
CHECK (Seq({"type=u", "a=1", "a"}) == contents(aa));
|
||||
CHECK (Seq({"a=α", "a=β", "⟂", "a"}) == contents(a));
|
||||
CHECK (Seq({"a=1", "a"}) == contents(aa));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue