| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #pragma once
- #include "base/basic_types.h"
- #include <atomic>
- #include <memory>
- namespace base {
- class has_weak_ptr;
- namespace details {
- struct alive_tracker {
- explicit alive_tracker(const has_weak_ptr *value) noexcept
- : value(value) {
- }
- std::atomic<int> counter = 1;
- std::atomic<const has_weak_ptr*> value;
- };
- inline alive_tracker *check_and_increment(alive_tracker *tracker) noexcept {
- if (tracker) {
- ++tracker->counter;
- }
- return tracker;
- }
- inline void decrement(alive_tracker *tracker) noexcept {
- if (tracker->counter.fetch_sub(1) == 0) {
- delete tracker;
- }
- }
- } // namespace details
- template <typename T>
- class weak_ptr;
- class has_weak_ptr {
- public:
- has_weak_ptr() = default;
- has_weak_ptr(const has_weak_ptr &other) noexcept {
- }
- has_weak_ptr(has_weak_ptr &&other) noexcept {
- }
- has_weak_ptr &operator=(const has_weak_ptr &other) noexcept {
- return *this;
- }
- has_weak_ptr &operator=(has_weak_ptr &&other) noexcept {
- return *this;
- }
- ~has_weak_ptr() {
- if (const auto alive = _alive.load()) {
- alive->value.store(nullptr);
- details::decrement(alive);
- }
- }
- friend inline void invalidate_weak_ptrs(has_weak_ptr *object) noexcept {
- if (auto alive = object ? object->_alive.load() : nullptr) {
- if (object->_alive.compare_exchange_strong(alive, nullptr)) {
- alive->value.store(nullptr);
- details::decrement(alive);
- }
- }
- }
- friend inline int weak_ptrs_count(has_weak_ptr *object) noexcept {
- if (const auto alive = object ? object->_alive.load() : nullptr) {
- return alive->counter.load();
- }
- return 0;
- }
- private:
- template <typename Child>
- friend class weak_ptr;
- details::alive_tracker *incrementAliveTracker() const noexcept {
- auto current = _alive.load();
- if (!current) {
- auto alive = std::make_unique<details::alive_tracker>(this);
- if (_alive.compare_exchange_strong(current, alive.get())) {
- return alive.release();
- }
- }
- ++current->counter;
- return current;
- }
- mutable std::atomic<details::alive_tracker*> _alive = nullptr;
- };
- template <typename T>
- class weak_ptr {
- public:
- weak_ptr() = default;
- weak_ptr(std::nullptr_t) noexcept {
- }
- weak_ptr(T *value) noexcept
- : _alive(value ? value->incrementAliveTracker() : nullptr) {
- }
- weak_ptr(gsl::not_null<T*> value) noexcept
- : _alive(value->incrementAliveTracker()) {
- }
- weak_ptr(const std::unique_ptr<T> &value) noexcept
- : weak_ptr(value.get()) {
- }
- weak_ptr(const std::shared_ptr<T> &value) noexcept
- : weak_ptr(value.get()) {
- }
- weak_ptr(const std::weak_ptr<T> &value) noexcept
- : weak_ptr(value.lock().get()) {
- }
- weak_ptr(const weak_ptr &other) noexcept
- : _alive(details::check_and_increment(other._alive)) {
- }
- weak_ptr(weak_ptr &&other) noexcept
- : _alive(std::exchange(other._alive, nullptr)) {
- }
- template <
- typename Other,
- typename = std::enable_if_t<
- std::is_base_of_v<T, Other> && !std::is_same_v<T, Other>>>
- weak_ptr(const weak_ptr<Other> &other) noexcept
- : _alive(details::check_and_increment(other._alive)) {
- }
- template <
- typename Other,
- typename = std::enable_if_t<
- std::is_base_of_v<T, Other> && !std::is_same_v<T, Other>>>
- weak_ptr(weak_ptr<Other> &&other) noexcept
- : _alive(std::exchange(other._alive, nullptr)) {
- }
- weak_ptr &operator=(T *value) noexcept {
- reset(value);
- return *this;
- }
- weak_ptr &operator=(gsl::not_null<T*> value) noexcept {
- reset(value.get());
- return *this;
- }
- weak_ptr &operator=(const std::unique_ptr<T> &value) noexcept {
- reset(value.get());
- return *this;
- }
- weak_ptr &operator=(const std::shared_ptr<T> &value) noexcept {
- reset(value.get());
- return *this;
- }
- weak_ptr &operator=(const std::weak_ptr<T> &value) noexcept {
- reset(value.lock().get());
- return *this;
- }
- weak_ptr &operator=(const weak_ptr &other) noexcept {
- if (_alive != other._alive) {
- destroy();
- _alive = details::check_and_increment(other._alive);
- }
- return *this;
- }
- weak_ptr &operator=(weak_ptr &&other) noexcept {
- if (_alive != other._alive) {
- destroy();
- _alive = std::exchange(other._alive, nullptr);
- }
- return *this;
- }
- template <
- typename Other,
- typename = std::enable_if_t<
- std::is_base_of_v<T, Other> && !std::is_same_v<T, Other>>>
- weak_ptr &operator=(const weak_ptr<Other> &other) noexcept {
- if (_alive != other._alive) {
- destroy();
- _alive = details::check_and_increment(other._alive);
- }
- return *this;
- }
- template <
- typename Other,
- typename = std::enable_if_t<
- std::is_base_of_v<T, Other> && !std::is_same_v<T, Other>>>
- weak_ptr &operator=(weak_ptr<Other> &&other) noexcept {
- if (_alive != other._alive) {
- destroy();
- _alive = std::exchange(other._alive, nullptr);
- }
- return *this;
- }
- ~weak_ptr() {
- destroy();
- }
- [[nodiscard]] bool null() const noexcept {
- return !_alive;
- }
- [[nodiscard]] bool empty() const noexcept {
- return !_alive || !_alive->value;
- }
- [[nodiscard]] T *get() const noexcept {
- const auto strong = _alive ? _alive->value.load() : nullptr;
- if constexpr (std::is_const_v<T>) {
- return static_cast<T*>(strong);
- } else {
- return const_cast<T*>(static_cast<const T*>(strong));
- }
- }
- [[nodiscard]] explicit operator bool() const noexcept {
- return !empty();
- }
- [[nodiscard]] T &operator*() const noexcept {
- return *get();
- }
- [[nodiscard]] T *operator->() const noexcept {
- return get();
- }
- friend inline auto operator<=>(
- weak_ptr,
- weak_ptr) noexcept = default;
- void reset(T *value = nullptr) noexcept {
- if ((!value && _alive) || (get() != value)) {
- destroy();
- _alive = value ? value->incrementAliveTracker() : nullptr;
- }
- }
- private:
- void destroy() noexcept {
- if (_alive) {
- details::decrement(_alive);
- }
- }
- details::alive_tracker *_alive = nullptr;
- template <typename Other>
- friend class weak_ptr;
- };
- template <typename T>
- inline bool operator==(const weak_ptr<T> &pointer, std::nullptr_t) noexcept {
- return (pointer.get() == nullptr);
- }
- template <typename T>
- inline bool operator==(std::nullptr_t, const weak_ptr<T> &pointer) noexcept {
- return (pointer == nullptr);
- }
- template <typename T>
- inline bool operator!=(const weak_ptr<T> &pointer, std::nullptr_t) noexcept {
- return !(pointer == nullptr);
- }
- template <typename T>
- inline bool operator!=(std::nullptr_t, const weak_ptr<T> &pointer) noexcept {
- return !(pointer == nullptr);
- }
- template <
- typename T,
- typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
- weak_ptr<T> make_weak(T *value) {
- return value;
- }
- template <
- typename T,
- typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
- weak_ptr<T> make_weak(gsl::not_null<T*> value) {
- return value;
- }
- template <
- typename T,
- typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
- weak_ptr<T> make_weak(const std::unique_ptr<T> &value) {
- return value;
- }
- template <
- typename T,
- typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
- weak_ptr<T> make_weak(const std::shared_ptr<T> &value) {
- return value;
- }
- template <
- typename T,
- typename = std::enable_if_t<std::is_base_of_v<has_weak_ptr, T>>>
- weak_ptr<T> make_weak(const std::weak_ptr<T> &value) {
- return value;
- }
- } // namespace base
- namespace crl {
- template <typename T, typename Enable>
- struct guard_traits;
- template <typename T>
- struct guard_traits<base::weak_ptr<T>, void> {
- static base::weak_ptr<T> create(const base::weak_ptr<T> &value) {
- return value;
- }
- static base::weak_ptr<T> create(base::weak_ptr<T> &&value) {
- return std::move(value);
- }
- static bool check(const base::weak_ptr<T> &guard) {
- return guard.get() != nullptr;
- }
- };
- template <typename T>
- struct guard_traits<
- T*,
- std::enable_if_t<
- std::is_base_of_v<base::has_weak_ptr, std::remove_cv_t<T>>>> {
- static base::weak_ptr<T> create(T *value) {
- return value;
- }
- static bool check(const base::weak_ptr<T> &guard) {
- return guard.get() != nullptr;
- }
- };
- template <typename T>
- struct guard_traits<
- gsl::not_null<T*>,
- std::enable_if_t<
- std::is_base_of_v<base::has_weak_ptr, std::remove_cv_t<T>>>> {
- static base::weak_ptr<T> create(gsl::not_null<T*> value) {
- return value;
- }
- static bool check(const base::weak_ptr<T> &guard) {
- return guard.get() != nullptr;
- }
- };
- } // namespace crl
|