after sleeping one night over the problem, this seems to be
the most natural solution, since the possibility of assignment
naturally arises from the fact that, for tree diff, we have
to distinguish between the *identity* of an element node and
its payload (which could be recursive). Thus, IFF the payoad
is an assignable value, why not allow to assign it. Doing so
elegnatly solves the problem with assignment of attributes
Signed-off-by: Ichthyostega <prg@ichthyostega.de>
I assumed that, since GenNode is composed of copyable and
assignable types, the standard implementation will do.
But I overlooked the run time type check on the opaque
payload type within lib::Variant. When a type mismatch
is detected, the default implementation has already
assigned and thus altered the IDs.
So we need to roll our own implementation, and to add
insult to injury, we can't use the copy-and-swap idiom either.
This is actually a STL library feature, and was added precisely
for the reason encountered here: if we want logarithmic search,
we'll have to construct a new GenNode object, just to have something
for the set to invoke the comparison operator.
C++14 introduced the convention that the Comparator of the set
may define a marker type `is_transparent` alongside with a generic
comparison operator. But, as is obvious from the source code of
our GNU Standard library implementation, our std::set has no such
overload to make use of that feature
http://en.cppreference.com/w/cpp/container/set/findhttp://stackoverflow.com/questions/20317413/what-are-transparent-comparators
The only good thing is that, just 10 minutes ago, I felt like
a complete moron because I'm writing a unit test for such a simple
storage class. ;-)
the values.child() call would also do a bounds check,
but only to rise a error::Invalid "index out of bounds".
So now we generate a clear message to indicate that
actually a runtime-checked type mismatch caused this problem
the functionality as such is already covered,
but it seems important enough to warrant a dedicated test.
incidentally, Duration still lacked a default ctor.
Time values are default constructible, yet immutable.
incidentally, this uncovered yet another unwanted narrowing conversion,
namely from double via gavl_time_t to TimeValue or alternatively
from double via FSecs (= rational<long>) to Duration.
As in all the previos cases, actually the compiler is to blame,
and GCC-5 is known to get that one right, i.e. let the SFINAE fail
instead of passing it with a "narrowing conversion" warning.
Note: the real test for command binding with immutable types
can be found in BusTerm_test
Completely removed the nested hierarchy, where
the top-level implementation forwarded to yet another
sub-implementation of the same interface. Rather, this
sub-implementation (OpClosure) is now a mere implementation
detail class without VTable, and without half-baked
re-implementation of the CmdClosure interface. And the
state-switch from unbound to bound arguments is now
implemented as a plain-flat boolean flag, instead of
hiding it in the VTable.
To make this possible, without having to rewrite lots of
tests, I've created a clone of StorageHolder as a
"proof-of-concept" dummy implementation, for the sole
purpose of writing test fixtures. This one behaves
similar to the real-world thing, but cares only
for closing the command operation and omits all
the gory details of memento capturing and undo.
...probably just an omission. TimeValue and Time are
also default constructible, and this makes sense, semantically.
Please note that Time values are *immutable* though.
Only TimeVar can be reassigned. This is so by design
recently, I've introduced this ability in our toString template.
as it turned out, the bool type was not selected by our
boost::format frontend for special treatment, thus showing
just the fallback «bool»
...when the Test-Nexus processes a command binding message.
In the real system of course we do not want to log every bind message.
The challenge here is the fact that command binding as such
is opaque, and the types of the data within the bind message
are opaque as well. Finally I settled on the compromise
to log them as strings, but only the DataCap part;
most value types applicable within GenNode
have a string representation to match.
the rationale is that I deliberately do not want to provide
a mechanism to iterate "over all contents in stringified form".
Because this could be seen as an invitation to process GenNode-
datastructures in an imperative way. Please recall we do not
want that. Users shall either *match* contents (using a visitor),
or they are required to know the type of the contents beforehand.
Both cases favour structural and type based programming over
dynamic run-time based inspection of contents
The actual task prompting me to add this iteration mechanism
is that I want to build a diagnostic, which allows to verify
that a binding message was sent over the bus with some
specific parameter values.
...also for the existing variant, which packages an
arbitrary number of arguments in stringified form
into a given container type. Moreover, the new
form of stringify allows to write util::join
in a clearer way, eliminating the lambda.
...since, semantically, the template param INT is expected to be
"number like", which implies to base the "in range" notion
on a comparison concept (e.g. we might use floating point numbers)
...this was clearly wrong; it went unnoticed just
because the linker cleans up duplicates of
template instantiations. (I'd expect GCC-5
to spot such errors)
very similar to boost::irange, but without heavyweight boost
includes, and moreover based on our Lumiera Forward Iterator concept
Such a inline-range construct makes writing simple tests easy
based on the new generic tuple builder, we're now able to
add a new binding function into the command implementation
machinery, alongside the existing one. As it stands, the
latter will be used rather by unit tests, while the new
access path is what will be actually taken within
the application, when receiving argument binding
messages dispatched via the UI-Bus.
since this is a quick-n-dirty workariound, until we're using GCC-5,
I'll err for the simple and safe side and disallow any conversion
from LuidH do some algebraic data type. The problem arises,
sincd LuidH defines a conversion to size_t, which depends
on the platform. So, without checking the actual NumericLimits,
there is no way we can allow a conversion to size_t in a
hard wired way, while disallowing a narrowing conversion
to 32bit unsigned int on 64bit platforms.
And in the end, we don't want conversions from LUID to
numeric values to happen automatically anyway. But of
course we *do* want automatic promotion from a LuidH
to a PlacementRef...
...to avoid warnings when deriving a publicly visible type
from that interface. Newer GCC and CLang versions emit
warnings when details from an anonymous implementation
namespace will leak into type signatures visible outside
the translation unit. In this case here, it's the VTable.
because this element picking mechanism for tuples
looks like an instance of something generic.
At least I've written almost the same just some days ago
for the revised version of function-closure, where the
task was to replace a stretch of type arguments in
a given tuple type with a stretch of placeholder types
and then to build a modified ctor, which just fills
in the remaining arguments, while default constructing
the placeholder types. And if we look into the GNU
implementation of std::bind, they're using a similar
concept (with the difference that they're building
a functor object, where we use a type converter)
This refactoring also integrates some generally useful
bits into our standard metaprogramming helper collection
based on the previous experiments, this adds a fake operation
and a definition frame to hook this operation as pseudo Proc-Layer command
WIP: the invocation itself is not yet implemented.
We need to build a custom invocation pattern for that,
in order to be able to capture the instance-ID of the command
on invocation
NOTE: also, because of #989, we can not bind a time value for this test
not sure yet if any of this works, because the
technicalities of dealing with variadic types are
quite different to our LISP-style typelist processing.
The good news is that with variadic templates it is
indeed possible, to supply dynamically picked arguments
to another function taking arbitrary arguments.
This all relies on the feature to unpack argument packs,
and, more specifically, about the possiblity to "wrap"
this unpacking around interspersed function call syntax
template<size_t...i>
Xyz
do_something(MyTuple myTuple)
{
return Xyz (std::get<i> (myTuple) ... );
}
Here the '...' will be applied to the i... and then
the whole std::get-construct will be wrapped around
each element. Mind bogging, but very powerful
we made double use of our Tuple type, not only as a
generic record, but also as a metaprogramming helper.
This changeset replaces these helpers with other
metafunctions available for our typelists or type sequences
(with the exception of code directly related to Tuple itself,
since the intention is to delete this code alltogether shortly)
there was a muddeled mix of type lists and type sequences,
and both where used for processing. Probably the origin
of that confusion was the design of our own Tuple class,
which is implemented based on typelists but accepts a
type sequence at the front-end. From there, a confusing
pattern of equivalence between lists and sequences emerged,
leading to several functions accepting "anything".
This misdesign is not eradicated yet, but in this specific
instance here, has cost me several hours to pinpoint a bug
introduced while refactoring.
See also #967 and #301
This definition -- together with the already existing specialisation
in typeseq-util, allows always to rebind from a given type-list back
to the corresponding type-sequence, by accessing the type member `Seq`
...which causes problems when a preceding include
has already dragged in <functional>
the actual problem is the std::hash hack, which probably
is even no longer possible and could be removed (but
I don't have the time to investigate this somewhat
tricky topic right now)
To prevent this confusing situation, I'm adding the
include of "lib/symbol.hpp", to ensure we do have
the actual definitions of string and Literal,
which trait.hpp just declares forward.
An note, lib/symbol.hpp also includes hash-standard.hpp
first, so we avoid triggering problematic situation
from a header (format-cout.hpp), which is pervasively used
all over the place....
since our test.sh runner can be used to verify the
expected output printed by tests, working with these
output transcripts of larger tests can be hard at times.
These separators help to find who produced which output
and they prevent a regexp match to grep beyond the feed
of a single function (which can be a common problem
when using the self-diagnostic output of the facility
currently in test, which obviously will be similar
on any data printed.
- replace remaining usages of typeid(T).name()
- add another type simplification to handle the STL map allocator
- clean-up usage in lib/format-string
- complete the unit tests
- fix some more bugs