/* * Copyright (c) 2018-2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include namespace AK { template class [[nodiscard]] WeakPtr { template friend class Weakable; public: WeakPtr() = default; template V> WeakPtr(V) { } template V> WeakPtr& operator=(V) { clear(); return *this; } template WeakPtr(WeakPtr const& other) requires(IsBaseOf) : m_link(other.m_link) { } template WeakPtr(WeakPtr&& other) requires(IsBaseOf) : m_link(other.take_link()) { } template WeakPtr& operator=(WeakPtr&& other) requires(IsBaseOf) { m_link = other.take_link(); return *this; } template WeakPtr& operator=(WeakPtr const& other) requires(IsBaseOf) { if ((void const*)this != (void const*)&other) m_link = other.m_link; return *this; } WeakPtr& operator=(nullptr_t) { clear(); return *this; } template WeakPtr(U const& object) requires(IsBaseOf) : m_link(object.template make_weak_ptr().take_link()) { } template WeakPtr(U const* object) requires(IsBaseOf) { if (object) m_link = object->template make_weak_ptr().take_link(); } template WeakPtr(RefPtr const& object) requires(IsBaseOf) { if (object) m_link = object->template make_weak_ptr().take_link(); } template WeakPtr(NonnullRefPtr const& object) requires(IsBaseOf) { m_link = object->template make_weak_ptr().take_link(); } template WeakPtr& operator=(U const& object) requires(IsBaseOf) { m_link = object.template make_weak_ptr().take_link(); return *this; } template WeakPtr& operator=(U const* object) requires(IsBaseOf) { if (object) m_link = object->template make_weak_ptr().take_link(); else m_link = nullptr; return *this; } template WeakPtr& operator=(RefPtr const& object) requires(IsBaseOf) { if (object) m_link = object->template make_weak_ptr().take_link(); else m_link = nullptr; return *this; } template WeakPtr& operator=(NonnullRefPtr const& object) requires(IsBaseOf) { m_link = object->template make_weak_ptr().take_link(); return *this; } [[nodiscard]] RefPtr strong_ref() const { return RefPtr { ptr() }; } T* ptr() const { return unsafe_ptr(); } T* operator->() const { return unsafe_ptr(); } operator T*() const { return unsafe_ptr(); } [[nodiscard]] T* unsafe_ptr() const { if (m_link) return m_link->template unsafe_ptr(); return nullptr; } [[nodiscard]] NonnullRefPtr value() const { VERIFY(has_value()); return *unsafe_ptr(); } operator bool() const { return m_link ? !m_link->is_null() : false; } [[nodiscard]] bool is_null() const { return !m_link || m_link->is_null(); } [[nodiscard]] bool has_value() const { return !is_null(); } void clear() { m_link = nullptr; } [[nodiscard]] RefPtr take_link() { return move(m_link); } private: WeakPtr(RefPtr const& link) : m_link(link) { } RefPtr m_link; }; template template inline ErrorOr> Weakable::try_make_weak_ptr() const { if (!m_link) m_link = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WeakLink(const_cast(static_cast(*this))))); return WeakPtr(m_link); } template struct Formatter> : Formatter { ErrorOr format(FormatBuilder& builder, WeakPtr const& value) { return Formatter::format(builder, value.ptr()); } }; template ErrorOr> try_make_weak_ptr_if_nonnull(T const* ptr) { if (ptr) { return ptr->template try_make_weak_ptr(); } return WeakPtr {}; } template WeakPtr make_weak_ptr_if_nonnull(T const* ptr) { return MUST(try_make_weak_ptr_if_nonnull(ptr)); } } #if USING_AK_GLOBALLY using AK::WeakPtr; #endif