after extended analysis, it turned out to be a "placeholder concept"
and introduces an indirection, which can be removed altogether
- simple command invocation happens at gui::model::Tangible
- it is based on the command (definition) ID
- instance management happens automatically and transparently
- the extended case of context-bound commands will be treated later,
and is entirely self-contained
while the initial design treated the commands in a strictly top-down manner,
where the ID is known solely to the CommandRegistry, this change and information
duplication became necessary now, since by default we now always enqueue and
dispatch anonymous clone copies from the original command definition (prototype).
This implementation uses the trick to tag this command-ID when a command-hanlde
is activated, which is also the moment when it is tracked in the registry.
due to the refactorings, the instance was moved out prior to checking for
bound arguments. This is ammended now, albeit at the price of passing an
additional flagn and some tricky boolean conditions
this seems like an obvious functionality and basically harmless,
since commands are designed to be inherently stateful, which is reflected
in all the internal storage holders to expos an assignment operator
(even while the actual implementation is based on placement new instead
of assigning values into the storage, and thus even supports immutable
values). The only possible ramification is that argument values must
be default constructible
in accordance to the design changes concluded yesterday.
- in the standard cases we now check the global registry first
- automatically create anonymous clone copy from global commands
- reorganise code internally to use common tail implementation
as it turns out, we can always trigger commands right away,
the moment all arguments are known. Thus it is sufficient to
send a single argument binding message, which allows us to
get rid of a lot or ugly complexities (payload visitor).
It seems more adequate to push the somewhat intricate mechanics
for the "fall back" onto generic commands down into the implementation
level of CommandInstanceManager. The point is, we know the standard
usage situation is to rely on the instance manager, and thus we want
to avoid redundant table lookups, only to support the rare case of
fallback to global commands. The latter is currently used only from
unit-tests, but might in future also be used by scripts.
Due to thread safety considerations, I have refrained from handing
out a direct reference to the command token sitting in the registry,
even while not doing so incurs a small runtime penalty (accessing
the shared ref-count for creating a copy of the smart-handle).
This is the typical situation where you'd be tempted to sacrifice
sanity for the sake of an imaginary performance benefit, which
in fact is dwarfed by all the machinery of UI-Bus and argument
passing via GenNode.
but I am not happy with the implementation yet: the maybeGet just
doesn't feel right. Likely it will be a better idea to push that
fallback mechanism generally down into the CommandInstanceManager?
this might turn into lock contention problem, but better optimise
a correct implementation than fix a fast yet broken one.
Hint: SessionCommandFunction_test demonstrates that the
symbol table can be corrupted by creating Symbol instances
in parallel without proper locking. So yes, this is for real.
since Symbol instance are now backed by a symbol table,
we can use a much faster hash function by just hashing the
pointer into the symbol table, since the Symbol string content
is already checked at initialisation.
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"
For this task, I've also investigated to use boost::operators
This would only incur a negligible penalty on build times and executable sizes,
however, I don't consider the boost based solution to improve readability,
since many of these comparisons are tricky or subtly different.
Moreover, since boost::operators needs to be mixed-in, the initialisation
of Symbol objects becomes difficult, not to mention the additional base class
information visible in the debugger when inspecting Symbol or Literal objects
For that reason, I decided *against* using Boost here and coded up
all the operators in all combinations manually
...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
The instance manager opens (creates) a new instance by cloning
from the prototype. Unless this instance is dispatched, it does not
allow to open a further instance (for the same instanceID). But of course
it allows to open a different instance from the same prototype
just by reasoning from the concept, an instance should always correspond
to a single invocation trail. Having several sets of invocation state
compete with each other, means to keep them distinct, otherwise the
implicit state is going to be corrupted
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.
this is indeed a change of concept.
A 'command instance' can not be found through the official
Command front-end anymore, since we do not create a registration.
This allows us to avoid decorating command IDs with running counters
interesting new twist: we do not even need to decorate with a running number,
since we'll get away with an anonymous command instance, thanks to Command
being a smart-handle
it is not *that* hard to behave in a somewhat sane manner here.
And even more: this *is* basically the symbol table implementation we need.
Thus we only need to build the right front-end now...
Up to now, these dummy functions where used by various unit tests
directly, by creating command definitions within the test fixture.
But since it is foreseeable that we'll need dummy commands for various
further unit tests, it seems adequate to setup a global static registration
with the newly created system of command registrations for these dummies.