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