Add libbabeltrace2 C++ interface base
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 8 Dec 2020 14:37:17 +0000 (09:37 -0500)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 28 Jan 2022 16:22:26 +0000 (11:22 -0500)
This patch adds three new C++ headers to `src/cpp-common/bt2/internal`:

`borrowed-obj.hpp`:
    Defines `bt2::internal::BorrowedObj` which wraps a libbabeltrace2
    object pointer without managing reference counting.

`shared-obj.hpp`:
    Defines `bt2::internal::SharedObj` which contains a
    `bt2::internal::BorrowedObj` instance and manages the underlying
    reference count of the libbabeltrace2 object.

Those classes are meant to be used by public classes in
`src/cpp-common/bt2`, hence their `internal` namespace.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I1433ef3c1ed9cca5677012ebe68f63545dbbe547
Reviewed-on: https://review.lttng.org/c/babeltrace/+/4505

configure.ac
src/Makefile.am
src/cpp-common/Makefile.am [new file with mode: 0644]
src/cpp-common/bt2/internal/borrowed-obj.hpp [new file with mode: 0644]
src/cpp-common/bt2/internal/shared-obj.hpp [new file with mode: 0644]

index d6428ccdd0ee4901d7ddb79162c6c414f461391e..f9f3fab71632018a2e7138fec64a63283edfe148 100644 (file)
@@ -793,6 +793,7 @@ AC_CONFIG_FILES([
   src/bindings/python/Makefile
   src/cli/Makefile
   src/common/Makefile
+  src/cpp-common/Makefile
   src/compat/Makefile
   src/ctfser/Makefile
   src/ctf-writer/Makefile
index d73f5c46a37828d7f2b1d2d95645d16e2ffd9088..6e01a12d7efbb59199fcd8f5973ae11fa85cdffc 100644 (file)
@@ -3,6 +3,7 @@
 SUBDIRS = \
        common \
        py-common \
+       cpp-common \
        autodisc \
        argpar \
        ctfser \
diff --git a/src/cpp-common/Makefile.am b/src/cpp-common/Makefile.am
new file mode 100644 (file)
index 0000000..f7b9f3c
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: MIT
+
+EXTRA_DIST = bt2
diff --git a/src/cpp-common/bt2/internal/borrowed-obj.hpp b/src/cpp-common/bt2/internal/borrowed-obj.hpp
new file mode 100644 (file)
index 0000000..89feb62
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019-2020 (c) Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_BT2_INTERNAL_BORROWED_OBJ_HPP
+#define BABELTRACE_CPP_COMMON_BT2_INTERNAL_BORROWED_OBJ_HPP
+
+#include <type_traits>
+
+#include "common/assert.h"
+
+namespace bt2 {
+namespace internal {
+
+template <typename ObjT, typename LibObjT, typename RefFuncsT>
+class SharedObj;
+
+/*
+ * An instance of this class wraps a pointer to a libbabeltrace2 object
+ * of type `LibObjT` without managing any reference counting.
+ *
+ * This is an abstract base class for any libbabeltrace2 object wrapper.
+ *
+ * `LibObjT` is the direct libbabeltrace2 object type, for example
+ * `bt_stream_class` or `const bt_value`.
+ *
+ * Methods of a derived class can call _libObjPtr() to access the
+ * libbabeltrace2 object pointer.
+ */
+template <typename LibObjT>
+class BorrowedObj
+{
+    static_assert(!std::is_pointer<LibObjT>::value, "`LibObjT` must not be a pointer");
+
+    /*
+     * This makes it possible for a `BorrowedObj<const bt_something>`
+     * instance to get assigned an instance of
+     * `BorrowedObj<bt_something>` (copy constructor and assignment
+     * operator).
+     *
+     * C++ forbids the other way around.
+     */
+    template <typename AnyLibObjT>
+    friend class BorrowedObj;
+
+    /*
+     * This is to allow a `SharedObj<_ThisBorrowedObj, LibObjT, ...>`
+     * instance containing a `BorrowedObj<LibObjT>` instance to access
+     * _libObjPtr() in order to increment/decrement its libbabeltrace2
+     * reference count.
+     */
+    template <typename ObjT, typename AnyLibObjT, typename RefFuncsT>
+    friend class SharedObj;
+
+protected:
+    // libbabeltrace2 object pointer
+    using _LibObjPtr = LibObjT *;
+
+    // This complete borrowed object
+    using _ThisBorrowedObj = BorrowedObj<LibObjT>;
+
+    /*
+     * Builds a borrowed object to wrap the libbabeltrace2 object
+     * pointer `libObjPtr`.
+     *
+     * `libObjPtr` must not be `nullptr`.
+     */
+    explicit BorrowedObj(const _LibObjPtr libObjPtr) noexcept : _mLibObjPtr {libObjPtr}
+    {
+        BT_ASSERT(libObjPtr);
+    }
+
+    /*
+     * Generic copy constructor.
+     *
+     * This converting constructor accepts both an instance of
+     * `_ThisBorrowedObj` and an instance (`other`) of
+     * `BorrowedObj<ConstLibObjT>`, where `ConstLibObjT` is the `const`
+     * version of `LibObjT`, if applicable.
+     *
+     * This makes it possible for a `BorrowedObj<const bt_something>`
+     * instance to be built from an instance of
+     * `BorrowedObj<bt_something>`. C++ forbids the other way around.
+     */
+    template <typename OtherLibObjT>
+    BorrowedObj(const BorrowedObj<OtherLibObjT>& other) noexcept : BorrowedObj {other._mLibObjPtr}
+    {
+    }
+
+    /*
+     * Generic assignment operator.
+     *
+     * This operator accepts both an instance of
+     * `_ThisBorrowedObj` and an instance (`other`) of
+     * `BorrowedObj<ConstLibObjT>`, where `ConstLibObjT` is the `const`
+     * version of `LibObjT`, if applicable.
+     *
+     * This makes it possible for a `BorrowedObj<const bt_something>`
+     * instance to get assigned an instance of
+     * `BorrowedObj<bt_something>`. C++ forbids the other way around.
+     */
+    template <typename OtherLibObjT>
+    _ThisBorrowedObj& operator=(const BorrowedObj<OtherLibObjT>& other) noexcept
+    {
+        _mLibObjPtr = other._mLibObjPtr;
+        return *this;
+    }
+
+    // Wrapped libbabeltrace2 object pointer
+    _LibObjPtr _libObjPtr() const noexcept
+    {
+        return _mLibObjPtr;
+    }
+
+private:
+    _LibObjPtr _mLibObjPtr;
+};
+
+} // namespace internal
+} // namespace bt2
+
+#endif // BABELTRACE_CPP_COMMON_BT2_INTERNAL_BORROWED_OBJ_HPP
diff --git a/src/cpp-common/bt2/internal/shared-obj.hpp b/src/cpp-common/bt2/internal/shared-obj.hpp
new file mode 100644 (file)
index 0000000..5451be5
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2019-2020 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP
+#define BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP
+
+#include "common/assert.h"
+#include "cpp-common/optional.hpp"
+
+namespace bt2 {
+namespace internal {
+
+/*
+ * An instance of this class wraps an optional instance of `ObjT` and
+ * manages the reference counting of the underlying libbabeltrace2
+ * object.
+ *
+ * When you move a shared object, it becomes invalid, in that
+ * operator*() and operator->() will either fail to assert in debug mode
+ * or trigger a segmentation fault.
+ *
+ * `LibObjT` is the direct libbabeltrace2 object type, for example
+ * `bt_stream_class` or `const bt_value`.
+ *
+ * RefFuncsT::get() must accept a `const LibObjT *` value and increment
+ * its reference count.
+ *
+ * RefFuncsT::put() must accept a `const LibObjT *` value and decrement
+ * its reference count.
+ */
+template <typename ObjT, typename LibObjT, typename RefFuncsT>
+class SharedObj final
+{
+    /*
+     * This makes it possible for a
+     * `SharedObj<Something, bt_something, ...>` instance to get
+     * assigned an instance of
+     * `SharedObj<SpecificSomething, bt_something, ...>` (copy/move
+     * constructor and assignment operator), given that
+     * `SpecificSomething` inherits `Something`.
+     */
+    template <typename AnyObjT, typename AnyLibObjT, typename AnyRefFuncsT>
+    friend class SharedObj;
+
+public:
+    // This complete shared object
+    using ThisSharedObj = SharedObj<ObjT, LibObjT, RefFuncsT>;
+
+    /*
+     * Builds a shared object from `obj` without an initial reference.
+     *
+     * Use this constructor to build a shared object wrapping a newly
+     * created libbabeltrace2 object.
+     *
+     * Use createWithInitialRef() to build a shared object having an
+     * initial reference count.
+     */
+    explicit SharedObj(const ObjT& obj) noexcept : _mObj {obj}
+    {
+    }
+
+    /*
+     * Builds a shared object from `obj` with an initial reference.
+     *
+     * Use this constructor to build a shared object wrapping a newly
+     * created libbabeltrace2 object.
+     */
+    static ThisSharedObj createWithInitialRef(const ObjT& obj) noexcept
+    {
+        ThisSharedObj sharedObj {obj};
+
+        sharedObj._getRef();
+        return sharedObj;
+    }
+
+    /*
+     * Generic copy constructor.
+     *
+     * See the `friend class SharedObj` comment above.
+     */
+    template <typename OtherObjT, typename OtherLibObjT>
+    SharedObj(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept :
+        _mObj {other._mObj}
+    {
+        this->_getRef();
+    }
+
+    /*
+     * Generic move constructor.
+     *
+     * See the `friend class SharedObj` comment above.
+     */
+    template <typename OtherObjT, typename OtherLibObjT>
+    SharedObj(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept : _mObj {other._mObj}
+    {
+        // Reset moved-from object
+        other._reset();
+    }
+
+    /*
+     * Generic copy assignment operator.
+     *
+     * See the `friend class SharedObj` comment above.
+     */
+    template <typename OtherObjT, typename OtherLibObjT>
+    ThisSharedObj& operator=(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept
+    {
+        // Put current object's reference
+        this->_putRef();
+
+        // Set new current object and get a reference
+        _mObj = other._mObj;
+        this->_getRef();
+
+        return *this;
+    }
+
+    /*
+     * Generic move assignment operator.
+     *
+     * See the `friend class SharedObj` comment above.
+     */
+    template <typename OtherObjT, typename OtherLibObjT>
+    ThisSharedObj& operator=(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept
+    {
+        // Put current object's reference
+        this->_putRef();
+
+        // Set new current object
+        _mObj = other._mObj;
+
+        // Reset moved-from object
+        other._reset();
+
+        return *this;
+    }
+
+    ~SharedObj()
+    {
+        this->_putRef();
+    }
+
+    ObjT& operator*() noexcept
+    {
+        BT_ASSERT_DBG(_mObj);
+        return *_mObj;
+    }
+
+    const ObjT& operator*() const noexcept
+    {
+        BT_ASSERT_DBG(_mObj);
+        return *_mObj;
+    }
+
+    ObjT *operator->() noexcept
+    {
+        BT_ASSERT_DBG(_mObj);
+        return &*_mObj;
+    }
+
+    const ObjT *operator->() const noexcept
+    {
+        BT_ASSERT_DBG(_mObj);
+        return &*_mObj;
+    }
+
+private:
+    /*
+     * Resets this shared object.
+     *
+     * To be used when moving it.
+     */
+    void _reset() noexcept
+    {
+        _mObj.reset();
+    }
+
+    /*
+     * Gets a new reference using the configured libbabeltrace2
+     * reference incrementation function.
+     */
+    void _getRef() const noexcept
+    {
+        if (_mObj) {
+            RefFuncsT::get(_mObj->_libObjPtr());
+        }
+    }
+
+    /*
+     * Puts a reference using the configured libbabeltrace2 reference
+     * decrementation function.
+     */
+    void _putRef() const noexcept
+    {
+        if (_mObj) {
+            RefFuncsT::put(_mObj->_libObjPtr());
+        }
+    }
+
+    nonstd::optional<ObjT> _mObj;
+};
+
+} // namespace internal
+} // namespace bt2
+
+#endif // BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP
This page took 0.030024 seconds and 4 git commands to generate.