ReadMostlySharedPtr.h 9.6 KB

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