From 7bdf11a1a672ad4e1416c9e9c075c7f4aa7e6421 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 31 Oct 2023 23:03:36 -0400 Subject: [PATCH] cpp-common/bt2: add `bt2::Const*Component` and `bt2::Const*Port` This patch adds the `bt2::ConstComponent`, `bt2::ConstSourceComponent`, `bt2::ConstFilterComponent`, and `bt2::ConstSinkComponent` wrapper classes to wrap resp. `const bt_component`, `const bt_component_source`, `const bt_component_filter`, and `const bt_component_sink`. I didn't find a clever way to make `bt2::ConstSourceComponent`, for example, inherit `bt2::ConstComponent`, because they manage different library types (`const bt_component` vs. `const bt_component_source`). I think this is a first in `src/cpp-common/bt2` for this situation: for example, all value objects have the `bt_value` type, all field classes have the `bt_field_class` type, and so on, making it possible to also express the intended relations in C++. I though about using a library upcasting function (for example, bt_component_source_as_component_const()) to call the parent constructor, but then there would be no "safe" way to return to `const bt_component_source` because there aren't downcasting functions (`reinterpret_cast()` would probably work, but isn't super legit). Therefore there's no relation between specific component wrapper classes and `bt2::ConstComponent`. That being said, `bt2::ConstComponent` is courteous and offers all the copy constructors and assignment operators to copy and assign from specific component wrappers. For example: void f(const bt2::ConstComponent myComp) { // ... } void g(const bt_component_source * const libCompPtr) { const bt2::ConstComponent comp {libCompPtr}; const bt2::ConstSourceComponent srcComp {libCompPtr}; f(srcComp); } However, the shared versions aren't directly compatible because the reference count functions aren't the same (an obvious requirement to construct a shared object from another one). To make things easier, each specific component wrapper class has the sharedComponent() method which returns a `bt2::ConstComponent::Shared` instance: void f(bt2::ConstComponent::Shared myComp) { // ... } void g(bt2::ConstSourceComponent::Shared srcComp) { f(srcComp->sharedComponent()); } Each specific component wrapper class kindly offers the name() and loggingLevel() methods to avoid going to a `bt2::ConstComponent` by hand. Each specific component wrapper class has its inputPorts() and/or outputPorts() method(s). Those return an instance of `bt2::ConstComponentPorts` with the appropriate template arguments to make things just work. `bt2::ConstComponentPorts` has the length() method and various `[]` operators to access ports: mySrc.outputPorts()[3] myFlt.inputPorts()["file2"] The returned object is one of `bt2::ConstInputPort` or `bt2::ConstOutputPort` wrapping resp. `const bt_port_input` and `const bt_port_output`. Component and port wrapper classes are part of the same header, `component-port.hpp`, for the same reason all high-level trace IR wrapper classes are in the single `trace-ir.hpp`: a port object may return a component (component() method) and a component object may return a port (inputPorts()/outputPorts() methods), making it difficult, if not impossible, to use two different headers because we don't know the inclusion order of the user. Because the libbabeltrace2 API always deals with specific (input or output) port objects, there's no `const bt_port` wrapper class: you always use `bt2::ConstInputPort` or `bt2::ConstOutputPort`. In other words, no API function returns a general `const bt_port` pointer. Signed-off-by: Philippe Proulx Change-Id: I1324a59c8291cb83a432eeb7477c6b3e353924f5 Reviewed-on: https://review.lttng.org/c/babeltrace/+/11184 Reviewed-by: Simon Marchi CI-Build: Simon Marchi Tested-by: jenkins --- src/Makefile.am | 1 + src/cpp-common/bt2/component-port.hpp | 557 ++++++++++++++++++++++++++ 2 files changed, 558 insertions(+) create mode 100644 src/cpp-common/bt2/component-port.hpp diff --git a/src/Makefile.am b/src/Makefile.am index d2559c33..1a01d427 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ noinst_HEADERS = \ cpp-common/bt2/borrowed-object.hpp \ cpp-common/bt2/clock-class.hpp \ cpp-common/bt2/clock-snapshot.hpp \ + cpp-common/bt2/component-port.hpp \ cpp-common/bt2/exc.hpp \ cpp-common/bt2/field-class.hpp \ cpp-common/bt2/field.hpp \ diff --git a/src/cpp-common/bt2/component-port.hpp b/src/cpp-common/bt2/component-port.hpp new file mode 100644 index 00000000..6a7db67f --- /dev/null +++ b/src/cpp-common/bt2/component-port.hpp @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2023 Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#ifndef BABELTRACE_CPP_COMMON_BT2_COMPONENT_PORT_HPP +#define BABELTRACE_CPP_COMMON_BT2_COMPONENT_PORT_HPP + +#include +#include + +#include + +#include "logging.hpp" + +#include "borrowed-object-iterator.hpp" +#include "borrowed-object.hpp" +#include "shared-object.hpp" + +namespace bt2 { +namespace internal { + +struct ConstComponentRefFuncs final +{ + static void get(const bt_component * const libObjPtr) noexcept + { + bt_component_get_ref(libObjPtr); + } + + static void put(const bt_component * const libObjPtr) noexcept + { + bt_component_put_ref(libObjPtr); + } +}; + +} /* namespace internal */ + +class ConstSourceComponent; +class ConstFilterComponent; +class ConstSinkComponent; + +class ConstComponent final : public BorrowedObject +{ +private: + using typename BorrowedObject::_ThisBorrowedObject; + +public: + using Shared = + SharedObject; + + explicit ConstComponent(const bt_component * const libObjPtr) noexcept : + _ThisBorrowedObject {libObjPtr} + { + } + + explicit ConstComponent(const bt_component_source * const libObjPtr) noexcept : + _ThisBorrowedObject {bt_component_source_as_component_const(libObjPtr)} + { + } + + explicit ConstComponent(const bt_component_filter * const libObjPtr) noexcept : + _ThisBorrowedObject {bt_component_filter_as_component_const(libObjPtr)} + { + } + + explicit ConstComponent(const bt_component_sink * const libObjPtr) noexcept : + _ThisBorrowedObject {bt_component_sink_as_component_const(libObjPtr)} + { + } + + /* Not `explicit` to make them behave like copy constructors */ + ConstComponent(ConstSourceComponent other) noexcept; + ConstComponent(ConstFilterComponent other) noexcept; + ConstComponent(ConstSinkComponent other) noexcept; + + ConstComponent operator=(ConstSourceComponent other) noexcept; + ConstComponent operator=(ConstFilterComponent other) noexcept; + ConstComponent operator=(ConstSinkComponent other) noexcept; + + bool isSource() const noexcept + { + return static_cast(bt_component_is_source(this->libObjPtr())); + } + + bool isFilter() const noexcept + { + return static_cast(bt_component_is_filter(this->libObjPtr())); + } + + bool isSink() const noexcept + { + return static_cast(bt_component_is_sink(this->libObjPtr())); + } + + const char *name() const noexcept + { + return bt_component_get_name(this->libObjPtr()); + } + + LoggingLevel loggingLevel() const noexcept + { + return static_cast(bt_component_get_logging_level(this->libObjPtr())); + } + + Shared shared() const noexcept + { + return Shared::createWithRef(*this); + } +}; + +template +class ConstSpecificComponent : public BorrowedObject +{ +public: + using typename BorrowedObject::_LibObjPtr; + +protected: + explicit ConstSpecificComponent(const _LibObjPtr libObjPtr) noexcept : + BorrowedObject {libObjPtr} + { + } + +public: + const char *name() const noexcept + { + return this->_constComponent().name(); + } + + LoggingLevel loggingLevel() const noexcept + { + return this->_constComponent().loggingLevel(); + } + + ConstComponent::Shared sharedComponent() const noexcept + { + return this->_constComponent().shared(); + } + +private: + ConstComponent _constComponent() const noexcept + { + return ConstComponent {this->libObjPtr()}; + } +}; + +namespace internal { + +template +struct ConstComponentPortsSpec; + +template <> +struct ConstComponentPortsSpec final +{ + static std::uint64_t portCount(const bt_component_source * const libCompPtr) noexcept + { + return bt_component_source_get_output_port_count(libCompPtr); + } + + static const bt_port_output *portByIndex(const bt_component_source * const libCompPtr, + const std::uint64_t index) noexcept + { + return bt_component_source_borrow_output_port_by_index_const(libCompPtr, index); + } + + static const bt_port_output *portByName(const bt_component_source * const libCompPtr, + const char * const name) noexcept + { + return bt_component_source_borrow_output_port_by_name_const(libCompPtr, name); + } +}; + +template <> +struct ConstComponentPortsSpec final +{ + static std::uint64_t portCount(const bt_component_filter * const libCompPtr) noexcept + { + return bt_component_filter_get_output_port_count(libCompPtr); + } + + static const bt_port_output *portByIndex(const bt_component_filter * const libCompPtr, + const std::uint64_t index) noexcept + { + return bt_component_filter_borrow_output_port_by_index_const(libCompPtr, index); + } + + static const bt_port_output *portByName(const bt_component_filter * const libCompPtr, + const char * const name) noexcept + { + return bt_component_filter_borrow_output_port_by_name_const(libCompPtr, name); + } +}; + +template <> +struct ConstComponentPortsSpec final +{ + static std::uint64_t portCount(const bt_component_filter * const libCompPtr) noexcept + { + return bt_component_filter_get_input_port_count(libCompPtr); + } + + static const bt_port_input *portByIndex(const bt_component_filter * const libCompPtr, + const std::uint64_t index) noexcept + { + return bt_component_filter_borrow_input_port_by_index_const(libCompPtr, index); + } + + static const bt_port_input *portByName(const bt_component_filter * const libCompPtr, + const char * const name) noexcept + { + return bt_component_filter_borrow_input_port_by_name_const(libCompPtr, name); + } +}; + +template <> +struct ConstComponentPortsSpec final +{ + static std::uint64_t portCount(const bt_component_sink * const libCompPtr) noexcept + { + return bt_component_sink_get_input_port_count(libCompPtr); + } + + static const bt_port_input *portByIndex(const bt_component_sink * const libCompPtr, + const std::uint64_t index) noexcept + { + return bt_component_sink_borrow_input_port_by_index_const(libCompPtr, index); + } + + static const bt_port_input *portByName(const bt_component_sink * const libCompPtr, + const char * const name) noexcept + { + return bt_component_sink_borrow_input_port_by_name_const(libCompPtr, name); + } +}; + +} /* namespace internal */ + +template +class ConstPort; + +template +class ConstComponentPorts final : public BorrowedObject +{ +private: + using _Spec = internal::ConstComponentPortsSpec; + +public: + using typename BorrowedObject::_LibObjPtr; + using Port = ConstPort; + using Iterator = BorrowedObjectIterator; + + explicit ConstComponentPorts(const _LibObjPtr libObjPtr) noexcept : + BorrowedObject {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; +}; + +namespace internal { + +struct ConstSourceComponentRefFuncs final +{ + static void get(const bt_component_source * const libObjPtr) noexcept + { + bt_component_source_get_ref(libObjPtr); + } + + static void put(const bt_component_source * const libObjPtr) noexcept + { + bt_component_source_put_ref(libObjPtr); + } +}; + +} /* namespace internal */ + +class ConstSourceComponent final : public ConstSpecificComponent +{ +public: + using Shared = SharedObject; + + using OutputPorts = ConstComponentPorts; + + explicit ConstSourceComponent(const bt_component_source * const libObjPtr) noexcept : + ConstSpecificComponent {libObjPtr} + { + } + + OutputPorts outputPorts() const noexcept; + + Shared shared() const noexcept + { + return Shared::createWithRef(*this); + } +}; + +namespace internal { + +struct ConstFilterComponentRefFuncs final +{ + static void get(const bt_component_filter * const libObjPtr) noexcept + { + bt_component_filter_get_ref(libObjPtr); + } + + static void put(const bt_component_filter * const libObjPtr) noexcept + { + bt_component_filter_put_ref(libObjPtr); + } +}; + +} /* namespace internal */ + +class ConstFilterComponent final : public ConstSpecificComponent +{ +public: + using Shared = SharedObject; + + using InputPorts = ConstComponentPorts; + using OutputPorts = ConstComponentPorts; + + explicit ConstFilterComponent(const bt_component_filter * const libObjPtr) noexcept : + ConstSpecificComponent {libObjPtr} + { + } + + InputPorts inputPorts() const noexcept; + OutputPorts outputPorts() const noexcept; + + Shared shared() const noexcept + { + return Shared::createWithRef(*this); + } +}; + +namespace internal { + +struct ConstSinkComponentRefFuncs final +{ + static void get(const bt_component_sink * const libObjPtr) noexcept + { + bt_component_sink_get_ref(libObjPtr); + } + + static void put(const bt_component_sink * const libObjPtr) noexcept + { + bt_component_sink_put_ref(libObjPtr); + } +}; + +} /* namespace internal */ + +class ConstSinkComponent final : public ConstSpecificComponent +{ +public: + using Shared = SharedObject; + + using InputPorts = ConstComponentPorts; + + explicit ConstSinkComponent(const bt_component_sink * const libObjPtr) noexcept : + ConstSpecificComponent {libObjPtr} + { + } + + InputPorts inputPorts() const noexcept; + + Shared shared() const noexcept + { + return Shared::createWithRef(*this); + } +}; + +inline ConstComponent::ConstComponent(const ConstSourceComponent other) noexcept : + ConstComponent {other.libObjPtr()} +{ +} + +inline ConstComponent::ConstComponent(const ConstFilterComponent other) noexcept : + ConstComponent {other.libObjPtr()} +{ +} + +inline ConstComponent::ConstComponent(const ConstSinkComponent other) noexcept : + ConstComponent {other.libObjPtr()} +{ +} + +inline ConstComponent ConstComponent::operator=(const ConstSourceComponent other) noexcept +{ + *this = ConstComponent {other.libObjPtr()}; + return *this; +} + +inline ConstComponent ConstComponent::operator=(const ConstFilterComponent other) noexcept +{ + *this = ConstComponent {other.libObjPtr()}; + return *this; +} + +inline ConstComponent ConstComponent::operator=(const ConstSinkComponent other) noexcept +{ + *this = ConstComponent {other.libObjPtr()}; + return *this; +} + +namespace internal { + +template +struct ConstPortSpec; + +/* Functions specific to constant input ports */ +template <> +struct ConstPortSpec final +{ + static const bt_port *asPort(const bt_port_input * const libObjPtr) noexcept + { + return bt_port_input_as_port_const(libObjPtr); + } +}; + +/* Functions specific to constant output ports */ +template <> +struct ConstPortSpec final +{ + static const bt_port *asPort(const bt_port_output * const libObjPtr) noexcept + { + return bt_port_output_as_port_const(libObjPtr); + } +}; + +template +struct ConstPortRefFuncs final +{ + static void get(LibObjT * const libObjPtr) noexcept + { + bt_port_get_ref(ConstPortSpec::port(libObjPtr)); + } + + static void put(LibObjT * const libObjPtr) noexcept + { + bt_port_put_ref(ConstPortSpec::port(libObjPtr)); + } +}; + +} /* namespace internal */ + +template +class ConstPort final : public BorrowedObject +{ +public: + using typename BorrowedObject::_LibObjPtr; + using Shared = SharedObject>; + + explicit ConstPort(const _LibObjPtr libObjPtr) noexcept : BorrowedObject {libObjPtr} + { + } + + const char *name() const noexcept + { + return bt_port_get_name(this->_libConstPortPtr()); + } + + bool isConnected() const noexcept + { + return static_cast(bt_port_is_connected(this->_libConstPortPtr())); + } + + ConstComponent component() const noexcept + { + return ConstComponent {bt_port_borrow_component_const(this->_libConstPortPtr())}; + } + + Shared shared() const noexcept + { + return Shared::createWithRef(*this); + } + +private: + const bt_port *_libConstPortPtr() const noexcept + { + return internal::ConstPortSpec::asPort(this->libObjPtr()); + } +}; + +template +typename ConstComponentPorts::Port +ConstComponentPorts::operator[](const std::uint64_t index) const noexcept +{ + return Port {_Spec::portByIndex(this->libObjPtr(), index)}; +} + +template +typename ConstComponentPorts::Port +ConstComponentPorts::operator[](const char * const name) const noexcept +{ + return Port {_Spec::portByName(this->libObjPtr(), name)}; +} + +template +typename ConstComponentPorts::Port +ConstComponentPorts::operator[](const std::string& name) const noexcept +{ + return (*this)[name.data()]; +} + +template +typename ConstComponentPorts::Iterator +ConstComponentPorts::begin() const noexcept +{ + return Iterator {*this, 0}; +} + +template +typename ConstComponentPorts::Iterator +ConstComponentPorts::end() const noexcept +{ + return Iterator {*this, this->length()}; +} + +using ConstInputPort = ConstPort; +using ConstOutputPort = ConstPort; + +inline ConstSourceComponent::OutputPorts ConstSourceComponent::outputPorts() const noexcept +{ + return OutputPorts {this->libObjPtr()}; +} + +inline ConstFilterComponent::OutputPorts ConstFilterComponent::outputPorts() const noexcept +{ + return OutputPorts {this->libObjPtr()}; +} + +inline ConstFilterComponent::InputPorts ConstFilterComponent::inputPorts() const noexcept +{ + return InputPorts {this->libObjPtr()}; +} + +inline ConstSinkComponent::InputPorts ConstSinkComponent::inputPorts() const noexcept +{ + return InputPorts {this->libObjPtr()}; +} + +} /* namespace bt2 */ + +#endif /* BABELTRACE_CPP_COMMON_BT2_COMPONENT_PORT_HPP */ -- 2.34.1