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....
basically this comes down to provide some convenience fixture
within the test::Nexus, which automatically generates and wires
mock commands.
Not sure if this is even possible to the extent envisioned here
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
quite sure I never really meant to do that, just, at that time,
it seemed logical to treat Placement as yet another smart-ptr.
But in the light of what crucial entity Placement became meanwhile,
I can't imagine a single case where anyone wants to wrap away a
placement as if it was some shrink-wrap
turns out this is a tricky situation.
We want to accept pretty mutch everything, yet we want to get a grip
on anything object-like, so to reveal available RTTI information.
Now, given the way C++ template substitution works, the 'TY const&' overload
wins with only a few exceptions. The reason is, C++ invokes most functions
passing the concrete argument as reference, unless this is not possible,
because the concrete artument is a rvalue. The automatic reduction of
reference expressions does the rest. Consequently the overload with 'const&'
turns out to be the best match even when we invoke the function with a
pointer expression, which would then be made into a pointer-to-a pointer
by our forward call.
There are two remedies for this dilemma:
- make the second overload just typeStr (TY&)
- explicitly remove the second overload for pointers
The first solution unfortunately would rule out passing of anonymous
objects like concatenated strings; in fact it would rule out passing
rvalues as such. While the second solution, chosen here, works really
for everything, and also has the nice side effect of stripping away
any const, pointer and reference adornements elegantly before we
even start to analyse the type.
The only downside of this solution is that it looks intimidating
to the casual reader. Well, I'd say, get used to it.
over time, we got quite a jungle with all those
shome-me-the-type-of helper functions.
Reduced and unified all those into
- typeString : a human readable, slightly simplified full type
- typeSymbol : a single word identifier, extracted lexically from the type
note: this changeset causes a lot of tests to break,
since we're using unmangeled type-IDs pretty much everywhere now.
Beore fixing those, I'll have to implement a better simplification
scheme for the "human readable" type names....
...based on all the clean-up and reorganisation done thus far,
we're now able to rebuild the util::str in a more direct and
sane way, and thus to disentangle the header inclusion problem.
due to the new automatic string conversion in operator<<
the representation of objects has changed occasionally.
I've investigated and verified all those incidents.
...other than intended, the bomb did explode on random occasions,
with an probability of about 4% (when rr >= 96).
Btw, there was also the mistake to throw an heap allocated
object by pointer. Damn Java habits.
- remove unnecessary includes
- expunge all remaining usages of boost::format
- able to leave out the expliti string(elm) in output
- drop various operator<<, since we're now picking up
custom string conversions automatically
- delete diagnostics headers, which are now largely superfluous
- use newer helper functions occasionally
I didn't blindly change any usage of <iostream> though;
sometimes, just using the output streams right away
seems adequate.
the usual drill...
only when wrapped into a factory function, RAII is really
airtight, even when used from within expression evaluation.
Thanks C++11 we're now able to provide such en passant
our lib::P smart-pointer is built on top of std::shared_ptr,
while additionally delegating comparisons to the pointee.
In a similar vein, I've now added a custom string conversion,
delegating to the pointee, with a type-string as fallback.
Together with the built-in string conversion for output streams,
we should now be able to remove most of the explicit string
conversions and calls to util::str in all of our test code.
This removes the last roadblock towards disentangling the
pretty-printing header includes, which in turn should allow
us to remove any conditional code in the built-in string
conversion of GenNode, Variant and the like. Which basically
was the objective for ticket #985
use a shortened display, showing only the last 4 bytes for diagnostics
since we're typically only interested in spotting "same" and "different",
while the full memory address is irrelevant
provide a generic overload for the stream inserter operator<<
to use custom string conversions when applicable.
The overload will be disabled when a direct lexical conversion
is possible (which means, we can expect the output stream to
know allready how to print those values, like e.g. all kinds
of numbers).
Additionally, we provide a pretty-printing mechansim for pointers,
to show the address and possibly invoke a custom string conversion
on the pointee
No more fiddling with printf just to show a number reliably!
simple functions to pretty-print addresses,
doubles and floats (fixed-point, with rounding).
Also make all these basic formatting helpers noexcept
- simple function to pick up the mangled type
- pretty-printing is implemented in format-obj.cpp
- also move the demangleCxx()-Function to that location,
it starts to be used for real, outside the test framework
our minimal compiler requirement is gcc-4.9 since the
transition to Debian/Jessie as reference system.
gcc-4.9 is known to treat SFINAE on private fields properly
this is a stripped-down and very leightweight variant
of the well-known enable_if metaprogramming trick.
Providing this standard variant in a header with minimal
dependencies will allow us to phase out boost inclusions
from many further headers. As a plus, our own variant
is written such as to be more conciese in usage
(no "typename" and no acces of an embedded "::type" menber)
this includes a reorganisation concept for the header includes,
a minimal version (with minimal include dependencies), and
a generic ostream inserter operator<<
...and learned a lot about the new type_traits on the way.
As it seems, it is not possible to get a clean error message
when passing an "object" with no custom string conversion;
instead, some overload for an rvalue-ostream kicks in.
probably I'll go for shoing a type string in these cases
now we use boost::format through our own front-end util::_Fmt
solely, which both helps to reduce compilation time and code size,
and gives us a direct string conversion, which automatically
uses any custom operator string() available on arguments.
While desirable as such, I did this conversion now, since
it allows us to get rid of boost::str, which in turn helps
to drill down any remaning uses of our own util::str
the fixed version is actually more permissive,
insofar it matches any type of event, when ID = classifier
(or alternatively it matches events with type = classifier)
our formatting helper for diagnostics output,
which is primarily used in the unit-tests,
first tries to invoke a custom string conversion.
If that is not possible, it falls back to printing
the demangled type name of the object in question.
With just a minor change we're able to evaluate RTTI here
and print the actual type name, instead of the static
supertype the compiler sees on invocation. We just rely
on the typeid(obj) built-in function.
The only catch is we have to strip the " const*" suffix
(and no, it is not possible to do that on metaprogramming
level, due to the special situation where we have a void*)
This also prompted me to write some util functions for
this often encountered task to check / remove a prefix or suffix
Hopefully I've got those functions correct and safe....
...this is necessary whenever the mocked facility covered
by log matching is managed automatically as singleton,
because then other test cases will leave garbage
in the log
I worked under the erroneous assumption, that Doxygen
will use its internal entity-IDs as the link-IDs when
generating mardown-links. Yes, this seemed logical and
this would be the way I'd implement it....
But seemingly, Doxygen is not so consistent when it
comes to questions of syntax. The same holds true for
markdown, which lacking a coherent definition anyway.
Another problem is that Doxygen's auto-link generation
frequently fails, for reasons not yet clear to me.
Sometimes it seems to be necessary to give it a nudge
by including the \ref command. While I'm not willing
to go into focussed invstigation of Doxygen syntax
right now, at least I've done a search-and-replace
to remove the malformed links I've written the
last days
the initial draft of this concept is in place now, and
the first round of unit tests pass. I've got some understanding
of the purpose of the interactions and involved elements
and I'm confident this design is evolving in a sane way.
Note: extensive documentation is in the TiddlyWiki,
here I've just pasted and reworded some paragraphs from there
and integrated them into the Doxygen docs
Explanation: sigC++ was already linked as transitive dependency
from gtkmm, since it is used for the "signal-slot" system wihin GTK.
But now we want to use sigC++ itself from our generic UI-Backbone,
so we need to pick up the additional compiler and linker flags
and use them when building the relevant parts of both the application
and the test suite
at the point when we're connecting a new node to the UI-Bus,
the new node's BusTerm is not yet initialised, since we need
the uplink connection we're about to create for setting up
this BusTerm.
Consequently, the new nodes's ID is not yet initialised,
so we need to pass this endpoint-ID explicitly to the
registration function.
since, by definition, the Nexus is "the" up-link,
all we need is clever overriding of the relevant
handling functions, so the nexus will care for the routing,
while the CoreService cares for command and presentation
state handling
next step will be to rig the mock element and set up
and cover the basic / generic element behaviour
This changeset
- adapts the (planned) unit test to the semantic of
the EventLog, which is now fully implemented
- adjusts the function names on the public Tangible interface,
to be better in line with the naming convention of the
corrsponding operations on the UI-Bus:
* "mark" operations are towards the UI element
* "note" messages are from the UI element towards some
state manager, which can be reached via the bus
so this turned out to be rather expensive,
while actually not difficult to implement.
On the way, I've learned
- how to build a backtracking matcher, based on
a filtering (monadic) structure and chained lambdas
- learned the hard way how (not) to return a container
by move-reference
- made first contact with the regular expressions
now available from the standard library
this function is of use also for creating a vector of strings
from a bunch of C-Strings, but it could also be used to
construct other stuff initialised by strings (e.g. RegExps)
this deals with a recurring problem in test code:
very common "simple" fractional values can not be represented
precisely as binary floating point. The classical example is 0.1
Since this is a diagnostics facility, we can cheat around this
insidious problem by just setting a limited rendering precision.
Floating point numbers behave deterministic; you just need
to know how to deal with limited precision.
abandon the use of an assertion exception to signal match failure,
rather use a final bool conversion to retrieve the results.
Error messages are now delivered by side effect into STDERR
The reason is we're unable to deliver the desisred behaviour
with the chosen DSL syntax in C++ ; on a second thought the
new approach is even better aligned with the overall way
we're writing tests in Lumiera. And we produce match-trace
messages to indicate the complete matching path now
implemented a solution to determine negative matches.
But because this solution relies on throwing from a destructor,
it is not possible to catch the resulting assertion failure.
Not sure why (AFAIK there is no second exception thrown
while unwinding the stack), but throwing from dtors is
considered "undefined behaviour" anyway.
So this solution is of limited use
beyond that solution, I'm not sure if the desired syntax
can be implemented at all in C++. Seems that we need to build
a bracketing construct, first to initiate a negated match
and finally, after all queries, to detect if there happened
any failure or not
...no need to enclose empty sections when there are no
attributes or no children. Makes test code way more readable.
TestEventLog_test PASS as far as implemented
...and fix an error (header include order of diagnostics facility)
which prevented the first matcher implementation to work
the after()-match now works as expected
this is the tiny bit of operational functionality needed on top:
whenever we're reconfiguring the predicate, we need to re-trigger
the evaluation (and clear the cached value)
n.b.: I've verified in debugger that the closure is
allocated on the heap and the functors are passed by value
after looking into our various iterator tools,
it seems obvious that our filtering iterator implementation
has almost all of the required behaviour; we only need to
add a hook to rewrite and extend the filtering functor,
which can now nicely done with a lambda closure.
This means all memory management, if necessary, is
pushed into std::function and the automated memory
management for closures provided by the runtime.