From 3f91997cf180bb3f6c66e0b9f816c511b4994b5c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 11 Sep 2015 18:41:18 +0200 Subject: [PATCH] WIP: rearrange types to make the recursive iteration work The only substantial change (besides compilation fixes) is to confine the iteration to *const access* This is a good thing; the whole Record/GenNode structure was designed to represent immutable data, necessitating a dedicated *Mutator* for any reshaping. --- src/lib/diff/gen-node.hpp | 137 ++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 57 deletions(-) diff --git a/src/lib/diff/gen-node.hpp b/src/lib/diff/gen-node.hpp index ba8f98248..fd9e788d7 100644 --- a/src/lib/diff/gen-node.hpp +++ b/src/lib/diff/gen-node.hpp @@ -68,21 +68,19 @@ ** - finally, the handling of changes prompts us to support installation ** of a specifically typed change handling closure. ** - ** \par monadic nature + ** \par monadic nature? ** ** As suggested by the usage for representation of tree shaped data, we acknowledge - ** that GenNode is a Monad. We support the basic operations \em construction - ** and \em flatMap. To fit in with this generic processing pattern, the one element - ** flavours of GenNode are considered the special case, while the collective flavours - ** form the base case -- every GenNode can be iterated. The \em construction requirement - ** suggests that GenNode may be created readily, just by wrapping any given and suitable - ** element, thereby picking up the element's type. For sake of code organisation and - ** dependency management, we solve this requirement with the help of a trait type, - ** expecting the actual usage to supply the necessary specialisations on site. + ** that GenNode could be a Monad. We support the basic operation \em construction, + ** and the operation \em flatMap would be trivial to add. To fit in with this generic + ** processing pattern, the one element flavours of GenNode are considered the special case, + ** while the collective flavours form the base case -- every GenNode can be iterated. + ** The \em construction requirement suggests that GenNode may be created readily, just + ** by wrapping any given and suitable element, thereby picking up the element's type. ** - ** @todo the purpose and goal of the monadic approach is not clear yet (5/2015). - ** To begin with, for the task of diff detection and application, it is sufficient - ** to get the children as traversable collection + ** But the purpose and goal of the monadic approach is not clear yet (5/2015). + ** To begin with, for the task of diff detection and application, it is sufficient + ** to get the children as traversable collection and to offer a depth-first expansion. ** ** @see GenNodeBasic_test ** @see diff-list-generation-test.cpp @@ -186,7 +184,10 @@ namespace diff{ bool matchRec (RecRef const&) const; bool matchRec (Rec const&) const; - operator string() const; + struct Locator; + Locator expand() const; + + operator string() const; }; @@ -342,60 +343,82 @@ namespace diff{ }; + + /* === iteration / recursive expansion / references === */ + + /** - * Monad-like depth-first expansion of a GenNode + * @internal Helper to refer to any element position, + * irrespective if on top level or within a nested scope + * @remarks typically used within lib::IterStateWrapper + * @see DataCap#expand() + */ + struct DataCap::Locator + { + const GenNode* node_; + Rec::iterator scope_; + + Locator() + : node_(nullptr) + { } + + Locator(GenNode const& n) + : node_(&n) + { } + + Locator(Rec const& r) + : node_(nullptr) + , scope_(r.begin()) + { } + + const GenNode * + get() const + { + return node_? node_ + : scope_? scope_.operator->() + : nullptr; + } + + /* === Iteration control API for IterStateWrapper == */ + + friend bool + checkPoint (Locator const& loc) + { + return loc.get(); + } + + friend GenNode const& + yield (Locator const& loc) + { + return *loc.get(); + } + + friend void + iterNext (Locator & loc) + { + if (loc.node_) + loc.node_ = nullptr; + else + ++loc.scope_; + } + }; + + + /** + * Building block for monad-like depth-first expansion of a GenNode. */ class GenNode::ScopeExplorer { - struct Locator - { - const GenNode* node_; - Rec::iterator scope_; - - Locator() - : node_(nullptr) - { } - - Locator(GenNode const& n) - : node_(&n) - { } - - Locator(Rec const& r) - : node_(nullptr) - , scope_(r.begin()) - { } - - friend bool - checkPoint (Locator const& loc) - { - return bool(node_) || bool(scope_); - } - - friend GenNode const& - yield (Locator const& loc) - { - return node_? *node_ : *scope_; - } - - friend void - iterNext (Locator & loc) - { - if (node_) - node_ = nullptr; - else - ++scope_; - } - }; - - using ScopeIter = IterStateWrapper; + using ScopeIter = IterStateWrapper; std::deque scopes_; public: ScopeExplorer() { } ScopeExplorer(GenNode const& n) - : scopes_({n}) - { } + { + scopes_.emplace_back(n); + } /* === Iteration control API for IterStateWrapper == */