cpp-common/bt2: use `std::unique_ptr` to manage `UserMessageIterator::_mSavedLibError`
[babeltrace.git] / src / cpp-common / bt2 / component-class-dev.hpp
index 1174140f1118b9f21bac3452c86641cab7fc76a9..f97228360d3856e155500ee12013312094b8acf7 100644 (file)
@@ -16,6 +16,7 @@
 #include "cpp-common/vendor/fmt/core.h"
 
 #include "exc.hpp"
+#include "internal/comp-cls-bridge.hpp"
 #include "private-query-executor.hpp"
 #include "self-component-port.hpp"
 
@@ -41,6 +42,9 @@ public:
     using InitData = InitDataT;
     using QueryData = QueryDataT;
 
+    static constexpr auto description = nullptr;
+    static constexpr auto help = nullptr;
+
 protected:
     explicit UserComponent(const SelfCompT selfComp, const std::string& logTag) :
         _mLogger {selfComp, fmt::format("{}/[{}]", logTag, selfComp.name())}, _mSelfComp {selfComp}
@@ -77,6 +81,13 @@ private:
 /*
  * Base class of a user source component `UserComponentT` (CRTP).
  *
+ * `UserComponentT` must define a static member `name` of type
+ * `const char *` to provide the name of the component class.
+ *
+ * `UserComponentT` may define the static members `description` and/or
+ * `help` of type `const char *` to provide the description and/or help
+ * of the component class.
+ *
  * UserComponentT::UserComponentT() must accept, in this order:
  *
  *  1. A `bt2::SelfSourceComponent` parameter, which it needs to forward
@@ -173,6 +184,13 @@ protected:
 /*
  * Base class of a user filter component `UserComponentT` (CRTP).
  *
+ * `UserComponentT` must define a static member `name` of type
+ * `const char *` to provide the name of the component class.
+ *
+ * `UserComponentT` may define the static members `description` and/or
+ * `help` of type `const char *` to provide the description and/or help
+ * of the component class.
+ *
  * UserComponentT::UserComponentT() must accept, in this order:
  *
  *  1. A `bt2::SelfFilterComponent` parameter, which it needs to forward
@@ -297,6 +315,13 @@ protected:
 /*
  * Base class of a user sink component `UserComponentT` (CRTP).
  *
+ * `UserComponentT` must define a static member `name` of type
+ * `const char *` to provide the name of the component class.
+ *
+ * `UserComponentT` may define the static members `description` and/or
+ * `help` of type `const char *` to provide the description and/or help
+ * of the component class.
+ *
  * UserComponentT::UserComponentT() must accept, in this order:
  *
  *  1. A `bt2::SelfSinkComponent` parameter, which it needs to forward
@@ -462,18 +487,13 @@ protected:
     }
 
 public:
-    ~UserMessageIterator()
-    {
-        this->_resetError();
-    }
-
     void next(bt2::ConstMessageArray& messages)
     {
         /* Any saved error? Now is the time to throw */
         if (G_UNLIKELY(_mExcToThrowType != _ExcToThrowType::NONE)) {
             /* Move `_mSavedLibError`, if any, as current thread error */
             if (_mSavedLibError) {
-                BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(_mSavedLibError);
+                bt_current_thread_move_error(_mSavedLibError.release());
             }
 
             /* Throw the corresponding exception */
@@ -524,7 +544,7 @@ public:
                 "An error occurred, but there are {} messages to return: delaying the error reporting.",
                 messages.length());
             BT_ASSERT(!_mSavedLibError);
-            _mSavedLibError = bt_current_thread_take_error();
+            _mSavedLibError.reset(bt_current_thread_take_error());
         }
     }
 
@@ -604,10 +624,7 @@ private:
     void _resetError() noexcept
     {
         _mExcToThrowType = _ExcToThrowType::NONE;
-
-        if (_mSavedLibError) {
-            bt_error_release(_mSavedLibError);
-        }
+        _mSavedLibError.reset();
     }
 
     SelfMessageIterator _mSelfMsgIter;
@@ -621,12 +638,232 @@ private:
      * It also saves the type of the exception to throw the next time.
      */
     _ExcToThrowType _mExcToThrowType = _ExcToThrowType::NONE;
