Commit graph

5666 commits

Author SHA1 Message Date
03a1d58198 EventLog: verify and complete the TestEventLog_test
can now cover all the cases as initially intended,
including backtracking
2018-09-19 02:52:38 +02:00
3994f805b0 EventLog: further bugfix to get the augmented sequencing logic correct.
For the before / after chaining search functions,
we now do one single step in the respective direction before evaluating
the new (next) filter condition. However, we also need to *deactivate* the
previous condition, otherwise that single "step" might cause us to jump
or even exhaust the underlying filter, due to the old filter condition
still being applied.
2018-09-19 01:24:26 +02:00
991b8ace82 EventLog: rectify the quirky logic for before / after chains
due to the lack of real backtracking, the existing solution
relied on a quirk, and started the before / after chained search
conditions /at/ the current element, not after / before it.

Now we're able to remove this somewhat surprising behaviour, yet to do so
we also need to introduce basic "just search" variations of all search
operations, in order to define the initial condition for a chained search.
Without that, the first condition in a chain would never be able to
match on the header entry of the log
2018-09-19 00:21:09 +02:00
0c7996fe90 EventLog: drop-in the new IterChainSerach engine
- need to use dedicated steps in the chain for every added condition now

- seems to break the logic on tests on non-match.
  This doesn't come as a surprise, since backtracking can be expected
  to reveal additional solutions.

NOTE: some tests broken, to be investigated

est-event-log-test.cpp:228: thread_1: verify_callLogging: (log.ensureNot("fun").after("fun").after("fun2"))
2018-09-16 03:02:22 +02:00
1683439b32 ChainSearch: backtracking verified -- finished 2018-09-16 01:08:49 +02:00
84399aa407 ChainSearch: verify proper interplay of two dynamic search conditions 2018-09-16 01:08:49 +02:00
84c30fe802 ChainSearch: need to gear up immediately after backtracking
...which can be achieved by checking the backtracking loop
always right after the non-backtracking iteration, exploiting
the fact that the guard conditions of both are complimentary.
So the only case when we'd actually enter the backtracking
loop after regular iteration would precisely be when
we drop down due to exahausting an upper layer.

The result now reads

"sausage-bacon-tomato-and-spam-spam-bacon-spam-tomato-and-spam-bacon-tomato-and-bacon-tomato-and-tomato-and"

...which sounds correct, yay!
2018-09-16 01:08:48 +02:00
646a2e42cf ChainSearch: need to overload also the iterator function
...since usually such evaluation layers are finally wrapped into
an IterableDecorator and then presented as TreeEplorer -- an exercise
we do not want to perform here, since it is pointless in the typicall
use case. The IterChainSearch is already meant to be ready-for-use.

Thus, instead of wrapping again, the pragmatic solution is simply
to overload the missing operator++ and make it call the augmented
iterNext() function. Related to this, we also need to ensure
proper operation in case no further expansion is mandated
2018-09-16 01:08:48 +02:00
38a1aad897 ChainSearch: bugfixes on reworked construction
...seems basically sane now.
Just we still need to wrap it one more time into IterableDecorator;
which means the overall scheme how to build and package the whole pipeline
is not correct yet.

Maybe it is not possible to get it packaged all into one single class?
2018-09-16 01:08:48 +02:00
05e6e7f316 ChainSearch: remould construction to get the logic correct
on closer investigation it turned out that the logic of the
first design attempt was broken altogether. It did not properly
support backtracking (which was the reason to start this whole
exercise) and it caused dangling references within the lambda
closure once the produced iterator pipeline was moved out
into the target location.

Reasoning from first principles then indicated that the only sane
way to build such a search evaluation component is to use *two*
closely collaborating layers. The actual filter configuration
and evaluation logic can not reside and work from within the
expander. Rather, it must sit in a layer on top and work in
a conventional, imperative way (with a while loop).

Sometimes, functional programming is *not* the natural way
of doing things, and we should then stop attempting to force
matters against their nature.
2018-09-16 01:08:45 +02:00
767156e912 TreeExplorer: unit test coverage for injected custom layer 2018-09-16 01:07:23 +02:00
09d923db06 TreeExplorer: add the ability to inject a custom defined layer
this is an rather obvious extension to the TreeExplorer framework.
In some cases, client code wants to define its own very specific
processing layers, beyond of what can be done with filters and
transformers. Obviously, writing such a custom layer requires
intimate knowledge about the internals of TreeExplorer

