1
/* This file is part of the KDE libraries
2
   Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
3
4
    This library is free software; you can redistribute it and/or
5
    modify it under the terms of the GNU Lesser General Public
6
    License as published by the Free Software Foundation; either
7
    version 2.1 of the License, or (at your option) version 3, or any
8
    later version accepted by the membership of KDE e.V. (or its
9
    successor approved by the membership of KDE e.V.), Nokia Corporation 
10
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
11
    act as a proxy defined in Section 6 of version 3 of the license.
12
13
    This library is distributed in the hope that it will be useful,
14
    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
    Lesser General Public License for more details.
17
18
    You should have received a copy of the GNU Lesser General Public 
19
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
20
*/
21
22
#ifndef PHONON_GLOBALSTATIC_P_H
23
#define PHONON_GLOBALSTATIC_P_H
24
25
#include <QtCore/QAtomicPointer>
26
27
//
28
// WARNING!!
29
// This code uses undocumented Qt API
30
// Do not copy it to your application! Use only the functions that are here!
31
// Otherwise, it could break when a new version of Qt ships.
32
//
33
34
QT_BEGIN_NAMESPACE
35
36
namespace Phonon
37
{
38
39
/**
40
 * @internal
41
 */
42
typedef void (*CleanUpFunction)();
43
44
/**
45
 * @internal
46
 *
47
 * Helper class for PHONON_GLOBAL_STATIC to clean up the object on library unload or application
48
 * shutdown.
49
 */
50
class CleanUpGlobalStatic
51
{
52
    public:
53
        CleanUpFunction func;
54
55
        inline ~CleanUpGlobalStatic() { func(); }
56
};
57
58
} // namespace Phonon
59
60
#ifdef Q_CC_MSVC
61
/**
62
 * @internal
63
 *
64
 * MSVC seems to give anonymous structs the same name which fails at link time. So instead we name
65
 * the struct and hope that by adding the line number to the name it's unique enough to never clash.
66
 */
67
# define PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME) _k_##NAME##__LINE__
68
#else
69
/**
70
 * @internal
71
 *
72
 * Make the struct of the PHONON_GLOBAL_STATIC anonymous.
73
 */
74
# define PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME)
75
#endif
76
77
/**
78
 * This macro makes it easy to use non-POD types as global statics.
79
 * The object is created on first use and creation is threadsafe.
80
 *
81
 * The object is destructed on library unload or application exit.
82
 * Be careful with calling other objects in the destructor of the class
83
 * as you have to be sure that they (or objects they depend on) are not already destructed.
84
 *
85
 * @param TYPE The type of the global static object. Do not add a *.
86
 * @param NAME The name of the function to get a pointer to the global static object.
87
 *
88
 * If you have code that might be called after the global object has been destroyed you can check
89
 * for that using the isDestroyed() function.
90
 *
91
 * If needed (If the destructor of the global object calls other functions that depend on other
92
 * global statics (e.g. KConfig::sync) your destructor has to be called before those global statics
93
 * are destroyed. A Qt post routine does that.) you can also install a post routine (@ref qAddPostRoutine) to clean up the object
94
 * using the destroy() method. If you registered a post routine and the object is destroyed because
95
 * of a lib unload you have to call qRemovePostRoutine!
96
 *
97
 * Example:
98
 * @code
99
 * class A {
100
 * public:
101
 *     ~A();
102
 *     ...
103
 * };
104
 *
105
 * PHONON_GLOBAL_STATIC(A, globalA)
106
 * // The above creates a new globally static variable named 'globalA' which you
107
 * // can use as a pointer to an instance of A.
108
 *
109
 * void doSomething()
110
 * {
111
 *     //  The first time you access globalA a new instance of A will be created automatically.
112
 *     A *a = globalA;
113
 *     ...
114
 * }
115
 *
116
 * void doSomethingElse()
117
 * {
118
 *     if (globalA.isDestroyed()) {
119
 *         return;
120
 *     }
121
 *     A *a = globalA;
122
 *     ...
123
 * }
124
 *
125
 * void installPostRoutine()
126
 * {
127
 *     // A post routine can be used to delete the object when QCoreApplication destructs,
128
 *     // not adding such a post routine will delete the object normally at program unload
129
 *     qAddPostRoutine(globalA.destroy);
130
 * }
131
 *
132
 * A::~A()
133
 * {
134
 *     // When you install a post routine you have to remove the post routine from the destructor of
135
 *     // the class used as global static!
136
 *     qRemovePostRoutine(globalA.destroy);
137
 * }
138
 * @endcode
139
 *
140
 * A common case for the need of deletion on lib unload/app shutdown are Singleton classes. Here's
141
 * an example how to do it:
142
 * @code
143
 * class MySingletonPrivate;
144
 * class EXPORT_MACRO MySingleton
145
 * {
146
 * friend class MySingletonPrivate;
147
 * public:
148
 *     static MySingleton *self();
149
 *     QString someFunction();
150
 *
151
 * private:
152
 *     MySingleton();
153
 *     ~MySingleton();
154
 * };
155
 * @endcode
156
 * in the .cpp file:
157
 * @code
158
 * // This class will be instantiated and referenced as a singleton in this example
159
 * class MySingletonPrivate
160
 * {
161
 * public:
162
 *     QString foo;
163
 *     MySingleton instance;
164
 * };
165
 *
166
 * PHONON_GLOBAL_STATIC(MySingletonPrivate, mySingletonPrivate)
167
 *
168
 * MySingleton *MySingleton::self()
169
 * {
170
 *     // returns the singleton; automatically creates a new instance if that has not happened yet.
171
 *     return &mySingletonPrivate->instance;
172
 * }
173
 * QString MySingleton::someFunction()
174
 * {
175
 *     // Refencing the singleton directly is possible for your convenience
176
 *     return mySingletonPrivate->foo;
177
 * }
178
 * @endcode
179
 *
180
 * Instead of the above you can use also the following pattern (ignore the name of the namespace):
181
 * @code
182
 * namespace MySingleton
183
 * {
184
 *     EXPORT_MACRO QString someFunction();
185
 * }
186
 * @endcode
187
 * in the .cpp file:
188
 * @code
189
 * class MySingletonPrivate
190
 * {
191
 * public:
192
 *     QString foo;
193
 * };
194
 *
195
 * PHONON_GLOBAL_STATIC(MySingletonPrivate, mySingletonPrivate)
196
 *
197
 * QString MySingleton::someFunction()
198
 * {
199
 *     return mySingletonPrivate->foo;
200
 * }
201
 * @endcode
202
 *
203
 * Now code that wants to call someFunction() doesn't have to do
204
 * @code
205
 * MySingleton::self()->someFunction();
206
 * @endcode
207
 * anymore but instead:
208
 * @code
209
 * MySingleton::someFunction();
210
 * @endcode
211
 *
212
 * @ingroup KDEMacros
213
 */
