cpp-common/bt2: add `bt2::Const*Component` and `bt2::Const*Port`
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 1 Nov 2023 03:03:36 +0000 (23:03 -0400)
committerSimon Marchi <simon.marchi@efficios.com>
Thu, 14 Dec 2023 15:57:04 +0000 (10:57 -0500)
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<const bt_component_source *>()` 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 <eeppeliteloop@gmail.com>
Change-Id: I1324a59c8291cb83a432eeb7477c6b3e353924f5
Reviewed-on: https://review.lttng.org/c/babeltrace/+/11184
Reviewed-by: Simon Marchi <simon.marchi@efficios.com>
CI-Build: Simon Marchi <simon.marchi@efficios.com>
Tested-by: jenkins <jenkins@lttng.org>
src/Makefile.am
src/cpp-common/bt2/component-port.hpp [new file with mode: 0644]

index d2559c3382de4f06b7d7ea763c57f2fd1b46aeb4..1a01d4278b6a05d347249975cbb2f2f32a3b99e1 100644 (file)
@@ -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 (file)
index 0000000..6a7db67
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 2023 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_BT2_COMPONENT_PORT_HPP
+#define BABELTRACE_CPP_COMMON_BT2_COMPONENT_PORT_HPP
+
+#include <cstdint>
+#include <string>
+
+#include <babeltrace2/babeltrace.h>
+
+#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<const bt_component>
+{
+private:
+    using typename BorrowedObject<const bt_component>::_ThisBorrowedObject;
+
+public:
+    using Shared =
+        SharedObject<ConstComponent, const bt_component, internal::ConstComponentRefFuncs>;
+
+    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<bool>(bt_component_is_source(this->libObjPtr()));
+    }
+
+    bool isFilter() const noexcept
+    {
+        return static_cast<bool>(bt_component_is_filter(this->libObjPtr()));
+    }
+
+    bool isSink() const noexcept
+    {
+        return static_cast<bool>(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<LoggingLevel>(bt_component_get_logging_level(this->libObjPtr()));
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared::createWithRef(*this);
+    }
+};
+
+template <typename LibObjT>
+class ConstSpecificComponent : public BorrowedObject<LibObjT>
+{
+public:
+    using typename BorrowedObject<LibObjT>::_LibObjPtr;
+
+protected:
+    explicit ConstSpecificComponent(const _LibObjPtr libObjPtr) noexcept :
+        BorrowedObject<LibObjT> {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 <typename LibCompT, typename LibPortPtrT>
+struct ConstComponentPortsSpec;
+
+template <>
+struct ConstComponentPortsSpec<const bt_component_source, const bt_port_output> 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<const bt_component_filter, const bt_port_output> 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<const bt_component_filter, const bt_port_input> 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<const bt_component_sink, const bt_port_input> 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 <typename>
+class ConstPort;
+
+template <typename LibCompT, typename LibPortT>
+class ConstComponentPorts final : public BorrowedObject<LibCompT>
+{
+private:
+    using _Spec = internal::ConstComponentPortsSpec<LibCompT, LibPortT>;
+
+public:
+    using typename BorrowedObject<LibCompT>::_LibObjPtr;
+    using Port = ConstPort<LibPortT>;
+    using Iterator = BorrowedObjectIterator<ConstComponentPorts>;
+
+    explicit ConstComponentPorts(const _LibObjPtr libObjPtr) noexcept :
+        BorrowedObject<LibCompT> {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<const bt_component_source>
+{
+public:
+    using Shared = SharedObject<ConstSourceComponent, const bt_component_source,
+                                internal::ConstSourceComponentRefFuncs>;
+
+    using OutputPorts = ConstComponentPorts<const bt_component_source, const bt_port_output>;
+
+    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<const bt_component_filter>
+{
+public:
+    using Shared = SharedObject<ConstFilterComponent, const bt_component_filter,
+                                internal::ConstFilterComponentRefFuncs>;
+
+    using InputPorts = ConstComponentPorts<const bt_component_filter, const bt_port_input>;
+    using OutputPorts = ConstComponentPorts<const bt_component_filter, const bt_port_output>;
+
+    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<const bt_component_sink>
+{
+public:
+    using Shared = SharedObject<ConstSinkComponent, const bt_component_sink,
+                                internal::ConstSinkComponentRefFuncs>;
+
+    using InputPorts = ConstComponentPorts<const bt_component_sink, const bt_port_input>;
+
+    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 <typename LibObjT>
+struct ConstPortSpec;
+
+/* Functions specific to constant input ports */
+template <>
+struct ConstPortSpec<const bt_port_input> 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<const bt_port_output> final
+{
+    static const bt_port *asPort(const bt_port_output * const libObjPtr) noexcept
+    {
+        return bt_port_output_as_port_const(libObjPtr);
+    }
+};
+
+template <typename LibObjT>
+struct ConstPortRefFuncs final
+{
+    static void get(LibObjT * const libObjPtr) noexcept
+    {
+        bt_port_get_ref(ConstPortSpec<LibObjT>::port(libObjPtr));
+    }
+
+    static void put(LibObjT * const libObjPtr) noexcept
+    {
+        bt_port_put_ref(ConstPortSpec<LibObjT>::port(libObjPtr));
+    }
+};
+
+} /* namespace internal */
+
+template <typename LibObjT>
+class ConstPort final : public BorrowedObject<LibObjT>
+{
+public:
+    using typename BorrowedObject<LibObjT>::_LibObjPtr;
+    using Shared = SharedObject<ConstPort, LibObjT, internal::ConstPortRefFuncs<LibObjT>>;
+
+    explicit ConstPort(const _LibObjPtr libObjPtr) noexcept : BorrowedObject<LibObjT> {libObjPtr}
+    {
+    }
+
+    const char *name() const noexcept
+    {
+        return bt_port_get_name(this->_libConstPortPtr());
+    }
+
+    bool isConnected() const noexcept
+    {
+        return static_cast<bool>(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<LibObjT>::asPort(this->libObjPtr());
+    }
+};
+
+template <typename LibCompT, typename LibPortT>
+typename ConstComponentPorts<LibCompT, LibPortT>::Port
+ConstComponentPorts<LibCompT, LibPortT>::operator[](const std::uint64_t index) const noexcept
+{
+    return Port {_Spec::portByIndex(this->libObjPtr(), index)};
+}
+
+template <typename LibCompT, typename LibPortT>
+typename ConstComponentPorts<LibCompT, LibPortT>::Port
+ConstComponentPorts<LibCompT, LibPortT>::operator[](const char * const name) const noexcept
+{
+    return Port {_Spec::portByName(this->libObjPtr(), name)};
+}
+
+template <typename LibCompT, typename LibPortT>
+typename ConstComponentPorts<LibCompT, LibPortT>::Port
+ConstComponentPorts<LibCompT, LibPortT>::operator[](const std::string& name) const noexcept
+{
+    return (*this)[name.data()];
+}
+
+template <typename LibCompT, typename LibPortT>
+typename ConstComponentPorts<LibCompT, LibPortT>::Iterator
+ConstComponentPorts<LibCompT, LibPortT>::begin() const noexcept
+{
+    return Iterator {*this, 0};
+}
+
+template <typename LibCompT, typename LibPortT>
+typename ConstComponentPorts<LibCompT, LibPortT>::Iterator
+ConstComponentPorts<LibCompT, LibPortT>::end() const noexcept
+{
+    return Iterator {*this, this->length()};
+}
+
+using ConstInputPort = ConstPort<const bt_port_input>;
+using ConstOutputPort = ConstPort<const bt_port_output>;
+
+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 */
This page took 0.031303 seconds and 4 git commands to generate.