the actual use case prompting this extension is IterChainSearch;
it turned out that the original design can not be implemented,
unless the resulting object is non-copyable (which violates
the basic traits of a TreeExplorer based pipeline).
2018-09-15 03:09:48 +02:00
0626444855 Improve where transport controls are actually defined
Paragraph ordering was somewhat confusing: you talk about
transport controls before defining what they actually are. Better
to define them first so that the reader knows what you are talking
about.
2018-09-14 22:01:01 +02:00
8fd1941c14 supply the definition for the term 'Viewer Switch Board' 2018-09-14 21:43:53 +02:00
860da2d401 Review glossary and add missing definition
Noticed the term 'viewer switch board'.
Is mentioned in the intro.txt. Need defining and mentioning etc

Add stupid definition of a Viewer Switch Board
2018-09-14 21:37:59 +02:00
e4ef2e9dde DOC: Improve slightly 'Lumiera As seen From Outer Space' 2018-09-14 21:37:59 +02:00
99ea662876 Fix gramatical error 2018-09-14 21:26:58 +02:00
9cf5c4c37e Add link to Mailing List and IRC under contributing
The important page on contacting Lumiera was buried below
somewhere in Contributing to Lumiera. This information must
be provided top-level and easily accessible. So I've added it,
maybe not terribly suitably, to the tutorials page. However its
position there is saved and justified by placing it under the
tutorial on contributing to Lumiera.
Maybe someone has a better idea.
2018-09-14 21:26:57 +02:00
2bd38e46c1 Add xmlto dependency 2018-09-14 21:26:57 +02:00
f4244b9d96 Fix GDL-mm build
Description of building GDL-mm was defect.
2018-09-14 21:26:57 +02:00
aea64d1fbc Fix and update some links
- Cinelrra-CV is now at cinelerra-cv.org
- Fix links to the embedded Reports of Openhub.net
2018-09-14 21:23:06 +02:00
8aae789b82 ChainSearch: test case to scrutinise chained filter reconfiguration
...and TADAA ... there we get an insidious bug:

we capture *this by reference into the expansion functor,
and then we move *this away, out from the builder into the target....
2018-09-14 21:06:15 +02:00
29d2c151b3 ChainSearch: add builder function just to replace the filter
Up to now, we had a very simplistic configuration option just
to search for a match, and we had the complete full-blown reconfiguration
builder option, which accepts a functor to work on and reconfigure the
embedded Filter chain.

It occurred to me that in many cases you'd rather want some intermediary
level of flexibility: you want to replace the filter predicate entirely
by some explicitly given functor, yet you don't need the full ability
to re-shape the Filter chain as a whole. In fact the intended use case
for IterChainSearch (which is the EventLog I am about to augment with
backtracking capabilities) will only ever need that intermediate level.


Thus wer're adding this intermediary level of configurability now.

The only twist is that doing so requires us to pass an "arbitrary function like thing"
(captured by universal reference) through a "layer of lambdas". Which means,
we have to capture an "arbitrary thingie" by value.

Fortunately, as I just found out today, C++14 allows something which comes
close to that requirement: the value capture of a lambda is allowe to have
an intialiser. Which means, we can std::forward into the value captured
by the intermediary lambda. I just hope I never need to know or understand
the actual type this captured "value" takes on.... :-)
2018-09-14 21:06:15 +02:00
10f21f77f8 ChainSearch: resolve the problems and get basic functionality to work
with the augmented TreeExplorer, we're now able to get rid of the
spurious base layer, and we're able to discard the filter and
continue with the unfiltered sequence starting from current position.
2018-09-14 21:06:15 +02:00
df7a9492b7 TreeExplorer: helper function so support ChainSearch::clearFilter()
build a special feature into the Explorer component of TreeExplorer,
causing it to "lock into" the current child sequence and discard
all previous sequences from the stack of child explorations
2018-09-14 21:06:15 +02:00
5b92f5cf74 ChainSearch: fix broken logic when configuring base layer
There is an asymetry, insofar the base layer configuration is
evaluated immediately, causing the MutableFilter to be reconfigured
and forwarded to the first match.

to the contrary, when configuring an additional layer, we just
add it to the chain, but then need to iterate once to cause
this configuration actually to be unfolded onto the stack
2018-09-14 21:06:15 +02:00
2ca3e95e9e ChainSearch: allow for overconstrained search
...which just turns the pipeline into exhausted state,
instead of raising an Assertion failure

