TreeExplorer: transform-operation implemented and covered in test

This commit is contained in:
Fischlurch 2017-12-03 05:52:26 +01:00
parent b5453cc429
commit ca270028a9
4 changed files with 99 additions and 94 deletions

View file

@ -72,21 +72,17 @@
#include "lib/error.hpp"
#include "lib/meta/trait.hpp"
#include "lib/meta/duck-detector.hpp"
#include "lib/meta/function.hpp"
#include "lib/meta/trait.hpp"
#include "lib/wrapper.hpp" ////////////TODO : could be more lightweight by splitting FunctionResult into separate header. Relevant?
#include "lib/iter-adapter.hpp"
#include "lib/iter-stack.hpp"
#include "lib/meta/trait.hpp" ////////////////TODO
#include "lib/null-value.hpp" ////////////////TODO
#include "lib/util.hpp"
#include "lib/test/test-helper.hpp"///////////TODO Bug-o
//#include <boost/utility/enable_if.hpp> //////////////TODO
#include <stack> ////////////////TODO
#include <utility>
#include <functional>
#include <utility>
namespace lib {
@ -322,11 +318,14 @@ namespace lib {
/**
* @internal technical details of adapting an _"expansion functor"_ to allow
* expanding a given element from the TreeExploer (iterator) into a sequence of child elements.
* @internal technical details of binding a functor into the TreeExplorer.
* Notably, this happens when adapting an _"expansion functor"_ to allow expanding a given element
* from the TreeExploer (iterator) into a sequence of child elements. A quite similar situation
* arises when binding a _transformation function_ to be mapped onto each result element.
*
* The TreeExplorer::expand() operation accepts various flavours of functors, and depending on
* the signature of such a functor, an appropriate adapter will be constructed here, allowing
* to write a generic Expander::expand() operation. The following details are handled here
* the signature of such a functor, an appropriate adapter will be constructed here, allowing to
* write a generic Expander::expandChildren() operation. The following details are handled here:
* - detect if the passed functor is generic, or a regular "function-like" entity.
* - in case it is generic (generic lambda), we assume it actually accepts a reference to
* the source iterator type `SRC`. Thus we instantiate a templated functor with this
@ -341,10 +340,10 @@ namespace lib {
* special adapter supports the case when the _expansion functor_ yields a child sequence
* type different but compatible to the original source sequence embedded in TreeExplorer.
* @tparam FUN something _"function-like"_ passed as functor to be bound
* @tparam IT the source iterator type to apply when attempting to use a generic lambda as functor
* @tparam SRC the source iterator type to apply when attempting to use a generic lambda as functor
*/
template<class FUN, typename SRC>
struct _ExpansionTraits
struct _BoundFunctorTraits
{
/** handle all regular "function-like" entities */
template<typename F, typename SEL =void>
@ -408,11 +407,12 @@ namespace lib {
namespace iter_explorer {
/**
* @internal Decorator for TreeExplorer adding the ability to "expand children".
* The expand() operation is the key element of a depth-first evaluation: it consumes
* The expandChildren() operation is the key element of a depth-first evaluation: it consumes
* one element and performs a preconfigured _expansion functor_ on that element to yield
* its "children". These are given in the form of another iterator, which needs to be
* compatible to the source iterator ("compatibility" boils down to both iterators
@ -428,7 +428,7 @@ namespace lib {
* the source iterator wrapped by this decorator.
* @remark since we allow a lot of leeway regarding the actual form and definition of the
* _expansion functor_, there is a lot of minute technical details, mostly confined
* within the _ExpansionTraits.
* within the _BoundFunctorTraits.
* @tparam SRC the wrapped source iterator, typically a TreeExplorer or nested decorator.
* @tparam FUN the concrete type of the functor passed. Will be dissected to find the signature
*/
@ -437,7 +437,7 @@ namespace lib {
: public SRC
{
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
using _Traits = _ExpansionTraits<FUN,SRC>;
using _Traits = _BoundFunctorTraits<FUN,SRC>;
using ExpandFunctor = typename _Traits::Functor;
using ResIter = typename _DecoratorTraits<typename _Traits::Res>::SrcIter;
@ -514,14 +514,18 @@ namespace lib {
/**
*
* @internal Decorator for TreeExplorer to map a transformation function on all results.
* The transformation function is invoked on demand, and only once per item to be treated,
* storing the treated result into an universal value holder buffer. The given functor
* is adapted in a similar way as the "expand functor", so to detect and convert the
* expected input on invocation.
*/
template<class SRC, class FUN>
class Transformer
: public SRC
{
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
using _Traits = _ExpansionTraits<FUN,SRC>;
using _Traits = _BoundFunctorTraits<FUN,SRC>;
using Res = typename _Traits::Res;
using TransformFunctor = typename _Traits::Functor;
@ -591,6 +595,9 @@ namespace lib {
* based on a custom opaque _state core_. TreeExploer adheres to the _Monad_
* pattern known from functional programming, insofar the _expansion step_ is
* tied into the basic template by means of a function provided at usage site.
* This allows to separate the mechanics of evaluation and result combination
* from the actual processing and thus to define tree structured computations
* based on a not further disclosed, opaque source data structure.
*
* @todo WIP -- preliminary draft as of 11/2017
*/
@ -671,7 +678,14 @@ namespace lib {
}
/** @todo WIP 11/17 implement the transforming decorator and apply it here
/** adapt this TreeExplorer to pipe each result value through a transformation function.
* Several "layers" of mapping can be piled on top of each other, possibly mixed with the
* other types of adaptation, like the child-expanding operation, or a filter. Obviously,
* when building such processing pipelines, the input and output types of the functors
* bound into the pipeline need to be compatible or convertible. The transformation
* functor supports the same definition styles as described for #expand
* - it can be pure functional, src -> res
* - it can accept the underlying source iterator and exploit side-effects
*/
template<class FUN>
auto
@ -693,21 +707,6 @@ namespace lib {
namespace iter_explorer {
/////TODO RLY?
// using util::unConst;
// using lib::meta::enable_if;
// using lib::meta::disable_if;
// using std::function;
// using meta::_Fun;
}
/* ==== convenient builder free functions ==== */
/** start building a TreeExplorer
@ -725,24 +724,5 @@ namespace lib {
}
/*
template<class IT>
inline iter_explorer::DepthFirst<IT>
depthFirst (IT const& srcSeq)
{
return iter_explorer::DepthFirst<IT> (srcSeq);
}
template<class IT>
inline iter_explorer::BreadthFirst<IT>
breadthFirst (IT const& srcSeq)
{
return iter_explorer::BreadthFirst<IT> (srcSeq);
}
*/
} // namespace lib
#endif /* LIB_ITER_TREE_EXPLORER_H */

View file

@ -243,7 +243,7 @@ return: 0
END
TEST "Iterator monad variations" IterExplorer_test <<END
TEST "Iterator monad variations (1st draft)" IterExplorer_test <<END
out-lit: 1-2-3-4-5-6-7-8
out-lit: 0-1-2-3-4-0-1-2-3-4-5-6-0-1-2-3-4-5-6-7-8
out-lit: 0-1-2-3-4-5-6-7-8
@ -252,6 +252,11 @@ return: 0
END
PLANNED "Iterator monad variations (2nd draft)" IterTreeExplorer_test <<END
return: 0
END
TEST "Stack-like iterator" IterStack_test <<END
return: 0
END

View file

@ -448,7 +448,6 @@ namespace test{
void
verify_transformOperation()
{
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #888
auto multiply = [](int v){ return 2*v; };
_Fmt embrace{"≺%s≻"};
@ -472,18 +471,18 @@ namespace test{
vector<int64_t> numz{1,-2,3,-5,8,-13};
cout << materialise (treeExplore(numz)
.transform(formatify)) <<endl;
CHECK ("≺1≻-≺-2≻-≺3≻-≺-5≻-≺8≻-≺-13≻" == materialise (treeExplore(numz)
.transform(formatify)) );
cout << materialise (treeExplore(numz)
.transform(multiply)
.transform(formatify)) <<endl;
CHECK ("≺2≻-≺-4≻-≺6≻-≺-10≻-≺16≻-≺-26≻" == materialise (treeExplore(numz)
.transform(multiply)
.transform(formatify)) );
cout << materialise (treeExplore(numz)
.transform(multiply)
.transform(multiply)
.transform(formatify)
.transform(formatify)) <<endl;
CHECK ("≺≺4≻≻-≺≺-8≻≻-≺≺12≻≻-≺≺-20≻≻-≺≺32≻≻-≺≺-52≻≻" == materialise (treeExplore(numz)
.transform(multiply)
.transform(multiply)
.transform(formatify)
.transform(formatify)) );
// demonstrate the functor is evaluated only once per step
@ -503,25 +502,31 @@ namespace test{
CHECK (3*4 == *jj);
++jj;
CHECK (fact == -2*3); // NOTE : functor is evaluated on first demand
CHECK (-2*3*3 == *jj); // ...which happens on yield (access the iterator value)
CHECK (fact == 2*2*3); // and this also causes the side-effect
CHECK (-2*3*3 == *jj);
CHECK (-2*3*3 == *jj);
CHECK (fact == 2*2*3);
CHECK (fact == 2*2*3); // no further evaluation and thus no further side-effect
++jj;
CHECK (fact == -2*2*2*3);
CHECK (2*2*3*2 == *jj);
CHECK (fact == -2*2*2*3);
fact = -23;
CHECK (2*2*3*2 == *jj);
++jj;
CHECK (fact == 2*23);
CHECK (fact == -23);
CHECK (-23*1 == *jj);
CHECK (fact == 2*23);
++jj;
CHECK (fact == 2*23);
CHECK (isnil (jj));
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #888
CHECK (fact == 2*23);
VERIFY_ERROR (ITER_EXHAUST, *ii );
CHECK (fact == 2*23); // exhaustion detected on source and thus no further evaluation
}

View file

@ -5344,7 +5344,7 @@
</node>
<node CREATED="1511831658137" ID="ID_295934398" MODIFIED="1511831665696" TEXT="Dekorator-Ansatz">
<icon BUILTIN="forward"/>
<node CREATED="1512262147649" ID="ID_1592901896" MODIFIED="1512262272749" TEXT="Dekorator auf Core">
<node CREATED="1512262147649" FOLDED="true" ID="ID_1592901896" MODIFIED="1512271476980" TEXT="Dekorator auf Core">
<icon BUILTIN="button_cancel"/>
<node CREATED="1512262162366" ID="ID_1471773970" MODIFIED="1512262276131" TEXT="kann direkt Core -&gt; Core verarbeiten">
<icon BUILTIN="idea"/>
@ -5442,10 +5442,19 @@
<node CREATED="1512010566105" ID="ID_1750414732" MODIFIED="1512010610681" TEXT="Umbenennung: _DecoratorTraits">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1512010575367" ID="ID_736035875" MODIFIED="1512010607511" TEXT="soll k&#xfc;nftig zwei F&#xe4;lle unterst&#xfc;tzen">
<icon BUILTIN="yes"/>
<node CREATED="1512010575367" ID="ID_736035875" MODIFIED="1512271535475" TEXT="soll k&#xfc;nftig zwei F&#xe4;lle unterst&#xfc;tzen">
<icon BUILTIN="button_cancel"/>
<node CREATED="1512010586173" ID="ID_1016627565" MODIFIED="1512010597616" TEXT="Finde parent-Iterator"/>
<node CREATED="1512010598540" ID="ID_771604715" MODIFIED="1512010603735" TEXT="Finde parent-Core"/>
<node CREATED="1512010598540" ID="ID_771604715" MODIFIED="1512271540773" TEXT="Finde parent-Core">
<icon BUILTIN="button_cancel"/>
<node CREATED="1512271542268" ID="ID_1668978885" MODIFIED="1512271546128" TEXT="war keine gute Idee"/>
</node>
</node>
<node CREATED="1512271554250" ID="ID_6017634" MODIFIED="1512271576099" TEXT="gel&#xf6;st durch stets regelm&#xe4;&#xdf;igen Aufbau der Dekorator-Kette">
<node CREATED="1512271577423" ID="ID_1273633642" MODIFIED="1512271590865" TEXT="TreeExplorer wird gestrippt"/>
<node CREATED="1512271591477" ID="ID_1932230950" MODIFIED="1512271605470" TEXT="Konsequenz: unmittelbare Src == Lumiera Iterator stets">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1511837060201" ID="ID_88038793" MODIFIED="1512010385590" TEXT="brauche WrappedIteratorCore">
@ -5466,11 +5475,12 @@
<node CREATED="1512182296169" ID="ID_770503153" MODIFIED="1512182333744" TEXT="mu&#xdf; Info aus dem Funktor gewinnen">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1512182308255" ID="ID_215116122" MODIFIED="1512183510137" TEXT="komme mit generischem Lambda in den Value-Zweig">
<node COLOR="#338800" CREATED="1512182308255" FOLDED="true" ID="ID_215116122" MODIFIED="1512271761209" TEXT="komme mit generischem Lambda in den Value-Zweig">
<linktarget COLOR="#a83e54" DESTINATION="ID_215116122" ENDARROW="Default" ENDINCLINATION="351;347;" ID="Arrow_ID_891457048" SOURCE="ID_23118252" STARTARROW="None" STARTINCLINATION="683;0;"/>
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1512182336428" ID="ID_1075031476" MODIFIED="1512182799182" TEXT="WTF??">
<icon BUILTIN="pencil"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1512182336428" ID="ID_1075031476" MODIFIED="1512271631969" TEXT="WTF??">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1512182366016" ID="ID_146727217" MODIFIED="1512182454305">
<richcontent TYPE="NODE"><html>
@ -5541,12 +5551,12 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1512183184560" ID="ID_1174618775" MODIFIED="1512183215189" TEXT="Anpassungs-Logik fehlt">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1512183184560" ID="ID_1174618775" MODIFIED="1512271661006" TEXT="Anpassungs-Logik fehlt">
<icon BUILTIN="button_ok"/>
<node CREATED="1512183196119" ID="ID_1543276489" MODIFIED="1512183210239" TEXT="hatte nur den Sonnenschein-Fall gecodet">
<icon BUILTIN="smiley-angry"/>
</node>
<node CREATED="1512183218675" ID="ID_293046899" MODIFIED="1512250712443" TEXT="brauche Adapter um yield">
<node CREATED="1512183218675" FOLDED="true" ID="ID_293046899" MODIFIED="1512271754033" TEXT="brauche Adapter um yield">
<icon BUILTIN="button_cancel"/>
<node CREATED="1512183306032" ID="ID_710747972" MODIFIED="1512183310819" TEXT="normalerweise 1:1"/>
<node CREATED="1512183311551" ID="ID_783747294" MODIFIED="1512183352965" TEXT="aber je nach Funktion...">
@ -5612,12 +5622,11 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1512183706657" ID="ID_1135345978" MODIFIED="1512183725664" TEXT="oder: dritter Zweig in ArgAcessor?">
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="idea"/>
<node CREATED="1512183706657" FOLDED="true" ID="ID_1135345978" MODIFIED="1512271747585" TEXT="oder: dritter Zweig in ArgAcessor?">
<icon BUILTIN="button_cancel"/>
<node CREATED="1512251027232" ID="ID_755375196" MODIFIED="1512251042682" TEXT="soll also universell die F&#xe4;lle adaptieren k&#xf6;nnen"/>
<node CREATED="1512251172916" ID="ID_378084629" MODIFIED="1512251199899" TEXT="Entscheidung: StateCore wird bevorzugt">
<icon BUILTIN="yes"/>
<node CREATED="1512251172916" ID="ID_378084629" MODIFIED="1512271739160" TEXT="Entscheidung: StateCore wird bevorzugt">
<icon BUILTIN="button_cancel"/>
<node CREATED="1512251214046" ID="ID_1353274464" MODIFIED="1512251270499" TEXT="Konsequenz: alle Layer m&#xfc;ssen StateCore sein">
<richcontent TYPE="NOTE"><html>
<head>
@ -5635,7 +5644,12 @@
</node>
<node CREATED="1512251276054" ID="ID_236669144" MODIFIED="1512251283329" TEXT="Kurzschlu&#xdf; Core -&gt; Core"/>
</node>
<node CREATED="1512251305810" ID="ID_737982099" MODIFIED="1512251319908" TEXT="Iterator nur, wenn Quelle keine Core ist"/>
<node CREATED="1512251305810" ID="ID_737982099" MODIFIED="1512271742802" TEXT="Iterator nur, wenn Quelle keine Core ist">
<icon BUILTIN="stop-sign"/>
</node>
</node>
<node COLOR="#338800" CREATED="1512271698231" ID="ID_1260885042" MODIFIED="1512271712854" TEXT="gel&#xf6;st durch Bereinigung des Design">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -5761,25 +5775,26 @@
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1511835550655" ID="ID_1305788204" MODIFIED="1511835762571" TEXT="Transformer(Iter&lt;Core&gt;)">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1511835603751" ID="ID_6147833" MODIFIED="1511835760603" TEXT="Transformer(Iter&lt;Val&gt;)">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1511835603751" ID="ID_6147833" MODIFIED="1512276267722" TEXT="Transformer(Iter&lt;Val&gt;)">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1511835572331" ID="ID_90684440" MODIFIED="1511835751909" TEXT="Transformer(Core)">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1511835638915" ID="ID_678182318" MODIFIED="1511835751909" TEXT="geht nicht direkt auf TreeExplorer"/>
<node CREATED="1511835638915" ID="ID_678182318" MODIFIED="1512276256127" TEXT="nicht m&#xf6;glich direkt auf TreeExplorer"/>
<node CREATED="1511835650761" ID="ID_1585618081" MODIFIED="1511835751909" TEXT="aber chained Transform sollte so funktionieren"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1511835667743" ID="ID_1089942674" MODIFIED="1511835751909" TEXT="Typ verifizieren!">
<font NAME="SansSerif" SIZE="10"/>
<icon BUILTIN="flag-pink"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1511835716176" ID="ID_1407397782" MODIFIED="1511835898309" TEXT="Transformer mit Seiteneffekt">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1511835716176" ID="ID_1407397782" MODIFIED="1512276211354" TEXT="Transformer mit Seiteneffekt">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1511835691963" ID="ID_175353270" MODIFIED="1511835736414" TEXT="Transform: generic Lambda">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1512181454244" ID="ID_23118252" MODIFIED="1512183510137" TEXT="AUA: warum wird hier ein Value als Arguement &#xfc;bergeben">
<node COLOR="#338800" CREATED="1511835691963" ID="ID_175353270" MODIFIED="1512276275698" TEXT="Transform: generic Lambda">
<icon BUILTIN="button_ok"/>
<node CREATED="1512181454244" ID="ID_23118252" MODIFIED="1512271778125" TEXT="AUA: warum wird hier ein Value als Arguement &#xfc;bergeben">
<arrowlink COLOR="#a83e54" DESTINATION="ID_215116122" ENDARROW="Default" ENDINCLINATION="351;347;" ID="Arrow_ID_891457048" STARTARROW="None" STARTINCLINATION="683;0;"/>
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="help"/>
</node>
<node COLOR="#338800" CREATED="1512181480616" FOLDED="true" ID="ID_1099744034" MODIFIED="1512355551250" TEXT="Beobachtung: move in join">