weak_ptr.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include "base/basic_types.h"
  9. #include <atomic>
  10. #include <memory>
  11. namespace base {
  12. class has_weak_ptr;
  13. namespace details {
  14. struct alive_tracker {
  15. explicit alive_tracker(const has_weak_ptr *value) noexcept
  16. : value(value) {
  17. }
  18. std::atomic<int> counter = 1;
  19. std::atomic<const has_weak_ptr*> value;
  20. };
  21. inline alive_tracker *check_and_increment(alive_tracker *tracker) noexcept {
  22. if (tracker) {
  23. ++tracker->counter;
  24. }
  25. return tracker;
  26. }
  27. inline void decrement(alive_tracker *tracker) noexcept {
  28. if (tracker->counter.fetch_sub(1) == 0) {
  29. delete tracker;
  30. }
  31. }
  32. } // namespace details
  33. template <typename T>
  34. class weak_ptr;
  35. class has_weak_ptr {
  36. public:
  37. has_weak_ptr() = default;
  38. has_weak_ptr(const has_weak_ptr &other) noexcept {
  39. }
  40. has_weak_ptr(has_weak_ptr &&other) noexcept {
  41. }
  42. has_weak_ptr &operator=(const has_weak_ptr &other) noexcept {
  43. return *this;
  44. }
  45. has_weak_ptr &operator=(has_weak_ptr &&other) noexcept {
  46. return *this;
  47. }
  48. ~has_weak_ptr() {
  49. if (const auto alive = _alive.load()) {
  50. alive->value.store(nullptr);
  51. details::decrement(alive);
  52. }
  53. }
  54. friend inline void invalidate_weak_ptrs(has_weak_ptr *object) noexcept {
  55. if (auto alive = object ? object->_alive.load() : nullptr) {
  56. if (object->_alive.compare_exchange_strong(alive, nullptr)) {
  57. alive->value.store(nullptr);
  58. details::decrement(alive);
  59. }
  60. }
  61. }
  62. friend inline int weak_ptrs_count(has_weak_ptr *object) noexcept {
  63. if (const auto alive = object ? object->_alive.load() : nullptr) {
  64. return alive->counter.load();
  65. }
  66. return 0;
  67. }
  68. private:
  69. template <typename Child>
  70. friend class weak_ptr;
  71. details::alive_tracker *incrementAliveTracker() const noexcept {
  72. auto current = _alive.load();
  73. if (!current) {
  74. auto alive = std::make_unique<details::alive_tracker>(this);
  75. if (_alive.compare_exchange_strong(current, alive.get())) {
  76. return alive.release();
  77. }
  78. }
  79. ++current->counter;
  80. return current;
  81. }
  82. mutable std::atomic<details::alive_tracker*> _alive = nullptr;
  83. };
  84. template <typename T>
  85. class weak_ptr {
  86. public:
  87. weak_ptr() = default;
  88. weak_ptr(std::nullptr_t) noexcept {
  89. }
  90. weak_ptr(T *value) noexcept
  91. : _alive(value ? value->incrementAliveTracker() : nullptr) {
  92. }
  93. weak_ptr(gsl::not_null<T*> value) noexcept
  94. : _alive(value->incrementAliveTracker()) {
  95. }
  96. weak_ptr(const std::unique_ptr<T> &value) noexcept
  97. : weak_ptr(value.get()) {
  98. }
  99. weak_ptr(const std::shared_ptr<T> &value) noexcept
  100. : weak_ptr(value.get()) {
  101. }
  102. weak_ptr(const std::weak_ptr<T> &value) noexcept
  103. : weak_ptr(value.lock().get()) {
  104. }
  105. weak_ptr(const weak_ptr &other) noexcept
  106. : _alive(details::check_and_increment(other._alive)) {
  107. }
  108. weak_ptr(weak_ptr &&other) noexcept
  109. : _alive(std::exchange(other._alive, nullptr)) {
  110. }
  111. template <
  112. typename Other,
  113. typename = std::enable_if_t<
  114. std::is_base_of_v<T, Other> && !std::is_same_v<T, Other>>>
  115. weak_ptr(const weak_ptr<Other> &other) noexcept
  116. : _alive(details::check_and_increment(other._alive)) {
  117. }
  118. template <
  119. typename Other,
  120. typename = std::enable_if_t<
  121. std::is_base_of_v<T, Other> && !std::is_same_v<T, Other>>>
  122. weak_ptr(weak_ptr<Other> &&other) noexcept
  123. : _alive(std::exchange(other._alive, nullptr)) {
  124. }
  125. weak_ptr &operator=(T *value) noexcept {
  126. reset(value);
  127. return *this;
  128. }
  129. weak_ptr &operator=(gsl::not_null<T*> value) noexcept {
  130. reset(value.get());
  131. return *this;
  132. }
  133. weak_ptr &operator=(const std::unique_ptr<T> &value) noexcept {
  134. reset(value.get());
  135. return *this;
  136. }
  137. weak_ptr &operator=(const std::shared_ptr<T> &value) noexcept {
  138. reset(value.get());
  139. return *this;
  140. }
  141. weak_ptr &operator=(const std::weak_ptr<T> &value) noexcept {
  142. reset(value.lock().get());
  143. return *this;
  144. }
  145. weak_ptr &operator=(const weak_ptr &other) noexcept {
  146. if (_alive != other._alive) {
  147. destroy();
  148. _alive = details::check_and_increment(other._alive);
  149. }
  150. return *this;
  151. }
  152. weak_ptr &operator=(weak_ptr &&other) noexcept {
  153. if (_alive != other._alive) {
  154. destroy();
  155. _alive = std::exchange(other._alive, nullptr);
  156. }
  157. return *this;
  158. }
  159. template <
  160. typename Other,
  161. typename = std::enable_if_t<
  162. std::is_base_of_v<T, Other> && !std::is_same_v<T, Other>>>
  163. weak_ptr &operator=(const weak_ptr<Other> &other) noexcept {
  164. if (_alive != other._alive) {
  165. destroy();
  166. _alive = details::check_and_increment(other._alive);
  167. }
  168. return *this;
  169. }
  170. template <
  171. typename Other,
  172. typename = std::enable_if_t<
  173. std::is_base_of_v<T, Other> && !std::is_same_v<T, Other>>>
  174. weak_ptr &operator=(weak_ptr<Other> &&other) noexcept {
  175. if (_alive != other._alive) {
  176. destroy();
  177. _alive = std::exchange(other._alive, nullptr);
  178. }
  179. return *this;
  180. }
  181. ~weak_ptr() {
  182. destroy();
  183. }
  184. [[nodiscard]] bool null() const noexcept {
  185. return !_alive;
  186. }
  187. [[nodiscard]] bool empty() const noexcept {
  188. return !_alive || !_alive->value;
  189. }
  190. [[nodiscard]] T *get() const noexcept {
  191. const auto strong = _alive ? _alive->value.load() : nullptr;
  192. if constexpr (std::is_const_v<T>) {
  193. return static_cast<T*>(strong);
  194. } else {
  195. return const_cast<T*>(static_cast<const T*>(strong));
  196. }
  197. }
  198. [[nodiscard]] explicit operator bool() const noexcept {
  199. return !empty();
  200. }
  201. [[nodiscard]] T &operator*() const noexcept {
  202. return *get();
  203. }
  204. [[nodiscard]] T *operator->() const noexcept {
  205. return get();
  206. }
  207. friend inline auto operator<=>(
  208. weak_ptr,
  209. weak_ptr) noexcept = default;
  210. void reset(T *value = nullptr) noexcept {
  211. if ((!value && _alive) || (get() != value)) {
  212. destroy();
  213. _alive = value ? value->incrementAliveTracker() : nullptr;
  214. }
  215. }
  216. private:
  217. void destroy() noexcept {
  218. if (_alive) {
  219. details::decrement(_alive);
  220. }
  221. }
  222. details::alive_tracker *_alive = nullptr;
  223. template <typename Other>
  224. friend class weak_ptr;
  225. };
  226. template <typename T>
  227. inline bool operator==(const weak_ptr<T> &pointer, std::nullptr_t) noexcept {
  228. return (pointer.get() == nullptr);
  229. }
  230. template <typename T>
  231. inline bool operator==(std::nullptr_t, const weak_ptr<T> &pointer) noexcept {
  232. return (pointer == nullptr);
  233. }
  234. template <typename T>
  235. inline bool operator!=(const weak_ptr<T> &pointer, std::nullptr_t) noexcept {
  236. return !(pointer == nullptr);
  237. }
  238. template <typename T>
  239. inline bool operator!=(std::nullptr_t, const weak_ptr<T> &pointer) noexcept {
  240. return !(pointer == nullptr);
  241. }
  242. template <
  243. typename T,
  244. typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
  245. weak_ptr<T> make_weak(T *value) {
  246. return value;
  247. }
  248. template <
  249. typename T,
  250. typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
  251. weak_ptr<T> make_weak(gsl::not_null<T*> value) {
  252. return value;
  253. }
  254. template <
  255. typename T,
  256. typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
  257. weak_ptr<T> make_weak(const std::unique_ptr<T> &value) {
  258. return value;
  259. }
  260. template <
  261. typename T,
  262. typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
  263. weak_ptr<T> make_weak(const std::shared_ptr<T> &value) {
  264. return value;
  265. }
  266. template <
  267. typename T,
  268. typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
  269. weak_ptr<T> make_weak(const std::weak_ptr<T> &value) {
  270. return value;
  271. }
  272. } // namespace base
  273. namespace crl {
  274. template <typename T, typename Enable>
  275. struct guard_traits;
  276. template <typename T>
  277. struct guard_traits<base::weak_ptr<T>, void> {
  278. static base::weak_ptr<T> create(const base::weak_ptr<T> &value) {
  279. return value;
  280. }
  281. static base::weak_ptr<T> create(base::weak_ptr<T> &&value) {
  282. return std::move(value);
  283. }
  284. static bool check(const base::weak_ptr<T> &guard) {
  285. return guard.get() != nullptr;
  286. }
  287. };
  288. template <typename T>
  289. struct guard_traits<
  290. T*,
  291. std::enable_if_t<
  292. std::is_base_of_v<base::has_weak_ptr, std::remove_cv_t<T>>>> {
  293. static base::weak_ptr<T> create(T *value) {
  294. return value;
  295. }
  296. static bool check(const base::weak_ptr<T> &guard) {
  297. return guard.get() != nullptr;
  298. }
  299. };
  300. template <typename T>
  301. struct guard_traits<
  302. gsl::not_null<T*>,
  303. std::enable_if_t<
  304. std::is_base_of_v<base::has_weak_ptr, std::remove_cv_t<T>>>> {
  305. static base::weak_ptr<T> create(gsl::not_null<T*> value) {
  306. return value;
  307. }
  308. static bool check(const base::weak_ptr<T> &guard) {
  309. return guard.get() != nullptr;
  310. }
  311. };
  312. } // namespace crl