Commit graph

160 commits

Author SHA1 Message Date
7d461adabc Upgrade: explore construction of a ''tuple-like'' concept
Motivated by the difficulties encountered with `std::apply` —
which basically forced us to define our own alternative with
conceptually more adequate limitations....

...so these are the first attempts towards building a C++20 concept.
2025-06-22 19:42:03 +02:00
20392eee1c clean-up: successfully replaced the old fixed type sequence (closes: #987)
This resolves an intricate problem related to metaprogramming with
variadic templates and function signatures. Due to exceptional complexity,
a direct solution was blocked for several years, and required a better
organisation of the support code involved; several workarounds were
developed, gradually leading to a transition path, which could now
be completed in an focused clean-up effort over the last week.

Metaprogramming with sequences of types is organised into three layers:
- simple tasks can be solved with the standard facilities of the language,
  using pattern match with variadic template specialisations
- the ''type-sequence'' construct `Types<T...>` takes the centre stage
  for the explicit definition of collections of types; it can be re-bound
  to other variadic templates and supports simple direct manipulation
- for more elaborate and advanced processing tasks, a ''Loki-style type list''
  can be obtained from a type-sequence, allowing to perform recursive
  list processing task with a technique similar to LISP.
2025-06-07 18:04:59 +02:00
95a9ceac35 clean-up: simplify function-closure -- avoiding std::function
A very performance relevant shortcoming of the existing implementation
of partial function closure is that the result is always wrapped into a
std::function, which typically causes a heap allocation when more than
a single pre-bound argument must be stored — which is annoying,
since the underlying Binder provides inline storage and thus
could be handled directly as a value object.

However, returning the Binder directly is also problematic, since
this object is outfitted with several overloaded function call operators,
which defeats most techniques to detect a function signature. Notably,
relevant down-stream metaprogramming code, like the tuple-closure used
in the `NodeBuilder` would break when being confronted directly with
a binder object.

An investigation shows that there is no direct remedy, short of
wrapping the binder into another functor. This can be accomplished
with a helper template, that generates a wrapper; however, this
wrapper builder must be supplied with explicit type information
regarding the function arguments (precisely because this type
signature can not be picked up from the Binder object itself)
2025-06-06 19:44:24 +02:00
03b17c78da Buffer-Provider: investigate Problem with embedded type-constructor-arguments
This is a possible extension which frequently comes up again during the design of the Engine.
Basically, the `TypeHandler` in the metadata-descriptor used by the `BufferProvder` could capture
additional context-arguments, which are then later passed to an object instance embedded into the buffer.

Yesterday I attempted to use this feature for a simple demonstration in `NodeBasic_test`,
just to find out that passing additional constructor arguments to the capture fails with
a confusing compilation error message. This failure could be traced down to the function binder;
and what at first sight seemed to be a compiler error, turned out to be a quite logical limitation:
When we »close« some objects of the constructor, but delay the construction itself, we'll have to
store a copy in the constructor-λ. And this implies, that we'll have to change the types
used for instantiation of the compiler, so that the construction-function can be invoked
by passing references from the captured copy of the additional arguments.

When naively passing those forwarded arguments into the std::bind()-call,
the resulting functor will fail at instantiation, when the compiler attempts
to generate the function-call `operator()`

see: https://stackoverflow.com/q/30968573/444796
2024-12-17 00:09:18 +01:00
e6403cbc7e Invocation: get structural bindings to work
It seemed like we're doomed...
Yet we barely escaped our horrid fate, because the C++ structured bindings happen to look also for get<i> member functions!

Any other solution involving a free function `get<i>(h)` would not work, since the `std::tuple` used as base class would inevitably drag in std::get via ADL
Obviously, the other remedy would be to turn the `StorageFrame` into a member; yet doing so is not desirable, as makes the actual storage layout more obscure (and also more brittle)
2024-12-12 19:03:43 +01:00
41a6e93057 Invocation: clarify cause of problems
Actually it is the implementation of `std::get` from our STL implementation
which causes the problems; our new custom implementation works as intended an
would also be picked by the compiler's overload resolution. But unfortunately,
the bounds checking assertion built into std::tuple_element<I,T> triggers
immediately when instantiated with out-of-bounds argument, which happens
during the preparation of overload resolution, even while the compiler
would pick another implementation in the following routine.

So we're out of luck and need to find a workaround...
2024-12-12 16:22:04 +01:00
4a7e1eeb36 Invocation: problems with function template overload resolution
Why is our specialisation of `std::get` not picked up by the compiler?

 * it must somehow be related to the fact that `std::tuple` itself is a base class of lib::HeteroData
 * if we remove this inheritance relation, our specialisation is used by the compiler and works as intended
 * however, this strange behaviour can not be reproduced in a simple synthetic setup

It must be some further subtlety which marks the tuple case as preferrable
2024-12-12 04:38:55 +01:00
806db414dd Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
 * there is no entity "Lumiera.org" which holds any copyrights
 * Lumiera source code is provided under the GPL Version 2+

== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''

The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!

The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
7ed8486774 Library: rework detection of ''same object''
We use the memory address to detect reference to ''the same language object.''
While primarily a testing tool, this predicate is also used in the
core application at places, especially to prevent self-assignment
and to handle custom allocations.

It turns out that actually we need two flavours for convenient usage
 - `isSameObject` uses strict comparison of address and accepts only references
 - `isSameAdr` can also accept pointers and even void*, but will dereference pointers
This leads to some further improvements of helper utilities related to memory addresses...
2024-11-15 00:11:14 +01:00
0b9e184fa3 Library: replace usages of rand() in the whole code base
* most usages are drop-in replacements
 * occasionally the other convenience functions can be used
 * verify call-paths from core code to identify usages
 * ensure reseeding for all tests involving some kind of randomness...

__Note__: some tests were not yet converted,
since their usage of randomness is actually not thread-safe.
This problem existed previously, since also `rand()` is not thread safe,
albeit in most cases it is possible to ignore this problem, as
''garbled internal state'' is also somehow „random“
2024-11-13 04:23:46 +01:00
59390cd2f8 Library: reorder some pervasively used includes
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
2024-03-21 19:57:34 +01:00
a780d696e5 Chain-Load: verify connectivity and recalculation
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.
2023-11-27 21:58:37 +01:00
e5f5953b15 Library: RandomDraw - extract as generic component
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.
2023-11-20 16:38:55 +01:00
e127d0ad9a Chain-Load: develop a design for a random-number-drawing DSL
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.
2023-11-20 03:16:23 +01:00
34f1b0da89 Chain-Load: investigate ways for notation of topology rules
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...
2023-11-19 23:12:54 +01:00
d67c62b02f Scheduler: solve difficulties with member function signature
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)
2023-10-22 00:42:57 +02:00
52d3231226 Timeline: finish ZoomWindow implementation and boundrary tests 2022-12-18 03:47:40 +01:00
ed7e3b4b32 ElementBox: extract builder qualifier support as library implementation
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
2022-08-28 23:36:27 +02:00
ff6234829a ElementBox: investigate ctor syntax possibilites
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
2022-08-28 01:02:10 +02:00
acb674a9d2 Project: update and clean-up Doxygen configuration
...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
2021-01-24 19:35:45 +01:00
06dbb9fad5 DiffFramework: simplify existing bindings
...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
2021-01-23 12:55:10 +01:00
c7d157e295 Library: integrate generic min/max function
...built while investigating type deduction problems on PtrDerefIter
...also allow PtrDerefIter to work with std::unique_ptr
2020-03-08 02:05:39 +01:00
4070cc0d83 DisplayEvaluation: draft evaluation invocation per track
...however, running into some type deduction problems...
2020-03-08 01:11:21 +01:00
a508ad751f Investigation: clarify handling of CSS3 box-shadow for custom drawing
- 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
2019-08-08 19:08:04 +02:00
7bf7c51375 Investigation: inconclusive further research (context_save/restore)
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
2019-08-08 19:08:04 +02:00
ec3c49f612 Investigation: can reproduce the problematic behaviour with minimal setup
when we create a new Gtk::StyleContext and just apply a path,
then the style context looses its styling properties on context_save()
2019-08-08 19:08:04 +02:00
06aa5c4c8c Investigation: get the border resizing to work
...as it turns out, a problem with Cascading prevented the additional classes to become effective
2019-08-03 15:45:36 +02:00
1b3cc73d07 Investigation: rebuild the problematic situation in this controlled environment
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 :-)
2019-08-03 13:34:56 +02:00
3921a9d41c Investigation: use a StyleContext for custom drawing
- 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
2019-08-01 01:07:22 +02:00
aacc4ca041 Investigation: install a custom stylesheet 2019-08-01 00:48:04 +02:00
0280000854 Investigation: setup a minimal standalone GTK application
...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
2019-08-01 00:02:56 +02:00
06163f6016 Timeline: filter to select the pinned prefix part of the profile
...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
2019-06-21 23:18:44 +02:00
8f43c2591e Library: investigate malfunction in metaprogramming
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
2019-05-10 02:19:01 +02:00
a57799d018 Library: further narrowing down the tuple-forwarding problem
...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
2019-05-09 17:10:35 +02:00
612a442550 Library: unable to reproduce the problem with an "equivalent" demo example
...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....?
2019-04-22 17:45:38 +02:00
5191073558 Library: continue Investigation with workaround, inconclusive yet
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.
2019-04-20 17:27:47 +02:00
805d83c2db Library: Investigate forwarding of tuple elements
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
2019-04-19 18:37:30 +02:00
5b8aef9623 Yoshimi: found the bug
plain flat off by one :-D
end pointer must be behind the last array element.
Thus we didn't use all state values, and thus our random numbers diverged
2018-12-31 09:50:53 +01:00
f0e482ad78 Yoshimi: investigation of the random number algorithm from the C standard lib
(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
2018-12-31 09:05:45 +01:00
02c5809707 Global-Layer-Renaming: adjust namespace qualification 2018-11-15 23:59:23 +01:00
2d5ebcd5fa Global-Layer-Renaming: adjust header includes 2018-11-15 23:42:43 +01:00
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
3f87ef43ec ...tidy.up: preserve the Gtk::Canvas experiment (see #1020)
Turning this investigation experiment from 2016 into a stand-alone Gtk application.
Using the research folder as final disposal site for now...
2018-10-07 17:31:49 +02:00
76dd4fb5dc ...tidy.up: prepare for working on the timeline display
''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
2018-10-07 03:44:00 +02:00
3b8965c0b6 Heisenbug hunt.... Segfault related to regular expression (#1158)
not yet able to reproduce these seemingly random segfaults
2018-09-14 21:04:25 +02:00
852a3521db Static-Init: switch lib::Depend to embed the factory as Meyer's Singleton (#1142)
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).
2018-05-01 18:49:20 +02:00
22b934673f Investigation: init order of static template member fields
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.
2018-05-01 16:59:15 +02:00
fe10ab92dc DI: adjust codebase to the new DependInject configuration API 2018-03-31 01:06:10 +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
7a250ca9e5 DI: benchmark atomic locking 2018-03-24 11:02:44 +01:00