The point is, expandChildren() does not guard itself,
since it _requires_ an non-empty iterator as precondition.
Thus, any function downstream, which invokes expandChildren(),
has to check and guard this call apropriately.

In the concrete case at hand we just stop adding further constraints
when the pipeline is already in exhausted state
2018-09-14 21:06:15 +02:00
0eec4d3b5f ChainSearch: now use the improved TreeExplorer capabilities to address the shortcoming
...the solution built thus far was logically broken, since it retained the unfiltered
source sequence within the base layer. Thus it would backtrack into this unfiltered
sequence eventually.

The idea was to build a special treatment for attaching the first filter condition;
in fact the first one does not need to be added to the chain, but rather should be
planted directly into the base layer.

WIP: this is a solution draft, but does not work yet
  - when attaching the base layer, the filter is pulled twice
  - an overconstrained filter raises an Assertion failure
    (instead of just transitioning into exhausted state)
2018-09-14 21:06:15 +02:00
5b84e0e823 TreeExplorer: remove spurous function template argument
In all practical use cases, this argument gets the same type as the
SRC template argument of _FunTraits
2018-09-14 21:06:15 +02:00
7cdd680e78 TreeExplorer: clean-up after refactoring
So we have now a reworked version of the internals of TreeExplorer in place.
It should be easier to debug template instantation traces now, since most
of the redundancy on the type parameters could be remove. Moreover, existing
pipelines can now be re-assigned with similarily built pipelines in many cases,
since the concrete type of the functor is now erased.

The price tag for this refactoring is that we have now to perform a call
through a function pointer on each functor invocation (due to the type erasure).
And seemingly the bloat in the debugging information has been increased slightly
(this overhead is removed by stripping the binary)
2018-09-14 21:06:15 +02:00
9067740456 TreeExplorer: refactor Expander to fit in with the reworked design
Here the design trardeoff becomes clearly visiblie
- on the plus side, we removed that spurous redundant info
  from the template parameter, and we simplified functor rebinding
- but as a tradeoff, we now always have two std::function objects
  nested into each other, which also means that at least the outer
  object resides on the heap and /inevitably/ calls through a
  function pointer, even in case the target function is a lambda,
  simply because some type erasure happened, and the call site
  does not know the actual type anymore
2018-09-14 21:06:15 +02:00
36d79be8b2 TreeExplorer: refactor Filter in a similar way 2018-09-14 21:06:15 +02:00
1e657acbff TreeExplorer: refactor Transformer to employ the improved wrapping style
...step by step switch over to the new usage pattern.
Transformer should be the blueprint for all other functor usages.


The reworked solutions behaves as expected;
we see two functor invocations; the outer functor, which does
the argument adaptation, is allocated in heap memory
2018-09-14 21:06:15 +02:00
a91025bfe0 TreeExplorer: perpare a builder for a suitably adapted, wrapped functor.
This does not touch the existing code-path,
but the idea is to use the _FunTraits directly from within the
constructor of the respective processing layer, and to confine the
knowledge of the actual FUN functor type to within that limited context.
Only the generic signature of the resulting std::function need to be
encoded into the type of the processing component, which should help
to simplify the type signatures
2018-09-14 21:06:15 +02:00
a175306f50 TreeExplorer: allow to drive the function traits solely by the function signature
...which still needs to be the *concrete* signature of the funcition to pass,
but we'll attempt to loosen that requirement in the next refactoring steps
2018-09-14 21:06:15 +02:00
5d4f1015aa TreeExplorer: consider refactoring of the functor adaptatiion mechanism
...and in preparation start with some renamings...


The overall goal is to simplify the type signatures and thereby
to make the generates pipelines more assignment compatible.

The debugging experience form the last days indicated that the
current design is not maintainable on the long run. Both the
template instantiation chains and the call stacks are way to
complicated and hard to understand and diagnose
2018-09-14 21:06:15 +02:00
e3ca8548a4 TreeExplorer: allow for a disabled filter
...considered as one of the building blocks to resolve Problems in the Design of ChainSearch
2018-09-14 21:06:15 +02:00
34b78fc47e ChainSearch: identify some possible problems
- as implemented now, we will finally backtrack into the unfiltered base iterator
- it is not possible to implement a clearFilter() operation
2018-09-14 21:06:15 +02:00
c0b8b63df0 ChainSearch: ensure to pass current state without spurious copy
It is essential that we pass the current state of the filter
into the expand functor, where it needs to be copied (once!)
to create a child state, which can then be augmented.

