diff --git a/Telegram/SourceFiles/base/weak_ptr.h b/Telegram/SourceFiles/base/weak_ptr.h index 507610a14..ddab64a2e 100644 --- a/Telegram/SourceFiles/base/weak_ptr.h +++ b/Telegram/SourceFiles/base/weak_ptr.h @@ -14,8 +14,11 @@ namespace base { namespace details { struct alive_tracker { + explicit alive_tracker(const void *value) : value(value) { + } + std::atomic counter = 1; - std::atomic dead = false; + std::atomic value; }; inline alive_tracker *check_and_increment(alive_tracker *tracker) noexcept { @@ -54,7 +57,7 @@ public: ~has_weak_ptr() { if (auto alive = _alive.load()) { - alive->dead.store(true); + alive->value.store(nullptr); details::decrement(alive); } } @@ -66,7 +69,8 @@ private: details::alive_tracker *incrementAliveTracker() const { auto current = _alive.load(); if (!current) { - auto alive = std::make_unique(); + auto alive = std::make_unique( + static_cast(this)); if (_alive.compare_exchange_strong(current, alive.get())) { return alive.release(); } @@ -84,8 +88,7 @@ class weak_ptr { public: weak_ptr() = default; weak_ptr(T *value) - : _alive(value ? value->incrementAliveTracker() : nullptr) - , _value(value) { + : _alive(value ? value->incrementAliveTracker() : nullptr) { } weak_ptr(const std::unique_ptr &value) : weak_ptr(value.get()) { @@ -97,28 +100,24 @@ public: : weak_ptr(value.lock().get()) { } weak_ptr(const weak_ptr &other) noexcept - : _alive(details::check_and_increment(other._alive)) - , _value(other._value) { + : _alive(details::check_and_increment(other._alive)) { } weak_ptr(weak_ptr &&other) noexcept - : _alive(std::exchange(other._alive, nullptr)) - , _value(std::exchange(other._value, nullptr)) { + : _alive(std::exchange(other._alive, nullptr)) { } template < typename Other, typename = std::enable_if_t< std::is_base_of_v && !std::is_same_v>> weak_ptr(const weak_ptr &other) noexcept - : _alive(details::check_and_increment(other._alive)) - , _value(other._value) { + : _alive(details::check_and_increment(other._alive)) { } template < typename Other, typename = std::enable_if_t< std::is_base_of_v && !std::is_same_v>> weak_ptr(weak_ptr &&other) noexcept - : _alive(std::exchange(other._alive, nullptr)) - , _value(std::exchange(other._value, nullptr)) { + : _alive(std::exchange(other._alive, nullptr)) { } weak_ptr &operator=(T *value) { @@ -138,18 +137,16 @@ public: return *this; } weak_ptr &operator=(const weak_ptr &other) noexcept { - if (_value != other._value) { + if (_alive != other._alive) { destroy(); _alive = details::check_and_increment(other._alive); - _value = other._value; } return *this; } weak_ptr &operator=(weak_ptr &&other) noexcept { - if (_value != other._value) { + if (_alive != other._alive) { destroy(); _alive = std::exchange(other._alive, nullptr); - _value = std::exchange(other._value, nullptr); } return *this; } @@ -158,10 +155,9 @@ public: typename = std::enable_if_t< std::is_base_of_v && !std::is_same_v>> weak_ptr &operator=(const weak_ptr &other) noexcept { - if (_value != other._value) { + if (_alive != other._alive) { destroy(); _alive = details::check_and_increment(other._alive); - _value = other._value; } return *this; } @@ -170,10 +166,9 @@ public: typename = std::enable_if_t< std::is_base_of_v && !std::is_same_v>> weak_ptr &operator=(weak_ptr &&other) noexcept { - if (_value != other._value) { + if (_alive != other._alive) { destroy(); _alive = std::exchange(other._alive, nullptr); - _value = std::exchange(other._value, nullptr); } return *this; } @@ -183,10 +178,19 @@ public: } T *get() const noexcept { - return (_alive && !_alive->dead) ? _value : nullptr; + if constexpr (std::is_const_v) { + return _alive + ? static_cast(_alive->value.load()) + : nullptr; + } else { + return _alive + ? const_cast( + static_cast(_alive->value.load())) + : nullptr; + } } explicit operator bool() const noexcept { - return (_alive && !_alive->dead); + return (_alive && _alive->value); } T &operator*() const noexcept { return *get(); @@ -196,10 +200,9 @@ public: } void reset(T *value = nullptr) { - if (_value != value) { + if (get() != value) { destroy(); _alive = value ? value->incrementAliveTracker() : nullptr; - _value = value; } } @@ -211,7 +214,6 @@ private: } details::alive_tracker *_alive = nullptr; - T *_value = nullptr; template friend class weak_ptr;