Improve use of NeverDestroyed
[WebKit-https.git] / Source / WTF / wtf / NeverDestroyed.h
index b824634..8784b6e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef NeverDestroyed_h
-#define NeverDestroyed_h
+#pragma once
 
 #include <type_traits>
 #include <utility>
-#include <wtf/Noncopyable.h>
 #include <wtf/RefCounted.h>
 
-// NeverDestroyed is a smart pointer like class who ensures that the destructor
+// NeverDestroyed is a smart-pointer-like class that ensures that the destructor
 // for the given object is never called, but doesn't use the heap to allocate it.
 // It's useful for static local variables, and can be used like so:
 //
@@ -47,32 +45,39 @@ template<typename T> class NeverDestroyed {
     WTF_MAKE_NONCOPYABLE(NeverDestroyed);
 
 public:
-    template<typename... Args>
-    NeverDestroyed(Args&&... args)
+    template<typename... Args> NeverDestroyed(Args&&... args)
     {
-        MaybeRelax<T>(new (asPtr()) T(std::forward<Args>(args)...));
+        MaybeRelax<T>(new (storagePointer()) T(std::forward<Args>(args)...));
     }
 
-    operator T&() { return *asPtr(); }
-    T& get() { return *asPtr(); }
+    operator T&() { return *storagePointer(); }
+    T& get() { return *storagePointer(); }
+
+    operator const T&() const { return *storagePointer(); }
+    const T& get() const { return *storagePointer(); }
 
 private:
-    typedef typename std::remove_const<T>::type* PointerType;
+    using PointerType = typename std::remove_const<T>::type*;
 
-    PointerType asPtr() { return reinterpret_cast<PointerType>(&m_storage); }
+    PointerType storagePointer() const { return const_cast<PointerType>(reinterpret_cast<const T*>(&m_storage)); }
 
     // FIXME: Investigate whether we should allocate a hunk of virtual memory
     // and hand out chunks of it to NeverDestroyed instead, to reduce fragmentation.
     typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type m_storage;
 
-    template <typename PtrType, bool ShouldRelax = std::is_base_of<RefCountedBase, PtrType>::value> struct MaybeRelax {
+    template<typename PtrType, bool ShouldRelax = std::is_base_of<RefCountedBase, PtrType>::value> struct MaybeRelax {
         explicit MaybeRelax(PtrType*) { }
     };
-    template <typename PtrType> struct MaybeRelax<PtrType, true> {
+    template<typename PtrType> struct MaybeRelax<PtrType, true> {
         explicit MaybeRelax(PtrType* ptr) { ptr->relaxAdoptionRequirement(); }
     };
 };
 
+template<typename T> NeverDestroyed<T> makeNeverDestroyed(T&&);
+
+// FIXME: It's messy to have to repeat the whole class just to make this "lazy" version.
+// Should revisit clients to see if we really need this, and perhaps use templates to
+// share more of the code with the main NeverDestroyed above.
 template<typename T> class LazyNeverDestroyed {
     WTF_MAKE_NONCOPYABLE(LazyNeverDestroyed);
 
@@ -88,45 +93,53 @@ public:
         m_isConstructed = true;
 #endif
 
-        MaybeRelax<T>(new (asPtr()) T(std::forward<Args>(args)...));
+        MaybeRelax<T>(new (storagePointer()) T(std::forward<Args>(args)...));
     }
 
-    operator T&() { return *asPtr(); }
-    T& get() { return *asPtr(); }
+    operator T&() { return *storagePointer(); }
+    T& get() { return *storagePointer(); }
+
+    T* operator->() { return storagePointer(); }
 
-    T* operator->() { return asPtr(); }
+    operator const T&() const { return *storagePointer(); }
+    const T& get() const { return *storagePointer(); }
+
+    const T* operator->() const { return storagePointer(); }
 
 private:
-    typedef typename std::remove_const<T>::type* PointerType;
+    using PointerType = typename std::remove_const<T>::type*;
 
-    PointerType asPtr()
+    PointerType storagePointer() const
     {
         ASSERT(m_isConstructed);
-
-        return reinterpret_cast<PointerType>(&m_storage);
+        return const_cast<PointerType>(reinterpret_cast<const T*>(&m_storage));
     }
 
     // FIXME: Investigate whether we should allocate a hunk of virtual memory
     // and hand out chunks of it to NeverDestroyed instead, to reduce fragmentation.
     typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type m_storage;
 
-    template <typename PtrType, bool ShouldRelax = std::is_base_of<RefCountedBase, PtrType>::value> struct MaybeRelax {
+    template<typename PtrType, bool ShouldRelax = std::is_base_of<RefCountedBase, PtrType>::value> struct MaybeRelax {
         explicit MaybeRelax(PtrType*) { }
     };
-    template <typename PtrType> struct MaybeRelax<PtrType, true> {
+    template<typename PtrType> struct MaybeRelax<PtrType, true> {
         explicit MaybeRelax(PtrType* ptr) { ptr->relaxAdoptionRequirement(); }
     };
 
 #if !ASSERT_DISABLED
     // LazyNeverDestroyed objects are always static, so this variable is initialized to false.
-    // It must not be initialized dynamically, because that would not be thread safe.
+    // It must not be initialized dynamically; that would not be thread safe.
     bool m_isConstructed;
 #endif
 };
 
+template<typename T> inline NeverDestroyed<T> makeNeverDestroyed(T&& argument)
+{
+    return WTFMove(argument);
+}
+
 } // namespace WTF;
 
 using WTF::LazyNeverDestroyed;
 using WTF::NeverDestroyed;
-
-#endif // NeverDestroyed_h
+using WTF::makeNeverDestroyed;