add LockTraits
[folly.git] / folly / experimental / ReadMostlySharedPtr.h
1 /*
2  * Copyright 2016 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/TLRefCount.h>
22
23 namespace folly {
24
25 template <typename T, typename RefCount>
26 class ReadMostlyMainPtr;
27 template <typename T, typename RefCount>
28 class ReadMostlyWeakPtr;
29 template <typename T, typename RefCount>
30 class ReadMostlySharedPtr;
31
32 using DefaultRefCount = TLRefCount;
33
34 namespace detail {
35
36 template <typename T, typename RefCount = DefaultRefCount>
37 class ReadMostlySharedPtrCore {
38  public:
39   T* get() {
40     return ptrRaw_;
41   }
42
43   std::shared_ptr<T> getShared() {
44     return ptr_;
45   }
46
47   bool incref() {
48     return ++count_ > 0;
49   }
50
51   void decref() {
52     if (--count_ == 0) {
53       ptrRaw_ = nullptr;
54       ptr_.reset();
55
56       decrefWeak();
57     }
58   }
59
60   void increfWeak() {
61     auto value = ++weakCount_;
62     DCHECK_GT(value, 0);
63   }
64
65   void decrefWeak() {
66     if (--weakCount_ == 0) {
67       delete this;
68     }
69   }
70
71   size_t useCount() const {
72     return *count_;
73   }
74
75   ~ReadMostlySharedPtrCore() noexcept {
76     assert(*count_ == 0);
77     assert(*weakCount_ == 0);
78   }
79
80  private:
81   friend class ReadMostlyMainPtr<T, RefCount>;
82
83   explicit ReadMostlySharedPtrCore(std::shared_ptr<T> ptr) :
84       ptrRaw_(ptr.get()),
85       ptr_(std::move(ptr)) {
86   }
87
88   T* ptrRaw_;
89   RefCount count_;
90   RefCount weakCount_;
91   std::shared_ptr<T> ptr_;
92 };
93
94 }
95
96 template <typename T, typename RefCount = DefaultRefCount>
97 class ReadMostlyMainPtr {
98  public:
99   ReadMostlyMainPtr() {
100   }
101
102   explicit ReadMostlyMainPtr(std::shared_ptr<T> ptr) {
103     reset(std::move(ptr));
104   }
105
106   ReadMostlyMainPtr(const ReadMostlyMainPtr&) = delete;
107   ReadMostlyMainPtr& operator=(const ReadMostlyMainPtr&) = delete;
108
109   ReadMostlyMainPtr(ReadMostlyMainPtr&& other) noexcept {
110     *this = std::move(other);
111   }
112
113   ReadMostlyMainPtr& operator=(ReadMostlyMainPtr&& other) noexcept {
114     std::swap(impl_, other.impl_);
115
116     return *this;
117   }
118
119   bool operator==(const ReadMostlyMainPtr<T, RefCount>& other) const {
120     return get() == other.get();
121   }
122
123   bool operator==(T* other) const {
124     return get() == other;
125   }
126
127   bool operator==(const ReadMostlySharedPtr<T, RefCount>& other) const {
128     return get() == other.get();
129   }
130
131   ~ReadMostlyMainPtr() noexcept {
132     reset();
133   }
134
135   void reset() noexcept {
136     if (impl_) {
137       impl_->count_.useGlobal();
138       impl_->weakCount_.useGlobal();
139       impl_->decref();
140       impl_ = nullptr;
141     }
142   }
143
144   void reset(std::shared_ptr<T> ptr) {
145     reset();
146     if (ptr) {
147       impl_ = new detail::ReadMostlySharedPtrCore<T, RefCount>(std::move(ptr));
148     }
149   }
150
151   T* get() const {
152     if (impl_) {
153       return impl_->ptrRaw_;
154     } else {
155       return nullptr;
156     }
157   }
158
159   std::shared_ptr<T> getStdShared() {
160     if (impl_) {
161       return impl_->ptr_;
162     } else {
163       return {};
164     }
165   }
166
167   T& operator*() const {
168     return *get();
169   }
170
171   T* operator->() const {
172     return get();
173   }
174
175   ReadMostlySharedPtr<T, RefCount> getShared() const {
176     return ReadMostlySharedPtr<T, RefCount>(*this);
177   }
178
179   explicit operator bool() const {
180     return impl_ != nullptr;
181   }
182
183  private:
184   friend class ReadMostlyWeakPtr<T, RefCount>;
185   friend class ReadMostlySharedPtr<T, RefCount>;
186
187   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
188 };
189
190 template <typename T, typename RefCount = DefaultRefCount>
191 class ReadMostlyWeakPtr {
192  public:
193   ReadMostlyWeakPtr() {}
194
195   explicit ReadMostlyWeakPtr(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
196     reset(mainPtr.impl_);
197   }
198
199   explicit ReadMostlyWeakPtr(const ReadMostlySharedPtr<T, RefCount>& ptr) {
200     reset(ptr.impl_);
201   }
202
203   ReadMostlyWeakPtr(const ReadMostlyWeakPtr& other) {
204     *this = other;
205   }
206
207   ReadMostlyWeakPtr& operator=(const ReadMostlyWeakPtr& other) {
208     reset(other.impl_);
209     return *this;
210   }
211
212   ReadMostlyWeakPtr& operator=(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
213     reset(mainPtr.impl_);
214     return *this;
215   }
216
217   ReadMostlyWeakPtr(ReadMostlyWeakPtr&& other) noexcept {
218     *this = other;
219   }
220
221   ReadMostlyWeakPtr& operator=(ReadMostlyWeakPtr&& other) noexcept {
222     std::swap(impl_, other.impl_);
223     return *this;
224   }
225
226   ~ReadMostlyWeakPtr() noexcept {
227     reset(nullptr);
228   }
229
230   ReadMostlySharedPtr<T, RefCount> lock() {
231     return ReadMostlySharedPtr<T, RefCount>(*this);
232   }
233
234  private:
235   friend class ReadMostlySharedPtr<T, RefCount>;
236
237   void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) {
238     if (impl_) {
239       impl_->decrefWeak();
240     }
241     impl_ = impl;
242     if (impl_) {
243       impl_->increfWeak();
244     }
245   }
246
247   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
248 };
249
250 template <typename T, typename RefCount = DefaultRefCount>
251 class ReadMostlySharedPtr {
252  public:
253   ReadMostlySharedPtr() {}
254
255   explicit ReadMostlySharedPtr(const ReadMostlyWeakPtr<T, RefCount>& weakPtr) {
256     reset(weakPtr.impl_);
257   }
258
259   // Generally, this shouldn't be used.
260   explicit ReadMostlySharedPtr(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
261     reset(mainPtr.impl_);
262   }
263
264   ReadMostlySharedPtr(const ReadMostlySharedPtr& other) {
265     *this = other;
266   }
267
268   ReadMostlySharedPtr& operator=(const ReadMostlySharedPtr& other) {
269     reset(other.impl_);
270     return *this;
271   }
272
273   ReadMostlySharedPtr& operator=(const ReadMostlyWeakPtr<T, RefCount>& other) {
274     reset(other.impl_);
275     return *this;
276   }
277
278   ReadMostlySharedPtr& operator=(const ReadMostlyMainPtr<T, RefCount>& other) {
279     reset(other.impl_);
280     return *this;
281   }
282
283   ReadMostlySharedPtr(ReadMostlySharedPtr&& other) noexcept {
284     *this = std::move(other);
285   }
286
287   ~ReadMostlySharedPtr() noexcept {
288     reset(nullptr);
289   }
290
291   ReadMostlySharedPtr& operator=(ReadMostlySharedPtr&& other) noexcept {
292     std::swap(ptr_, other.ptr_);
293     std::swap(impl_, other.impl_);
294     return *this;
295   }
296
297   bool operator==(const ReadMostlyMainPtr<T, RefCount>& other) const {
298     return get() == other.get();
299   }
300
301   bool operator==(T* other) const {
302     return get() == other;
303   }
304
305   bool operator==(const ReadMostlySharedPtr<T, RefCount>& other) const {
306     return get() == other.get();
307   }
308
309   void reset() {
310     reset(nullptr);
311   }
312
313   T* get() const {
314     return ptr_;
315   }
316
317   std::shared_ptr<T> getStdShared() const {
318     if (impl_) {
319       return impl_->ptr_;
320     } else {
321       return {};
322     }
323   }
324
325   T& operator*() const {
326     return *get();
327   }
328
329   T* operator->() const {
330     return get();
331   }
332
333   size_t use_count() const {
334     return impl_->useCount();
335   }
336
337   bool unique() const {
338     return use_count() == 1;
339   }
340
341   explicit operator bool() const {
342     return impl_ != nullptr;
343   }
344
345  private:
346   friend class ReadMostlyWeakPtr<T, RefCount>;
347
348   void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) {
349     if (impl_) {
350       impl_->decref();
351       impl_ = nullptr;
352       ptr_ = nullptr;
353     }
354
355     if (impl && impl->incref()) {
356       impl_ = impl;
357       ptr_ = impl->get();
358     }
359   }
360
361   T* ptr_{nullptr};
362   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
363 };
364
365 }