]> git.proxmox.com Git - ceph.git/blob - ceph/src/msg/async/dpdk/shared_ptr.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / msg / async / dpdk / shared_ptr.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:4; indent-tabs-mode:nil -*-
2 /*
3 * This file is open source software, licensed to you under the terms
4 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
5 * distributed with this work for additional information regarding copyright
6 * ownership. You may not use this file except in compliance with the License.
7 *
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 /*
20 * Copyright (C) 2014 Cloudius Systems, Ltd.
21 */
22
23 #ifndef CEPH_LW_SHARED_PTR_H_
24 #define CEPH_LW_SHARED_PTR_H_
25
26 #include <utility>
27 #include <type_traits>
28 #include <functional>
29 #include <iostream>
30
31 // This header defines a shared pointer facility, lw_shared_ptr<>,
32 // modeled after std::shared_ptr<>.
33 //
34 // Unlike std::shared_ptr<>, this implementation is thread
35 // safe, and two pointers sharing the same object must not be used in
36 // different threads.
37 //
38 // lw_shared_ptr<> is the more lightweight variant, with a lw_shared_ptr<>
39 // occupying just one machine word, and adding just one word to the shared
40 // object. However, it does not support polymorphism.
41 //
42 // It supports shared_from_this() via enable_shared_from_this<>
43 // and lw_enable_shared_from_this<>().
44 //
45
46 template <typename T>
47 class lw_shared_ptr;
48
49 template <typename T>
50 class enable_lw_shared_from_this;
51
52 template <typename T>
53 class enable_shared_from_this;
54
55 template <typename T, typename... A>
56 lw_shared_ptr<T> make_lw_shared(A&&... a);
57
58 template <typename T>
59 lw_shared_ptr<T> make_lw_shared(T&& a);
60
61 template <typename T>
62 lw_shared_ptr<T> make_lw_shared(T& a);
63
64 struct lw_shared_ptr_counter_base {
65 long _count = 0;
66 };
67
68
69 namespace internal {
70
71 template <class T, class U>
72 struct lw_shared_ptr_accessors;
73
74 template <class T>
75 struct lw_shared_ptr_accessors_esft;
76
77 template <class T>
78 struct lw_shared_ptr_accessors_no_esft;
79
80 }
81
82
83 // We want to support two use cases for shared_ptr<T>:
84 //
85 // 1. T is any type (primitive or class type)
86 //
87 // 2. T is a class type that inherits from enable_shared_from_this<T>.
88 //
89 // In the first case, we must wrap T in an object containing the counter,
90 // since T may be a primitive type and cannot be a base class.
91 //
92 // In the second case, we want T to reach the counter through its
93 // enable_shared_from_this<> base class, so that we can implement
94 // shared_from_this().
95 //
96 // To implement those two conflicting requirements (T alongside its counter;
97 // T inherits from an object containing the counter) we use std::conditional<>
98 // and some accessor functions to select between two implementations.
99
100
101 // CRTP from this to enable shared_from_this:
102 template <typename T>
103 class enable_lw_shared_from_this : private lw_shared_ptr_counter_base {
104 using ctor = T;
105 protected:
106 enable_lw_shared_from_this() noexcept {}
107 enable_lw_shared_from_this(enable_lw_shared_from_this&&) noexcept {}
108 enable_lw_shared_from_this(const enable_lw_shared_from_this&) noexcept {}
109 enable_lw_shared_from_this& operator=(const enable_lw_shared_from_this&) noexcept { return *this; }
110 enable_lw_shared_from_this& operator=(enable_lw_shared_from_this&&) noexcept { return *this; }
111 public:
112 lw_shared_ptr<T> shared_from_this();
113 lw_shared_ptr<const T> shared_from_this() const;
114
115 template <typename X>
116 friend class lw_shared_ptr;
117 template <typename X>
118 friend class ::internal::lw_shared_ptr_accessors_esft;
119 template <typename X, class Y>
120 friend class ::internal::lw_shared_ptr_accessors;
121 };
122
123 template <typename T>
124 struct shared_ptr_no_esft : private lw_shared_ptr_counter_base {
125 T _value;
126
127 shared_ptr_no_esft() = default;
128 shared_ptr_no_esft(const T& x) : _value(x) {}
129 shared_ptr_no_esft(T&& x) : _value(std::move(x)) {}
130 template <typename... A>
131 shared_ptr_no_esft(A&&... a) : _value(std::forward<A>(a)...) {}
132
133 template <typename X>
134 friend class lw_shared_ptr;
135 template <typename X>
136 friend class ::internal::lw_shared_ptr_accessors_no_esft;
137 template <typename X, class Y>
138 friend class ::internal::lw_shared_ptr_accessors;
139 };
140
141
142 /// Extension point: the user may override this to change how \ref lw_shared_ptr objects are destroyed,
143 /// primarily so that incomplete classes can be used.
144 ///
145 /// Customizing the deleter requires that \c T be derived from \c enable_lw_shared_from_this<T>.
146 /// The specialization must be visible for all uses of \c lw_shared_ptr<T>.
147 ///
148 /// To customize, the template must have a `static void dispose(T*)` operator that disposes of
149 /// the object.
150 template <typename T>
151 struct lw_shared_ptr_deleter; // No generic implementation
152
153 namespace internal {
154
155 template <typename T>
156 struct lw_shared_ptr_accessors_esft {
157 using concrete_type = std::remove_const_t<T>;
158 static T* to_value(lw_shared_ptr_counter_base* counter) {
159 return static_cast<T*>(counter);
160 }
161 static void dispose(lw_shared_ptr_counter_base* counter) {
162 delete static_cast<T*>(counter);
163 }
164 static void instantiate_to_value(lw_shared_ptr_counter_base* p) {
165 // since to_value() is defined above, we don't need to do anything special
166 // to force-instantiate it
167 }
168 };
169
170 template <typename T>
171 struct lw_shared_ptr_accessors_no_esft {
172 using concrete_type = shared_ptr_no_esft<T>;
173 static T* to_value(lw_shared_ptr_counter_base* counter) {
174 return &static_cast<concrete_type*>(counter)->_value;
175 }
176 static void dispose(lw_shared_ptr_counter_base* counter) {
177 delete static_cast<concrete_type*>(counter);
178 }
179 static void instantiate_to_value(lw_shared_ptr_counter_base* p) {
180 // since to_value() is defined above, we don't need to do anything special
181 // to force-instantiate it
182 }
183 };
184
185 // Generic case: lw_shared_ptr_deleter<T> is not specialized, select
186 // implementation based on whether T inherits from enable_lw_shared_from_this<T>.
187 template <typename T, typename U = void>
188 struct lw_shared_ptr_accessors : std::conditional_t<
189 std::is_base_of<enable_lw_shared_from_this<T>, T>::value,
190 lw_shared_ptr_accessors_esft<T>,
191 lw_shared_ptr_accessors_no_esft<T>> {
192 };
193
194 // Overload when lw_shared_ptr_deleter<T> specialized
195 template <typename T>
196 struct lw_shared_ptr_accessors<T, std::void_t<decltype(lw_shared_ptr_deleter<T>{})>> {
197 using concrete_type = T;
198 static T* to_value(lw_shared_ptr_counter_base* counter);
199 static void dispose(lw_shared_ptr_counter_base* counter) {
200 lw_shared_ptr_deleter<T>::dispose(to_value(counter));
201 }
202 static void instantiate_to_value(lw_shared_ptr_counter_base* p) {
203 // instantiate to_value(); must be defined by shared_ptr_incomplete.hh
204 to_value(p);
205 }
206 };
207
208 }
209
210 template <typename T>
211 class lw_shared_ptr {
212 using accessors = ::internal::lw_shared_ptr_accessors<std::remove_const_t<T>>;
213 using concrete_type = typename accessors::concrete_type;
214 mutable lw_shared_ptr_counter_base* _p = nullptr;
215 private:
216 lw_shared_ptr(lw_shared_ptr_counter_base* p) noexcept : _p(p) {
217 if (_p) {
218 ++_p->_count;
219 }
220 }
221 template <typename... A>
222 static lw_shared_ptr make(A&&... a) {
223 auto p = new concrete_type(std::forward<A>(a)...);
224 accessors::instantiate_to_value(p);
225 return lw_shared_ptr(p);
226 }
227 public:
228 using element_type = T;
229
230 lw_shared_ptr() noexcept = default;
231 lw_shared_ptr(std::nullptr_t) noexcept : lw_shared_ptr() {}
232 lw_shared_ptr(const lw_shared_ptr& x) noexcept : _p(x._p) {
233 if (_p) {
234 ++_p->_count;
235 }
236 }
237 lw_shared_ptr(lw_shared_ptr&& x) noexcept : _p(x._p) {
238 x._p = nullptr;
239 }
240 [[gnu::always_inline]]
241 ~lw_shared_ptr() {
242 if (_p && !--_p->_count) {
243 accessors::dispose(_p);
244 }
245 }
246 lw_shared_ptr& operator=(const lw_shared_ptr& x) noexcept {
247 if (_p != x._p) {
248 this->~lw_shared_ptr();
249 new (this) lw_shared_ptr(x);
250 }
251 return *this;
252 }
253 lw_shared_ptr& operator=(lw_shared_ptr&& x) noexcept {
254 if (_p != x._p) {
255 this->~lw_shared_ptr();
256 new (this) lw_shared_ptr(std::move(x));
257 }
258 return *this;
259 }
260 lw_shared_ptr& operator=(std::nullptr_t) noexcept {
261 return *this = lw_shared_ptr();
262 }
263 lw_shared_ptr& operator=(T&& x) noexcept {
264 this->~lw_shared_ptr();
265 new (this) lw_shared_ptr(make_lw_shared<T>(std::move(x)));
266 return *this;
267 }
268
269 T& operator*() const noexcept { return *accessors::to_value(_p); }
270 T* operator->() const noexcept { return accessors::to_value(_p); }
271 T* get() const noexcept {
272 if (_p) {
273 return accessors::to_value(_p);
274 } else {
275 return nullptr;
276 }
277 }
278
279 long int use_count() const noexcept {
280 if (_p) {
281 return _p->_count;
282 } else {
283 return 0;
284 }
285 }
286
287 operator lw_shared_ptr<const T>() const noexcept {
288 return lw_shared_ptr<const T>(_p);
289 }
290
291 explicit operator bool() const noexcept {
292 return _p;
293 }
294
295 bool owned() const noexcept {
296 return _p->_count == 1;
297 }
298
299 bool operator==(const lw_shared_ptr<const T>& x) const {
300 return _p == x._p;
301 }
302
303 bool operator!=(const lw_shared_ptr<const T>& x) const {
304 return !operator==(x);
305 }
306
307 bool operator==(const lw_shared_ptr<std::remove_const_t<T>>& x) const {
308 return _p == x._p;
309 }
310
311 bool operator!=(const lw_shared_ptr<std::remove_const_t<T>>& x) const {
312 return !operator==(x);
313 }
314
315 bool operator<(const lw_shared_ptr<const T>& x) const {
316 return _p < x._p;
317 }
318
319 bool operator<(const lw_shared_ptr<std::remove_const_t<T>>& x) const {
320 return _p < x._p;
321 }
322
323 template <typename U>
324 friend class lw_shared_ptr;
325
326 template <typename X, typename... A>
327 friend lw_shared_ptr<X> make_lw_shared(A&&...);
328
329 template <typename U>
330 friend lw_shared_ptr<U> make_lw_shared(U&&);
331
332 template <typename U>
333 friend lw_shared_ptr<U> make_lw_shared(U&);
334
335 template <typename U>
336 friend class enable_lw_shared_from_this;
337 };
338
339 template <typename T, typename... A>
340 inline
341 lw_shared_ptr<T> make_lw_shared(A&&... a) {
342 return lw_shared_ptr<T>::make(std::forward<A>(a)...);
343 }
344
345 template <typename T>
346 inline
347 lw_shared_ptr<T> make_lw_shared(T&& a) {
348 return lw_shared_ptr<T>::make(std::move(a));
349 }
350
351 template <typename T>
352 inline
353 lw_shared_ptr<T> make_lw_shared(T& a) {
354 return lw_shared_ptr<T>::make(a);
355 }
356
357 template <typename T>
358 inline
359 lw_shared_ptr<T>
360 enable_lw_shared_from_this<T>::shared_from_this() {
361 return lw_shared_ptr<T>(this);
362 }
363
364 template <typename T>
365 inline
366 lw_shared_ptr<const T>
367 enable_lw_shared_from_this<T>::shared_from_this() const {
368 return lw_shared_ptr<const T>(const_cast<enable_lw_shared_from_this*>(this));
369 }
370
371 template <typename T>
372 static inline
373 std::ostream& operator<<(std::ostream& out, const lw_shared_ptr<T>& p) {
374 if (!p) {
375 return out << "null";
376 }
377 return out << *p;
378 }
379
380 namespace std {
381
382 template <typename T>
383 struct hash<lw_shared_ptr<T>> : private hash<T*> {
384 size_t operator()(const lw_shared_ptr<T>& p) const {
385 return hash<T*>::operator()(p.get());
386 }
387 };
388
389 }
390
391 #endif /* CEPH_LW_SHARED_PTR_H_ */