cpp-common/bt2: add `plugin-dev.hpp`
This new file makes it possible to write pure C++ component and message
iterator classes without having to deal with C methods.
`plugin-dev.hpp` offers this to the C++ component class author:
* Inherit `bt2::UserSourceComponent`, `bt2::UserFilterComponent`, or
`bt2::UserSinkComponent` to implement a C++ component class.
This class template uses the CRTP to implement static polymorphism.
Its only template parameter is your actual user component class.
The protected constructor of those base classes accept a specific self
component wrapper and keeps it privately.
The constructor also accepts a logging tag prefix with which it builds
a protected `bt2c::Logger` named `_mLogger` so that you may use the
BT_CPPLOG*() macros in your own component class. The constructor
appends `/[`, the name of the component, and `]` to the logging tag
(for example, if your tag prefix is `SRC.CTF.FS`, working with a
component named `mein-comp`, then the complete tag is
`SRC.CTF.FS/[mein-comp]`).
Those base classes implement default, overloadable methods
(_inputPortConnected() and _getSupportedMipVersions(), for example)
when possible.
They also offer protected methods which are proxies of the contained
specific self component wrapper, for example _loggingLevel() and
_addOutputPort().
* Inherit `bt2::UserMessageIterator` to implement a C++ message
iterator.
This class template uses the CRTP to implement static polymorphism.
Its first template parameter is your actual user message iterator
class.
The other parameter is your C++ component class, for example:
class MeinSourceComponent :
public bt2::UserSourceComponent<MeinSourceComponent>
{
friend bt2::UserSourceComponent<MeinSourceComponent>;
// ...
};
class MeinMessageIterator :
public bt2::UserMessageIterator<MeinMessageIterator,
MeinSourceComponent>
{
friend bt2::UserMessageIterator<MeinMessageIterator,
MeinSourceComponent>;
// ...
};
This makes MeinMessageIterator::_component() return
`MeinSourceComponent&` (parent source component).
`bt2::UserMessageIterator` also offers the a protected `bt2c::Logger`
named `_mLogger` so that you may use the BT_CPPLOG*() macros in your
own message iterator class. When you build a
`bt2::UserMessageIterator`, you pass a logging tag suffix which will
be appended to the logging tag of the main logger of the component to
form the complete tag, for example `SRC.CTF.FS/[mein-comp]/MSG-ITER`.
The public next() method (called by the bridge) implements the very
common pattern of appending messages into the output array, and,
meanwhile:
If it catches a `bt2::TryAgain` exception:
If the message array isn't empty, transform this into a success
(don't throw).
Otherwise rethrow.
If it catches an error:
If the message array isn't empty, transform this into a success
(don't throw), but save the error of the current thread and the
type of error to throw the next time the user calls next().
Otherwise rethrow.
The derived class must implement:
void _next(bt2::ConstMessageArray& messages);
This method fills `messages` with at most `messages.capacity()`
messages and may throw `bt2::TryAgain` or a valid error whenever.
Leaving an empty `messages` means the end of iteration.
* When you inherit `bt2::User*Component` and `bt2::UserMessageIterator`,
your own methods may throw allowed exceptions (in `exc.hpp`): they'll
get translated to corresponding library status codes.
In general, prefer using BT_CPPLOGE_APPEND_CAUSE_AND_THROW() or
BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW().
* Use BT_CPP_PLUGIN_SOURCE_COMPONENT_CLASS(),
BT_CPP_PLUGIN_FILTER_COMPONENT_CLASS(), or
BT_CPP_PLUGIN_SINK_COMPONENT_CLASS() to translate your C++ component
and message iterator classes into library classes, for example:
BT_CPP_PLUGIN_SOURCE_COMPONENT_CLASS(mein, MeinSourceComponent,
MeinMessageIterator);
Those macros take care of all the C methods.
You may still add a description and help with the usual
BT_PLUGIN_*_COMPONENT_CLASS_DESCRIPTION() and
BT_PLUGIN_*_COMPONENT_CLASS_HELP() macros.
You may also used the `_WITH_ID` versions if your component class name
isn't a valid C identifier.
Internally, the C++ plugin macros use bridging classes (thank you Simon
for the initial version of those). A bridging class offers static
methods which have the signature which libbabeltrace2 expects: such a
method calls the corresponding instance method of the user C++ class.
For example,
bt2::internal::MsgIterClsBridge<MeinMessageIterator>::canSeekBeginning()
calls MeinMessageIterator::canSeekBeginning() with the correct instance
which in turns calls MeinMessageIterator::_canSeekBeginning().
The init() method of a bridging class instantiates the user C++ class
and keeps it as the private data of the C class. The finalize() method
of a bridging class destroys the user C++ class instance.
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: If8ff312b3557202f1a4dfb1584c9abff1cd35e03
Reviewed-on: https://review.lttng.org/c/babeltrace/+/11299
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Simon Marchi <simon.marchi@efficios.com>
CI-Build: Simon Marchi <simon.marchi@efficios.com>
This page took 0.025652 seconds and 4 git commands to generate.