From 1fdeb08f199480be667865d86458aafad63ee30f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 17 Dec 2017 03:02:00 +0100 Subject: [PATCH] TreeExplorer: finished and unit test PASS several extensions and convenience features are conceivable, but I'll postpone all of them for later, when actual need arises Note especially there is one recurring design challenge, when creating such a demand-driven tree evaluation: more often than not it turns out that "downstream" will need some information about the nested tree structure, even while, on the surfice, it looks as if the evaluation could be working completely "linearised". Often, such a need arises from diagnostic features, and sometimes we want to invoke another API, which in turn could benefit from knowing something about the original tree structure, even if just abstracted. I have no real solution for this problem, but implementing this pipeline builder leads to a pragmatic workaround: since the iterator already exposes a expandChildren(), it may as well expose a depth() call, even while keeping anything beyond that opaque. This is not the clean solution you'd like, but it comes without any overhead and does not really break the abstraction. --- src/lib/iter-tree-explorer.hpp | 11 +- tests/12metaprogramming.tests | 5 +- tests/library/iter-tree-explorer-test.cpp | 36 +++--- wiki/renderengine.html | 43 ++----- wiki/thinkPad.ichthyo.mm | 133 ++++++++++++---------- 5 files changed, 106 insertions(+), 122 deletions(-) diff --git a/src/lib/iter-tree-explorer.hpp b/src/lib/iter-tree-explorer.hpp index fb22357ca..9de94078e 100644 --- a/src/lib/iter-tree-explorer.hpp +++ b/src/lib/iter-tree-explorer.hpp @@ -118,7 +118,6 @@ #include "lib/iter-source.hpp" /////////////TICKET #493 : only using the IterSource base feature / interface here. Should really split the iter-source.hpp #include "lib/iter-stack.hpp" #include "lib/util.hpp" -#include "lib/test/test-helper.hpp"///////////TODO Bug-o #include #include @@ -547,11 +546,11 @@ namespace lib { ResIter expanded{ hasChildren()? expandChildren_(*expansions_) : expandChildren_(*this)}; - incrementCurrent(); // consume current head element + incrementCurrent(); // consume current head element (but don't clean-up) if (not isnil(expanded)) expansions_.push (move(expanded)); else - dropExhaustedChildren(); + dropExhaustedChildren(); // clean-up only here to preserve the logical depth ENSURE (invariant()); } @@ -629,7 +628,7 @@ namespace lib { * be several flavours of child expansion. Unfortunately, most of these conceivable extensions would * require a flexibilisation of Expander's internals and thus increase the complexity of the code. * Thus, if ever encounter the need of anything beyond the basic expansion pattern, we should - * rework the design of Expander and introduce building blocks to define the evaluation strategy. + * rework the design of Expander and introduce building blocks to define the evaluation strategy. */ template class AutoExpander @@ -820,8 +819,10 @@ namespace lib { /** - * Interface to indicate the ability for _child expansion_. + * Interface to indicate and expose the ability for _child expansion_. * This interface is used when packaging a TreeExplorer pipeline opaquely into IterSource. + * @remark the depth() call indicates the depth of the child expansion tree. This information + * can be used by a "downstream" consumer to react according to a nested scope structure. * @todo expandChildren() should not return the value pointer. * This is just a workaround to cope with the design mismatch in IterSource; * the fact that latter just passes around a pointer into the implementation is diff --git a/tests/12metaprogramming.tests b/tests/12metaprogramming.tests index 0118f0bae..b559425aa 100644 --- a/tests/12metaprogramming.tests +++ b/tests/12metaprogramming.tests @@ -252,7 +252,10 @@ return: 0 END -PLANNED "Iterator monad variations (2nd draft)" IterTreeExplorer_test <; DataSrc searchSpace = treeExplore(RandomSeq{-1}) - .expand([](char){ return RandomSeq{4}; }) + .expand([](char){ return RandomSeq{15}; }) .asIterSource(); // Layer-2: State for search algorithm @@ -982,20 +989,9 @@ namespace test{ { while (it->src.depth() < it->toFind.size() - 1 and it->isMatch()) - { - cout <<"|!| expand "<protocol)<expandChildren(); - cout <<"|.| "<<*(it->src)<<" -->> "<protocol)<isMatch(); - if (it->isMatch()) - return true; - else { - cout << "|↯| "<<*(it->src)<< " ... " <protocol)<isMatch(); }); diff --git a/wiki/renderengine.html b/wiki/renderengine.html index d51765837..5fdf0602b 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -4260,7 +4260,7 @@ The UI-Bus offers a dedicated API to direct ~MutationMessages towards {{{Tangibl In the case at hand, the basic building block of the Lumiera UI, the {{{Tangible}}} offers this interface and thus the ability to construct a concrete TreeMutator, which in turn is bound to the internals of the actual UI-Element in question. Together this allows for a generic implementation of MutationMessage handling, where the designated UI-Element is reshaped by applying a concrete diff sequence embedded in the message with the help of a {{{DiffApplicator<DiffMutable>}}}, based on the TreeMutator exposed. -
+
//Service to navigate through the UI as generic structure.//
 The Navigator is a component maintained by the InteractionDirector, and the actual implementation is backed by several facilities of the GuiTopLevel. It serves as foundation to treat the UI as a topological network of abstracted locations, represented as [[UI-Coordinates|UICoord]]. This design, together with the UI-Bus helps to reduce coupling within the UI implementation, since it enables to //get somewhere// and reach //some place// -- without the necessity to rely on concrete widget implementation structure.
 
