--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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