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

source code of phonon/phonon/globalstatic_p.h