From 01bf7a3a1fbc42bb8b069793619ca786f52ca6de Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 8 Dec 2020 09:37:17 -0500 Subject: [PATCH] Add libbabeltrace2 C++ interface base 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 Change-Id: I1433ef3c1ed9cca5677012ebe68f63545dbbe547 Reviewed-on: https://review.lttng.org/c/babeltrace/+/4505 --- configure.ac | 1 + src/Makefile.am | 1 + src/cpp-common/Makefile.am | 3 + src/cpp-common/bt2/internal/borrowed-obj.hpp | 124 +++++++++++ src/cpp-common/bt2/internal/shared-obj.hpp | 209 +++++++++++++++++++ 5 files changed, 338 insertions(+) create mode 100644 src/cpp-common/Makefile.am create mode 100644 src/cpp-common/bt2/internal/borrowed-obj.hpp create mode 100644 src/cpp-common/bt2/internal/shared-obj.hpp diff --git a/configure.ac b/configure.ac index d6428ccd..f9f3fab7 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index d73f5c46..6e01a12d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 00000000..f7b9f3cb --- /dev/null +++ b/src/cpp-common/Makefile.am @@ -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 index 00000000..89feb620 --- /dev/null +++ b/src/cpp-common/bt2/internal/borrowed-obj.hpp @@ -0,0 +1,124 @@ +/* + * Copyright 2019-2020 (c) Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#ifndef BABELTRACE_CPP_COMMON_BT2_INTERNAL_BORROWED_OBJ_HPP +#define BABELTRACE_CPP_COMMON_BT2_INTERNAL_BORROWED_OBJ_HPP + +#include + +#include "common/assert.h" + +namespace bt2 { +namespace internal { + +template +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 +class BorrowedObj +{ + static_assert(!std::is_pointer::value, "`LibObjT` must not be a pointer"); + + /* + * This makes it possible for a `BorrowedObj` + * instance to get assigned an instance of + * `BorrowedObj` (copy constructor and assignment + * operator). + * + * C++ forbids the other way around. + */ + template + friend class BorrowedObj; + + /* + * This is to allow a `SharedObj<_ThisBorrowedObj, LibObjT, ...>` + * instance containing a `BorrowedObj` instance to access + * _libObjPtr() in order to increment/decrement its libbabeltrace2 + * reference count. + */ + template + friend class SharedObj; + +protected: + // libbabeltrace2 object pointer + using _LibObjPtr = LibObjT *; + + // This complete borrowed object + using _ThisBorrowedObj = BorrowedObj; + + /* + * 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`, where `ConstLibObjT` is the `const` + * version of `LibObjT`, if applicable. + * + * This makes it possible for a `BorrowedObj` + * instance to be built from an instance of + * `BorrowedObj`. C++ forbids the other way around. + */ + template + BorrowedObj(const BorrowedObj& other) noexcept : BorrowedObj {other._mLibObjPtr} + { + } + + /* + * Generic assignment operator. + * + * This operator accepts both an instance of + * `_ThisBorrowedObj` and an instance (`other`) of + * `BorrowedObj`, where `ConstLibObjT` is the `const` + * version of `LibObjT`, if applicable. + * + * This makes it possible for a `BorrowedObj` + * instance to get assigned an instance of + * `BorrowedObj`. C++ forbids the other way around. + */ + template + _ThisBorrowedObj& operator=(const BorrowedObj& 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 index 00000000..5451be5f --- /dev/null +++ b/src/cpp-common/bt2/internal/shared-obj.hpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2019-2020 Philippe Proulx + * + * 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 +class SharedObj final +{ + /* + * This makes it possible for a + * `SharedObj` instance to get + * assigned an instance of + * `SharedObj` (copy/move + * constructor and assignment operator), given that + * `SpecificSomething` inherits `Something`. + */ + template + friend class SharedObj; + +public: + // This complete shared object + using ThisSharedObj = SharedObj; + + /* + * 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 + SharedObj(const SharedObj& other) noexcept : + _mObj {other._mObj} + { + this->_getRef(); + } + + /* + * Generic move constructor. + * + * See the `friend class SharedObj` comment above. + */ + template + SharedObj(SharedObj&& other) noexcept : _mObj {other._mObj} + { + // Reset moved-from object + other._reset(); + } + + /* + * Generic copy assignment operator. + * + * See the `friend class SharedObj` comment above. + */ + template + ThisSharedObj& operator=(const SharedObj& 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 + ThisSharedObj& operator=(SharedObj&& 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 _mObj; +}; + +} // namespace internal +} // namespace bt2 + +#endif // BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP -- 2.34.1