diff --git a/src/lib/iter-tree-explorer.hpp b/src/lib/iter-tree-explorer.hpp index d49c24b33..5a8cc558a 100644 --- a/src/lib/iter-tree-explorer.hpp +++ b/src/lib/iter-tree-explorer.hpp @@ -93,7 +93,7 @@ namespace lib { using std::forward; using std::function; - namespace iter_explorer { + namespace iter_source { template using iterator = typename meta::Strip::TypeReferred::iterator; @@ -122,6 +122,107 @@ namespace lib { // standard copy operations acceptable }; + + /** + * Decorate a state or logic core to treat it as Lumiera Forward Iterator. + * This Adapter does essentially the same as \ref IterStateWrapper, but here + * the state core is not encapsulated opaque, but rather inherited, and thus + * the full interface of the core remains publicly accessible. + */ + template + class IterableDecorator + : public COR + { + COR & _core() { return static_cast (*this); } + COR const& _core() const { return static_cast (*this); } + + void + __throw_if_empty() const + { + if (not isValid()) + throw lumiera::error::Invalid ("Can't iterate further", + lumiera::error::LUMIERA_ERROR_ITER_EXHAUST); + } + + + public: + typedef T* pointer; + typedef T& reference; + typedef T value_type; + + template + IterableDecorator (ARGS&& ...init) + : COR(std::forward(init)...) + { } + + IterableDecorator() =default; + IterableDecorator (IterableDecorator&&) =default; + IterableDecorator (IterableDecorator const&) =default; + IterableDecorator& operator= (IterableDecorator&&) =default; + IterableDecorator& operator= (IterableDecorator const&) =default; + + operator bool() const { return isValid(); } + + + /* === lumiera forward iterator concept === */ + + reference + operator*() const + { + __throw_if_empty(); + return yield (_core()); // extension point: yield + } + + pointer + operator->() const + { + __throw_if_empty(); + return & yield(_core()); // extension point: yield + } + + IterableDecorator& + operator++() + { + __throw_if_empty(); + iterNext (_core()); // extension point: iterNext + return *this; + } + + bool + isValid () const + { + return checkPoint(_core()); // extension point: checkPoint + } + + bool + empty () const + { + return not isValid(); + } + + + + ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (IterableDecorator); + + + /// Supporting equality comparisons of equivalent iterators (same state core)... + template + friend bool + operator== (IterableDecorator const& il, IterableDecorator const& ir) + { + return (il.empty() and ir.empty()) + or (il.isValid() and ir.isValid() and il._core() == ir._core()); + } + + template + friend bool + operator!= (IterableDecorator const& il, IterableDecorator const& ir) + { + return not (il == ir); + } + }; + + }//(End) namespace iter_explorer : predefined policies and configurations @@ -130,6 +231,7 @@ namespace lib { using meta::enable_if; using meta::Yes_t; using meta::No_t; + using meta::_Fun; using std::__and_; using std::__not_; using std::is_constructible; @@ -180,7 +282,16 @@ namespace lib { { static_assert (not std::is_rvalue_reference::value, "container needs to exist elsewhere during the lifetime of the iteration"); - using SrcIter = iter_explorer::StlRange; + using SrcIter = iter_source::StlRange; + }; + + + template + struct _ExpansionTraits + { + using ExpandedChildren = typename _Fun::Ret; + + using Core = typename _TreeExplorerTraits::SrcIter; }; }//(End) TreeExplorer traits @@ -189,20 +300,29 @@ namespace lib { namespace iter_source { - template + template class Expander - : public EXP + : public SRC { + using Core = typename _ExpansionTraits::Core; + + static_assert (std::is_convertible::value, + "the iterator from the expansion must yield compatible values"); + static_assert (std::is_convertible::Args::List::Head, typename SRC::value_type>::value, + "the expansion functor must accept a parameter compatible to the source iterator value type"); + function expandChildren_; + IterStack expansions_; public: Expander() =default; // inherited default copy operations template - Expander (EXP&& parentExplorer, FUN&& expandFunctor) - : EXP{move (parentExplorer)} + Expander (SRC&& parentExplorer, FUN&& expandFunctor) + : SRC{move (parentExplorer)} , expandChildren_{forward (expandFunctor)} + , expansions_{} { } @@ -210,15 +330,52 @@ namespace lib { Expander& expand() { - UNIMPLEMENTED ("expand-children core operation"); + REQUIRE (checkPoint(*this), "attempt to expand an empty explorer"); + + Core expanded = expandChildren_ (yield(*this)); + iterNext (*this); // consume current head element + if (expanded.isValid()) + expansions_.push (move(expanded)); + + return *this; } /** diagnostics: current level of nested child expansion */ size_t depth() const { - UNIMPLEMENTED ("implementation of the expand mechanics"); + return expansions_.size(); } + + + protected: /* === Iteration control API for IterableDecorator === */ + + friend bool + checkPoint (Expander const& tx) + { + return 0 < tx.depth() + or tx.isValid(); + } + + friend typename SRC::reference + yield (Expander const& tx) + { + return 0 < tx.depth()? **tx.expansions_ + : *tx; + } + + friend void + iterNext (Expander & tx) + { + if (0 < tx.depth()) + { + ++(*tx.expansions_); + while (0 < tx.depth() and not *tx.expansions_) + ++tx.expansions_; + } + else + ++tx; + } }; } @@ -241,9 +398,9 @@ namespace lib { public: - typedef typename SRC::value_type value_type; - typedef typename SRC::reference reference; - typedef typename SRC::pointer pointer; + using value_type = typename SRC::value_type; + using reference = typename SRC::reference; + using pointer = typename SRC::pointer; /** by default create an empty iterator */ @@ -271,8 +428,12 @@ namespace lib { { using FunSig = typename meta::_Fun::Sig; using This = typename meta::Strip::TypeReferred; + using Value = typename This::value_type; + using Core = iter_source::Expander; - return iter_source::Expander {move(*this), forward(expandFunctor)}; + using ExpandableExplorer = iter_source::IterableDecorator; + + return ExpandableExplorer{move(*this), forward(expandFunctor)}; } private: }; @@ -295,7 +456,7 @@ namespace lib { // using lib::meta::disable_if; // using std::function; // using meta::_Fun; - } + } diff --git a/tests/library/iter-tree-explorer-test.cpp b/tests/library/iter-tree-explorer-test.cpp index b075b02b9..a34c0ba88 100644 --- a/tests/library/iter-tree-explorer-test.cpp +++ b/tests/library/iter-tree-explorer-test.cpp @@ -125,15 +125,15 @@ namespace test{ class NumberSequence : public IterStateWrapper { - - public: - explicit - NumberSequence(uint end = 0) - : IterStateWrapper (CountDown(0,end)) - { } - NumberSequence(uint start, uint end) - : IterStateWrapper (CountDown(start,end)) - { } + + public: + explicit + NumberSequence(uint end = 0) + : IterStateWrapper (CountDown(0,end)) + { } + NumberSequence(uint start, uint end) + : IterStateWrapper (CountDown(start,end)) + { } }; @@ -297,7 +297,7 @@ namespace test{ * and consequently this result needs to be again an iterable with compatible value type. * Conceptually, the evaluation _forks into the children of the expanded element_, before * continuing with the successor of the expansion point. Obviously, expansion can be applied - * again on the result of the expansion, possibly leading to a tree of side evaluations. + * again on the result of the expansion, possibly leading to a tree of side evaluations. */ void verify_expandOperation()