Home | History | Annotate | Download | only in common
      1 // Copyright (C) 2014 The Android Open Source Project
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 // http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #ifndef EMUGL_COMMON_LAZY_INSTANCE_H
     16 #define EMUGL_COMMON_LAZY_INSTANCE_H
     17 
     18 #include <new>
     19 
     20 #ifdef _WIN32
     21 #  define WIN32_LEAN_AND_MEAN 1
     22 #  include <windows.h>
     23 #endif
     24 
     25 namespace emugl {
     26 namespace internal {
     27 
     28 // A LazyInstance is a helper template that can be used to perform
     29 // thread-safe lazy initialization of static C++ objects without forcing
     30 // the generation of C++ static constructors in the final executable.
     31 //
     32 // In a nutshell, you can replace a statement like:
     33 //
     34 //    static Foo gFoo;
     35 //
     36 // With:
     37 //
     38 //    static LazyInstance<Foo> gFoo = LAZY_INSTANCE_INIT;
     39 //
     40 // In the first case, a hidden static C++ constructor is embedded in the
     41 // final executable, and executed at *load* *time* to call the Foo::Foo
     42 // constructor on the gFoo object.
     43 //
     44 // On the second case, gFoo will only be initialized lazily, i.e. the first
     45 // time any code actually tries to access the variable.
     46 //
     47 // Note that access is slightly different, i.e.:
     48 //
     49 //    gFoo.get() returns a reference to the lazy-initialized object.
     50 //    gFoo.ptr() returns a pointer to it.
     51 //    gFoo->Something() is equivalent to doing gFoo.ptr()->Something().
     52 //
     53 // 'gFoo' is stored in the .bss section and this doesn't use heap allocation.
     54 // This class can only be used to perform lazy initialization through the
     55 // class' default constructor. For more specialized cases, you will have
     56 // to create a derived class, e.g.:
     57 //
     58 //    class FoorWithDefaultParams : public Foo {
     59 //    public:
     60 //       FooWithDefaultParams() : Foo(<default-parameters>) {}
     61 //    };
     62 //
     63 //    LazyInstance<FooWithDefaultParams> gFoo = LAZY_INSTANCE_INIT;
     64 //
     65 // The implementation of LazyInstance relies on atomic operations and
     66 // POD-struct class definitions, i.e. one that doesn't have any constructor,
     67 // destructor, virtual members, or private ones, and that can be
     68 // zero-initialized at link time.
     69 //
     70 // You can also use LazyInstance<> instances as static local variables,
     71 // e.g.:
     72 //
     73 //     Foo*  getFooSingleton() {
     74 //        static LazyInstance<Foo> sFoo = LAZY_INSTANCE_INIT;
     75 //        return sFoo.ptr();
     76 //     }
     77 //
     78 // This is useful on Windows which doesn't support thread-safe lazy
     79 // initialization of static C++ local variables, or when the code is
     80 // compiled with -fno-threadsafe-statics.
     81 //
     82 // This class is heavily inspired by Chromium's implementation of the
     83 // same-named class (see $CHROMIUM/src/base/lazy_instance.h).
     84 
     85 // Atomic state variable type. Used to ensure to synchronize concurrent
     86 // initialization and access without incurring the full cost of a mutex
     87 // lock/unlock.
     88 struct LazyInstanceState {
     89     enum {
     90         STATE_INIT = 0,
     91         STATE_CONSTRUCTING = 1,
     92         STATE_DONE = 2,
     93     };
     94 
     95     bool inInitState();
     96     bool needConstruction();
     97     void doneConstructing();
     98 
     99 #ifdef _WIN32
    100     typedef LONG volatile AtomicType;
    101 #else
    102     typedef int volatile AtomicType;
    103 #endif
    104 
    105     volatile AtomicType mState;
    106 };
    107 
    108 #define LAZY_INSTANCE_STATE_INIT  \
    109     { ::emugl::internal::LazyInstanceState::STATE_INIT }
    110 
    111 }  // namespace internal
    112 
    113 // LazyInstance template definition, see comment above for usage
    114 // instructions. It is crucial to make this a POD-struct compatible
    115 // type [1].
    116 //
    117 // [1] http://en.wikipedia.org/wiki/Plain_Old_Data_Structures
    118 //
    119 template <class T>
    120 struct LazyInstance {
    121     bool hasInstance() const { return !mState.inInitState(); }
    122 
    123     T& get() const { return *ptr(); }
    124 
    125     T* ptr() const;
    126 
    127     const T* operator->() const { return ptr(); }
    128 
    129     T* operator->() { return ptr(); }
    130 
    131     T& operator*() { return get(); }
    132 
    133     // Really private, do not use.
    134     union {
    135         mutable internal::LazyInstanceState mState;
    136         double mPadding;
    137     };
    138     mutable char mStorage[sizeof(T)];
    139 };
    140 
    141 // Initialization value, must resolve to all-0 to ensure the object
    142 // instance is actually placed in the .bss
    143 #define LAZY_INSTANCE_INIT  { { LAZY_INSTANCE_STATE_INIT }, { 0 } }
    144 
    145 template <class T>
    146 T* LazyInstance<T>::ptr() const {
    147     if (mState.needConstruction()) {
    148         new (mStorage) T();
    149         mState.doneConstructing();
    150     }
    151     return reinterpret_cast<T*>(mStorage);
    152 }
    153 
    154 }  // namespace emugl
    155 
    156 #endif  // EMUGL_COMMON_LAZY_INSTANCE_H
    157