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

View file

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

View file

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