bt2::internal::BorrowedObj: add static assertions for generic copy ops.
[babeltrace.git] / src / cpp-common / bt2 / internal / borrowed-obj.hpp
1 /*
2 * Copyright 2019-2020 (c) Philippe Proulx <pproulx@efficios.com>
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 #ifndef BABELTRACE_CPP_COMMON_BT2_INTERNAL_BORROWED_OBJ_HPP
8 #define BABELTRACE_CPP_COMMON_BT2_INTERNAL_BORROWED_OBJ_HPP
9
10 #include <functional>
11 #include <type_traits>
12
13 #include "common/assert.h"
14
15 namespace bt2 {
16 namespace internal {
17
18 template <typename ObjT, typename LibObjT, typename RefFuncsT>
19 class SharedObj;
20
21 /*
22 * An instance of this class wraps a pointer to a libbabeltrace2 object
23 * of type `LibObjT` without managing any reference counting.
24 *
25 * This is an abstract base class for any libbabeltrace2 object wrapper.
26 *
27 * `LibObjT` is the direct libbabeltrace2 object type, for example
28 * `bt_stream_class` or `const bt_value`.
29 *
30 * Methods of a derived class can call libObjPtr() to access the
31 * libbabeltrace2 object pointer.
32 */
33 template <typename LibObjT>
34 class BorrowedObj
35 {
36 static_assert(!std::is_pointer<LibObjT>::value, "`LibObjT` must not be a pointer");
37
38 /*
39 * This makes it possible for a `BorrowedObj<const bt_something>`
40 * instance to get assigned an instance of
41 * `BorrowedObj<bt_something>` ("copy" constructor and "assignment"
42 * operator).
43 *
44 * C++ forbids the other way around.
45 */
46 template <typename>
47 friend class BorrowedObj;
48
49 private:
50 /*
51 * Provides `val` which indicates whether or not you can assign this
52 * object from a borrowed object of type `OtherLibObjT`.
53 */
54 template <typename OtherLibObjT>
55 struct _AssignableFromConst final
56 {
57 /*
58 * If `LibObjT` is const (for example, `const bt_value`), then
59 * you may always assign from its non-const equivalent (for
60 * example, `bt_value`). In C (correct):
61 *
62 * bt_value * const meow = bt_value_bool_create_init(BT_TRUE);
63 * const bt_value * const mix = meow;
64 *
65 * If `LibObjT` is non-const, then you may not assign from its
66 * const equivalent. In C (not correct):
67 *
68 * const bt_value * const meow =
69 * bt_value_array_borrow_element_by_index_const(some_val, 17);
70 * bt_value * const mix = meow;
71 */
72 static constexpr bool val =
73 std::is_const<LibObjT>::value || !std::is_const<OtherLibObjT>::value;
74 };
75
76 protected:
77 /* libbabeltrace2 object pointer */
78 using _LibObjPtr = LibObjT *;
79
80 /* This complete borrowed object */
81 using _ThisBorrowedObj = BorrowedObj<LibObjT>;
82
83 /*
84 * Builds a borrowed object to wrap the libbabeltrace2 object
85 * pointer `libObjPtr`.
86 *
87 * `libObjPtr` must not be `nullptr`.
88 */
89 explicit BorrowedObj(const _LibObjPtr libObjPtr) noexcept : _mLibObjPtr {libObjPtr}
90 {
91 BT_ASSERT(libObjPtr);
92 }
93
94 /* Default copy operations */
95 BorrowedObj(const BorrowedObj&) noexcept = default;
96 BorrowedObj& operator=(const BorrowedObj&) noexcept = default;
97
98 /*
99 * Generic "copy" constructor.
100 *
101 * This converting constructor accepts both an instance of
102 * `_ThisBorrowedObj` and an instance (`other`) of
103 * `BorrowedObj<ConstLibObjT>`, where `ConstLibObjT` is the `const`
104 * version of `LibObjT`, if applicable.
105 *
106 * This makes it possible for a `BorrowedObj<const bt_something>`
107 * instance to be built from an instance of
108 * `BorrowedObj<bt_something>`. C++ forbids the other way around.
109 */
110 template <typename OtherLibObjT>
111 BorrowedObj(const BorrowedObj<OtherLibObjT>& other) noexcept : BorrowedObj {other._mLibObjPtr}
112 {
113 static_assert(_AssignableFromConst<OtherLibObjT>::val,
114 "Don't assign a non-const wrapper from a const wrapper.");
115 }
116
117 /*
118 * Generic "assignment" operator.
119 *
120 * This operator accepts both an instance of
121 * `_ThisBorrowedObj` and an instance (`other`) of
122 * `BorrowedObj<ConstLibObjT>`, where `ConstLibObjT` is the `const`
123 * version of `LibObjT`, if applicable.
124 *
125 * This makes it possible for a `BorrowedObj<const bt_something>`
126 * instance to get assigned an instance of
127 * `BorrowedObj<bt_something>`. C++ forbids the other way around,
128 * therefore we use `_EnableIfAssignableT` to show a more relevant
129 * context in the compiler error message.
130 */
131 template <typename OtherLibObjT>
132 _ThisBorrowedObj& operator=(const BorrowedObj<OtherLibObjT>& other) noexcept
133 {
134 static_assert(_AssignableFromConst<OtherLibObjT>::val,
135 "Don't assign a non-const wrapper from a const wrapper.");
136
137 _mLibObjPtr = other._mLibObjPtr;
138 return *this;
139 }
140
141 public:
142 /*
143 * Returns a hash of this object, solely based on its raw libbabeltrace2
144 * pointer.
145 */
146 std::size_t hash() const noexcept
147 {
148 return std::hash<_LibObjPtr> {}(_mLibObjPtr);
149 }
150
151 /*
152 * Returns whether or not this object is the exact same as `other`,
153 * solely based on the raw libbabeltrace2 pointers.
154 */
155 bool isSame(const _ThisBorrowedObj& other) const noexcept
156 {
157 return _mLibObjPtr == other._mLibObjPtr;
158 }
159
160 /* Wrapped libbabeltrace2 object pointer */
161 _LibObjPtr libObjPtr() const noexcept
162 {
163 return _mLibObjPtr;
164 }
165
166 private:
167 _LibObjPtr _mLibObjPtr;
168 };
169
170 } /* namespace internal */
171 } /* namespace bt2 */
172
173 #endif /* BABELTRACE_CPP_COMMON_BT2_INTERNAL_BORROWED_OBJ_HPP */
This page took 0.032792 seconds and 4 git commands to generate.