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:
Fischlurch 2015-08-17 06:17:00 +02:00
parent 0cde55a67f
commit 46bfc0638f
3 changed files with 32 additions and 22 deletions

View file

@ -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())

View file

@ -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

View file

@ -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));
} }