reduce footprint of lib/util.hpp
(Note: it is not possible to forward-declare std::string here)
define the shorthand "cStr()" in lib/symbol.hpp
reorder relevant includes to ensure std::hash is "hijacked" first
It seams indicated to verify the generated connectivity
and the hash calculation and recalculation explicitly
at least for one example topology; choosing a topology
comprised of several sub-graphs, to also verify the
propagation of seed values to further start-nodes.
In order to avoid addressing nodes directly by index number,
those sub-graphs can be processed by ''grouping of nodes'';
all parts are congruent because topology is determined by
the node hashes and thus a regular pattern can be exploited.
To allow for easy processing of groups, I have developed a
simplistic grouping device within the IterExplorer framework.
The idea is to use some source of randomness to pick a
limited parameter value with controllable probability.
While the core of the implementation is nothing more
than some simple numeric adjustments, these turn out
to be rather intricate and obscure; the desire to
package these technicalities into a component
however necessitates to make invocations
at usage site self explanatory.
This might seem totally overblown -- but already the development
of this prototype showed me time and again, that it is warranted.
Because it is damn hard to get the probabilities and the mappings
to fixed output values correct.
After in-depth analysis, I decided completely to abandon the
initially chosen approach with the Cap helper, where the user
just specifies an upper and lower bound. While this seems
compellingly simple at start, it directly lures into writing
hard-to-understand code tied to the implementation logic.
With the changed approach, most code should get along rather with
auto myRule = Draw().probabilty(0.6).maxVal(4);
...which is obviously a thousand times more legible than
any kind of tricky modulus expressions with shifted bounds.
While the Cap-Helper introduced yesterday was already a step in the
right direction, I had considerable difficulties picking the correct
parameters for the upper/lower bounds and the divisor for random generation
so as to match an intended probability profile. Since this tool shall be
used for load testing, an easier to handle notation will both help
with focusing on the main tasks and later to document the test cases.
Thus engaging (again) into the DSL building game...
The approach to provide the ExecutionCtx seems to work out well;
after some investigation I found a solution how to code a generic
signature-check for "any kind of function-like member"...
(the trick is to pass a pointer or member-pointer, which happens
to be syntactically the same and can be handled with our existing
function signature helper after some minor tweaks)
Complete the investigation and turn the solution into a generic
mix-in-template, which can be used in flexible ways to support
this qualifier notation.
Moreover, recapitulate requirements for the ElementBoxWidget
Basically we want to create ElementBoxWidgets according to a
preconfigured layout scheme, yet we'll need to pass some additional
qualifiers and optional features, and these need to be checked
and used in accordance with the chosen flavour...
Investigating a possible solution based on additional ctor parameters,
which are given as "algebraic terms", and actually wrap a functor
to manipulate a builder configuration record
...in an attempt to clarify why numerous cross links are not generated.
In the end, this attempt was not very successful, yet I could find some breadcrumbs...
- file comments generally seem to have a problem with auto link generation;
only fully qualified names seem to work reliably
- cross links to entities within a namespace do not work,
if the corresponding namespace is not documented in Doxygen
- documentation for entities within anonymous namespaces
must be explicitly enabled. Of course this makes only sense
for detailed documentation (but we do generate detailed
documentation here, including implementation notes)
- and the notorious problem: each file needs a valid @file comment
- the hierarchy of Markdown headings must be consistent within each
documentation section. This entails also to individual documented
entities. Basically, there must be a level-one heading (prefix "#"),
otherwise all headings will just disappear...
- sometimes the doc/devel/doxygen-warnings.txt gives further clues
...by relying on the newly implemented automatic standard binding
Looks like a significant improvement for me, now the actual bindings
only details aspects, which are related to the target, and no longer
such technicalitis like how to place a Child-Mutator into a buffer handle
- CSS3 effects like box-shadow are applied with the StyleContext::render_background() function
* first, an outset box-shadow is rendered _outside_ the box given as parameter to `render_background()`
* then the box is filled with the background colour
* and last, an inset box-shadow is rendered _inside_ the area of a would-be border,
without rendering the border itself.
* consequently we can not shade the border itself and we can not shade the content
Indeed I had missed to connect the new "free standing" StyleContext to
some Gdk::Screen, typically the default screen (connected to the current
top level window). But seemingly this was not really necessary, since,
somehow magically, the style context must have connected itself to some
screen, otherwise it wouldn't be able to access the CSS cascade.
Anyhow, fixing this omission does not resolve our problem.
Nor does any combination of re-connecting, invalidating etc.
I poked around in the GTK (C) code a lot, but could not spot any obvious
missing initialisation step. To much magic around here. Without massive
debugging into GTK internals, I don't see any way to further this
investigation. And, moreover there is a viable workaround
(namely to set and remove the classes explicitly, which works as intended)
I posted a question on Stackoverflow and for now
I'll file this topic as "inconclusive"
https://stackoverflow.com/q/57342478
Within the timeline drawing code, adding a class to the Gtk::StyleContext on the fly seemingly did not work.
Now we're doing basically the same here in this small Gtk test application,
and it does not work either :-)
- add a separate dummy Gtk::Frame widget
- apply custom styling to that frame, by virtue of a CSS class '.experiment'
- pick up the Gtk::StyleContext of that testFrame
- use this style context to draw a custom frame onto the canvas
- control extension of that custom frame through the top margin of testFrame
...to find out about GTK's implementation of some aspects of CSS
through Gtk::StyleContext and friends
Basically this is a clone of the existing gtk-canvas-experiment application
...when rendering this part, which shall be always visible.
And the rest of the profile needs to be rendered into a second canvas,
which is placed within a pane with scrollbar.
Implemented as a statefull iterator filter
the template lib::PolymorphicValue seemingly picked the wrong
implementation strategy for "virtual copy support": In fact it is possible
to use the optimal strategy here, since our interface inherits from CloneSupport,
yet the metaprogramming logic picked the mix-in-adapter (which requires one additional "slot"
of storage plus a dynamic_cast at runtime).
The reason for this malfunction was the fact that we used META_DETECT_FUNCTION
to detect the presence of a clone-support-function. This is not correct, since
it can only detect a function in the *same* class, not an inherited function.
Thus, switching to META_DETECT_FUNCTION_NAME solves this problem
Well, this solution has some downsides, but since I intend to rewrite the
whole virtual copy support (#1197) anyway, I'll deem this acceptable for now
TODO / WIP: still some diagnostics code to clean up, plus a better solution for the EmptyBase
...yet still not successful.
The mechanism used for std::apply(tuple&) works fine when applied directly to the target function,
but fails to select the proper overload when passed to a std::forward-call for
"perfect forwarding". I tried again to re-build the situation of std::forward
with an explicitly coded function, but failed in the end to supply a type parameter
to std::forward suitably for all possible cases
...the simplified demo variant in try.cpp is accepted by the compiler and works as intended,
while the seemingly equivalent construction in verb-visitor.hpp is rejected by the compiler
This discrepancy might lead to a solution....?
A simple yet weird workaround (and basically equivalent to our helper function)
is to wrap the argument tuple itself into std::forward<Args> -- which has the
effect of exposing RValue references to the forwarding function, thus silencing
the compiler.
I am not happy with this result, since it contradicts the notion of perfect forwarding.
As an asside, the ressearch has sorted out some secondary suspicions..
- it is *not* the Varargs argument pack as such
- it is *not* the VerbToken type as such
The problem clearly is related to exposing tuple elements to a forwarding function.
basically this is similar to std::invoke...
However, we can not yet use std::invoke, and in addition to this,
the actual situation is somewhat more contrieved, so even using std::invoke
would require to inject another argument into the passed argument tuple.
In the previous commit, I more or less blindly coded some solution,
while I did not fully understand the complaints of the compiler and why
it finally passed. I still have some doubts that I am in fact moving the
contents out of the tuple, which would lead to insidious errors on
repeated invocation.
Thus this invstigation here, starting from a clean slate textbook implementation
(ab)using the Lumiera tree here for research work on behalf of the Yoshimi project
For context, we stumbled over sonic changes due to using different random number algorighims,
in spite of all those algorithms producing mathematically sane numbers
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
''a new hope''
This was quite a long way until we're back at the point of
re-building the timeline anew.
Stash the canvas research code to make room for new things to come
this is a (hopefully just temporary) workaround to deal with static initialisation
ordering problems. The original solution was cleaner from a code readability viewpoint,
however, when lib::Depend was used from static initialisation code, it could
be observed that the factory constructor was invoked after first use.
And while this did not interfer with the instance lifecycle management itself,
because the zero-initialisation of the instance (atomic) pointer did happen
beforehand, it would discard any special factory functions installed from such
a context (and this counts as bug for my taste).
indicates rather questionable behaviour.
The standard demands a templated static field to be defined before first odr-use.
IIRC, it even demands a static field to be initialised prior to use in a ctor.
But here the definition of the templated static member field is dropped off even after
the definition of another static field, which uses the (templated) Front-end-class
in its initialiser.
- 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
This is essentially the solution we used since start of the Lumiera project.
This solution is not entirely correct in theory, because the assignment to the
instance pointer can be visible prior to releasing the Mutex -- so another thread
might see a partially initialised object
_not_ using the dependency factory, rather direct access
- to a shared object in the enclosing stack frame
- to a heap allocated existing object accessed through uniqe_ptr
This is a complete makeover of our lib::Depend and lib::DependencyFactory templates.
While retaining the basic idea, the configuration has been completely rewritten
to favour configuration at the point where a service is provided rather,
than at the point where a dependency is used.
Note: we use differently named headers, so the entire Lumiera
code base still uses the old implementation. Next step will be
to switch the tests (which should be drop-in)