d6c04cdbcea4b9d5855f229bb400bf334bda65bb
[folly.git] / folly / experimental / ReadMostlySharedPtr.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /* -*- Mode: C++; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
17 #pragma once
18
19 #include <atomic>
20
21 #include <folly/experimental/RCURefCount.h>
22 #include <folly/experimental/TLRefCount.h>
23
24 namespace folly {
25
26 template <typename T, typename RefCount>
27 class ReadMostlyMainPtr;
28 template <typename T, typename RefCount>
29 class ReadMostlyWeakPtr;
30 template <typename T, typename RefCount>
31 class ReadMostlySharedPtr;
32
33 using DefaultRefCount = TLRefCount;
34
35 namespace detail {
36
37 template <typename T, typename RefCount = DefaultRefCount>
38 class ReadMostlySharedPtrCore {
39  public:
40   T* get() {
41     return ptrRaw_;
42   }
43
44   std::shared_ptr<T> getShared() {
45     return ptr_;
46   }
47
48   bool incref() {
49     return ++count_ > 0;
50   }
51
52   void decref() {
53     if (--count_ == 0) {
54       ptrRaw_ = nullptr;
55       ptr_.reset();
56
57       decrefWeak();
58     }
59   }
60
61   void increfWeak() {
62     auto value = ++weakCount_;
63     assert(value > 0);
64   }
65
66   void decrefWeak() {
67     if (--weakCount_ == 0) {
68       delete this;
69     }
70   }
71
72   size_t useCount() const {
73     return *count_;
74   }
75
76   ~ReadMostlySharedPtrCore() noexcept {
77     assert(*count_ == 0);
78     assert(*weakCount_ == 0);
79   }
80
81  private:
82   friend class ReadMostlyMainPtr<T, RefCount>;
83
84   explicit ReadMostlySharedPtrCore(std::shared_ptr<T> ptr) :
85       ptrRaw_(ptr.get()),
86       ptr_(std::move(ptr)) {
87   }
88
89   T* ptrRaw_;
90   RefCount count_;
91   RefCount weakCount_;
92   std::shared_ptr<T> ptr_;
93 };
94
95 }
96
97 template <typename T, typename RefCount = DefaultRefCount>
98 class ReadMostlyMainPtr {
99  public:
100   ReadMostlyMainPtr() {
101   }
102
103   explicit ReadMostlyMainPtr(std::shared_ptr<T> ptr) {
104     reset(std::move(ptr));
105   }
106
107   ReadMostlyMainPtr(const ReadMostlyMainPtr&) = delete;
108   ReadMostlyMainPtr& operator=(const ReadMostlyMainPtr&) = delete;
109
110   ReadMostlyMainPtr(ReadMostlyMainPtr&& other) noexcept {
111     *this = std::move(other);
112   }
113
114   ReadMostlyMainPtr& operator=(ReadMostlyMainPtr&& other) noexcept {
115     std::swap(impl_, other.impl_);
116
117     return *this;
118   }
119
120   bool operator==(const ReadMostlyMainPtr<T, RefCount>& other) const {
121     return get() == other.get();
122   }
123
124   bool operator==(T* other) const {
125     return get() == other;
126   }
127
128   bool operator==(const ReadMostlySharedPtr<T, RefCount>& other) const {
129     return get() == other.get();
130   }
131
132   ~ReadMostlyMainPtr() noexcept {
133     reset();
134   }
135
136   void reset() noexcept {
137     if (impl_) {
138       impl_->count_.useGlobal();
139       impl_->weakCount_.useGlobal();
140       impl_->decref();
141       impl_ = nullptr;
142     }
143   }
144
145   void reset(std::shared_ptr<T> ptr) {
146     reset();
147     if (ptr) {
148       impl_ = new detail::ReadMostlySharedPtrCore<T, RefCount>(std::move(ptr));
149     }
150   }
151
152   T* get() const {
153     if (impl_) {
154       return impl_->ptrRaw_;
155     } else {
156       return nullptr;
157     }
158   }
159
160   std::shared_ptr<T> getStdShared() {
161     if (impl_) {
162       return impl_->ptr_;
163     } else {
164       return {};
165     }
166   }
167
168   T& operator*() const {
169     return *get();
170   }
171
172   T* operator->() const {
173     return get();
174   }
175
176   ReadMostlySharedPtr<T, RefCount> getShared() const {
177     return ReadMostlySharedPtr<T, RefCount>(*this);
178   }
179
180   explicit operator bool() const {
181     return impl_ != nullptr;
182   }
183
184  private:
185   friend class ReadMostlyWeakPtr<T, RefCount>;
186   friend class ReadMostlySharedPtr<T, RefCount>;
187
188   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
189 };
190
191 template <typename T, typename RefCount = DefaultRefCount>
192 class ReadMostlyWeakPtr {
193  public:
194   ReadMostlyWeakPtr() {}
195
196   explicit ReadMostlyWeakPtr(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
197     reset(mainPtr.impl_);
198   }
199
200   ReadMostlyWeakPtr(const ReadMostlyWeakPtr& other) {
201     *this = other;
202   }
203
204   ReadMostlyWeakPtr& operator=(const ReadMostlyWeakPtr& other) {
205     reset(other.impl_);
206     return *this;
207   }
208
209   ReadMostlyWeakPtr(ReadMostlyWeakPtr&& other) noexcept {
210     *this = other;
211   }
212
213   ReadMostlyWeakPtr& operator=(ReadMostlyWeakPtr&& other) noexcept {
214     std::swap(impl_, other.impl_);
215     return *this;
216   }
217
218   ~ReadMostlyWeakPtr() noexcept {
219     reset(nullptr);
220   }
221
222   ReadMostlySharedPtr<T, RefCount> lock() {
223     return ReadMostlySharedPtr<T, RefCount>(*this);
224   }
225
226  private:
227   friend class ReadMostlySharedPtr<T, RefCount>;
228
229   void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) {
230     if (impl_) {
231       impl_->decrefWeak();
232     }
233     impl_ = impl;
234     if (impl_) {
235       impl_->increfWeak();
236     }
237   }
238
239   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
240 };
241
242 template <typename T, typename RefCount = DefaultRefCount>
243 class ReadMostlySharedPtr {
244  public:
245   ReadMostlySharedPtr() {}
246
247   explicit ReadMostlySharedPtr(const ReadMostlyWeakPtr<T, RefCount>& weakPtr) {
248     reset(weakPtr.impl_);
249   }
250
251   // Generally, this shouldn't be used.
252   explicit ReadMostlySharedPtr(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
253     reset(mainPtr.impl_);
254   }
255
256   ReadMostlySharedPtr(const ReadMostlySharedPtr& other) {
257     *this = other;
258   }
259
260   ReadMostlySharedPtr& operator=(const ReadMostlySharedPtr& other) {
261     reset(other.impl_);
262     return *this;
263   }
264
265   ReadMostlySharedPtr& operator=(const ReadMostlyWeakPtr<T, RefCount>& other) {
266     reset(other.impl_);
267     return *this;
268   }
269
270   ReadMostlySharedPtr& operator=(const ReadMostlyMainPtr<T, RefCount>& other) {
271     reset(other.impl_);
272     return *this;
273   }
274
275   ReadMostlySharedPtr(ReadMostlySharedPtr&& other) noexcept {
276     *this = std::move(other);
277   }
278
279   ~ReadMostlySharedPtr() noexcept {
280     reset(nullptr);
281   }
282
283   ReadMostlySharedPtr& operator=(ReadMostlySharedPtr&& other) noexcept {
284     std::swap(ptr_, other.ptr_);
285     std::swap(impl_, other.impl_);
286     return *this;
287   }
288
289   bool operator==(const ReadMostlyMainPtr<T, RefCount>& other) const {
290     return get() == other.get();
291   }
292
293   bool operator==(T* other) const {
294     return get() == other;
295   }
296
297   bool operator==(const ReadMostlySharedPtr<T, RefCount>& other) const {
298     return get() == other.get();
299   }
300
301   void reset() {
302     reset(nullptr);
303   }
304
305   T* get() const {
306     return ptr_;
307   }
308
309   std::shared_ptr<T> getStdShared() const {
310     if (impl_) {
311       return impl_->ptr_;
312     } else {
313       return {};
314     }
315   }
316
317   T& operator*() const {
318     return *get();
319   }
320
321   T* operator->() const {
322     return get();
323   }
324
325   size_t use_count() const {
326     return impl_->useCount();
327   }
328
329   bool unique() const {
330     return use_count() == 1;
331   }
332
333   explicit operator bool() const {
334     return impl_ != nullptr;
335   }
336
337  private:
338   void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) {
339     if (impl_) {
340       impl_->decref();
341       impl_ = nullptr;
342       ptr_ = nullptr;
343     }
344
345     if (impl && impl->incref()) {
346       impl_ = impl;
347       ptr_ = impl->get();
348     }
349   }
350
351   T* ptr_{nullptr};
352   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
353 };
354
355 }