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 
~CleanUpGlobalStatic()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
294