diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WTF/wtf/Ref.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WTF/wtf/Ref.h')
-rw-r--r-- | Source/WTF/wtf/Ref.h | 184 |
1 files changed, 170 insertions, 14 deletions
diff --git a/Source/WTF/wtf/Ref.h b/Source/WTF/wtf/Ref.h index 6ff7c8223..e955352df 100644 --- a/Source/WTF/wtf/Ref.h +++ b/Source/WTF/wtf/Ref.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * 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 @@ -26,55 +26,211 @@ #ifndef WTF_Ref_h #define WTF_Ref_h -#include "Noncopyable.h" +#include <wtf/Assertions.h> +#include <wtf/GetPtr.h> +#include <wtf/Noncopyable.h> +#include <wtf/StdLibExtras.h> +#include <wtf/TypeCasts.h> + +#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 { -template<typename T> class PassRef; +inline void adopted(const void*) { } + +template<typename T> class Ref; +template<typename T> Ref<T> adoptRef(T&); template<typename T> class Ref { - WTF_MAKE_NONCOPYABLE(Ref) public: - Ref(T& object) : m_ptr(&object) { m_ptr->ref(); } - template<typename U> Ref(PassRef<U> reference) : m_ptr(&reference.leakRef()) { } + 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(); + } - ~Ref() { m_ptr->deref(); } + // Use copyRef() instead. + Ref(const Ref& other) = delete; + template<typename U> Ref(const Ref<U>& other) = delete; + + Ref(Ref&& other) + : m_ptr(&other.leakRef()) + { + ASSERT(m_ptr); + } + + template<typename U> + Ref(Ref<U>&& 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; } - template<typename U> Ref& operator=(PassRef<U> reference) + + // Use copyRef() and the move assignment operators instead. + Ref& operator=(const Ref& reference) = delete; + template<typename U> Ref& operator=(const Ref<U>& reference) = delete; + + Ref& operator=(Ref&& reference) { + ASSERT(m_ptr); m_ptr->deref(); m_ptr = &reference.leakRef(); + ASSERT(m_ptr); return *this; } - const T* operator->() const { return m_ptr; } - T* operator->() { return m_ptr; } + template<typename U> Ref& operator=(Ref<U>&& reference) + { + ASSERT(m_ptr); + m_ptr->deref(); + m_ptr = &reference.leakRef(); + ASSERT(m_ptr); + return *this; + } + + // Hash table deleted values, which are only constructed and never copied or destroyed. + Ref(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { } + bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); } + static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } + + Ref(HashTableEmptyValueType) : m_ptr(hashTableEmptyValue()) { } + bool isHashTableEmptyValue() const { return m_ptr == hashTableEmptyValue(); } + static T* hashTableEmptyValue() { return nullptr; } + + const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return m_ptr; } + T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return m_ptr; } + + void assignToHashTableEmptyValue(Ref&& reference) + { + ASSERT(m_ptr == hashTableEmptyValue()); + m_ptr = &reference.leakRef(); + ASSERT(m_ptr); + } + + T* operator->() const { ASSERT(m_ptr); return m_ptr; } + T* ptr() const { ASSERT(m_ptr); return m_ptr; } + T& get() const { ASSERT(m_ptr); return *m_ptr; } + operator T&() const { ASSERT(m_ptr); return *m_ptr; } + + template<typename U> Ref<T> replace(Ref<U>&&) 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 - const T& get() const { return *m_ptr; } - T& get() { return *m_ptr; } + T& leakRef() WARN_UNUSED_RETURN + { + ASSERT(m_ptr); - template<typename U> PassRef<T> replace(PassRef<U>) WARN_UNUSED_RETURN; + 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>(T&); + + enum AdoptTag { Adopt }; + Ref(T& object, AdoptTag) + : m_ptr(&object) + { + } + T* m_ptr; }; -template<typename T> template<typename U> inline PassRef<T> Ref<T>::replace(PassRef<U> reference) +template<typename T> template<typename U> inline Ref<T> Ref<T>::replace(Ref<U>&& reference) { auto oldReference = adoptRef(*m_ptr); m_ptr = &reference.leakRef(); return oldReference; } +template<typename T, typename U> inline Ref<T> static_reference_cast(Ref<U>& reference) +{ + return Ref<T>(static_cast<T&>(reference.get())); +} + +template<typename T, typename U> inline Ref<T> static_reference_cast(Ref<U>&& reference) +{ + return adoptRef(static_cast<T&>(reference.leakRef())); +} + +template<typename T, typename U> inline Ref<T> static_reference_cast(const Ref<U>& reference) +{ + return Ref<T>(static_cast<T&>(reference.copyRef().get())); +} + +template <typename T> +struct GetPtrHelper<Ref<T>> { + typedef T* PtrType; + static T* getPtr(const Ref<T>& p) { return const_cast<T*>(p.ptr()); } +}; + +template <typename T> +struct IsSmartPtr<Ref<T>> { + static const bool value = true; +}; + +template<typename T> +inline Ref<T> adoptRef(T& reference) +{ + adopted(&reference); + return Ref<T>(reference, Ref<T>::Adopt); +} + +template<typename T> +inline Ref<T> makeRef(T& reference) +{ + return Ref<T>(reference); +} + +template<typename ExpectedType, typename ArgType> inline bool is(Ref<ArgType>& source) +{ + return is<ExpectedType>(source.get()); +} + +template<typename ExpectedType, typename ArgType> inline bool is(const Ref<ArgType>& source) +{ + return is<ExpectedType>(source.get()); +} + } // namespace WTF using WTF::Ref; +using WTF::adoptRef; +using WTF::makeRef; +using WTF::static_reference_cast; #endif // WTF_Ref_h |