OLD | NEW |
(Empty) | |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 // The LazyInstance<Type, Traits> class manages a single instance of Type, |
| 29 // which will be lazily created on the first time it's accessed. This class is |
| 30 // useful for places you would normally use a function-level static, but you |
| 31 // need to have guaranteed thread-safety. The Type constructor will only ever |
| 32 // be called once, even if two threads are racing to create the object. Get() |
| 33 // and Pointer() will always return the same, completely initialized instance. |
| 34 // |
| 35 // LazyInstance is completely thread safe, assuming that you create it safely. |
| 36 // The class was designed to be POD initialized, so it shouldn't require a |
| 37 // static constructor. It really only makes sense to declare a LazyInstance as |
| 38 // a global variable using the LAZY_INSTANCE_INITIALIZER initializer. |
| 39 // |
| 40 // LazyInstance is similar to Singleton, except it does not have the singleton |
| 41 // property. You can have multiple LazyInstance's of the same type, and each |
| 42 // will manage a unique instance. It also preallocates the space for Type, as |
| 43 // to avoid allocating the Type instance on the heap. This may help with the |
| 44 // performance of creating the instance, and reducing heap fragmentation. This |
| 45 // requires that Type be a complete type so we can determine the size. See |
| 46 // notes for advanced users below for more explanations. |
| 47 // |
| 48 // Example usage: |
| 49 // static LazyInstance<MyClass>::type my_instance = LAZY_INSTANCE_INITIALIZER; |
| 50 // void SomeMethod() { |
| 51 // my_instance.Get().SomeMethod(); // MyClass::SomeMethod() |
| 52 // |
| 53 // MyClass* ptr = my_instance.Pointer(); |
| 54 // ptr->DoDoDo(); // MyClass::DoDoDo |
| 55 // } |
| 56 // |
| 57 // Additionally you can override the way your instance is constructed by |
| 58 // providing your own trait: |
| 59 // Example usage: |
| 60 // struct MyCreateTrait { |
| 61 // static void Construct(MyClass* allocated_ptr) { |
| 62 // new (allocated_ptr) MyClass(/* extra parameters... */); |
| 63 // } |
| 64 // }; |
| 65 // static LazyInstance<MyClass, MyCreateTrait>::type my_instance = |
| 66 // LAZY_INSTANCE_INITIALIZER; |
| 67 // |
| 68 // Notes for advanced users: |
| 69 // LazyInstance can actually be used in two different ways: |
| 70 // |
| 71 // - "Static mode" which is the default mode since it is the most efficient |
| 72 // (no extra heap allocation). In this mode, the instance is statically |
| 73 // allocated (stored in the global data section at compile time). |
| 74 // The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER) |
| 75 // must be used to initialize static lazy instances. |
| 76 // |
| 77 // - "Dynamic mode". In this mode, the instance is dynamically allocated and |
| 78 // constructed (using new) by default. This mode is useful if you have to |
| 79 // deal with some code already allocating the instance for you (e.g. |
| 80 // OS::Mutex() which returns a new private OS-dependent subclass of Mutex). |
| 81 // The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize |
| 82 // dynamic lazy instances. |
| 83 |
| 84 #ifndef V8_LAZY_INSTANCE_H_ |
| 85 #define V8_LAZY_INSTANCE_H_ |
| 86 |
| 87 #include "once.h" |
| 88 |
| 89 namespace v8 { |
| 90 namespace internal { |
| 91 |
| 92 #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, {} } |
| 93 #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 } |
| 94 |
| 95 // Default to static mode. |
| 96 #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER |
| 97 |
| 98 |
| 99 template <typename T> |
| 100 struct LeakyInstanceTrait { |
| 101 static void Destroy(T* /* instance */) {} |
| 102 }; |
| 103 |
| 104 |
| 105 // Traits that define how an instance is allocated and accessed. |
| 106 |
| 107 template <typename T> |
| 108 struct StaticallyAllocatedInstanceTrait { |
| 109 typedef char StorageType[sizeof(T)]; |
| 110 |
| 111 static T* MutableInstance(StorageType* storage) { |
| 112 return reinterpret_cast<T*>(storage); |
| 113 } |
| 114 |
| 115 template <typename ConstructTrait> |
| 116 static void InitStorageUsingTrait(StorageType* storage) { |
| 117 ConstructTrait::Construct(MutableInstance(storage)); |
| 118 } |
| 119 }; |
| 120 |
| 121 |
| 122 template <typename T> |
| 123 struct DynamicallyAllocatedInstanceTrait { |
| 124 typedef T* StorageType; |
| 125 |
| 126 static T* MutableInstance(StorageType* storage) { |
| 127 return *storage; |
| 128 } |
| 129 |
| 130 template <typename CreateTrait> |
| 131 static void InitStorageUsingTrait(StorageType* storage) { |
| 132 *storage = CreateTrait::Create(); |
| 133 } |
| 134 }; |
| 135 |
| 136 |
| 137 template <typename T> |
| 138 struct DefaultConstructTrait { |
| 139 // Constructs the provided object which was already allocated. |
| 140 static void Construct(T* allocated_ptr) { |
| 141 new(allocated_ptr) T(); |
| 142 } |
| 143 }; |
| 144 |
| 145 |
| 146 template <typename T> |
| 147 struct DefaultCreateTrait { |
| 148 static T* Create() { |
| 149 return new T(); |
| 150 } |
| 151 }; |
| 152 |
| 153 |
| 154 // TODO(pliard): Handle instances destruction (using global destructors). |
| 155 template <typename T, typename AllocationTrait, typename CreateTrait, |
| 156 typename DestroyTrait /* not used yet. */ > |
| 157 struct LazyInstanceImpl { |
| 158 public: |
| 159 typedef typename AllocationTrait::StorageType StorageType; |
| 160 |
| 161 private: |
| 162 static void InitInstance(StorageType* storage) { |
| 163 AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage); |
| 164 } |
| 165 |
| 166 void Init() const { |
| 167 CallOnce(&once_, &InitInstance, &storage_); |
| 168 } |
| 169 |
| 170 public: |
| 171 T* Pointer() { |
| 172 Init(); |
| 173 return AllocationTrait::MutableInstance(&storage_); |
| 174 } |
| 175 |
| 176 const T& Get() const { |
| 177 Init(); |
| 178 return *AllocationTrait::MutableInstance(&storage_); |
| 179 } |
| 180 |
| 181 mutable OnceType once_; |
| 182 // Note that the previous field, OnceType, is an AtomicWord which guarantees |
| 183 // the correct alignment of the storage field below. |
| 184 mutable StorageType storage_; |
| 185 }; |
| 186 |
| 187 |
| 188 template <typename T, |
| 189 typename CreateTrait = DefaultConstructTrait<T>, |
| 190 typename DestroyTrait = LeakyInstanceTrait<T> > |
| 191 struct LazyStaticInstance { |
| 192 typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, CreateTrait, |
| 193 DestroyTrait> type; |
| 194 }; |
| 195 |
| 196 |
| 197 template <typename T, |
| 198 typename CreateTrait = DefaultConstructTrait<T>, |
| 199 typename DestroyTrait = LeakyInstanceTrait<T> > |
| 200 struct LazyInstance { |
| 201 // A LazyInstance is a LazyStaticInstance. |
| 202 typedef typename LazyStaticInstance<T, CreateTrait, DestroyTrait>::type type; |
| 203 }; |
| 204 |
| 205 |
| 206 template <typename T, |
| 207 typename CreateTrait = DefaultConstructTrait<T>, |
| 208 typename DestroyTrait = LeakyInstanceTrait<T> > |
| 209 struct LazyDynamicInstance { |
| 210 typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, CreateTrait, |
| 211 DestroyTrait> type; |
| 212 }; |
| 213 |
| 214 } } // namespace v8::internal |
| 215 |
| 216 #endif // V8_LAZY_INSTANCE_H_ |
OLD | NEW |