logging: rename the `DEBUG` log level to `DBG`
[folly.git] / folly / experimental / ReadMostlySharedPtr.h
1 /*
2  * Copyright 2017 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 template <typename RefCount>
32 class ReadMostlyMainPtrDeleter;
33
34 using DefaultRefCount = TLRefCount;
35
36 namespace detail {
37
38 template <typename T, typename RefCount = DefaultRefCount>
39 class ReadMostlySharedPtrCore {
40  public:
41   T* get() {
42     return ptrRaw_;
43   }
44
45   std::shared_ptr<T> getShared() {
46     return ptr_;
47   }
48
49   bool incref() {
50     return ++count_ > 0;
51   }
52
53   void decref() {
54     if (--count_ == 0) {
55       ptrRaw_ = nullptr;
56       ptr_.reset();
57
58       decrefWeak();
59     }
60   }
61
62   void increfWeak() {
63     auto value = ++weakCount_;
64     DCHECK_GT(value, 0);
65   }
66
67   void decrefWeak() {
68     if (--weakCount_ == 0) {
69       delete this;
70     }
71   }
72
73   size_t useCount() const {
74     return *count_;
75   }
76
77   ~ReadMostlySharedPtrCore() noexcept {
78     assert(*count_ == 0);
79     assert(*weakCount_ == 0);
80   }
81
82  private:
83   friend class ReadMostlyMainPtr<T, RefCount>;
84   friend class ReadMostlyMainPtrDeleter<RefCount>;
85
86   explicit ReadMostlySharedPtrCore(std::shared_ptr<T> ptr) :
87       ptrRaw_(ptr.get()),
88       ptr_(std::move(ptr)) {
89   }
90
91   T* ptrRaw_;
92   RefCount count_;
93   RefCount weakCount_;
94   std::shared_ptr<T> ptr_;
95 };
96
97 } // namespace detail
98
99 template <typename T, typename RefCount = DefaultRefCount>
100 class ReadMostlyMainPtr {
101  public:
102   ReadMostlyMainPtr() {
103   }
104
105   explicit ReadMostlyMainPtr(std::shared_ptr<T> ptr) {
106     reset(std::move(ptr));
107   }
108
109   ReadMostlyMainPtr(const ReadMostlyMainPtr&) = delete;
110   ReadMostlyMainPtr& operator=(const ReadMostlyMainPtr&) = delete;
111
112   ReadMostlyMainPtr(ReadMostlyMainPtr&& other) noexcept {
113     *this = std::move(other);
114   }
115
116   ReadMostlyMainPtr& operator=(ReadMostlyMainPtr&& other) noexcept {
117     std::swap(impl_, other.impl_);
118
119     return *this;
120   }
121
122   bool operator==(const ReadMostlyMainPtr<T, RefCount>& other) const {
123     return get() == other.get();
124   }
125
126   bool operator==(T* other) const {
127     return get() == other;
128   }
129
130   bool operator==(const ReadMostlySharedPtr<T, RefCount>& other) const {
131     return get() == other.get();
132   }
133
134   ~ReadMostlyMainPtr() noexcept {
135     reset();
136   }
137
138   void reset() noexcept {
139     if (impl_) {
140       impl_->count_.useGlobal();
141       impl_->weakCount_.useGlobal();
142       impl_->decref();
143       impl_ = nullptr;
144     }
145   }
146
147   void reset(std::shared_ptr<T> ptr) {
148     reset();
149     if (ptr) {
150       impl_ = new detail::ReadMostlySharedPtrCore<T, RefCount>(std::move(ptr));
151     }
152   }
153
154   T* get() const {
155     if (impl_) {
156       return impl_->ptrRaw_;
157     } else {
158       return nullptr;
159     }
160   }
161
162   std::shared_ptr<T> getStdShared() const {
163     if (impl_) {
164       return impl_->getShared();
165     } else {
166       return {};
167     }
168   }
169
170   T& operator*() const {
171     return *get();
172   }
173
174   T* operator->() const {
175     return get();
176   }
177
178   ReadMostlySharedPtr<T, RefCount> getShared() const {
179     return ReadMostlySharedPtr<T, RefCount>(*this);
180   }
181
182   explicit operator bool() const {
183     return impl_ != nullptr;
184   }
185
186  private:
187   friend class ReadMostlyWeakPtr<T, RefCount>;
188   friend class ReadMostlySharedPtr<T, RefCount>;
189   friend class ReadMostlyMainPtrDeleter<RefCount>;
190
191   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
192 };
193
194 template <typename T, typename RefCount = DefaultRefCount>
195 class ReadMostlyWeakPtr {
196  public:
197   ReadMostlyWeakPtr() {}
198
199   explicit ReadMostlyWeakPtr(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
200     reset(mainPtr.impl_);
201   }
202
203   explicit ReadMostlyWeakPtr(const ReadMostlySharedPtr<T, RefCount>& ptr) {
204     reset(ptr.impl_);
205   }
206
207   ReadMostlyWeakPtr(const ReadMostlyWeakPtr& other) {
208     *this = other;
209   }
210
211   ReadMostlyWeakPtr& operator=(const ReadMostlyWeakPtr& other) {
212     reset(other.impl_);
213     return *this;
214   }
215
216   ReadMostlyWeakPtr& operator=(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
217     reset(mainPtr.impl_);
218     return *this;
219   }
220
221   ReadMostlyWeakPtr(ReadMostlyWeakPtr&& other) noexcept {
222     *this = other;
223   }
224
225   ReadMostlyWeakPtr& operator=(ReadMostlyWeakPtr&& other) noexcept {
226     std::swap(impl_, other.impl_);
227     return *this;
228   }
229
230   ~ReadMostlyWeakPtr() noexcept {
231     reset(nullptr);
232   }
233
234   ReadMostlySharedPtr<T, RefCount> lock() {
235     return ReadMostlySharedPtr<T, RefCount>(*this);
236   }
237
238  private:
239   friend class ReadMostlySharedPtr<T, RefCount>;
240
241   void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) {
242     if (impl_) {
243       impl_->decrefWeak();
244     }
245     impl_ = impl;
246     if (impl_) {
247       impl_->increfWeak();
248     }
249   }
250
251   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
252 };
253
254 template <typename T, typename RefCount = DefaultRefCount>
255 class ReadMostlySharedPtr {
256  public:
257   ReadMostlySharedPtr() {}
258
259   explicit ReadMostlySharedPtr(const ReadMostlyWeakPtr<T, RefCount>& weakPtr) {
260     reset(weakPtr.impl_);
261   }
262
263   // Generally, this shouldn't be used.
264   explicit ReadMostlySharedPtr(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
265     reset(mainPtr.impl_);
266   }
267
268   ReadMostlySharedPtr(const ReadMostlySharedPtr& other) {
269     *this = other;
270   }
271
272   ReadMostlySharedPtr& operator=(const ReadMostlySharedPtr& other) {
273     reset(other.impl_);
274     return *this;
275   }
276
277   ReadMostlySharedPtr& operator=(const ReadMostlyWeakPtr<T, RefCount>& other) {
278     reset(other.impl_);
279     return *this;
280   }
281
282   ReadMostlySharedPtr& operator=(const ReadMostlyMainPtr<T, RefCount>& other) {
283     reset(other.impl_);
284     return *this;
285   }
286
287   ReadMostlySharedPtr(ReadMostlySharedPtr&& other) noexcept {
288     *this = std::move(other);
289   }
290
291   ~ReadMostlySharedPtr() noexcept {
292     reset(nullptr);
293   }
294
295   ReadMostlySharedPtr& operator=(ReadMostlySharedPtr&& other) noexcept {
296     std::swap(ptr_, other.ptr_);
297     std::swap(impl_, other.impl_);
298     return *this;
299   }
300
301   bool operator==(const ReadMostlyMainPtr<T, RefCount>& other) const {
302     return get() == other.get();
303   }
304
305   bool operator==(T* other) const {
306     return get() == other;
307   }
308
309   bool operator==(const ReadMostlySharedPtr<T, RefCount>& other) const {
310     return get() == other.get();
311   }
312
313   void reset() {
314     reset(nullptr);
315   }
316
317   T* get() const {
318     return ptr_;
319   }
320
321   std::shared_ptr<T> getStdShared() const {
322     if (impl_) {
323       return impl_->getShared();
324     } else {
325       return {};
326     }
327   }
328
329   T& operator*() const {
330     return *get();
331   }
332
333   T* operator->() const {
334     return get();
335   }
336
337   size_t use_count() const {
338     return impl_->useCount();
339   }
340
341   bool unique() const {
342     return use_count() == 1;
343   }
344
345   explicit operator bool() const {
346     return impl_ != nullptr;
347   }
348
349  private:
350   friend class ReadMostlyWeakPtr<T, RefCount>;
351
352   void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) {
353     if (impl_) {
354       impl_->decref();
355       impl_ = nullptr;
356       ptr_ = nullptr;
357     }
358
359     if (impl && impl->incref()) {
360       impl_ = impl;
361       ptr_ = impl->get();
362     }
363   }
364
365   T* ptr_{nullptr};
366   detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr};
367 };
368
369 /**
370  * This can be used to destroy multiple ReadMostlyMainPtrs at once.
371  */
372 template <typename RefCount = DefaultRefCount>
373 class ReadMostlyMainPtrDeleter {
374  public:
375   ~ReadMostlyMainPtrDeleter() noexcept {
376     RefCount::useGlobal(refCounts_);
377     for (auto& decref : decrefs_) {
378       decref();
379     }
380   }
381
382   template <typename T>
383   void add(ReadMostlyMainPtr<T, RefCount> ptr) noexcept {
384     if (!ptr.impl_) {
385       return;
386     }
387
388     refCounts_.push_back(&ptr.impl_->count_);
389     refCounts_.push_back(&ptr.impl_->weakCount_);
390     decrefs_.push_back([impl = ptr.impl_] { impl->decref(); });
391     ptr.impl_ = nullptr;
392   }
393
394  private:
395   std::vector<RefCount*> refCounts_;
396   std::vector<folly::Function<void()>> decrefs_;
397 };
398
399 template <typename T, typename RefCount>
400 inline bool operator==(
401     const ReadMostlyMainPtr<T, RefCount>& ptr,
402     std::nullptr_t) {
403   return ptr.get() == nullptr;
404 }
405
406 template <typename T, typename RefCount>
407 inline bool operator==(
408     std::nullptr_t,
409     const ReadMostlyMainPtr<T, RefCount>& ptr) {
410   return ptr.get() == nullptr;
411 }
412
413 template <typename T, typename RefCount>
414 inline bool operator==(
415     const ReadMostlySharedPtr<T, RefCount>& ptr,
416     std::nullptr_t) {
417   return ptr.get() == nullptr;
418 }
419
420 template <typename T, typename RefCount>
421 inline bool operator==(
422     std::nullptr_t,
423     const ReadMostlySharedPtr<T, RefCount>& ptr) {
424   return ptr.get() == nullptr;
425 }
426
427 template <typename T, typename RefCount>
428 inline bool operator!=(
429     const ReadMostlyMainPtr<T, RefCount>& ptr,
430     std::nullptr_t) {
431   return !(ptr == nullptr);
432 }
433
434 template <typename T, typename RefCount>
435 inline bool operator!=(
436     std::nullptr_t,
437     const ReadMostlyMainPtr<T, RefCount>& ptr) {
438   return !(ptr == nullptr);
439 }
440
441 template <typename T, typename RefCount>
442 inline bool operator!=(
443     const ReadMostlySharedPtr<T, RefCount>& ptr,
444     std::nullptr_t) {
445   return !(ptr == nullptr);
446 }
447
448 template <typename T, typename RefCount>
449 inline bool operator!=(
450     std::nullptr_t,
451     const ReadMostlySharedPtr<T, RefCount>& ptr) {
452   return !(ptr == nullptr);
453 }
454 } // namespace folly