File indexing completed on 2025-02-09 05:31:48
0001 /* This file is part of the KDE libraries 0002 Copyright (C) 2007 Matthias Kretz <kretz@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Lesser General Public 0006 License as published by the Free Software Foundation; either 0007 version 2.1 of the License, or (at your option) version 3, or any 0008 later version accepted by the membership of KDE e.V. (or its 0009 successor approved by the membership of KDE e.V.), Nokia Corporation 0010 (or its successors, if any) and the KDE Free Qt Foundation, which shall 0011 act as a proxy defined in Section 6 of version 3 of the license. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Lesser General Public License for more details. 0017 0018 You should have received a copy of the GNU Lesser General Public 0019 License along with this library. If not, see <http://www.gnu.org/licenses/>. 0020 */ 0021 0022 #ifndef PHONON_GLOBALSTATIC_P_H 0023 #define PHONON_GLOBALSTATIC_P_H 0024 0025 #include <QAtomicPointer> 0026 0027 // 0028 // WARNING!! 0029 // This code uses undocumented Qt API 0030 // Do not copy it to your application! Use only the functions that are here! 0031 // Otherwise, it could break when a new version of Qt ships. 0032 // 0033 0034 namespace Phonon 0035 { 0036 0037 /** 0038 * @internal 0039 */ 0040 typedef void (*CleanUpFunction)(); 0041 0042 /** 0043 * @internal 0044 * 0045 * Helper class for PHONON_GLOBAL_STATIC to clean up the object on library unload or application 0046 * shutdown. 0047 */ 0048 class CleanUpGlobalStatic 0049 { 0050 public: 0051 CleanUpFunction func; 0052 0053 inline ~CleanUpGlobalStatic() { func(); } 0054 }; 0055 0056 } // namespace Phonon 0057 0058 #ifdef Q_CC_MSVC 0059 /** 0060 * @internal 0061 * 0062 * MSVC seems to give anonymous structs the same name which fails at link time. So instead we name 0063 * the struct and hope that by adding the line number to the name it's unique enough to never clash. 0064 */ 0065 # define PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME) _k_##NAME##__LINE__ 0066 #else 0067 /** 0068 * @internal 0069 * 0070 * Make the struct of the PHONON_GLOBAL_STATIC anonymous. 0071 */ 0072 # define PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME) 0073 #endif 0074 0075 /** 0076 * This macro makes it easy to use non-POD types as global statistics. 0077 * The object is created on first use and creation is threadsafe. 0078 * 0079 * The object is destructed on library unload or application exit. 0080 * Be careful with calling other objects in the destructor of the class 0081 * as you have to be sure that they (or objects they depend on) are not already destructed. 0082 * 0083 * @param TYPE The type of the global static object. Do not add a *. 0084 * @param NAME The name of the function to get a pointer to the global static object. 0085 * 0086 * If you have code that might be called after the global object has been destroyed you can check 0087 * for that using the isDestroyed() function. 0088 * 0089 * If needed (If the destructor of the global object calls other functions that depend on other 0090 * global statistics (e.g. KConfig::sync) your destructor has to be called before those global statistics 0091 * are destroyed. A Qt post routine does that.) you can also install a post routine (@ref qAddPostRoutine) to clean up the object 0092 * using the destroy() method. If you registered a post routine and the object is destroyed because 0093 * of a lib unload you have to call qRemovePostRoutine! 0094 * 0095 * Example: 0096 * @code 0097 * class A { 0098 * public: 0099 * ~A(); 0100 * ... 0101 * }; 0102 * 0103 * PHONON_GLOBAL_STATIC(A, globalA) 0104 * // The above creates a new globally static variable named 'globalA' which you 0105 * // can use as a pointer to an instance of A. 0106 * 0107 * void doSomething() 0108 * { 0109 * // The first time you access globalA a new instance of A will be created automatically. 0110 * A *a = globalA; 0111 * ... 0112 * } 0113 * 0114 * void doSomethingElse() 0115 * { 0116 * if (globalA.isDestroyed()) { 0117 * return; 0118 * } 0119 * A *a = globalA; 0120 * ... 0121 * } 0122 * 0123 * void installPostRoutine() 0124 * { 0125 * // A post routine can be used to delete the object when QCoreApplication destructs, 0126 * // not adding such a post routine will delete the object normally at program unload 0127 * qAddPostRoutine(globalA.destroy); 0128 * } 0129 * 0130 * A::~A() 0131 * { 0132 * // When you install a post routine you have to remove the post routine from the destructor of 0133 * // the class used as global static! 0134 * qRemovePostRoutine(globalA.destroy); 0135 * } 0136 * @endcode 0137 * 0138 * A common case for the need of deletion on lib unload/app shutdown are Singleton classes. Here's 0139 * an example how to do it: 0140 * @code 0141 * class MySingletonPrivate; 0142 * class EXPORT_MACRO MySingleton 0143 * { 0144 * friend class MySingletonPrivate; 0145 * public: 0146 * static MySingleton *self(); 0147 * QString someFunction(); 0148 * 0149 * private: 0150 * MySingleton(); 0151 * ~MySingleton(); 0152 * }; 0153 * @endcode 0154 * in the .cpp file: 0155 * @code 0156 * // This class will be instantiated and referenced as a singleton in this example 0157 * class MySingletonPrivate 0158 * { 0159 * public: 0160 * QString foo; 0161 * MySingleton instance; 0162 * }; 0163 * 0164 * PHONON_GLOBAL_STATIC(MySingletonPrivate, mySingletonPrivate) 0165 * 0166 * MySingleton *MySingleton::self() 0167 * { 0168 * // returns the singleton; automatically creates a new instance if that has not happened yet. 0169 * return &mySingletonPrivate->instance; 0170 * } 0171 * QString MySingleton::someFunction() 0172 * { 0173 * // Refencing the singleton directly is possible for your convenience 0174 * return mySingletonPrivate->foo; 0175 * } 0176 * @endcode 0177 * 0178 * Instead of the above you can use also the following pattern (ignore the name of the namespace): 0179 * @code 0180 * namespace MySingleton 0181 * { 0182 * EXPORT_MACRO QString someFunction(); 0183 * } 0184 * @endcode 0185 * in the .cpp file: 0186 * @code 0187 * class MySingletonPrivate 0188 * { 0189 * public: 0190 * QString foo; 0191 * }; 0192 * 0193 * PHONON_GLOBAL_STATIC(MySingletonPrivate, mySingletonPrivate) 0194 * 0195 * QString MySingleton::someFunction() 0196 * { 0197 * return mySingletonPrivate->foo; 0198 * } 0199 * @endcode 0200 * 0201 * Now code that wants to call someFunction() doesn't have to do 0202 * @code 0203 * MySingleton::self()->someFunction(); 0204 * @endcode 0205 * anymore but instead: 0206 * @code 0207 * MySingleton::someFunction(); 0208 * @endcode 0209 * 0210 * @ingroup KDEMacros 0211 */ 0212 #define PHONON_GLOBAL_STATIC(TYPE, NAME) PHONON_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ()) 0213 0214 /** 0215 * @overload 0216 * This is the same as PHONON_GLOBAL_STATIC, but can take arguments that are passed 0217 * to the object's constructor 0218 * 0219 * @param TYPE The type of the global static object. Do not add a *. 0220 * @param NAME The name of the function to get a pointer to the global static object. 0221 * @param ARGS the list of arguments, between brackets 0222 * 0223 * Example: 0224 * @code 0225 * class A 0226 * { 0227 * public: 0228 * A(const char *s, int i); 0229 * ... 0230 * }; 0231 * 0232 * PHONON_GLOBAL_STATIC_WITH_ARG(A, globalA, ("foo", 0)) 0233 * // The above creates a new globally static variable named 'globalA' which you 0234 * // can use as a pointer to an instance of A. 0235 * 0236 * void doSomething() 0237 * { 0238 * // The first time you access globalA a new instance of A will be created automatically. 0239 * A *a = globalA; 0240 * ... 0241 * } 0242 * @endcode 0243 * 0244 * @ingroup KDEMacros 0245 */ 0246 #define PHONON_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ 0247 static QBasicAtomicPointer<TYPE > _k_static_##NAME = Q_BASIC_ATOMIC_INITIALIZER(nullptr); \ 0248 static bool _k_static_##NAME##_destroyed; \ 0249 static struct PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME) \ 0250 { \ 0251 inline bool isDestroyed() const \ 0252 { \ 0253 return _k_static_##NAME##_destroyed; \ 0254 } \ 0255 inline bool exists() const \ 0256 { \ 0257 return _k_static_##NAME.loadRelaxed() != nullptr; \ 0258 } \ 0259 inline operator TYPE*() \ 0260 { \ 0261 return operator->(); \ 0262 } \ 0263 inline TYPE *operator->() \ 0264 { \ 0265 if (!_k_static_##NAME.loadRelaxed()) { \ 0266 if (isDestroyed()) { \ 0267 qFatal("Fatal Error: Accessed global static '%s *%s()' after destruction. " \ 0268 "Defined at %s:%d", #TYPE, #NAME, __FILE__, __LINE__); \ 0269 } \ 0270 TYPE *x = new TYPE ARGS; \ 0271 if (!_k_static_##NAME.testAndSetOrdered(nullptr, x) \ 0272 && _k_static_##NAME.loadRelaxed() != x ) { \ 0273 delete x; \ 0274 } else { \ 0275 static Phonon::CleanUpGlobalStatic cleanUpObject = { destroy }; \ 0276 } \ 0277 } \ 0278 return _k_static_##NAME.loadRelaxed(); \ 0279 } \ 0280 inline TYPE &operator*() \ 0281 { \ 0282 return *operator->(); \ 0283 } \ 0284 static void destroy() \ 0285 { \ 0286 _k_static_##NAME##_destroyed = true; \ 0287 TYPE *x = _k_static_##NAME.loadRelaxed(); \ 0288 _k_static_##NAME.storeRelaxed(nullptr); \ 0289 delete x; \ 0290 } \ 0291 } NAME; 0292 0293 #endif // PHONON_GLOBALSTATIC_P_H