214
#define PHONON_GLOBAL_STATIC(TYPE, NAME) PHONON_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
215
216
/**
217
 * @overload
218
 * This is the same as PHONON_GLOBAL_STATIC,  but can take arguments that are passed 
219
 * to the object's constructor
220
 *
221
 * @param TYPE The type of the global static object. Do not add a *.
222
 * @param NAME The name of the function to get a pointer to the global static object.
223
 * @param ARGS the list of arguments, between brackets
224
 *
225
 * Example:
226
 * @code
227
 * class A
228
 * {
229
 * public:
230
 *     A(const char *s, int i);
231
 *     ...
232
 * };
233
 *
234
 * PHONON_GLOBAL_STATIC_WITH_ARG(A, globalA, ("foo", 0))
235
 * // The above creates a new globally static variable named 'globalA' which you
236
 * // can use as a pointer to an instance of A.
237
 *
238
 * void doSomething()
239
 * {
240
 *     //  The first time you access globalA a new instance of A will be created automatically.
241
 *     A *a = globalA;
242
 *     ...
243
 * }
244
 * @endcode
245
 *
246
 * @ingroup KDEMacros
247
 */
248
#define PHONON_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)                            \
249
static QBasicAtomicPointer<TYPE > _k_static_##NAME = Q_BASIC_ATOMIC_INITIALIZER(0); \
250
static bool _k_static_##NAME##_destroyed;                                      \
251
static struct PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME)                                \
252
{                                                                              \
253
    bool isDestroyed()                                                         \
254
    {                                                                          \
255
        return _k_static_##NAME##_destroyed;                                   \
256
    }                                                                          \
257
    inline operator TYPE*()                                                    \
258
    {                                                                          \
259
        return operator->();                                                   \
260
    }                                                                          \
261
    inline TYPE *operator->()                                                  \
262
    {                                                                          \
263
        TYPE *p = _k_static_##NAME;                                            \
264
        if (!p) {                                                              \
265
            if (isDestroyed()) {                                               \
266
                qFatal("Fatal Error: Accessed global static '%s *%s()' after destruction. " \
267
                       "Defined at %s:%d", #TYPE, #NAME, __FILE__, __LINE__);  \
268
            }                                                                  \
269
            p = new TYPE ARGS;                                                 \
270
            if (!_k_static_##NAME.testAndSetOrdered(0, p)) {                   \
271
                delete p;                                                      \
272
                p = _k_static_##NAME;                                          \
273
            } else {                                                           \
274
                static Phonon::CleanUpGlobalStatic cleanUpObject = { destroy }; \
275
            }                                                                  \
276
        }                                                                      \
277
        return p;                                                              \
278
    }                                                                          \
279
    inline TYPE &operator*()                                                   \
280
    {                                                                          \
281
        return *operator->();                                                  \
282
    }                                                                          \
283
    static void destroy()                                                      \
284
    {                                                                          \
285
        _k_static_##NAME##_destroyed = true;                                   \
286
        TYPE *x = _k_static_##NAME;                                            \
287
        _k_static_##NAME = 0;                                                  \
288
        delete x;                                                              \
289
    }                                                                          \
290
} NAME;
291
292
QT_END_NAMESPACE
293
#endif // PHONON_GLOBALSTATIC_P_H