1 | /* |
2 | * Copyright 2015-present 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()), ptr_(std::move(ptr)) {} |
88 | |
89 | T* ptrRaw_; |
90 | RefCount count_; |
91 | RefCount weakCount_; |
92 | std::shared_ptr<T> ptr_; |
93 | }; |
94 | |
95 | } // namespace detail |
96 | |
97 | template <typename T, typename RefCount = DefaultRefCount> |
98 | class ReadMostlyMainPtr { |
99 | public: |
100 | ReadMostlyMainPtr() {} |
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() const { |
160 | if (impl_) { |
161 | return impl_->getShared(); |
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 | friend class ReadMostlyMainPtrDeleter<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 | explicit ReadMostlyWeakPtr(const ReadMostlySharedPtr<T, RefCount>& ptr) { |
201 | reset(ptr.impl_); |
202 | } |
203 | |
204 | ReadMostlyWeakPtr(const ReadMostlyWeakPtr& other) { |
205 | *this = other; |
206 | } |
207 | |
208 | ReadMostlyWeakPtr& operator=(const ReadMostlyWeakPtr& other) { |
209 | reset(other.impl_); |
210 | return *this; |
211 | } |
212 | |
213 | ReadMostlyWeakPtr& operator=(const ReadMostlyMainPtr<T, RefCount>& mainPtr) { |
214 | reset(mainPtr.impl_); |
215 | return *this; |
216 | } |
217 | |
218 | ReadMostlyWeakPtr(ReadMostlyWeakPtr&& other) noexcept { |
219 | *this = other; |
220 | } |
221 | |
222 | ReadMostlyWeakPtr& operator=(ReadMostlyWeakPtr&& other) noexcept { |
223 | std::swap(impl_, other.impl_); |
224 | return *this; |
225 | } |
226 | |
227 | ~ReadMostlyWeakPtr() noexcept { |
228 | reset(nullptr); |
229 | } |
230 | |
231 | ReadMostlySharedPtr<T, RefCount> lock() { |
232 | return ReadMostlySharedPtr<T, RefCount>(*this); |
233 | } |
234 | |
235 | private: |
236 | friend class ReadMostlySharedPtr<T, RefCount>; |
237 | |
238 | void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) { |
239 | if (impl_) { |
240 | impl_->decrefWeak(); |
241 | } |
242 | impl_ = impl; |
243 | if (impl_) { |
244 | impl_->increfWeak(); |
245 | } |
246 | } |
247 | |
248 | detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr}; |
249 | }; |
250 | |
251 | template <typename T, typename RefCount = DefaultRefCount> |
252 | class ReadMostlySharedPtr { |
253 | public: |
254 | ReadMostlySharedPtr() {} |
255 | |
256 | explicit ReadMostlySharedPtr(const ReadMostlyWeakPtr<T, RefCount>& weakPtr) { |
257 | reset(weakPtr.impl_); |
258 | } |
259 | |
260 | // Generally, this shouldn't be used. |
261 | explicit ReadMostlySharedPtr(const ReadMostlyMainPtr<T, RefCount>& mainPtr) { |
262 | reset(mainPtr.impl_); |
263 | } |
264 | |
265 | ReadMostlySharedPtr(const ReadMostlySharedPtr& other) { |
266 | *this = other; |
267 | } |
268 | |
269 | ReadMostlySharedPtr& operator=(const ReadMostlySharedPtr& other) { |
270 | reset(other.impl_); |
271 | return *this; |
272 | } |
273 | |
274 | ReadMostlySharedPtr& operator=(const ReadMostlyWeakPtr<T, RefCount>& other) { |
275 | reset(other.impl_); |
276 | return *this; |
277 | } |
278 | |
279 | ReadMostlySharedPtr& operator=(const ReadMostlyMainPtr<T, RefCount>& other) { |
280 | reset(other.impl_); |
281 | return *this; |
282 | } |
283 | |
284 | ReadMostlySharedPtr(ReadMostlySharedPtr&& other) noexcept { |
285 | *this = std::move(other); |
286 | } |
287 | |
288 | ~ReadMostlySharedPtr() noexcept { |
289 | reset(nullptr); |
290 | } |
291 | |
292 | ReadMostlySharedPtr& operator=(ReadMostlySharedPtr&& other) noexcept { |
293 | std::swap(ptr_, other.ptr_); |
294 | std::swap(impl_, other.impl_); |
295 | return *this; |
296 | } |
297 | |
298 | bool operator==(const ReadMostlyMainPtr<T, RefCount>& other) const { |
299 | return get() == other.get(); |
300 | } |
301 | |
302 | bool operator==(T* other) const { |
303 | return get() == other; |
304 | } |
305 | |
306 | bool operator==(const ReadMostlySharedPtr<T, RefCount>& other) const { |
307 | return get() == other.get(); |
308 | } |
309 | |
310 | void reset() { |
311 | reset(nullptr); |
312 | } |
313 | |
314 | T* get() const { |
315 | return ptr_; |
316 | } |
317 | |
318 | std::shared_ptr<T> getStdShared() const { |
319 | if (impl_) { |
320 | return impl_->getShared(); |
321 | } else { |
322 | return {}; |
323 | } |
324 | } |
325 | |
326 | T& operator*() const { |
327 | return *get(); |
328 | } |
329 | |
330 | T* operator->() const { |
331 | return get(); |
332 | } |
333 | |
334 | size_t use_count() const { |
335 | return impl_->useCount(); |
336 | } |
337 | |
338 | bool unique() const { |
339 | return use_count() == 1; |
340 | } |
341 | |
342 | explicit operator bool() const { |
343 | return impl_ != nullptr; |
344 | } |
345 | |
346 | private: |
347 | friend class ReadMostlyWeakPtr<T, RefCount>; |
348 | |
349 | void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) { |
350 | if (impl_) { |
351 | impl_->decref(); |
352 | impl_ = nullptr; |
353 | ptr_ = nullptr; |
354 | } |
355 | |
356 | if (impl && impl->incref()) { |
357 | impl_ = impl; |
358 | ptr_ = impl->get(); |
359 | } |
360 | } |
361 | |
362 | T* ptr_{nullptr}; |
363 | detail::ReadMostlySharedPtrCore<T, RefCount>* impl_{nullptr}; |
364 | }; |
365 | |
366 | /** |
367 | * This can be used to destroy multiple ReadMostlyMainPtrs at once. |
368 | */ |
369 | template <typename RefCount = DefaultRefCount> |
370 | class ReadMostlyMainPtrDeleter { |
371 | public: |
372 | ~ReadMostlyMainPtrDeleter() noexcept { |
373 | RefCount::useGlobal(refCounts_); |
374 | for (auto& decref : decrefs_) { |
375 | decref(); |
376 | } |
377 | } |
378 | |
379 | template <typename T> |
380 | void add(ReadMostlyMainPtr<T, RefCount> ptr) noexcept { |
381 | if (!ptr.impl_) { |
382 | return; |
383 | } |
384 | |
385 | refCounts_.push_back(&ptr.impl_->count_); |
386 | refCounts_.push_back(&ptr.impl_->weakCount_); |
387 | decrefs_.push_back([impl = ptr.impl_] { impl->decref(); }); |
388 | ptr.impl_ = nullptr; |
389 | } |
390 | |
391 | private: |
392 | std::vector<RefCount*> refCounts_; |
393 | std::vector<folly::Function<void()>> decrefs_; |
394 | }; |
395 | |
396 | template <typename T, typename RefCount> |
397 | inline bool operator==( |
398 | const ReadMostlyMainPtr<T, RefCount>& ptr, |
399 | std::nullptr_t) { |
400 | return ptr.get() == nullptr; |
401 | } |
402 | |
403 | template <typename T, typename RefCount> |
404 | inline bool operator==( |
405 | std::nullptr_t, |
406 | const ReadMostlyMainPtr<T, RefCount>& ptr) { |
407 | return ptr.get() == nullptr; |
408 | } |
409 | |
410 | template <typename T, typename RefCount> |
411 | inline bool operator==( |
412 | const ReadMostlySharedPtr<T, RefCount>& ptr, |
413 | std::nullptr_t) { |
414 | return ptr.get() == nullptr; |
415 | } |
416 | |
417 | template <typename T, typename RefCount> |
418 | inline bool operator==( |
419 | std::nullptr_t, |
420 | const ReadMostlySharedPtr<T, RefCount>& ptr) { |
421 | return ptr.get() == nullptr; |
422 | } |
423 | |
424 | template <typename T, typename RefCount> |
425 | inline bool operator!=( |
426 | const ReadMostlyMainPtr<T, RefCount>& ptr, |
427 | std::nullptr_t) { |
428 | return !(ptr == nullptr); |
429 | } |
430 | |
431 | template <typename T, typename RefCount> |
432 | inline bool operator!=( |
433 | std::nullptr_t, |
434 | const ReadMostlyMainPtr<T, RefCount>& ptr) { |
435 | return !(ptr == nullptr); |
436 | } |
437 | |
438 | template <typename T, typename RefCount> |
439 | inline bool operator!=( |
440 | const ReadMostlySharedPtr<T, RefCount>& ptr, |
441 | std::nullptr_t) { |
442 | return !(ptr == nullptr); |
443 | } |
444 | |
445 | template <typename T, typename RefCount> |
446 | inline bool operator!=( |
447 | std::nullptr_t, |
448 | const ReadMostlySharedPtr<T, RefCount>& ptr) { |
449 | return !(ptr == nullptr); |
450 | } |
451 | } // namespace folly |
452 | |