Commit graph

608 commits

Author SHA1 Message Date
fa6ba76f85 investigate insidious ill-guided conversion
As it turns out, using the functional-notation form conversion
with *parentheses* will fall back on a C-style (wild, re-interpret) cast
when the target type is *not* a class. As in the case in question here, where
it is a const& to a class. To the contrary, using *curly braces* will always
attempt to go through a constructor, and thus fail as expected, when there is
no conversion path available.

I wasn't aware of that pitfall. I noticed it since the recently introduced
class TimelineGui lacked a conversion operator to BareEntryID const& and just
happily used the TimelineGui object itself and did a reinterpret_cast into BareEntryID
2018-10-12 23:42:56 +02:00
e81b0592d3 TreeMutator: combine no-op layer with selective other diff binding
...and complete unit test coverage.
This is complex stuff and we'd better be careful it actually works
2018-10-12 02:05:11 +02:00
fb93e349da TreeMutator: conjure up a black hole mutator
...which is a somewhat involved version of /dev/null
2018-10-11 23:56:33 +02:00
c6b8811af0 Library: utility to interpret a text as bool value (yes/no)
...also fixes the problem with the "expand" mark in DemoGuiRoundtrip
2018-10-03 04:43:16 +02:00
5a7a5a5720 DOC: fix syntax of some doxygen links
seemingly we really need the \ref in the link target expression
2018-09-21 14:33:12 +02:00
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
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
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
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
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
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
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
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
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
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
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
604ffbf73c TreeExplorer: fix a bug and finish the feature
we did an unnecessary copy of the argument, which was uncovered
by the test case manipulating the state core.


Whew.
Now we have a beautiful new overengineered solution
2018-09-14 21:06:14 +02:00
be7f47d5b7 TreeExplorer: rework the solution to allow for arbitrary functor types
outift the Filter base class with the most generic form of the Functor
wrapper, and rather wrap each functor argument individually. This allows
then to combine various kinds of functors
2018-09-14 21:06:14 +02:00
90c0f43cfd TreeExplorer: code all the combination cases
...this solution works, but has a shortcoming:
the type of the passed lambdas is effectively pinned to conform
with the signature of the first lambda used initially when building the filter.

Well, this is the standard use case, but it kind of turns all the
tricky warpping and re-binding into a nonsense excercise; in this form
the filter can only be used in the monadic case (value -> bool).

Especially this rules out all the advanced usages, where the filter
collaborates with the internals of the source.
2018-09-14 21:06:14 +02:00
e29d9ae19e TreeExplorer: better package this very specific code as subclass
while this is basically just code code cosmetics,
at least it marks this as a very distinct special case,
and keeps the API for the standard Filter layer clean.
2018-09-14 21:06:14 +02:00
8f70b4e902 TreeExplorer: prototype for the extracted boilerplate helper
a quite convoluted construct built from several nested generic lambdas.
When investigated in the debugger, the observed addresses and the
invoked code looks sane and as expected.
2018-09-14 21:06:14 +02:00
94da0f627f TreeExplorer: draft ability to remould the filter
The intention is to switch from the itertools-based filter
to the filter available in the TreeExplorer framework.
Thus "basically" we just need to copy the solution over,
since both are conceptually equivalent.