-    const bt_error *_mSavedLibError = nullptr;
+
+    struct LibErrorDeleter final
+    {
+        void operator()(const bt_error * const error) const noexcept
+        {
+            bt_error_release(error);
+        }
+    };
+
+    std::unique_ptr<const bt_error, LibErrorDeleter> _mSavedLibError;
 
 protected:
     bt2c::Logger _mLogger;
 };
 
+namespace internal {
+
+template <typename UserComponentT, typename CompClsBridgeT, typename LibSpecCompClsPtrT,
+          typename AsCompClsFuncT, typename SetInitMethodFuncT, typename SetFinalizeMethodFuncT,
+          typename SetGetSupportedMipVersionsMethodFuncT, typename SetQueryMethodFuncT>
+void setCompClsCommonProps(
+    LibSpecCompClsPtrT * const libSpecCompClsPtr, AsCompClsFuncT&& asCompClsFunc,
+    SetInitMethodFuncT&& setInitMethodFunc, SetFinalizeMethodFuncT&& setFinalizeMethodFunc,
+    SetGetSupportedMipVersionsMethodFuncT&& setGetSupportedMipVersionsMethodFunc,
+    SetQueryMethodFuncT&& setQueryMethodFunc)
+{
+    const auto libCompClsPtr = asCompClsFunc(libSpecCompClsPtr);
+
+    if (UserComponentT::description != nullptr) {
+        const auto status =
+            bt_component_class_set_description(libCompClsPtr, UserComponentT::description);
+
+        if (status == BT_COMPONENT_CLASS_SET_DESCRIPTION_STATUS_MEMORY_ERROR) {
+            throw MemoryError {};
+        }
+    }
+
+    if (UserComponentT::help != nullptr) {
+        const auto status = bt_component_class_set_help(libCompClsPtr, UserComponentT::help);
+
+        if (status == BT_COMPONENT_CLASS_SET_HELP_STATUS_MEMORY_ERROR) {
+            throw MemoryError {};
+        }
+    }
+
+    {
+        const auto status = setInitMethodFunc(libSpecCompClsPtr, CompClsBridgeT::init);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    {
+        const auto status = setFinalizeMethodFunc(libSpecCompClsPtr, CompClsBridgeT::finalize);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    {
+        const auto status = setGetSupportedMipVersionsMethodFunc(
+            libSpecCompClsPtr, CompClsBridgeT::getSupportedMipVersions);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    {
+        const auto status = setQueryMethodFunc(libSpecCompClsPtr, CompClsBridgeT::query);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+}
+
+template <typename MsgIterClsBridgeT>
+bt_message_iterator_class *createLibMsgIterCls()
+{
+    const auto libMsgIterClsPtr = bt_message_iterator_class_create(MsgIterClsBridgeT::next);
+
+    if (!libMsgIterClsPtr) {
+        throw MemoryError {};
+    }
+
+    {
+        const auto status = bt_message_iterator_class_set_initialize_method(
+            libMsgIterClsPtr, MsgIterClsBridgeT::init);
+
+        BT_ASSERT(status == BT_MESSAGE_ITERATOR_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    {
+        const auto status = bt_message_iterator_class_set_finalize_method(
+            libMsgIterClsPtr, MsgIterClsBridgeT::finalize);
+
+        BT_ASSERT(status == BT_MESSAGE_ITERATOR_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    return libMsgIterClsPtr;
+}
+
+template <typename UserComponentT>
+bt_component_class_source *createSourceCompCls()
+{
+    static_assert(
+        std::is_base_of<UserSourceComponent<
+                            UserComponentT, typename UserComponentT::MessageIterator,
+                            typename UserComponentT::InitData, typename UserComponentT::QueryData>,
+                        UserComponentT>::value,
+        "`UserComponentT` inherits `UserSourceComponent`");
+
+    using CompClsBridge = internal::SrcCompClsBridge<UserComponentT>;
+    using MsgIterClsBridge = internal::MsgIterClsBridge<typename UserComponentT::MessageIterator>;
+
+    const auto libMsgIterClsPtr = createLibMsgIterCls<MsgIterClsBridge>();
+    const auto libCompClsPtr =
+        bt_component_class_source_create(UserComponentT::name, libMsgIterClsPtr);
+
+    bt_message_iterator_class_put_ref(libMsgIterClsPtr);
+
+    if (!libCompClsPtr) {
+        throw MemoryError {};
+    }
+
+    setCompClsCommonProps<UserComponentT, CompClsBridge>(
+        libCompClsPtr, bt_component_class_source_as_component_class,
+        bt_component_class_source_set_initialize_method,
+        bt_component_class_source_set_finalize_method,
+        bt_component_class_source_set_get_supported_mip_versions_method,
+        bt_component_class_source_set_query_method);
+
+    {
+        const auto status = bt_component_class_source_set_output_port_connected_method(
+            libCompClsPtr, CompClsBridge::outputPortConnected);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    return libCompClsPtr;
+}
+
+template <typename UserComponentT>
+bt_component_class_filter *createFilterCompCls()
+{
+    static_assert(
+        std::is_base_of<UserFilterComponent<
+                            UserComponentT, typename UserComponentT::MessageIterator,
+                            typename UserComponentT::InitData, typename UserComponentT::QueryData>,
+                        UserComponentT>::value,
+        "`UserComponentT` inherits `UserFilterComponent`");
+
+    using CompClsBridge = internal::FltCompClsBridge<UserComponentT>;
+    using MsgIterClsBridge = internal::MsgIterClsBridge<typename UserComponentT::MessageIterator>;
+
+    const auto libMsgIterClsPtr = createLibMsgIterCls<MsgIterClsBridge>();
+    const auto libCompClsPtr =
+        bt_component_class_filter_create(UserComponentT::name, libMsgIterClsPtr);
+
+    bt_message_iterator_class_put_ref(libMsgIterClsPtr);
+
+    if (!libCompClsPtr) {
+        throw MemoryError {};
+    }
+
+    setCompClsCommonProps<UserComponentT, CompClsBridge>(
+        libCompClsPtr, bt_component_class_filter_as_component_class,
+        bt_component_class_filter_set_initialize_method,
+        bt_component_class_filter_set_finalize_method,
+        bt_component_class_filter_set_get_supported_mip_versions_method,
+        bt_component_class_filter_set_query_method);
+
+    {
+        const auto status = bt_component_class_filter_set_input_port_connected_method(
+            libCompClsPtr, CompClsBridge::inputPortConnected);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    {
+        const auto status = bt_component_class_filter_set_output_port_connected_method(
+            libCompClsPtr, CompClsBridge::outputPortConnected);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    return libCompClsPtr;
+}
+
+template <typename UserComponentT>
+bt_component_class_sink *createSinkCompCls()
+{
+    static_assert(
+        std::is_base_of<UserSinkComponent<UserComponentT, typename UserComponentT::InitData,
+                                          typename UserComponentT::QueryData>,
+                        UserComponentT>::value,
+        "`UserComponentT` inherits `UserSinkComponent`");
+
+    using CompClsBridge = internal::SinkCompClsBridge<UserComponentT>;
+
+    const auto libCompClsPtr =
+        bt_component_class_sink_create(UserComponentT::name, CompClsBridge::consume);
+
+    if (!libCompClsPtr) {
+        throw MemoryError {};
+    }
+
+    setCompClsCommonProps<UserComponentT, CompClsBridge>(
+        libCompClsPtr, bt_component_class_sink_as_component_class,
+        bt_component_class_sink_set_initialize_method, bt_component_class_sink_set_finalize_method,
+        bt_component_class_sink_set_get_supported_mip_versions_method,
+        bt_component_class_sink_set_query_method);
+
+    {
+        const auto status = bt_component_class_sink_set_graph_is_configured_method(
+            libCompClsPtr, CompClsBridge::graphIsConfigured);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    {
+        const auto status = bt_component_class_sink_set_input_port_connected_method(
+            libCompClsPtr, CompClsBridge::inputPortConnected);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    return libCompClsPtr;
+}
+
+} /* namespace internal */
 } /* namespace bt2 */
 
 #endif /* BABELTRACE_CPP_COMMON_BT2_COMPONENT_CLASS_DEV_HPP */
This page took 0.026121 seconds and 4 git commands to generate.