From b6f09a6bc2b3728aabe45508a43a1c303ae39537 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Thu, 2 Nov 2023 17:04:36 -0400 Subject: [PATCH] cpp-common/bt2: add `bt2::Self*Component` and `bt2::SelfComponent*Port` This new file is an adaptation of `component-port.hpp` and works the same way. That being said, I didn't bother: * Making equivalent objects in `component-port.hpp` accept the "self" versions. In theory, you could build a `bt2::ConstSourceComponent` from a `bt2::SelfSourceComponent`, for example, but I believe we won't do that often, if ever. Therefore you'll need to use the asConstComponent() and asConstPort() methods explicitly. However, I added aliases in the new classes to avoid going calling those in most situations. For example, bt2::SelfFilterComponent::name() calls bt2::SelfComponent::name() which calls bt2::ConstComponent::name(). * Implementing the constant versions of the new classes, for example `bt2::ConstSelfComponent`. For example, a method which would benefit this is bt2::SelfSinkComponent::isInterrupted(). Again, I don't think we'll need this. The "self" wrappers are for the component class author, and she rarely needs a constant view of its own object. Add a port to a self component with the addInputPort() or addOutputPort() methods, which return a borrowed reference of the created and added port. Those methods have an overload which accepts user data to store into the returned port. Create a message iterator from a self sink component with bt2::SelfSinkComponent::createMessageIterator(). Signed-off-by: Philippe Proulx Change-Id: Id6bcbfcea4a562780eee0700cee507431c4e5661 Reviewed-on: https://review.lttng.org/c/babeltrace/+/11235 CI-Build: Simon Marchi Reviewed-by: Simon Marchi Tested-by: jenkins --- src/Makefile.am | 1 + src/cpp-common/bt2/self-component-port.hpp | 783 +++++++++++++++++++++ 2 files changed, 784 insertions(+) create mode 100644 src/cpp-common/bt2/self-component-port.hpp diff --git a/src/Makefile.am b/src/Makefile.am index b572c728..5494041a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,6 +31,7 @@ noinst_HEADERS = \ cpp-common/bt2/message.hpp \ cpp-common/bt2/shared-object.hpp \ cpp-common/bt2/raw-value-proxy.hpp \ + cpp-common/bt2/self-component-port.hpp \ cpp-common/bt2/trace-ir.hpp \ cpp-common/bt2/type-traits.hpp \ cpp-common/bt2/value.hpp \ diff --git a/src/cpp-common/bt2/self-component-port.hpp b/src/cpp-common/bt2/self-component-port.hpp new file mode 100644 index 00000000..1dea532f --- /dev/null +++ b/src/cpp-common/bt2/self-component-port.hpp @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2023 Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#ifndef BABELTRACE_CPP_COMMON_BT2_SELF_COMPONENT_PORT_HPP +#define BABELTRACE_CPP_COMMON_BT2_SELF_COMPONENT_PORT_HPP + +#include +#include + +#include + +#include "logging.hpp" + +#include "common/assert.h" + +#include "borrowed-object-iterator.hpp" +#include "borrowed-object.hpp" +#include "component-port.hpp" +#include "message-iterator.hpp" + +namespace bt2 { + +class SelfSourceComponent; +class SelfFilterComponent; +class SelfSinkComponent; + +class SelfComponent final : public BorrowedObject +{ +public: + explicit SelfComponent(const _LibObjPtr libObjPtr) noexcept : _ThisBorrowedObject {libObjPtr} + { + } + + explicit SelfComponent(bt_self_component_source * const libObjPtr) noexcept : + _ThisBorrowedObject {bt_self_component_source_as_self_component(libObjPtr)} + { + } + + explicit SelfComponent(bt_self_component_filter * const libObjPtr) noexcept : + _ThisBorrowedObject {bt_self_component_filter_as_self_component(libObjPtr)} + { + } + + explicit SelfComponent(bt_self_component_sink * const libObjPtr) noexcept : + _ThisBorrowedObject {bt_self_component_sink_as_self_component(libObjPtr)} + { + } + + /* Not `explicit` to make them behave like copy constructors */ + SelfComponent(SelfSourceComponent other) noexcept; + SelfComponent(SelfFilterComponent other) noexcept; + SelfComponent(SelfSinkComponent other) noexcept; + + SelfComponent operator=(SelfSourceComponent other) noexcept; + SelfComponent operator=(SelfFilterComponent other) noexcept; + SelfComponent operator=(SelfSinkComponent other) noexcept; + + ConstComponent asConstComponent() const noexcept + { + return ConstComponent {bt_self_component_as_component(this->libObjPtr())}; + } + + bool isSource() const noexcept + { + return this->asConstComponent().isSource(); + } + + bool isFilter() const noexcept + { + return this->asConstComponent().isFilter(); + } + + bool isSink() const noexcept + { + return this->asConstComponent().isSink(); + } + + const char *name() const noexcept + { + return this->asConstComponent().name(); + } + + LoggingLevel loggingLevel() const noexcept + { + return this->asConstComponent().loggingLevel(); + } + + std::uint64_t graphMipVersion() const noexcept + { + return bt_self_component_get_graph_mip_version(this->libObjPtr()); + } + + template + T& data() const noexcept + { + return *static_cast(bt_self_component_get_data(this->libObjPtr())); + } + + template + void data(T& obj) const noexcept + { + bt_self_component_set_data(this->libObjPtr(), static_cast(&obj)); + } +}; + +template +class SelfSpecificComponent : public BorrowedObject +{ +private: + using typename BorrowedObject::_ThisBorrowedObject; + +public: + using typename BorrowedObject::_LibObjPtr; + +protected: + explicit SelfSpecificComponent(const _LibObjPtr libObjPtr) noexcept : + _ThisBorrowedObject {libObjPtr} + { + } + + template + PortT _addPort(const char * const name, DataT * const data, AddPortFuncT&& func) const + { + LibPortT *libPortPtr; + + const auto status = func(this->libObjPtr(), name, static_cast(data), &libPortPtr); + + switch (status) { + case BT_SELF_COMPONENT_ADD_PORT_STATUS_OK: + return PortT {libPortPtr}; + case BT_SELF_COMPONENT_ADD_PORT_STATUS_MEMORY_ERROR: + throw MemoryError {}; + case BT_SELF_COMPONENT_ADD_PORT_STATUS_ERROR: + throw Error {}; + default: + bt_common_abort(); + } + } + +public: + const char *name() const noexcept + { + return this->_selfComponent().name(); + } + + LoggingLevel loggingLevel() const noexcept + { + return this->_selfComponent().loggingLevel(); + } + + std::uint64_t graphMipVersion() const noexcept + { + return this->_selfComponent().graphMipVersion(); + } + + template + T& data() const noexcept + { + return this->_selfComponent().template data(); + } + + template + void data(T& obj) const noexcept + { + this->_selfComponent().data(obj); + } + +private: + SelfComponent _selfComponent() const noexcept + { + return SelfComponent {this->libObjPtr()}; + } +}; + +namespace internal { + +template +struct SelfComponentPortsSpec; + +template <> +struct SelfComponentPortsSpec final +{ + static std::uint64_t portCount(bt_self_component_source * const libCompPtr) noexcept + { + return bt_component_source_get_output_port_count( + bt_self_component_source_as_component_source(libCompPtr)); + } + + static bt_self_component_port_output *portByIndex(bt_self_component_source * const libCompPtr, + const std::uint64_t index) noexcept + { + return bt_self_component_source_borrow_output_port_by_index(libCompPtr, index); + } + + static bt_self_component_port_output *portByName(bt_self_component_source * const libCompPtr, + const char * const name) noexcept + { + return bt_self_component_source_borrow_output_port_by_name(libCompPtr, name); + } +}; + +template <> +struct SelfComponentPortsSpec final +{ + static std::uint64_t portCount(bt_self_component_filter * const libCompPtr) noexcept + { + return bt_component_filter_get_output_port_count( + bt_self_component_filter_as_component_filter(libCompPtr)); + } + + static bt_self_component_port_output *portByIndex(bt_self_component_filter * const libCompPtr, + const std::uint64_t index) noexcept + { + return bt_self_component_filter_borrow_output_port_by_index(libCompPtr, index); + } + + static bt_self_component_port_output *portByName(bt_self_component_filter * const libCompPtr, + const char * const name) noexcept + { + return bt_self_component_filter_borrow_output_port_by_name(libCompPtr, name); + } +}; + +template <> +struct SelfComponentPortsSpec final +{ + static std::uint64_t portCount(bt_self_component_filter * const libCompPtr) noexcept + { + return bt_component_filter_get_input_port_count( + bt_self_component_filter_as_component_filter(libCompPtr)); + } + + static bt_self_component_port_input *portByIndex(bt_self_component_filter * const libCompPtr, + const std::uint64_t index) noexcept + { + return bt_self_component_filter_borrow_input_port_by_index(libCompPtr, index); + } + + static bt_self_component_port_input *portByName(bt_self_component_filter * const libCompPtr, + const char * const name) noexcept + { + return bt_self_component_filter_borrow_input_port_by_name(libCompPtr, name); + } +}; + +template <> +struct SelfComponentPortsSpec final +{ + static std::uint64_t portCount(bt_self_component_sink * const libCompPtr) noexcept + { + return bt_component_sink_get_input_port_count( + bt_self_component_sink_as_component_sink(libCompPtr)); + } + + static bt_self_component_port_input *portByIndex(bt_self_component_sink * const libCompPtr, + const std::uint64_t index) noexcept + { + return bt_self_component_sink_borrow_input_port_by_index(libCompPtr, index); + } + + static bt_self_component_port_input *portByName(bt_self_component_sink * const libCompPtr, + const char * const name) noexcept + { + return bt_self_component_sink_borrow_input_port_by_name(libCompPtr, name); + } +}; + +} /* namespace internal */ + +template +class SelfComponentPort; + +template +class SelfComponentPorts final : public BorrowedObject +{ +private: + using typename BorrowedObject::_ThisBorrowedObject; + using _Spec = internal::SelfComponentPortsSpec; + +public: + using typename BorrowedObject::_LibObjPtr; + using Port = SelfComponentPort; + using Iterator = BorrowedObjectIterator; + + explicit SelfComponentPorts(const _LibObjPtr libObjPtr) noexcept : + _ThisBorrowedObject {libObjPtr} + { + } + + std::uint64_t length() const noexcept + { + return _Spec::portCount(this->libObjPtr()); + } + + Port operator[](std::uint64_t index) const noexcept; + Port operator[](const char *name) const noexcept; + Port operator[](const std::string& name) const noexcept; + Iterator begin() const noexcept; + Iterator end() const noexcept; + Port front() const noexcept; + Port back() const noexcept; +}; + +class SelfSourceComponent final : public SelfSpecificComponent +{ +public: + using OutputPorts = SelfComponentPorts; + + explicit SelfSourceComponent(bt_self_component_source * const libObjPtr) noexcept : + SelfSpecificComponent {libObjPtr} + { + } + + ConstSourceComponent asConstComponent() const noexcept + { + return ConstSourceComponent { + bt_self_component_source_as_component_source(this->libObjPtr())}; + } + + template + OutputPorts::Port addOutputPort(const char *name, DataT& data) const; + + OutputPorts::Port addOutputPort(const char *name) const; + + template + OutputPorts::Port addOutputPort(const std::string& name, DataT& data) const; + + OutputPorts::Port addOutputPort(const std::string& name) const; + OutputPorts outputPorts() const noexcept; + +private: + template + OutputPorts::Port _addOutputPort(const char *name, DataT *data) const; +}; + +class SelfFilterComponent final : public SelfSpecificComponent +{ +public: + using InputPorts = SelfComponentPorts; + using OutputPorts = SelfComponentPorts; + + explicit SelfFilterComponent(bt_self_component_filter * const libObjPtr) noexcept : + SelfSpecificComponent {libObjPtr} + { + } + + ConstFilterComponent asConstComponent() const noexcept + { + return ConstFilterComponent { + bt_self_component_filter_as_component_filter(this->libObjPtr())}; + } + + template + InputPorts::Port addInputPort(const char *name, DataT& data) const; + + InputPorts::Port addInputPort(const char *name) const; + + template + InputPorts::Port addInputPort(const std::string& name, DataT& data) const; + + InputPorts::Port addInputPort(const std::string& name) const; + InputPorts inputPorts() const noexcept; + + template + OutputPorts::Port addOutputPort(const char *name, DataT& data) const; + + OutputPorts::Port addOutputPort(const char *name) const; + + template + OutputPorts::Port addOutputPort(const std::string& name, DataT& data) const; + + OutputPorts::Port addOutputPort(const std::string& name) const; + OutputPorts outputPorts() const noexcept; + +private: + template + InputPorts::Port _addInputPort(const char *name, DataT *data) const; + + template + OutputPorts::Port _addOutputPort(const char *name, DataT *data) const; +}; + +class SelfSinkComponent final : public SelfSpecificComponent +{ +public: + using InputPorts = SelfComponentPorts; + + explicit SelfSinkComponent(bt_self_component_sink * const libObjPtr) noexcept : + SelfSpecificComponent {libObjPtr} + { + } + + ConstSinkComponent asConstComponent() const noexcept + { + return ConstSinkComponent {bt_self_component_sink_as_component_sink(this->libObjPtr())}; + } + + MessageIterator::Shared createMessageIterator(InputPorts::Port port) const; + + bool isInterrupted() const noexcept + { + return static_cast(bt_self_component_sink_is_interrupted(this->libObjPtr())); + } + + template + InputPorts::Port addInputPort(const char *name, DataT& data) const; + + InputPorts::Port addInputPort(const char *name) const; + + template + InputPorts::Port addInputPort(const std::string& name, DataT& data) const; + + InputPorts::Port addInputPort(const std::string& name) const; + InputPorts inputPorts() const noexcept; + +private: + template + InputPorts::Port _addInputPort(const char *name, DataT *data) const; +}; + +inline SelfComponent::SelfComponent(const SelfSourceComponent other) noexcept : + SelfComponent {other.libObjPtr()} +{ +} + +inline SelfComponent::SelfComponent(const SelfFilterComponent other) noexcept : + SelfComponent {other.libObjPtr()} +{ +} + +inline SelfComponent::SelfComponent(const SelfSinkComponent other) noexcept : + SelfComponent {other.libObjPtr()} +{ +} + +inline SelfComponent SelfComponent::operator=(const SelfSourceComponent other) noexcept +{ + *this = SelfComponent {other.libObjPtr()}; + return *this; +} + +inline SelfComponent SelfComponent::operator=(const SelfFilterComponent other) noexcept +{ + *this = SelfComponent {other.libObjPtr()}; + return *this; +} + +inline SelfComponent SelfComponent::operator=(const SelfSinkComponent other) noexcept +{ + *this = SelfComponent {other.libObjPtr()}; + return *this; +} + +namespace internal { + +template +struct SelfComponentPortSpec; + +/* Functions specific to self component input ports */ +template <> +struct SelfComponentPortSpec final +{ + static bt_self_component_port * + asSelfCompPort(bt_self_component_port_input * const libObjPtr) noexcept + { + return bt_self_component_port_input_as_self_component_port(libObjPtr); + } + + static const bt_port_input * + asConstPort(const bt_self_component_port_input * const libObjPtr) noexcept + { + return bt_self_component_port_input_as_port_input(libObjPtr); + } +}; + +/* Functions specific to self component output ports */ +template <> +struct SelfComponentPortSpec final +{ + static bt_self_component_port * + asSelfCompPort(bt_self_component_port_output * const libObjPtr) noexcept + { + return bt_self_component_port_output_as_self_component_port(libObjPtr); + } + + static const bt_port_output * + asConstPort(bt_self_component_port_output * const libObjPtr) noexcept + { + return bt_self_component_port_output_as_port_output(libObjPtr); + } +}; + +} /* namespace internal */ + +template +class SelfComponentPort final : public BorrowedObject +{ +public: + using typename BorrowedObject::_LibObjPtr; + + explicit SelfComponentPort(const _LibObjPtr libObjPtr) noexcept : + BorrowedObject {libObjPtr} + { + } + + ConstPort asConstPort() const noexcept + { + return ConstPort { + internal::SelfComponentPortSpec::asConstPort(this->libObjPtr())}; + } + + const char *name() const noexcept + { + return this->asConstPort().name(); + } + + bool isConnected() const noexcept + { + return this->asConstPort().isConnected(); + } + + SelfComponent component() const noexcept + { + return SelfComponent {bt_self_component_port_borrow_component(this->_libSelfCompPortPtr())}; + } + + template + T& data() const noexcept + { + *static_cast(bt_self_component_port_get_data(this->_libSelfCompPortPtr())); + } + +private: + bt_self_component_port *_libSelfCompPortPtr() const noexcept + { + return internal::SelfComponentPortSpec::asSelfCompPort(this->libObjPtr()); + } +}; + +template +typename SelfComponentPorts::Port +SelfComponentPorts::operator[]( + const std::uint64_t index) const noexcept +{ + return Port {_Spec::portByIndex(this->libObjPtr(), index)}; +} + +template +typename SelfComponentPorts::Port +SelfComponentPorts::operator[]( + const char * const name) const noexcept +{ + return Port {_Spec::portByName(this->libObjPtr(), name)}; +} + +template +typename SelfComponentPorts::Port +SelfComponentPorts::operator[]( + const std::string& name) const noexcept +{ + return (*this)[name.data()]; +} + +template +typename SelfComponentPorts::Iterator +SelfComponentPorts::begin() const noexcept +{ + return Iterator {*this, 0}; +} + +template +typename SelfComponentPorts::Iterator +SelfComponentPorts::end() const noexcept +{ + return Iterator {*this, this->length()}; +} + +template +typename SelfComponentPorts::Port +SelfComponentPorts::front() const noexcept +{ + return (*this)[0]; +} + +template +typename SelfComponentPorts::Port +SelfComponentPorts::back() const noexcept +{ + return (*this)[this->length() - 1]; +} + +using SelfComponentInputPort = SelfComponentPort; + +using SelfComponentOutputPort = + SelfComponentPort; + +template +SelfSourceComponent::OutputPorts::Port SelfSourceComponent::_addOutputPort(const char * const name, + DataT * const data) const +{ + return this->_addPort( + name, data, bt_self_component_source_add_output_port); +} + +template +SelfSourceComponent::OutputPorts::Port SelfSourceComponent::addOutputPort(const char * const name, + DataT& data) const +{ + return this->_addOutputPort(name, &data); +} + +inline SelfSourceComponent::OutputPorts::Port +SelfSourceComponent::addOutputPort(const char * const name) const +{ + return this->_addOutputPort(name, nullptr); +} + +template +SelfSourceComponent::OutputPorts::Port SelfSourceComponent::addOutputPort(const std::string& name, + DataT& data) const +{ + return this->_addOutputPort(name.data(), &data); +} + +inline SelfSourceComponent::OutputPorts::Port +SelfSourceComponent::addOutputPort(const std::string& name) const +{ + return this->_addOutputPort(name.data(), nullptr); +} + +inline SelfSourceComponent::OutputPorts SelfSourceComponent::outputPorts() const noexcept +{ + return OutputPorts {this->libObjPtr()}; +} + +template +SelfFilterComponent::OutputPorts::Port SelfFilterComponent::_addOutputPort(const char * const name, + DataT * const data) const +{ + return this->_addPort( + name, data, bt_self_component_filter_add_output_port); +} + +template +SelfFilterComponent::OutputPorts::Port SelfFilterComponent::addOutputPort(const char * const name, + DataT& data) const +{ + return this->_addOutputPort(name, &data); +} + +inline SelfFilterComponent::OutputPorts::Port +SelfFilterComponent::addOutputPort(const char * const name) const +{ + return this->_addOutputPort(name, nullptr); +} + +template +SelfFilterComponent::OutputPorts::Port SelfFilterComponent::addOutputPort(const std::string& name, + DataT& data) const +{ + return this->_addOutputPort(name.data(), &data); +} + +inline SelfFilterComponent::OutputPorts::Port +SelfFilterComponent::addOutputPort(const std::string& name) const +{ + return this->_addOutputPort(name.data(), nullptr); +} + +inline SelfFilterComponent::OutputPorts SelfFilterComponent::outputPorts() const noexcept +{ + return OutputPorts {this->libObjPtr()}; +} + +template +SelfFilterComponent::InputPorts::Port SelfFilterComponent::_addInputPort(const char * const name, + DataT * const data) const +{ + return this->_addPort( + name, data, bt_self_component_filter_add_input_port); +} + +template +SelfFilterComponent::InputPorts::Port SelfFilterComponent::addInputPort(const char * const name, + DataT& data) const +{ + return this->_addInputPort(name, &data); +} + +inline SelfFilterComponent::InputPorts::Port +SelfFilterComponent::addInputPort(const char * const name) const +{ + return this->_addInputPort(name, nullptr); +} + +template +SelfFilterComponent::InputPorts::Port SelfFilterComponent::addInputPort(const std::string& name, + DataT& data) const +{ + return this->_addInputPort(name.data(), &data); +} + +inline SelfFilterComponent::InputPorts::Port +SelfFilterComponent::addInputPort(const std::string& name) const +{ + return this->_addInputPort(name.data(), nullptr); +} + +inline SelfFilterComponent::InputPorts SelfFilterComponent::inputPorts() const noexcept +{ + return InputPorts {this->libObjPtr()}; +} + +inline MessageIterator::Shared +SelfSinkComponent::createMessageIterator(const InputPorts::Port port) const +{ + bt_message_iterator *libMsgIterPtr = nullptr; + + const auto status = bt_message_iterator_create_from_sink_component( + this->libObjPtr(), port.libObjPtr(), &libMsgIterPtr); + + switch (status) { + case BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK: + BT_ASSERT(libMsgIterPtr); + return MessageIterator::Shared::createWithoutRef(libMsgIterPtr); + case BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_MEMORY_ERROR: + throw MemoryError {}; + case BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_ERROR: + throw Error {}; + default: + bt_common_abort(); + } +} + +template +SelfSinkComponent::InputPorts::Port SelfSinkComponent::_addInputPort(const char * const name, + DataT * const data) const +{ + return this->_addPort( + name, data, bt_self_component_sink_add_input_port); +} + +template +SelfSinkComponent::InputPorts::Port SelfSinkComponent::addInputPort(const char * const name, + DataT& data) const +{ + return this->_addInputPort(name, &data); +} + +inline SelfSinkComponent::InputPorts::Port +SelfSinkComponent::addInputPort(const char * const name) const +{ + return this->_addInputPort(name, nullptr); +} + +template +SelfSinkComponent::InputPorts::Port SelfSinkComponent::addInputPort(const std::string& name, + DataT& data) const +{ + return this->_addInputPort(name.data(), &data); +} + +inline SelfSinkComponent::InputPorts::Port +SelfSinkComponent::addInputPort(const std::string& name) const +{ + return this->_addInputPort(name.data(), nullptr); +} + +inline SelfSinkComponent::InputPorts SelfSinkComponent::inputPorts() const noexcept +{ + return InputPorts {this->libObjPtr()}; +} + +} /* namespace bt2 */ + +#endif /* BABELTRACE_CPP_COMMON_BT2_SELF_COMPONENT_PORT_HPP */ -- 2.34.1