aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/opengl/shared/emugl/common/lazy_instance.h
blob: 6641c93d3db992506658a932ecd7d2f2286d44fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef EMUGL_COMMON_LAZY_INSTANCE_H
#define EMUGL_COMMON_LAZY_INSTANCE_H

#include <new>

#ifdef _WIN32
#  define WIN32_LEAN_AND_MEAN 1
#  include <windows.h>
#endif

namespace emugl {
namespace internal {

// A LazyInstance is a helper template that can be used to perform
// thread-safe lazy initialization of static C++ objects without forcing
// the generation of C++ static constructors in the final executable.
//
// In a nutshell, you can replace a statement like:
//
//    static Foo gFoo;
//
// With:
//
//    static LazyInstance<Foo> gFoo = LAZY_INSTANCE_INIT;
//
// In the first case, a hidden static C++ constructor is embedded in the
// final executable, and executed at *load* *time* to call the Foo::Foo
// constructor on the gFoo object.
//
// On the second case, gFoo will only be initialized lazily, i.e. the first
// time any code actually tries to access the variable.
//
// Note that access is slightly different, i.e.:
//
//    gFoo.get() returns a reference to the lazy-initialized object.
//    gFoo.ptr() returns a pointer to it.
//    gFoo->Something() is equivalent to doing gFoo.ptr()->Something().
//
// 'gFoo' is stored in the .bss section and this doesn't use heap allocation.
// This class can only be used to perform lazy initialization through the
// class' default constructor. For more specialized cases, you will have
// to create a derived class, e.g.:
//
//    class FoorWithDefaultParams : public Foo {
//    public:
//       FooWithDefaultParams() : Foo(<default-parameters>) {}
//    };
//
//    LazyInstance<FooWithDefaultParams> gFoo = LAZY_INSTANCE_INIT;
//
// The implementation of LazyInstance relies on atomic operations and
// POD-struct class definitions, i.e. one that doesn't have any constructor,
// destructor, virtual members, or private ones, and that can be
// zero-initialized at link time.
//
// You can also use LazyInstance<> instances as static local variables,
// e.g.:
//
//     Foo*  getFooSingleton() {
//        static LazyInstance<Foo> sFoo = LAZY_INSTANCE_INIT;
//        return sFoo.ptr();
//     }
//
// This is useful on Windows which doesn't support thread-safe lazy
// initialization of static C++ local variables, or when the code is
// compiled with -fno-threadsafe-statics.
//
// This class is heavily inspired by Chromium's implementation of the
// same-named class (see $CHROMIUM/src/base/lazy_instance.h).

// Atomic state variable type. Used to ensure to synchronize concurrent
// initialization and access without incurring the full cost of a mutex
// lock/unlock.
struct LazyInstanceState {
    enum {
        STATE_INIT = 0,
        STATE_CONSTRUCTING = 1,
        STATE_DONE = 2,
    };

    bool inInitState();
    bool needConstruction();
    void doneConstructing();

#ifdef _WIN32
    typedef LONG volatile AtomicType;
#else
    typedef int volatile AtomicType;
#endif

    volatile AtomicType mState;
};

#define LAZY_INSTANCE_STATE_INIT  \
    { ::emugl::internal::LazyInstanceState::STATE_INIT }

}  // namespace internal

// LazyInstance template definition, see comment above for usage
// instructions. It is crucial to make this a POD-struct compatible
// type [1].
//
// [1] http://en.wikipedia.org/wiki/Plain_Old_Data_Structures
//
template <class T>
struct LazyInstance {
    bool hasInstance() const { return !mState.inInitState(); }

    T& get() const { return *ptr(); }

    T* ptr() const;

    const T* operator->() const { return ptr(); }

    T* operator->() { return ptr(); }

    T& operator*() { return get(); }

    // Really private, do not use.
    union {
        mutable internal::LazyInstanceState mState;
        double mPadding;
    };
    mutable char mStorage[sizeof(T)];
};

// Initialization value, must resolve to all-0 to ensure the object
// instance is actually placed in the .bss
#define LAZY_INSTANCE_INIT  { { LAZY_INSTANCE_STATE_INIT }, { 0 } }

template <class T>
T* LazyInstance<T>::ptr() const {
    if (mState.needConstruction()) {
        new (mStorage) T();
        mState.doneConstructing();
    }
    return reinterpret_cast<T*>(mStorage);
}

}  // namespace emugl

#endif  // EMUGL_COMMON_LAZY_INSTANCE_H