However...... :-(
The TreeExplorer framework is designed to be way more generic
and accepts basically everything as argument and tries to adapt apropriately.

This means we have to use a lot of intricate boilerplate code,
just to get the same effect that was possible in Itertools with
a simple and elegant in-place lambda assignment
2018-09-14 21:06:14 +02:00
757258fb3a TreeExplorer: fix bug in Filter layer
Fillter needs to be re-evaluated, when an downstream entity requests
expandChildren() onto an upstream source. And obviously the ordering
of the chained calls was wrong here.

As it turns out, I had discovered that necessity to re-evaluate with
the Transformer layer. There is a dedicated test case for that, but
I cut short on verifying the filter in that situation as well, so
that piece of broken copy-n-paste code went through undetected.

This is in fact a rather esoteric corner case, because it is only
triggered when the expandChildren() call is passed through the filter.
When otoh the filter sits /after/ the entity generating the expandChildren()
calls, everything works as intended. And the latter is the typical standard
usage situation of an recursive evalutation algorithm: the filter is here
used as final part to drive the evaluation ahead and pick the solutions.
2018-09-14 21:06:14 +02:00
3fc5a94b87 TreeExplorer: investigate the backtracking abilities
There is a bug or shortcoming in the existing ErrorLog matcher implementation.
It is not really difficult to fix, however doing so would require us to intersperse
yet another helper facility into the log matcher. And it occurred to me, that
this helper would effectively re-implement the stack based backtracking ability,
which is already present in TreeExplorer (and was created precisely to support
this kind of recursive evaluation strategies).

Thus I intend to switch the implementation of the EventLog matcher from the
old IterTool framework to the newer TreeExplorer framework. And this intention
made me re-read the code, fixing several comments and re-thinking the design
2018-09-14 21:06:14 +02:00
2520ee82d1 EventLog: investigate failed match in EventLog
seemingly my quick-n-dirty implementation was to naiive.
We need real backtracking, if we want to support switches
in the search direction (match("y").after("x").before("z")

Up to now, I have cheated myself around this obvious problem :-/
2018-09-14 21:06:13 +02:00
f64e01a20c GCC-7: minor adjustments to make the testsuite PASS again
The boost::hash documentation does not mention a significant change in that area,
yet the frequent collisions on identifiers with number suffix do not occur anymore
in Boost 1.65
2018-04-29 03:15:57 +02:00
f06038828c GCC-7: integrate recent clean-up and refactoring work (lib::Depend)
# Conflicts:
#	src/lib/error-exception.cpp
#	src/lib/error.hpp
#	src/lib/opaque-holder.hpp
#	src/lib/wrapper.hpp
#	src/proc/mobject/session/sess-manager-impl.hpp
2018-04-27 02:23:20 +02:00
3296148dad pre-C++17: remove remaining old-style (dynamic) exception specifications 2018-04-26 12:07:08 +02:00
89d93a13e4 Modernise Unknown Exception handler and Exception messages 2018-04-02 01:48:51 +02:00
21e47e014a Modernise Lumiera Error baseclass 2018-04-01 23:45:00 +02:00
992056ea69 reduce include dependencies of DelStash
...get rid of some further Boost includes and remove unnecessary disable_if
2018-04-01 00:37:58 +02:00
fc546f71b4 Reorganise some tests
Dependency-Injection rather fits into the "fundamentals" section.
It is more than a mere library facility
2018-03-31 17:12:45 +02:00
80207ea224 DI: (WIP) switch to totally rewritten new implementation of lib::Depend (#1086)
- state-of-the-art implementation of access with Double Checked Locking + Atomics
- improved design for configuration of dependencies. Now at the provider, not the consumer
- support for exposing services with a lifecycle through the lib::Depend<SRV> front-end
2018-03-31 01:06:06 +02:00
5d0c2b6d2c DI: special solution for singletons with private default ctor
...which declare DependencyFactory as friend.
Yes, we want to encourrage that usage pattern.

Problem is, std::is_constructible<X> gives a misleading result in that case.
We need to do the instantiation check within the scope of DependencyFactory
2018-03-30 06:48:34 +02:00
b3d18c1a74 DI: rework dependency-injection configuration in terms of the new DependencyFactory
why is this so damn hard to get right?
2018-03-30 05:56:53 +02:00
5fc85df385 DI: inline into lib::Depend to obsolete InstanceHolder
but now we've got two factory functors.
So there is yet more potential for simplification & refactoring
2018-03-29 16:57:55 +02:00
c3e149028f DI: draft towards unified use of the singleton holder
ideally we want
 - just a plain unique_ptr
 - but with custom deleter delegating to lib::Depend
 - Depend can be made fried to support private ctor/dtor
 - reset the instance-ptr on deletion
 - always kill any instance
2018-03-28 03:27:05 +02:00
d6786870f3 DI: port the old Singleton unit tests
all these tests are ported by drop-in replacement
and should work afterwards exactly as before (and they do indeed)

A minor twist was spotted though (nice to have more unit tests indeed!):
Sometimes we want to pass a custom constructor *not* as modern-style lambda,
but rather as direct function reference, function pointer or even member
function pointer. However, we can not store those types into the closure
for later lazy invocation. This is basically the same twist I run into
yesterday, when modernising the thread-wrapper. And the solution is
similar. Our traits class _Fun<FUN> has a new typedef Functor
with a suitable functor type to be instantiated and copied. In case of
the Lambda this is the (anonymous) lamda class itself, but in case of
a function reference or pointer it is a std::function.
2018-03-26 07:54:16 +02:00