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;
|
namespace error = lumiera::error;
|
||||||
|
|
||||||
|
using util::isnil;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
template<typename VAL>
|
template<typename VAL>
|
||||||
|
|
@ -141,13 +142,15 @@ namespace diff{
|
||||||
Storage children_;
|
Storage children_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static const string TYPE_NIL;
|
||||||
|
|
||||||
Record()
|
Record()
|
||||||
: type_("NIL")
|
: type_(TYPE_NIL)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
template<typename A, typename C>
|
template<typename A, typename C>
|
||||||
Record(Symbol typeID, A&& att, C&& chi)
|
Record(Symbol typeID, A&& att, C&& chi)
|
||||||
: type_(typeID)
|
: type_(isnil(typeID)? TYPE_NIL:string(typeID))
|
||||||
, attribs_(std::forward<A> (att))
|
, attribs_(std::forward<A> (att))
|
||||||
, children_(std::forward<C> (chi))
|
, children_(std::forward<C> (chi))
|
||||||
{ }
|
{ }
|
||||||
|
|
@ -155,7 +158,7 @@ namespace diff{
|
||||||
template<typename A, typename C>
|
template<typename A, typename C>
|
||||||
Record(Symbol typeID, std::initializer_list<A> const&& att
|
Record(Symbol typeID, std::initializer_list<A> const&& att
|
||||||
, std::initializer_list<C> const&& chi)
|
, std::initializer_list<C> const&& chi)
|
||||||
: type_(typeID)
|
: type_(isnil(typeID)? TYPE_NIL:string(typeID))
|
||||||
, attribs_(att)
|
, attribs_(att)
|
||||||
, children_(chi)
|
, children_(chi)
|
||||||
{ }
|
{ }
|
||||||
|
|
@ -163,7 +166,7 @@ namespace diff{
|
||||||
template<typename SEQ>
|
template<typename SEQ>
|
||||||
explicit
|
explicit
|
||||||
Record (SEQ const& con)
|
Record (SEQ const& con)
|
||||||
: type_("NIL")
|
: type_(TYPE_NIL)
|
||||||
{
|
{
|
||||||
auto p = std::begin(con);
|
auto p = std::begin(con);
|
||||||
auto e = std::end(con);
|
auto e = std::end(con);
|
||||||
|
|
@ -259,7 +262,7 @@ namespace diff{
|
||||||
using valIter = TransformIter<scopeIter, Access>;
|
using valIter = TransformIter<scopeIter, Access>;
|
||||||
|
|
||||||
/** default iteration exposes all data within this "object", starting with the attributes */
|
/** 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(); }
|
iterator end () const { return iterator(); }
|
||||||
|
|
||||||
scopeIter attribs() const { return iter_stl::eachElm(attribs_); }
|
scopeIter attribs() const { return iter_stl::eachElm(attribs_); }
|
||||||
|
|
@ -271,9 +274,8 @@ namespace diff{
|
||||||
protected: /* ==== API for the IterAdapter ==== */
|
protected: /* ==== API for the IterAdapter ==== */
|
||||||
|
|
||||||
/** Implementation of Iteration-logic: pull next element. */
|
/** Implementation of Iteration-logic: pull next element. */
|
||||||
template<class ITER>
|
|
||||||
friend void
|
friend void
|
||||||
iterNext (const Record* src, ITER& pos)
|
iterNext (const Record* src, ElmIter& pos)
|
||||||
{
|
{
|
||||||
++pos;
|
++pos;
|
||||||
checkPoint (src,pos);
|
checkPoint (src,pos);
|
||||||
|
|
@ -284,22 +286,22 @@ namespace diff{
|
||||||
* the end of the attribute collection. In this implementation,
|
* the end of the attribute collection. In this implementation,
|
||||||
* we use the default constructed \c ITER() to mark iteration end.
|
* we use the default constructed \c ITER() to mark iteration end.
|
||||||
*/
|
*/
|
||||||
template<class ITER>
|
|
||||||
friend bool
|
friend bool
|
||||||
checkPoint (const Record* src, ITER& pos)
|
checkPoint (const Record* src, ElmIter& pos)
|
||||||
{
|
{
|
||||||
REQUIRE (src);
|
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();
|
pos = src->children_.begin();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (pos != ITER() && (pos != src->children_.end()))
|
if (pos != END && (pos != src->children_.end()))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pos = ITER();
|
pos = END;
|
||||||
return false;
|
return false;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
|
@ -340,6 +342,9 @@ namespace diff{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename VAL>
|
||||||
|
const string Record<VAL>::TYPE_NIL = "NIL";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename VAL>
|
template<typename VAL>
|
||||||
|
|
@ -620,6 +625,7 @@ namespace diff{
|
||||||
using lib::transformIterator;
|
using lib::transformIterator;
|
||||||
|
|
||||||
return "Rec("
|
return "Rec("
|
||||||
|
+ (TYPE_NIL==type_? "" : type_+"| ")
|
||||||
+ join (transformIterator (this->attribs(), renderAttribute))
|
+ join (transformIterator (this->attribs(), renderAttribute))
|
||||||
+ " |{"
|
+ " |{"
|
||||||
+ join (this->scope())
|
+ join (this->scope())
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ END
|
||||||
|
|
||||||
|
|
||||||
TEST "Generic Object Record" GenericRecordRepresentation_test <<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: Name = USS Enterprise
|
||||||
out-lit: Registry = NCC-1701-D
|
out-lit: Registry = NCC-1701-D
|
||||||
out-lit: Class = Galaxy
|
out-lit: Class = Galaxy
|
||||||
|
|
|
||||||
|
|
@ -139,10 +139,13 @@ namespace test{
|
||||||
|
|
||||||
VERIFY_ERROR (INVALID, enterprise.get("warp10"));
|
VERIFY_ERROR (INVALID, enterprise.get("warp10"));
|
||||||
|
|
||||||
cout << "enterprise = " << string(enterprise)<<endl;
|
cout << "enterprise = "
|
||||||
for (string elm : enterprise) cout << elm<<endl;
|
<< string(enterprise)<<endl;
|
||||||
|
for (string elm : enterprise)
|
||||||
|
cout << elm<<endl;
|
||||||
cout << "--Attributes--"<<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 << "--Keys--->" << join (enterprise.keys(), "<->")<<endl;
|
||||||
cout << "--Vals--->" << join (enterprise.vals(), "<->")<<endl;
|
cout << "--Vals--->" << join (enterprise.vals(), "<->")<<endl;
|
||||||
cout << "--Crew--->" << join (enterprise.scope()," | ")<<endl;
|
cout << "--Crew--->" << join (enterprise.scope()," | ")<<endl;
|
||||||
|
|
@ -155,6 +158,7 @@ namespace test{
|
||||||
RecS nil;
|
RecS nil;
|
||||||
CHECK (isnil(nil));
|
CHECK (isnil(nil));
|
||||||
CHECK ("NIL" == nil.getType());
|
CHECK ("NIL" == nil.getType());
|
||||||
|
CHECK (RecS::TYPE_NIL == nil.getType());
|
||||||
|
|
||||||
CHECK (!nil.begin());
|
CHECK (!nil.begin());
|
||||||
CHECK (nil.begin() == nil.end());
|
CHECK (nil.begin() == nil.end());
|
||||||
|
|
@ -176,10 +180,10 @@ namespace test{
|
||||||
CHECK (Seq{"z"} == contents (untyped2.scope()));
|
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 (!isnil(something));
|
||||||
CHECK ("thing" == something.getType());
|
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({"a", "b"}) == contents (something.keys()));
|
||||||
CHECK (Seq({"1", "2"}) == contents (something.vals()));
|
CHECK (Seq({"1", "2"}) == contents (something.vals()));
|
||||||
CHECK (Seq({"c", "d"}) == contents (something.scope()));
|
CHECK (Seq({"c", "d"}) == contents (something.scope()));
|
||||||
|
|
@ -189,7 +193,7 @@ namespace test{
|
||||||
void
|
void
|
||||||
copy_and_move()
|
copy_and_move()
|
||||||
{
|
{
|
||||||
RecS a({"type=thing", "a=1", "b=2", "c", "d"});
|
RecS a({"a=1", "b=2", "c", "d"});
|
||||||
RecS b(a);
|
RecS b(a);
|
||||||
CHECK (a.getType() == b.getType());
|
CHECK (a.getType() == b.getType());
|
||||||
CHECK (contents(a) == contents(b));
|
CHECK (contents(a) == contents(b));
|
||||||
|
|
@ -284,7 +288,7 @@ namespace test{
|
||||||
RecS aa(mut);
|
RecS aa(mut);
|
||||||
CHECK (a != aa);
|
CHECK (a != aa);
|
||||||
CHECK ("u" == aa.getType());
|
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({"a"}) == contents (aa.keys()));
|
||||||
CHECK (Seq({"1"}) == contents (aa.vals()));
|
CHECK (Seq({"1"}) == contents (aa.vals()));
|
||||||
CHECK (Seq({"a"}) == contents (aa.scope()));
|
CHECK (Seq({"a"}) == contents (aa.scope()));
|
||||||
|
|
@ -299,8 +303,8 @@ namespace test{
|
||||||
|
|
||||||
mut.replace(a);
|
mut.replace(a);
|
||||||
CHECK (isnil (mut));
|
CHECK (isnil (mut));
|
||||||
CHECK (Seq({"type=u", "a=α", "a=β", "⟂", "a"}) == contents(a));
|
CHECK (Seq({"a=α", "a=β", "⟂", "a"}) == contents(a));
|
||||||
CHECK (Seq({"type=u", "a=1", "a"}) == contents(aa));
|
CHECK (Seq({"a=1", "a"}) == contents(aa));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue