...yet this seems like a rather bad idea,
it breeds various problems and requires arcane trickery to make it fly
==> abandon this design
==> always intersperse an IterableDecorator between each pair of Layers
...especially relevant in the context of TreeExplorer,
where the general understanding is that the "Data Source" (whatever it is)
will be piggy-backed into the pipeline builder, and this wrapping is
conceived as being essentially a no-op.
It is quite possible we'll even start using such pipeline builders
in concert with move-only types. Just consider a UI-navigator state
hooked up with a massive implementation internal pointer tree attached
to all of the major widgets in the UI. Nothing you want to copy in passing by.
As it turned out, we had two bugs luring in the code base,
with the happy result of one cancelling out the adverse effects of the other
:-D
- a mistake in the invocation of the Itertools (transform, filter,...)
caused them to move and consume any input passed by forwarding, instead
of consuming only the RValue references.
- but util::join did an extraneous copy on its data source, meaning that
in all relevant cases where a *copy* got passed into the Itertools,
only that spurious temporary was consumed by Bug #1.
(Note that most usages of Itertools rely on RValues anyway, since the whole
point of Itertools is to write concise in-line transformation pipelines...)
*** Added additional testcode to prove util::stringify() behaves correct
now in all cases.
- we do strip references
- we delegate to nested typedefs
Hoever, we do *not* treat const or pointers in any way special --
if the user want to strip or level these, he has to do so explicitly.
Initially it seemed like a good idea to do something clever here, but
on the long run, such "special treatment" is just good for surprises
...automatically whenever those are present.
Up to now, we hat that as base case, which limited usage to those cases
where we already know such nested definitions are actually present
attempt to re-use the same traits as much as possible
NOTE: new code not passing compiler yet, but refactored old code
does, and still passes unit test
...which uncovered an error in the test fixture
plus helped to spot the spurious copy when passing the argument to the expand functor
And my GDB crashed when loading the executable, YAY!
so we'll need to coment out some code from now on,
until we're able to switch to a more recent toolchain (#1118)
but possible only for the iterator -> iterator case
Since we can not "probe" a generic lambda, we get only one shot:
we can try to bind it into a std::function with the assumed signature
This is a consequence of the experiments with generic lambdas.
Up to now, lib::meta::_Fun<F> failed with a compilation error
when passing the decltype of such a generic lambda.
The new behaviour is to pick the empty specialisation (std::false_type) in such cases,
allowing to guard explicit specialisations when no suitable functor type
is passed
this solution makes me feel somewhat queasy..
stacking several adaptors and wrappers and traits on top of each other.
Well, it type checks and passes the test, so let's trust functional programming
The plan is to use a monad-like scheme, but allow for a lot of leeway
with respect to the src and value types of the expand functor.
A key idea is to allow for a *different* state core than used in the source
The key trick is to form an expression with the free function, using a declval of the type to probe.
What is somewhat tricky is the fact that functions can be void, so we need just to pick up
the type and use it in another type expression
Here, the tricky question remains, how to relate this evalutaion scheme
to the well known monadic handling of collections and iterators.
It seems, we can not yet decide upon that question, rather we should
first try to build a concrete implementation of the envisioned algorithm
and then reconsider the question later, to what extent this is "monadic"
This can be seen as a side track, but the hope is
by relying on some kind of monadic evaluation pattern, we'll be
able to to reconcile the IterExplorer draft from 2012 with the requirement
to keep the implementation of "tree position" entirely opaque.
The latter is mandatory in the use case here, since we must not intermingle
the algorithm to resolve UI-coordinates in any way with the code actually
navigating and accessing GTK widgets. Thus, we're forced to build some kind
of abstraction barrier, and this turns out to be surprisingly difficult.
...which can be helpful when a function usually returns a somewhat dressed-up iterator,
but needs to return a specific fixed value under some circumstances
- fix some warnings due to uninitialised members
(no real problem, since these members get assigned anyway)
- use a lambda as example function right in the test
- use move initialisation and the new util::join
Explicitly assuming that those functions are called solely from IterAdapter
and that they are implemented in a typical standard style, we're able to elide
two redundant calls to the checkPoint() function. Since checkPoint typically performs
some non-trivial checks, this has the potential of a significant performance improvement
- we check (and throw ITER_EXHAUST) anyway from operator++, so we know that pos is valid
- the iterate() function ensures checkPoint is invoked right after iterNext,
and thus the typical standard implementation of iterNext need not do the same
...under the assumption that the content is normalised,
which means
- leading NULL is changed to Symbol::EMPTY
- missing elements in the middle are marked as "*"
- trailing NULL in extension storage is handled by adjusting nominal extension size
as it turned out, the solution from yesterday works only with uniform argument lists,
but not with arbitrarily mixed types. Moreover the whole trickery with the
indices was shitty -- better use a predicate decision on template argument level.
This simple solution somehow just didn't occur to me...
exploring the idea of a configuration DSL.
As a first step, this could be a simple internal DSL,
implemented as a bunch of static functor objects, which are internally bound
and thus implemented by the ViewLocator within InteractionDirector
again surprising how such fundamental bugs can hide for years...
Here the reason is that IterAdapter leaves the representation of "NIL" to
its instantiation / users; some users (here in for example the ScopedCollection)
can choose to allow for different representations of "NIL", but the comparison
provided by IterAdapter just compares the embedded pos by face value.
...while tests in the library subdirectory are linked only against
liblumierasupport, which does not provide the multithreading support
In this special case here the actual facility to be tested does not rely
on thread support, only on locking. But the stress test obviously needs
to create several threads. Simple workaround is to move the test into
a test collection linked against all of the application core...
for the simplistic implementation we're using right now this effort might look
exaggerated, but we should consider using a lock-free implementation at some
point in the future, at which point it is good to have a stress test in place
- concept for a first preliminary implementation of dispatch into the UI thread
- define an integration effort to build a complete working communication chain
Up to now, we tolerated null pointers in Literal instances.
But we can not tolerate passing a null cString to Symbol initialisation.
Rather, hereby we introduce a dedicated "bottom" Symbol, a valid "null object"
...which means, from now on identical input strings
will produce the same Symbol object (embedded pointer).
TODO: does not handle null pointers passed in as c-String properly
obsoleted by C++11
* in most cases, it can be replaced by an explicit conversion operator
* especially for the Lumiera Forward Iterators, we need an implicit conversion
This changeset fixes a huge pile of problems, as indicated in the
error log of the Doxygen run after merging all the recent Doxygen improvements
unfortunately, auto-linking does still not work at various places.
There is no clear indication what might be the problem.
Possibly the rather unstable Sqlite support in this Doxygen version
is the cause. Anyway, needs to be investigated further.
...since there is not any test coverage for this trait, which
turned out to be quite deeply rooted in the system by now and
handles several rather subtle special cases
this bit of Sed magic relies on the fact that we happen to write
the almost correct class name of a test into the header comment.
HOWTO:
for F in $(find tests -type f \( -name '*.cpp' \) -exec egrep -q '§§TODO§§' {} \; -print);
do sed -r -i -e'
2 {h;x;s/\s+(.+)\(Test\).*$/\\ref \1_test/;x};
/§§TODO§§/ {s/§§TODO§§//;G;s/\n//}'
$F;
done
Doxygen will only process files with a @file documentation comment.
Up to now, none of our test code has such a comment, preventing the
cross-links to unit tests from working.
This is unfortunate, since unit tests, and even the code comments there,
can be considered as the most useful form of technical documentation.
Thus I'll start an initiative to fill in those missing comments automatically
this was a spin-off activity from writing the SessionCommand
function(integration) test, where I noted that we can't just
capture "a time value" as command memento
basically this is not necessary, since the compiler figures out
to use the conversion to target type when attempting to resolve
an equality comparison. But it helps to avoid ambiguities in cases
where several conversion paths do exist, e.g. when comparing string
with C-string
explicitly observed with the debugger that the call path is sane;
the code looks innocuous, but it is quite magic how the compiler
picks precisely the right ctors and inserts conversions apropriately
...it occurred to me that very likely a casual reader of the code
will encounter here the first instance of such a diff binding function.
I am well aware this looks intimidating (and it is a tricky technical detail)
Even more so, if what you expect is just some access to a shared data model,
you might be completely puzzled by this code and nor recognise its importance.
reason is, only files with a @file comment will be processed
with further documentation commands. For this reason, our Doxygen
documentation is lacking a lot of entries.
HOWTO:
find src -type f \( -name '*.cpp' -or -name '*.hpp' \) -not -exec egrep -q '\*.+@file' {} \; -print -exec sed -i -r -e'\_\*/_,$ { 1,+0 a\
\
\
/** @file §§§\
** TODO §§§\
*/
}' {} \;
Damn sideeffect of the suppport for move-only types: since we're
moving our binding now into place /after/ construction, in some cases
the end() iterator (embedded in RangeIter) becomes invalid. Indeed this
was always broken, but didn't hurt, as long as we only used vectors.
Solution: use a dedicated init() hook, which needs to be invoked
*after* the TreeMutator has been constructed and moved into the final
location in the stack buffer.