1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
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.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
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
20 * Copyright (C) 2014 Cloudius Systems, Ltd.
23 #ifndef CEPH_LW_SHARED_PTR_H_
24 #define CEPH_LW_SHARED_PTR_H_
27 #include <type_traits>
31 // This header defines two shared pointer facilities, lw_shared_ptr<>
32 // modeled after std::shared_ptr<>.
34 // Unlike std::shared_ptr<>, neither of these implementations are thread
35 // safe, and two pointers sharing the same object must not be used in
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.
42 // Both variants support shared_from_this() via enable_shared_from_this<>
43 // and lw_enable_shared_from_this<>().
47 using remove_const_t = typename remove_const<T>::type;
52 template <typename T, typename... A>
53 lw_shared_ptr<T> make_lw_shared(A&&... a);
56 lw_shared_ptr<T> make_lw_shared(T&& a);
59 lw_shared_ptr<T> make_lw_shared(T& a);
61 // CRTP from this to enable shared_from_this:
63 class enable_lw_shared_from_this {
66 T* to_value() { return static_cast<T*>(this); }
67 T* to_internal_object() { return static_cast<T*>(this); }
69 enable_lw_shared_from_this() noexcept {}
70 enable_lw_shared_from_this(enable_lw_shared_from_this&&) noexcept {}
71 enable_lw_shared_from_this(const enable_lw_shared_from_this&) noexcept {}
72 enable_lw_shared_from_this& operator=(const enable_lw_shared_from_this&) noexcept { return *this; }
73 enable_lw_shared_from_this& operator=(enable_lw_shared_from_this&&) noexcept { return *this; }
75 lw_shared_ptr<T> shared_from_this();
76 lw_shared_ptr<const T> shared_from_this() const;
78 friend class lw_shared_ptr;
82 struct shared_ptr_no_esft {
84 using ctor = shared_ptr_no_esft;
86 T* to_value() { return &_value; }
87 shared_ptr_no_esft* to_internal_object() { return this; }
88 shared_ptr_no_esft() = default;
89 shared_ptr_no_esft(const T& x) : _value(x) {}
90 shared_ptr_no_esft(T&& x) : _value(std::move(x)) {}
91 template <typename... A>
92 shared_ptr_no_esft(A&&... a) : _value(std::forward<A>(a)...) {}
94 friend class lw_shared_ptr;
98 using shared_ptr_impl = typename std::conditional<
99 std::is_base_of<enable_lw_shared_from_this<remove_const_t<T>>, T>::value,
100 enable_lw_shared_from_this<remove_const_t<T>>,
101 shared_ptr_no_esft<remove_const_t<T>> >::type;
103 template <typename T>
104 class lw_shared_ptr {
105 mutable shared_ptr_impl<T>* _p = nullptr;
107 lw_shared_ptr(shared_ptr_impl<T>* p) noexcept : _p(p) {
112 template <typename... A>
113 static lw_shared_ptr make(A&&... a) {
114 return lw_shared_ptr(new typename shared_ptr_impl<T>::ctor(std::forward<A>(a)...));
117 using element_type = T;
119 lw_shared_ptr() noexcept = default;
120 lw_shared_ptr(std::nullptr_t) noexcept : lw_shared_ptr() {}
121 lw_shared_ptr(const lw_shared_ptr& x) noexcept : _p(x._p) {
126 lw_shared_ptr(lw_shared_ptr&& x) noexcept : _p(x._p) {
129 [[gnu::always_inline]]
131 if (_p && !--_p->_count) {
132 delete _p->to_internal_object();
135 lw_shared_ptr& operator=(const lw_shared_ptr& x) noexcept {
137 this->~lw_shared_ptr();
138 new (this) lw_shared_ptr(x);
142 lw_shared_ptr& operator=(lw_shared_ptr&& x) noexcept {
144 this->~lw_shared_ptr();
145 new (this) lw_shared_ptr(std::move(x));
149 lw_shared_ptr& operator=(std::nullptr_t) noexcept {
150 return *this = lw_shared_ptr();
152 lw_shared_ptr& operator=(T&& x) noexcept {
153 this->~lw_shared_ptr();
154 new (this) lw_shared_ptr(make_lw_shared<T>(std::move(x)));
158 T& operator*() const noexcept { return *_p->to_value(); }
159 T* operator->() const noexcept { return _p->to_value(); }
160 T* get() const noexcept { return _p->to_value(); }
162 long int use_count() const noexcept {
170 operator lw_shared_ptr<const T>() const noexcept {
171 return lw_shared_ptr<const T>(_p);
174 explicit operator bool() const noexcept {
178 bool owned() const noexcept {
179 return _p->_count == 1;
182 bool operator==(const lw_shared_ptr<const T>& x) const {
186 bool operator!=(const lw_shared_ptr<const T>& x) const {
187 return !operator==(x);
190 bool operator==(const lw_shared_ptr<remove_const_t<T>>& x) const {
194 bool operator!=(const lw_shared_ptr<remove_const_t<T>>& x) const {
195 return !operator==(x);
198 template <typename U>
199 friend class lw_shared_ptr;
201 template <typename X, typename... A>
202 friend lw_shared_ptr<X> make_lw_shared(A&&...);
204 template <typename U>
205 friend lw_shared_ptr<U> make_lw_shared(U&&);
207 template <typename U>
208 friend lw_shared_ptr<U> make_lw_shared(U&);
210 template <typename U>
211 friend class enable_lw_shared_from_this;
214 template <typename T, typename... A>
216 lw_shared_ptr<T> make_lw_shared(A&&... a) {
217 return lw_shared_ptr<T>::make(std::forward<A>(a)...);
220 template <typename T>
222 lw_shared_ptr<T> make_lw_shared(T&& a) {
223 return lw_shared_ptr<T>::make(std::move(a));
226 template <typename T>
228 lw_shared_ptr<T> make_lw_shared(T& a) {
229 return lw_shared_ptr<T>::make(a);
232 template <typename T>
235 enable_lw_shared_from_this<T>::shared_from_this() {
236 return lw_shared_ptr<T>(this);
239 template <typename T>
241 lw_shared_ptr<const T>
242 enable_lw_shared_from_this<T>::shared_from_this() const {
243 return lw_shared_ptr<const T>(const_cast<enable_lw_shared_from_this*>(this));
246 template <typename T>
248 std::ostream& operator<<(std::ostream& out, const lw_shared_ptr<T>& p) {
250 return out << "null";
257 template <typename T>
258 struct hash<lw_shared_ptr<T>> : private hash<T*> {
259 size_t operator()(const lw_shared_ptr<T>& p) const {
260 return hash<T*>::operator()(p.get());
266 #endif /* CEPH_LW_SHARED_PTR_H_ */