@@ -4287,36 +4287,7 @@ In the current situation ({{red{10/2017}}}), before engaging into the actual imp
 
 !!!Requirements clarified
 From these use cases we conclude that the actual requirements for a Navigator component are less than one might expect.
-In fact it is sufficient to keep //the actual element// entirely opaque, so the Navigator works on UI coordinates solely. The result -- some other UI coordinates -- can then be used to accomplish some tasks implemented elsewhere, like allocating a new view or actually moving [[the Spot|Spot]] (&rarr; InteractionControl)
-
-!Challenges of the implementation
-Some tricky problems remain to be solved, though: since the Navigator works on UI coordinates, the fundamental problem remains how to acquire the initial coordinates to start navigation. This is a problem of //reverse lookup:// given a concrete element of the UI, find it's UI coordinates. While we should note that it might not be necessary to "discover" coordinates, because in fact we may know them already -- either the element has to store them (on creation), or some lookup index table could be maintained to serve the same purpose//Service to navigate through the UI as generic structure.//
-The Navigator is a component maintained by the InteractionDirector, and the actual implementation is backed by several facilities of the GuiTopLevel. It serves as foundation to treat the UI as a topological network of abstracted locations, represented as [[UI-Coordinates|UICoord]]. This design, together with the UI-Bus helps to reduce coupling within the UI implementation, since it enables to //get somewhere// and reach //some place// -- without the necessity to rely on concrete widget implementation structure.
-
-!The problem of abstraction
-This goal initially poses some challenge, since it aims beyond the conventional notion of UI programming, where it is sufficient just to wire some widgets and manipulate the receiver of an event notification. The usual UI widgets are just not meant to be treated in a more systematic, generic way -- and indeed, in most cases and for most purposes it is not a good idea to approach UI programming in a to much schematic way. User interfaces need to be tangible, something concrete, with lots of specifics and local traits. Yet this very nature of UI programming tends to turn some //cross-cutting concerns// into serious liabilities. So the deliberate ''decision to introduce a Navigator'' in avoidance of these future burdens and liabilities is a decision of priorities when it comes to shaping the Lumiera UI.
-
-Which leaves us with the quest of mapping a generic location scheme onto a load of implementation defined structures not exposing any kind of genericness, and to accomplish this within an environment lacking meta information and support for self discovery beyond the most basic abstraction level. As a first step towards bridging this gap, we'll have to identify the actual //command-and-query operations// required to treat UI elements as a topological structure.
-
-!!!Analysis of expected functionality
-In order to build a navigation facility, we need to...
-* follow a path
-** which means to constitute a location
-** and to discover child nodes at that location
-* and we might want to extend (maybe also prune) the collection of children
-
-!!!Use cases
-In the current situation ({{red{10/2017}}}), before engaging into the actual implementation, we're able to identify two distinct use cases
-;View [[specification|GuiComponentView]]
-:locate a view based on a preconfigured placement
-:* either to allocate a new view instance
-:* or to get //just some instance// of a view identified by type
-;WorkSite navication
-:move the Spot to some other place in the UI known by its [[UI-Coordinates|UICoord]]
-
-!!!Requirements clarified
-From these use cases we conclude that the actual requirements for a Navigator component are less than one might expect.
-In fact it is sufficient to keep //the actual element// entirely opaque, so the Navigator works on UI coordinates solely. The result -- some other UI coordinates -- can then be used to accomplish some tasks implemented elsewhere, like allocating a new view or actually moving [[the Spot|Spot]] (&rarr; InteractionControl)
+In fact it is sufficient to keep //the actual element// entirely opaque, so the Navigator works on [[UI coordinates|UICoord]] solely. The result -- some other UI coordinates -- can then be used to accomplish some tasks implemented elsewhere, like allocating a new view or actually moving [[the Spot|Spot]] (&rarr; InteractionControl)
 
 !Challenges of the implementation
 Some tricky problems remain to be solved, though: since the Navigator works on UI coordinates, the fundamental problem remains how to acquire the initial coordinates to start navigation. This is a problem of //reverse lookup:// given a concrete element of the UI, find it's UI coordinates. While we should note that it might not be necessary to "discover" coordinates, because in fact we may know them already -- either the element has to store them (on creation), or some lookup index table could be maintained to serve the same purpose
