/* * Copyright (C) 2013 Google, Inc. All rights reserved. * Copyright (C) 2015-2020 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include namespace WTF { template class WeakHashSet; template class WeakPtrFactory; struct EmptyCounter { static void increment() { } static void decrement() { } }; enum class EnableWeakPtrThreadingAssertions : bool { No, Yes }; template class WeakPtrImpl : public ThreadSafeRefCounted> { WTF_MAKE_NONCOPYABLE(WeakPtrImpl); WTF_MAKE_FAST_ALLOCATED; public: template static Ref create(T* ptr) { return adoptRef(*new WeakPtrImpl(ptr)); } ~WeakPtrImpl() { Counter::decrement(); } template typename T::WeakValueType* get() { return static_cast(m_ptr); } explicit operator bool() const { return m_ptr; } void clear() { m_ptr = nullptr; } #if ASSERT_ENABLED bool wasConstructedOnMainThread() const { return m_wasConstructedOnMainThread; } #endif private: template explicit WeakPtrImpl(T* ptr) : m_ptr(static_cast(ptr)) #if ASSERT_ENABLED , m_wasConstructedOnMainThread(isMainThread()) #endif { Counter::increment(); } void* m_ptr; #if ASSERT_ENABLED bool m_wasConstructedOnMainThread; #endif }; template struct HashTraits>> : RefHashTraits> { static constexpr bool hasIsReleasedWeakValueFunction = true; static bool isReleasedWeakValue(const Ref>& value) { return !value.isHashTableDeletedValue() && !value.isHashTableEmptyValue() && !value.get(); } }; template class WeakPtr { WTF_MAKE_FAST_ALLOCATED; public: WeakPtr() { } WeakPtr(std::nullptr_t) { } template WeakPtr(const WeakPtr&); template WeakPtr(WeakPtr&&); T* get() const { // FIXME: Our GC threads currently need to get opaque pointers from WeakPtrs and have to be special-cased. ASSERT(!m_impl || !m_shouldEnableAssertions || Thread::mayBeGCThread() || m_impl->wasConstructedOnMainThread() == isMainThread()); return m_impl ? static_cast(m_impl->template get()) : nullptr; } bool operator!() const { return !m_impl || !*m_impl; } explicit operator bool() const { return m_impl && *m_impl; } WeakPtr& operator=(std::nullptr_t) { m_impl = nullptr; return *this; } template WeakPtr& operator=(const WeakPtr&); template WeakPtr& operator=(WeakPtr&&); T* operator->() const { ASSERT(!m_impl || !m_shouldEnableAssertions || m_impl->wasConstructedOnMainThread() == isMainThread()); return get(); } T& operator*() const { ASSERT(!m_impl || !m_shouldEnableAssertions || m_impl->wasConstructedOnMainThread() == isMainThread()); return *get(); } void clear() { m_impl = nullptr; } private: template friend class WeakHashMap; template friend class WeakHashSet; template friend class WeakPtr; template friend class WeakPtrFactory; explicit WeakPtr(Ref>&& ref, EnableWeakPtrThreadingAssertions shouldEnableAssertions) : m_impl(WTFMove(ref)) #if ASSERT_ENABLED , m_shouldEnableAssertions(shouldEnableAssertions == EnableWeakPtrThreadingAssertions::Yes) #endif { UNUSED_PARAM(shouldEnableAssertions); } RefPtr> m_impl; #if ASSERT_ENABLED bool m_shouldEnableAssertions { true }; #endif }; // Note: you probably want to inherit from CanMakeWeakPtr rather than use this directly. template class WeakPtrFactory { WTF_MAKE_NONCOPYABLE(WeakPtrFactory); WTF_MAKE_FAST_ALLOCATED; public: using CounterType = Counter; WeakPtrFactory() #if ASSERT_ENABLED : m_wasConstructedOnMainThread(isMainThread()) #endif { } ~WeakPtrFactory() { if (!m_impl) return; m_impl->clear(); } void initializeIfNeeded(const T& object) const { if (m_impl) return; ASSERT(m_wasConstructedOnMainThread == isMainThread()); m_impl = WeakPtrImpl::create(const_cast(&object)); } template WeakPtr createWeakPtr(U& object, EnableWeakPtrThreadingAssertions enableWeakPtrThreadingAssertions = EnableWeakPtrThreadingAssertions::Yes) const { initializeIfNeeded(object); ASSERT(&object == m_impl->template get()); return WeakPtr(makeRef(*m_impl), enableWeakPtrThreadingAssertions); } void revokeAll() { if (!m_impl) return; m_impl->clear(); m_impl = nullptr; } unsigned weakPtrCount() const { return m_impl ? m_impl->refCount() - 1 : 0; } #if ASSERT_ENABLED bool isInitialized() const { return m_impl; } #endif private: template friend class WeakHashSet; template friend class WeakHashMap; mutable RefPtr> m_impl; #if ASSERT_ENABLED bool m_wasConstructedOnMainThread; #endif }; // We use lazy initialization of the WeakPtrFactory by default to avoid unnecessary initialization. Eager // initialization is however useful if you plan to call makeWeakPtr() from other threads. enum class WeakPtrFactoryInitialization { Lazy, Eager }; template class CanMakeWeakPtr { public: using WeakValueType = T; const WeakPtrFactory& weakPtrFactory() const { return m_weakPtrFactory; } WeakPtrFactory& weakPtrFactory() { return m_weakPtrFactory; } protected: CanMakeWeakPtr() { if (initializationMode == WeakPtrFactoryInitialization::Eager) initializeWeakPtrFactory(); } void initializeWeakPtrFactory() { m_weakPtrFactory.initializeIfNeeded(static_cast(*this)); } private: WeakPtrFactory m_weakPtrFactory; }; template inline WeakPtrImpl* weak_ptr_impl_cast(WeakPtrImpl* impl) { static_assert(std::is_same_v, "Invalid weak pointer cast"); return impl; } template template inline WeakPtr::WeakPtr(const WeakPtr& o) : m_impl(weak_ptr_impl_cast(o.m_impl.get())) { } template template inline WeakPtr::WeakPtr(WeakPtr&& o) : m_impl(adoptRef(weak_ptr_impl_cast(o.m_impl.leakRef()))) { } template template inline WeakPtr& WeakPtr::operator=(const WeakPtr& o) { m_impl = weak_ptr_impl_cast(o.m_impl.get()); return *this; } template template inline WeakPtr& WeakPtr::operator=(WeakPtr&& o) { m_impl = adoptRef(weak_ptr_impl_cast(o.m_impl.leakRef())); return *this; } template::value>> inline auto makeWeakPtr(T& object, EnableWeakPtrThreadingAssertions enableWeakPtrThreadingAssertions = EnableWeakPtrThreadingAssertions::Yes) { return object.weakPtrFactory().template createWeakPtr(object, enableWeakPtrThreadingAssertions); } template::value>> inline auto makeWeakPtr(T* ptr, EnableWeakPtrThreadingAssertions enableWeakPtrThreadingAssertions = EnableWeakPtrThreadingAssertions::Yes) -> decltype(makeWeakPtr(*ptr)) { if (!ptr) return { }; return makeWeakPtr(*ptr, enableWeakPtrThreadingAssertions); } template::value>> inline auto makeWeakPtr(const Ref& object, EnableWeakPtrThreadingAssertions enableWeakPtrThreadingAssertions = EnableWeakPtrThreadingAssertions::Yes) { return makeWeakPtr(object.get(), enableWeakPtrThreadingAssertions); } template::value>> inline auto makeWeakPtr(const RefPtr& object, EnableWeakPtrThreadingAssertions enableWeakPtrThreadingAssertions = EnableWeakPtrThreadingAssertions::Yes) { return makeWeakPtr(object.get(), enableWeakPtrThreadingAssertions); } template inline bool operator==(const WeakPtr& a, const WeakPtr& b) { return a.get() == b.get(); } template inline bool operator==(const WeakPtr& a, U* b) { return a.get() == b; } template inline bool operator==(T* a, const WeakPtr& b) { return a == b.get(); } template inline bool operator!=(const WeakPtr& a, const WeakPtr& b) { return a.get() != b.get(); } template inline bool operator!=(const WeakPtr& a, U* b) { return a.get() != b; } template inline bool operator!=(T* a, const WeakPtr& b) { return a != b.get(); } } // namespace WTF using WTF::CanMakeWeakPtr; using WTF::EnableWeakPtrThreadingAssertions; using WTF::WeakPtr; using WTF::WeakPtrFactory; using WTF::WeakPtrFactoryInitialization; using WTF::makeWeakPtr;