Modified: trunk/Source/WTF/wtf/RetainPtr.h (280951 => 280952)
--- trunk/Source/WTF/wtf/RetainPtr.h 2021-08-12 01:11:15 UTC (rev 280951)
+++ trunk/Source/WTF/wtf/RetainPtr.h 2021-08-12 02:08:08 UTC (rev 280952)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2021 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,9 +24,10 @@
#if USE(CF) || defined(__OBJC__)
-#include <wtf/HashTraits.h>
#include <algorithm>
#include <cstddef>
+#include <wtf/HashTraits.h>
+#include <wtf/NeverDestroyed.h>
#if USE(CF)
#include <CoreFoundation/CoreFoundation.h>
@@ -65,7 +66,8 @@
template<typename T> class RetainPtr;
-template<typename T> RetainPtr<T> adoptCF(T CF_RELEASES_ARGUMENT) WARN_UNUSED_RETURN;
+template<typename T> constexpr RetainPtr<T> adoptCF(T CF_RELEASES_ARGUMENT) WARN_UNUSED_RETURN;
+
#ifdef __OBJC__
template<typename T> RetainPtr<typename RetainPtr<T>::HelperPtrType> adoptNS(T NS_RELEASES_ARGUMENT) WARN_UNUSED_RETURN;
#endif
@@ -72,50 +74,50 @@
template<typename T> class RetainPtr {
public:
- typedef typename std::remove_pointer<T>::type ValueType;
- typedef ValueType* PtrType;
- typedef CFTypeRef StorageType;
+ using ValueType = std::remove_pointer_t<T>;
+ using PtrType = ValueType*;
#ifdef __OBJC__
- typedef typename std::conditional<std::is_convertible<T, id>::value && !std::is_same<T, id>::value, typename std::remove_pointer<T>::type, T>::type HelperPtrType;
+ using HelperPtrType = typename std::conditional_t<std::is_convertible_v<T, id> && !std::is_same_v<T, id>, std::remove_pointer_t<T>, T>;
#else
- typedef T HelperPtrType;
+ using HelperPtrType = PtrType;
#endif
- RetainPtr() : m_ptr(nullptr) { }
- RetainPtr(PtrType ptr) : m_ptr(toStorageType(ptr)) { if (m_ptr) CFRetain(m_ptr); }
+ RetainPtr() = default;
+ RetainPtr(PtrType);
- RetainPtr(const RetainPtr& o) : m_ptr(o.m_ptr) { if (StorageType ptr = m_ptr) CFRetain(ptr); }
+ RetainPtr(const RetainPtr&);
+ template<typename U> RetainPtr(const RetainPtr<U>&);
- RetainPtr(RetainPtr&& o) : m_ptr(toStorageType(o.leakRef())) { }
- template<typename U> RetainPtr(RetainPtr<U>&& o) : m_ptr(toStorageType(o.leakRef())) { }
+ constexpr RetainPtr(RetainPtr&& o) : m_ptr(toStorageType(o.leakRef())) { }
+ template<typename U> constexpr RetainPtr(RetainPtr<U>&& o) : m_ptr(toStorageType(o.leakRef())) { }
// Hash table deleted values, which are only constructed and never copied or destroyed.
- RetainPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
- bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
-
+ constexpr RetainPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
+ constexpr bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
+
~RetainPtr();
-
- template<typename U> RetainPtr(const RetainPtr<U>&);
void clear();
PtrType leakRef() WARN_UNUSED_RETURN;
PtrType autorelease();
+
#ifdef __OBJC__
id bridgingAutorelease();
#endif
- PtrType get() const { return fromStorageType(m_ptr); }
- PtrType operator->() const { return fromStorageType(m_ptr); }
- explicit operator PtrType() const { return fromStorageType(m_ptr); }
- explicit operator bool() const { return m_ptr; }
+ constexpr PtrType get() const { return fromStorageType(m_ptr); }
+ constexpr PtrType operator->() const { return fromStorageType(m_ptr); }
+ constexpr explicit operator PtrType() const { return fromStorageType(m_ptr); }
+ constexpr explicit operator bool() const { return m_ptr; }
- bool operator!() const { return !m_ptr; }
+ constexpr bool operator!() const { return !m_ptr; }
// This conversion operator allows implicit conversion to bool but not to other integer types.
- typedef StorageType RetainPtr::*UnspecifiedBoolType;
+ // FIXME: Eventually we should remove this; it's an outdated technique and less needed since we have explicit operator bool.
+ typedef CFTypeRef RetainPtr::*UnspecifiedBoolType;
operator UnspecifiedBoolType() const { return m_ptr ? &RetainPtr::m_ptr : nullptr; }
-
+
RetainPtr& operator=(const RetainPtr&);
template<typename U> RetainPtr& operator=(const RetainPtr<U>&);
RetainPtr& operator=(PtrType);
@@ -126,7 +128,8 @@
void swap(RetainPtr&);
- template<typename U> friend RetainPtr<U> adoptCF(U CF_RELEASES_ARGUMENT) WARN_UNUSED_RETURN;
+ template<typename U> friend constexpr RetainPtr<U> adoptCF(U CF_RELEASES_ARGUMENT) WARN_UNUSED_RETURN;
+
#ifdef __OBJC__
template<typename U> friend RetainPtr<typename RetainPtr<U>::HelperPtrType> adoptNS(U NS_RELEASES_ARGUMENT) WARN_UNUSED_RETURN;
#endif
@@ -133,63 +136,64 @@
private:
enum AdoptTag { Adopt };
- RetainPtr(PtrType ptr, AdoptTag) : m_ptr(toStorageType(ptr)) { }
+ constexpr RetainPtr(PtrType ptr, AdoptTag) : m_ptr(toStorageType(ptr)) { }
- static PtrType hashTableDeletedValue() { return reinterpret_cast<PtrType>(-1); }
+ static constexpr PtrType hashTableDeletedValue() { return reinterpret_cast<PtrType>(-1); }
#ifdef __OBJC__
- template<typename U>
- typename std::enable_if<std::is_convertible<U, id>::value, PtrType>::type
- fromStorageTypeHelper(StorageType ptr) const
+ template<typename U> constexpr std::enable_if_t<std::is_convertible_v<U, id>, PtrType> fromStorageTypeHelper(CFTypeRef ptr) const
{
return (__bridge PtrType)const_cast<CF_BRIDGED_TYPE(id) void*>(ptr);
}
-
- template<typename U>
- typename std::enable_if<!std::is_convertible<U, id>::value, PtrType>::type
- fromStorageTypeHelper(StorageType ptr) const
+ template<typename U> constexpr std::enable_if_t<!std::is_convertible_v<U, id>, PtrType> fromStorageTypeHelper(CFTypeRef ptr) const
{
return (PtrType)const_cast<CF_BRIDGED_TYPE(id) void*>(ptr);
}
-
- PtrType fromStorageType(StorageType ptr) const { return fromStorageTypeHelper<PtrType>(ptr); }
- StorageType toStorageType(id ptr) const { return (__bridge StorageType)ptr; }
- StorageType toStorageType(CFTypeRef ptr) const { return (StorageType)ptr; }
+ constexpr PtrType fromStorageType(CFTypeRef ptr) const { return fromStorageTypeHelper<PtrType>(ptr); }
+ constexpr CFTypeRef toStorageType(id ptr) const { return (__bridge CFTypeRef)ptr; }
+ constexpr CFTypeRef toStorageType(CFTypeRef ptr) const { return (CFTypeRef)ptr; }
#else
- PtrType fromStorageType(StorageType ptr) const
+ constexpr PtrType fromStorageType(CFTypeRef ptr) const
{
return (PtrType)const_cast<CF_BRIDGED_TYPE(id) void*>(ptr);
}
- StorageType toStorageType(PtrType ptr) const { return (StorageType)ptr; }
+ constexpr CFTypeRef toStorageType(PtrType ptr) const { return (CFTypeRef)ptr; }
#endif
-#ifdef __OBJC__
- template<typename U> std::enable_if_t<std::is_convertible<U, id>::value, PtrType> autoreleaseHelper();
- template<typename U> std::enable_if_t<!std::is_convertible<U, id>::value, PtrType> autoreleaseHelper();
-#endif
-
- StorageType m_ptr;
+ CFTypeRef m_ptr { nullptr };
};
+template<typename T> RetainPtr(T) -> RetainPtr<std::remove_pointer_t<T>>;
+
// Helper function for creating a RetainPtr using template argument deduction.
template<typename T> RetainPtr<typename RetainPtr<T>::HelperPtrType> retainPtr(T) WARN_UNUSED_RETURN;
template<typename T> inline RetainPtr<T>::~RetainPtr()
{
- if (StorageType ptr = std::exchange(m_ptr, nullptr))
+ if (auto ptr = std::exchange(m_ptr, nullptr))
CFRelease(ptr);
}
+template<typename T> inline RetainPtr<T>::RetainPtr(PtrType ptr)
+ : m_ptr(toStorageType(ptr))
+{
+ if (m_ptr)
+ CFRetain(m_ptr);
+}
+
+template<typename T> inline RetainPtr<T>::RetainPtr(const RetainPtr& o)
+ : RetainPtr(o.get())
+{
+}
+
template<typename T> template<typename U> inline RetainPtr<T>::RetainPtr(const RetainPtr<U>& o)
- : m_ptr(toStorageType(o.get()))
+ : RetainPtr(o.get())
{
- if (StorageType ptr = m_ptr)
- CFRetain(ptr);
}
template<typename T> inline void RetainPtr<T>::clear()
{
- if (StorageType ptr = std::exchange(m_ptr, nullptr))
+ if (auto ptr = std::exchange(m_ptr, nullptr))
CFRelease(ptr);
}
@@ -198,35 +202,20 @@
return fromStorageType(std::exchange(m_ptr, nullptr));
}
-#ifndef __OBJC__
-
template<typename T> inline auto RetainPtr<T>::autorelease() -> PtrType
{
+#ifdef __OBJC__
+ if constexpr (std::is_convertible_v<PtrType, id>)
+ return CFBridgingRelease(std::exchange(m_ptr, nullptr));
+#endif
if (m_ptr)
CFAutorelease(m_ptr);
return leakRef();
}
-#else
+#ifdef __OBJC__
-template<typename T> template<typename U> inline auto RetainPtr<T>::autoreleaseHelper() -> std::enable_if_t<std::is_convertible<U, id>::value, PtrType>
-{
- return CFBridgingRelease(std::exchange(m_ptr, nullptr));
-}
-
-template<typename T> template<typename U> inline auto RetainPtr<T>::autoreleaseHelper() -> std::enable_if_t<!std::is_convertible<U, id>::value, PtrType>
-{
- if (m_ptr)
- CFAutorelease(m_ptr);
- return leakRef();
-}
-
-template<typename T> inline auto RetainPtr<T>::autorelease() -> PtrType
-{
- return autoreleaseHelper<PtrType>();
-}
-
-// FIXME: It would be nice if we could base the return type on the type that is toll-free bridged with T rather than using id.
+// FIXME: It would be better if we could base the return type on the type that is toll-free bridged with T rather than using id.
template<typename T> inline id RetainPtr<T>::bridgingAutorelease()
{
static_assert((!std::is_convertible<PtrType, id>::value), "Don't use bridgingAutorelease for Objective-C pointer types.");
@@ -287,37 +276,37 @@
a.swap(b);
}
-template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b)
+template<typename T, typename U> constexpr bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b)
{
return a.get() == b.get();
}
-template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, U* b)
+template<typename T, typename U> constexpr bool operator==(const RetainPtr<T>& a, U* b)
{
return a.get() == b;
}
-template<typename T, typename U> inline bool operator==(T* a, const RetainPtr<U>& b)
+template<typename T, typename U> constexpr bool operator==(T* a, const RetainPtr<U>& b)
{
return a == b.get();
}
-template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b)
+template<typename T, typename U> constexpr bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b)
{
return a.get() != b.get();
}
-template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, U* b)
+template<typename T, typename U> constexpr bool operator!=(const RetainPtr<T>& a, U* b)
{
return a.get() != b;
}
-template<typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b)
+template<typename T, typename U> constexpr bool operator!=(T* a, const RetainPtr<U>& b)
{
return a != b.get();
}
-template<typename T> inline RetainPtr<T> adoptCF(T CF_RELEASES_ARGUMENT ptr)
+template<typename T> constexpr RetainPtr<T> adoptCF(T CF_RELEASES_ARGUMENT ptr)
{
#ifdef __OBJC__
static_assert((!std::is_convertible<T, id>::value), "Don't use adoptCF with Objective-C pointer types, use adoptNS.");
@@ -331,7 +320,8 @@
#if __has_feature(objc_arc)
return ptr;
#elif defined(OBJC_NO_GC)
- return RetainPtr<typename RetainPtr<T>::HelperPtrType>(ptr, RetainPtr<typename RetainPtr<T>::HelperPtrType>::Adopt);
+ using ReturnType = RetainPtr<typename RetainPtr<T>::HelperPtrType>;
+ return ReturnType { ptr, ReturnType::Adopt };
#else
RetainPtr<typename RetainPtr<T>::HelperPtrType> result = ptr;
[ptr release];
@@ -345,7 +335,7 @@
return ptr;
}
-template <typename T> struct IsSmartPtr<RetainPtr<T>> {
+template<typename T> struct IsSmartPtr<RetainPtr<T>> {
static constexpr bool value = true;
};
@@ -354,17 +344,15 @@
template<typename P> struct DefaultHash<RetainPtr<P>> : PtrHash<RetainPtr<P>> { };
-template <typename P>
-struct RetainPtrObjectHashTraits : SimpleClassHashTraits<RetainPtr<P>> {
+template<typename P> struct RetainPtrObjectHashTraits : SimpleClassHashTraits<RetainPtr<P>> {
static const RetainPtr<P>& emptyValue()
{
- static RetainPtr<P>& null = *(new RetainPtr<P>);
+ static NeverDestroyed<RetainPtr<P>> null;
return null;
}
};
-template <typename P>
-struct RetainPtrObjectHash {
+template<typename P> struct RetainPtrObjectHash {
static unsigned hash(const RetainPtr<P>& o)
{
ASSERT_WITH_MESSAGE(o.get(), "attempt to use null RetainPtr in HashTable");