@@ -9773,7 +9744,7 @@ The dispatch of //diff messages// is directly integrated into the UI-Bus -- whic
 
 The Graphical User interface, the upper layer in this hierarchy, embodies everything of tangible relevance to the user working with the application. The interplay with Proc-Layer, the middle layer below the UI, is organised along the distinction between two realms of equal importance: on one side, there is the immediate //mechanics of the interface,// which is implemented directly within the ~UI-Layer, based on the Graphical User Interface Toolkit. And, on the other side, there are those //core concerns of working with media,// which are cast into the HighLevelModel at the heart of the middle layer.
-
+
//A topological addressing scheme to designate structural locations within the UI.//
 Contrary to conventional screen pixel coordinates, here we aim at a topological description of the UI structure. Such a framework of structural reference allows us                                                                     
 * to refer to some "place" or "space" within the interface                                    
@@ -9789,12 +9760,12 @@ As starting point for the design of such a framework, we'll pick the notion of a
 * plus a locally defined access path further down to the actual UI element
 
 !Properties
-UI coordinates are a symbolic specification, and as such, their representation is immutable value-like. Essentially, a coordinate specification designates a pathway, and thus is comprised of a sequence of symbols. The individual path component symbol can be addressed by its depth index, starting with the top level window as rooting point. The meaning of first steps of each path is thus always fixed (window, perspective, panel, view), followed by an essentially open sequence of local component names. Yet a given index position need not necessarily be actually defined. A coordinate spec can be indeterminate (nil), but in all other cases a minimal consecutive sequence of symbols is guaranteed to exist.
+UI coordinates are a symbolic specification, and as such, their representation is immutable value-like. Essentially, a coordinate specification designates a pathway, and thus is comprised of a sequence of symbols. The individual path component symbol can be addressed by its depth index, starting with the top level window as rooting point. The meaning of first steps within each path is thus always fixed (top-level window, perspective, panel, view), followed by an essentially open sequence of local component names. Yet a given index position need not necessarily be actually defined. A coordinate spec can be indeterminate (NIL), but in all other cases a minimal consecutive sequence of symbols is guaranteed to exist.
 
 !!!flavours of meaning
 A given coordinate spec needs to be //interpreted// with the help of a resolver, which supplies additional knowledge regarding the actual window and UI configuration backing those interpretations. Such an interpretation allows to query for some typical predications, and it allows for //mutating operations,// which actually build a new coordinate spec from the given one. The general assumption is for all those coordinate interpretations to happen not within an excessively performance critical zone, where a little bit of iteration and repeated recomputation is deemed less costly than extended caching of evaluation state.
 
-The first distinction to draw is the ''anchor point'' of a given coordinate spec. After anchoring, the designated path is explicitly rooted within a top level window. Obviously, the act of anchoring can be obvious(trivial), it can be //covered by wildcard,// or it can be a free interpolation or match against the existing environment. Starting from the anchor, the next predication to consider is the ''coverage'': the extent to which a given coordinate spec is actually covered by real UI structures. The test for coverage starts at the anchor point and descends following the coordinate spec in question. Backed by this evaluation process of interpretation and matching, we may judge a coordinate spec with respect to several predications
+The first distinction to draw is the ''anchor point'' of a given coordinate spec. After anchoring, the designated path is explicitly rooted within a top level window. The act of anchoring can thus be obvious(trivial), it can be //covered by wildcard,// or it can be a free interpolation or match against the existing environment. Starting from the anchor, the next predication to consider is the ''coverage'': the extent to which a given coordinate spec is actually covered by real UI structures. The test for coverage starts at the anchor point and descends following the coordinate spec in question. Backed by this evaluation process of interpretation and matching, we may judge a coordinate spec with respect to several predications
 * the coordinate spec may be totally ''explicit'' -- or it might contain wildcards
 * one specific path component of the coordinate spec may be known(present) or unknown
 * regarding the coverage, we may distinguish
@@ -9803,7 +9774,7 @@ The first distinction to draw is the ''anchor point'' of a given coordinate spec
 ** a coordinate spec impossible to cover
 
 !UI coordinate path evaluation
