LCOV - code coverage report
Current view: top level - src/base - lazy-instance.h (source / functions) Hit Total Coverage
Test: app.info Lines: 12 12 100.0 %
Date: 2019-04-19 Functions: 33 36 91.7 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : // The LazyInstance<Type, Traits> class manages a single instance of Type,
       6             : // which will be lazily created on the first time it's accessed.  This class is
       7             : // useful for places you would normally use a function-level static, but you
       8             : // need to have guaranteed thread-safety.  The Type constructor will only ever
       9             : // be called once, even if two threads are racing to create the object.  Get()
      10             : // and Pointer() will always return the same, completely initialized instance.
      11             : //
      12             : // LazyInstance is completely thread safe, assuming that you create it safely.
      13             : // The class was designed to be POD initialized, so it shouldn't require a
      14             : // static constructor.  It really only makes sense to declare a LazyInstance as
      15             : // a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
      16             : //
      17             : // LazyInstance is similar to Singleton, except it does not have the singleton
      18             : // property.  You can have multiple LazyInstance's of the same type, and each
      19             : // will manage a unique instance.  It also preallocates the space for Type, as
      20             : // to avoid allocating the Type instance on the heap.  This may help with the
      21             : // performance of creating the instance, and reducing heap fragmentation.  This
      22             : // requires that Type be a complete type so we can determine the size. See
      23             : // notes for advanced users below for more explanations.
      24             : //
      25             : // Example usage:
      26             : //   static LazyInstance<MyClass>::type my_instance = LAZY_INSTANCE_INITIALIZER;
      27             : //   void SomeMethod() {
      28             : //     my_instance.Get().SomeMethod();  // MyClass::SomeMethod()
      29             : //
      30             : //     MyClass* ptr = my_instance.Pointer();
      31             : //     ptr->DoDoDo();  // MyClass::DoDoDo
      32             : //   }
      33             : //
      34             : // Additionally you can override the way your instance is constructed by
      35             : // providing your own trait:
      36             : // Example usage:
      37             : //   struct MyCreateTrait {
      38             : //     static void Construct(void* allocated_ptr) {
      39             : //       new (allocated_ptr) MyClass(/* extra parameters... */);
      40             : //     }
      41             : //   };
      42             : //   static LazyInstance<MyClass, MyCreateTrait>::type my_instance =
      43             : //      LAZY_INSTANCE_INITIALIZER;
      44             : //
      45             : // WARNINGS:
      46             : // - This implementation of LazyInstance IS THREAD-SAFE by default. See
      47             : //   SingleThreadInitOnceTrait if you don't care about thread safety.
      48             : // - Lazy initialization comes with a cost. Make sure that you don't use it on
      49             : //   critical path. Consider adding your initialization code to a function
      50             : //   which is explicitly called once.
      51             : //
      52             : // Notes for advanced users:
      53             : // LazyInstance can actually be used in two different ways:
      54             : //
      55             : // - "Static mode" which is the default mode since it is the most efficient
      56             : //   (no extra heap allocation). In this mode, the instance is statically
      57             : //   allocated (stored in the global data section at compile time).
      58             : //   The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER)
      59             : //   must be used to initialize static lazy instances.
      60             : //
      61             : // - "Dynamic mode". In this mode, the instance is dynamically allocated and
      62             : //   constructed (using new) by default. This mode is useful if you have to
      63             : //   deal with some code already allocating the instance for you (e.g.
      64             : //   OS::Mutex() which returns a new private OS-dependent subclass of Mutex).
      65             : //   The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize
      66             : //   dynamic lazy instances.
      67             : 
      68             : #ifndef V8_BASE_LAZY_INSTANCE_H_
      69             : #define V8_BASE_LAZY_INSTANCE_H_
      70             : 
      71             : #include <type_traits>
      72             : 
      73             : #include "src/base/macros.h"
      74             : #include "src/base/once.h"
      75             : 
      76             : namespace v8 {
      77             : namespace base {
      78             : 
      79             : #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, { {} } }
      80             : #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 }
      81             : 
      82             : // Default to static mode.
      83             : #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
      84             : 
      85             : 
      86             : template <typename T>
      87             : struct LeakyInstanceTrait {
      88             :   static void Destroy(T* /* instance */) {}
      89             : };
      90             : 
      91             : 
      92             : // Traits that define how an instance is allocated and accessed.
      93             : 
      94             : 
      95             : template <typename T>
      96             : struct StaticallyAllocatedInstanceTrait {
      97             :   using StorageType =
      98             :       typename std::aligned_storage<sizeof(T), alignof(T)>::type;
      99             : 
     100             :   static T* MutableInstance(StorageType* storage) {
     101             :     return reinterpret_cast<T*>(storage);
     102             :   }
     103             : 
     104             :   template <typename ConstructTrait>
     105             :   static void InitStorageUsingTrait(StorageType* storage) {
     106       60084 :     ConstructTrait::Construct(storage);
     107             :   }
     108             : };
     109             : 
     110             : 
     111             : template <typename T>
     112             : struct DynamicallyAllocatedInstanceTrait {
     113             :   using StorageType = T*;
     114             : 
     115             :   static T* MutableInstance(StorageType* storage) {
     116             :     return *storage;
     117             :   }
     118             : 
     119             :   template <typename CreateTrait>
     120             :   static void InitStorageUsingTrait(StorageType* storage) {
     121         866 :     *storage = CreateTrait::Create();
     122             :   }
     123             : };
     124             : 
     125             : 
     126             : template <typename T>
     127             : struct DefaultConstructTrait {
     128             :   // Constructs the provided object which was already allocated.
     129      402426 :   static void Construct(void* allocated_ptr) { new (allocated_ptr) T(); }
     130             : };
     131             : 
     132             : 
     133             : template <typename T>
     134             : struct DefaultCreateTrait {
     135             :   static T* Create() {
     136             :     return new T();
     137             :   }
     138             : };
     139             : 
     140             : 
     141             : struct ThreadSafeInitOnceTrait {
     142             :   template <typename Function, typename Storage>
     143             :   static void Init(OnceType* once, Function function, Storage storage) {
     144    76018120 :     CallOnce(once, function, storage);
     145             :   }
     146             : };
     147             : 
     148             : 
     149             : // Initialization trait for users who don't care about thread-safety.
     150             : struct SingleThreadInitOnceTrait {
     151             :   template <typename Function, typename Storage>
     152             :   static void Init(OnceType* once, Function function, Storage storage) {
     153             :     if (*once == ONCE_STATE_UNINITIALIZED) {
     154             :       function(storage);
     155             :       *once = ONCE_STATE_DONE;
     156             :     }
     157             :   }
     158             : };
     159             : 
     160             : 
     161             : // TODO(pliard): Handle instances destruction (using global destructors).
     162             : template <typename T, typename AllocationTrait, typename CreateTrait,
     163             :           typename InitOnceTrait, typename DestroyTrait  /* not used yet. */>
     164             : struct LazyInstanceImpl {
     165             :  public:
     166             :   using StorageType = typename AllocationTrait::StorageType;
     167             : 
     168             :  private:
     169      343568 :   static void InitInstance(void* storage) {
     170             :     AllocationTrait::template InitStorageUsingTrait<CreateTrait>(
     171             :         static_cast<StorageType*>(storage));
     172      343568 :   }
     173             : 
     174             :   void Init() const {
     175       15968 :     InitOnceTrait::Init(&once_, &InitInstance, static_cast<void*>(&storage_));
     176             :   }
     177             : 
     178             :  public:
     179       15968 :   T* Pointer() {
     180             :     Init();
     181       15968 :     return AllocationTrait::MutableInstance(&storage_);
     182             :   }
     183             : 
     184             :   const T& Get() const {
     185             :     Init();
     186             :     return *AllocationTrait::MutableInstance(&storage_);
     187             :   }
     188             : 
     189             :   mutable OnceType once_;
     190             :   // Note that the previous field, OnceType, is an AtomicWord which guarantees
     191             :   // 4-byte alignment of the storage field below. If compiling with GCC (>4.2),
     192             :   // the LAZY_ALIGN macro above will guarantee correctness for any alignment.
     193             :   mutable StorageType storage_;
     194             : };
     195             : 
     196             : 
     197             : template <typename T,
     198             :           typename CreateTrait = DefaultConstructTrait<T>,
     199             :           typename InitOnceTrait = ThreadSafeInitOnceTrait,
     200             :           typename DestroyTrait = LeakyInstanceTrait<T> >
     201             : struct LazyStaticInstance {
     202             :   using type = LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>,
     203             :                                 CreateTrait, InitOnceTrait, DestroyTrait>;
     204             : };
     205             : 
     206             : 
     207             : template <typename T,
     208             :           typename CreateTrait = DefaultConstructTrait<T>,
     209             :           typename InitOnceTrait = ThreadSafeInitOnceTrait,
     210             :           typename DestroyTrait = LeakyInstanceTrait<T> >
     211             : struct LazyInstance {
     212             :   // A LazyInstance is a LazyStaticInstance.
     213             :   using type = typename LazyStaticInstance<T, CreateTrait, InitOnceTrait,
     214             :                                            DestroyTrait>::type;
     215             : };
     216             : 
     217             : 
     218             : template <typename T,
     219             :           typename CreateTrait = DefaultCreateTrait<T>,
     220             :           typename InitOnceTrait = ThreadSafeInitOnceTrait,
     221             :           typename DestroyTrait = LeakyInstanceTrait<T> >
     222             : struct LazyDynamicInstance {
     223             :   using type = LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>,
     224             :                                 CreateTrait, InitOnceTrait, DestroyTrait>;
     225             : };
     226             : 
     227             : // LeakyObject<T> wraps an object of type T, which is initialized in the
     228             : // constructor but never destructed. Thus LeakyObject<T> is trivially
     229             : // destructible and can be used in static (lazily initialized) variables.
     230             : template <typename T>
     231             : class LeakyObject {
     232             :  public:
     233             :   template <typename... Args>
     234         267 :   explicit LeakyObject(Args&&... args) {
     235      337080 :     new (&storage_) T(std::forward<Args>(args)...);
     236         267 :   }
     237             : 
     238             :   T* get() { return reinterpret_cast<T*>(&storage_); }
     239             : 
     240             :  private:
     241             :   typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
     242             : 
     243             :   DISALLOW_COPY_AND_ASSIGN(LeakyObject);
     244             : };
     245             : 
     246             : // Define a function which returns a pointer to a lazily initialized and never
     247             : // destructed object of type T.
     248             : #define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName, ...) \
     249             :   T* FunctionName() {                                         \
     250             :     static ::v8::base::LeakyObject<T> object{__VA_ARGS__};    \
     251             :     return object.get();                                      \
     252             :   }
     253             : 
     254             : }  // namespace base
     255             : }  // namespace v8
     256             : 
     257             : #endif  // V8_BASE_LAZY_INSTANCE_H_

Generated by: LCOV version 1.10