This augmented state is then pushed onto a stack, to enable backtracking.


Due to the flexible adapters and the wrapping into the TreeExplorer builder,
we ended up performing several spurious copies on the current state
2018-09-14 21:06:14 +02:00
d923138d1c ChainSearch: configure the core of the chained search mechanism
...based on a monadic tree expansion: we define a single step,
which takes the current filter configuration and builds the next
filter configuration, based on a stored chain of configuration functions

The actual exhausting depth-first results just by the greedy application pattern,
and uses the stack embedded in the "Explorer" layer of TreeExplorer
2018-09-14 21:06:14 +02:00
2b72175e04 ChainSearch: Storage for the filter chain 2018-09-14 21:06:14 +02:00
d398177a71 ChainSearch: now actually build the processing pipeline in the ctor
..this resolves the most challenging part of the construction work;
we use the static helper functions to infer a type and construct a suitable
processing pipeline and we invoke the same helper to initialise the base class
in the ctor.

Incidentally... we can now drop all the placeholder stubs,
since we now inherit the full iterator and child explorer API.
The test now starts actually to work... we get spam and sausage!

TODO: now actually fill in the expand functor such as to pick the
concrete filter step in the chain from a sequence of preconfigured
filter bindings
2018-09-14 21:06:14 +02:00
9b0937bc63 ChainSearch: move into namespace iter
...seems to be a not-so-commonly used helper
2018-09-14 21:06:14 +02:00
a52ed91de0 ChainSearch: draft a solution how to construct the Expand functor type
...now matters start to get really nasty,
since we have to pick up an infered type from a partially built pipeline
and use it to construct the signature for a functor to bind into the more elaborate complete pipeline
2018-09-14 21:06:14 +02:00
6834c26470 ChainSearch: draft a solution how to construct the pipeline builder base type
this is a tricky undertaking, since our treeExplore() helper constructs
a complex wrapped type, depending on the actual builder expressions used.

Solution is to use decltype on the result of a helper function,
and let the _DecoratorTraits from TreeExplorer do the necessary type adaptations
2018-09-14 21:06:14 +02:00
37b2e2e4ad TreeExplorer: prevent ill guided type adaptor choice
when adapting a functor, the wrapper automatically decides
if this functor was meant to be used in "monadic style" (value -> new monad)
or in "manipulate state-core style"  (iter& -> iter)

Unfortunately, in some cases functions accepting a partially built pipeline
will be classified in the wrong way, due to the fact that IterableDecorator
has a templated wildcard constructor and thus seems to accept the conversion
value_type -> IterableDecorator. This causes the "monadic style" to be chosen
erroneously, and leads to a template instantiation failure just at the point when
the generated functor will be used.

The solution is to explicitly *rule out* the monadic usage style
in all those cases, where the *argument* of the functor to bind can
in fact be directly constructed / converted from the source iterator
or state core. Because, if that is the case
- it is superfluous explicitly to dereference the source iterator;
  the functor can do the same
- chances are that the "manipulation style" was intended
  (as was the case in the concrete example at hand here)
2018-09-14 21:06:14 +02:00
4988153e15 Library: prevent implicit bool conversion on iterator-like objects
...it should have been this way all the time.
Generic code might otherwise be ill guided to assume a conversion
from the Iterator to its value type, while in fact an explicit dereferentiation is necessary
2018-09-14 21:06:14 +02:00
99e3eeca9f Library: formatting of simplified types adjusted
Need to be more careful when eating trailing spaces after a std::string.
Because the full-blown type is a template, sometimes the compiler adds a spurious
additional space behind the closing angle bracket, due to the now obsolete
"maximum munch rule" of C++98 -- to prevent closing angle brackets to become '>>'.
But in other cases, some type adornments or other language identifiers follow the
string type, like e.g. 'const'. In those cases, the trailing space must be retained.

We solve this by a look-ahead assertion in the regular expression:
consume the trailing space _only_ if a non-word character follows (like '>').
2018-09-14 21:06:14 +02:00
433543a2c7 DOC: some doxygen fixes 2018-09-14 21:06:14 +02:00
ec8d0557e8 ChainSearch: draft interface and possible implementation approach
The intention is to augment the iterator based (linear) search
used in EventLog to allow for real backtracking, based on a evaluation tree.
This should be rather staight forward to implement, relying on the
exploreChildren() functionality of TreeExplorer. The trick is to package
the chained search step as a monadic flatMap operation
2018-09-14 21:06:14 +02:00