-As indicated above, evaluation of UI coordinates requires a resolver, and this evaluation process is //stateless.// Evaluation state is confined within the individual query or mutation call. Evaluation is accomplished by first constituting an anchoring, followed by traversal of the coordinate spec and matching against a navigation path within the actual UI window configuration. This process might involve interpretation of some meta-symbols and interpolation of wildcards.
+As indicated above, evaluation of UI coordinates requires a ''resolver'', and this evaluation process is //stateless.// Evaluation state is confined within the individual query or mutation call. Evaluation is accomplished by first constituting an anchoring, followed by traversal of the coordinate spec and matching against a navigation path within the actual UI window configuration. This process might involve interpretation of some meta-symbols and interpolation of wildcards.
 
 Internally the coordinate resolver in turn relies on a context query interface, to find out about existing windows, panels, views and tabs and to navigate the real UI structure. The actual implementation of this context query interface is backed by the [[Navigator]] component exposed through the InteractionDirector.
 !!!Query operations
@@ -9821,7 +9792,7 @@ In addition to the //locally decidable properties// of a coordinate spec, which
 :* it is //partially covered// with an remaining, uncovered extension part
 :* it is //possible to cover completely//
 :* it is //impossible to cover//
-__Some fine points to note__: Anchorage and coverage are not the same thing, but coverage implies anchorage. Only when a path is complete (starts with the window spec) and explicit (has no wildcards), then anchorage implies also partial coverage (namely at least to depth 1). To determine the possible coverage means to perform a resolution with backtracking to pick the maximal solution. Moreover, since "covered" means that the path specification //is at least partially supported by the real UI,// we establish an additional constraint to ensure this resolution did not just match some arbitrary wildcards. Rather we demand that beind / below the last wildcard there is at least one further explicit component in the path spec, which is supported by the real UI. As a consequence, the coverage resolution may fail altogether, will still providing at least an possible anchor point.
+__Some fine points to note__: Anchorage and coverage are not the same thing, but coverage implies anchorage. Only when a path is complete (starts with the window spec) and explicit (has no wildcards), then anchorage implies also partial coverage (namely at least to depth 1). To determine the possible coverage means to perform a resolution with backtracking to pick the maximal solution. Moreover, since "covered" means that the path specification //is at least partially supported by the real UI,// we establish an additional constraint to ensure this resolution did not just match some arbitrary wildcards. Rather we demand that beind / below the last wildcard there is at least one further explicit component in the path spec, which is supported by the real UI. As a consequence, the coverage resolution may fail altogether, while still providing at least a possible anchor point.
 !!!Mutations
 In addition to querying the interpretation of a given coordinate spec with respect to the current UI environment, it is also possible to rewrite or extend the spec based on this environment
 ;anchoring
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index e0d59f22a..51a2745f8 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -4739,7 +4739,7 @@
 
 
 
-
+
 
 
 
@@ -4963,7 +4963,7 @@
 
 
 
-
+
 
   
     
@@ -4977,7 +4977,8 @@
     

- + + @@ -5082,12 +5083,15 @@ + + - - + + + @@ -5111,8 +5115,7 @@ ich brauche ihn nicht

- - +
@@ -5133,8 +5136,7 @@ Lösung wäre, das Iterator-API erst nach einem expliziten terminalen Aufruf freizuschalten

- -
+
@@ -5147,9 +5149,10 @@ - + + @@ -5889,7 +5892,7 @@ - + @@ -5900,7 +5903,7 @@ - + @@ -6206,7 +6209,7 @@ - + @@ -6243,8 +6246,7 @@ an einen bestehenden Iterator angeschlossen

- - +
@@ -6301,8 +6303,7 @@ Das Ergebnis ist eben nicht rein linear.

- - +
@@ -6318,8 +6319,7 @@ ...das ist nämlich der triviale Workaround

- - +
@@ -6354,8 +6354,7 @@ noch bevor wir dazu kommen, die Kinder zu pushen

- - +
@@ -6366,7 +6365,7 @@
- + @@ -6374,7 +6373,7 @@ - + @@ -6667,8 +6666,8 @@ - - + + @@ -6728,13 +6727,17 @@ - - + + + + + - - + + + @@ -7127,8 +7130,8 @@ - - + + @@ -7141,7 +7144,7 @@ - + @@ -7159,8 +7162,7 @@ siehe std::shuffle

- - +
@@ -7170,7 +7172,7 @@ - + @@ -7184,7 +7186,8 @@ - + + @@ -7196,8 +7199,7 @@ vorgegebene Zahlenfolge
in untendlichem Zufalls-Baum finden

- -
+
@@ -7212,17 +7214,18 @@ - - - - + + + + + - - + + - + @@ -7241,8 +7244,8 @@ - - + + @@ -7251,9 +7254,15 @@ + + + + + - - + + + @@ -7276,24 +7285,25 @@ - + - + + - - + + - + - + @@ -7422,10 +7432,14 @@ |↯| X ... 40882

- -
+ +
+ + + + + - @@ -7524,8 +7538,7 @@ Protocol of the search: 77944-1-0-3-1

- -
+