/* * Copyright (C) 2013-2014 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. AND ITS CONTRIBUTORS ``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 ITS 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. */ #ifndef WTF_Ref_h #define WTF_Ref_h #include #include #include #include #include #if ASAN_ENABLED extern "C" void __asan_poison_memory_region(void const volatile *addr, size_t size); extern "C" void __asan_unpoison_memory_region(void const volatile *addr, size_t size); extern "C" bool __asan_address_is_poisoned(void const volatile *addr); #endif namespace WTF { inline void adopted(const void*) { } template class Ref; template Ref adoptRef(T&); template class Ref { public: static constexpr bool isRef = true; ~Ref() { #if ASAN_ENABLED if (__asan_address_is_poisoned(this)) __asan_unpoison_memory_region(this, sizeof(*this)); #endif if (m_ptr) m_ptr->deref(); } Ref(T& object) : m_ptr(&object) { m_ptr->ref(); } // Use copyRef() instead. Ref(const Ref& other) = delete; template Ref(const Ref& other) = delete; Ref(Ref&& other) : m_ptr(&other.leakRef()) { ASSERT(m_ptr); } template Ref(Ref&& other) : m_ptr(&other.leakRef()) { ASSERT(m_ptr); } Ref& operator=(T& object) { ASSERT(m_ptr); object.ref(); m_ptr->deref(); m_ptr = &object; ASSERT(m_ptr); return *this; } // Use copyRef() and the move assignment operators instead. Ref& operator=(const Ref& reference) = delete; template Ref& operator=(const Ref& reference) = delete; Ref& operator=(Ref&& reference) { ASSERT(m_ptr); m_ptr->deref(); m_ptr = &reference.leakRef(); ASSERT(m_ptr); return *this; } template Ref& operator=(Ref&& reference) { ASSERT(m_ptr); m_ptr->deref(); m_ptr = &reference.leakRef(); ASSERT(m_ptr); return *this; } const T* operator->() const { ASSERT(m_ptr); return m_ptr; } T* operator->() { ASSERT(m_ptr); return m_ptr; } const T* ptr() const { ASSERT(m_ptr); return m_ptr; } T* ptr() { ASSERT(m_ptr); return m_ptr; } const T& get() const { ASSERT(m_ptr); return *m_ptr; } T& get() { ASSERT(m_ptr); return *m_ptr; } operator T&() { ASSERT(m_ptr); return *m_ptr; } operator const T&() const { ASSERT(m_ptr); return *m_ptr; } template Ref replace(Ref&&) WARN_UNUSED_RETURN; #if COMPILER_SUPPORTS(CXX_REFERENCE_QUALIFIED_FUNCTIONS) Ref copyRef() && = delete; Ref copyRef() const & WARN_UNUSED_RETURN { return Ref(*m_ptr); } #else Ref copyRef() const WARN_UNUSED_RETURN { return Ref(*m_ptr); } #endif T& leakRef() WARN_UNUSED_RETURN { ASSERT(m_ptr); T& result = *std::exchange(m_ptr, nullptr); #if ASAN_ENABLED __asan_poison_memory_region(this, sizeof(*this)); #endif return result; } private: friend Ref adoptRef(T&); enum AdoptTag { Adopt }; Ref(T& object, AdoptTag) : m_ptr(&object) { } T* m_ptr; }; template template inline Ref Ref::replace(Ref&& reference) { auto oldReference = adoptRef(*m_ptr); m_ptr = &reference.leakRef(); return oldReference; } template inline Ref static_reference_cast(Ref& reference) { return Ref(static_cast(reference.get())); } template inline Ref static_reference_cast(Ref&& reference) { return adoptRef(static_cast(reference.leakRef())); } template inline Ref static_reference_cast(const Ref& reference) { return Ref(static_cast(reference.copyRef().get())); } template struct GetPtrHelper> { typedef T* PtrType; static T* getPtr(const Ref& p) { return const_cast(p.ptr()); } }; template inline Ref adoptRef(T& reference) { adopted(&reference); return Ref(reference, Ref::Adopt); } template inline bool is(Ref& source) { return is(source.get()); } template inline bool is(const Ref& source) { return is(source.get()); } } // namespace WTF using WTF::Ref; using WTF::adoptRef; using WTF::static_reference_cast; #endif // WTF_Ref_h