File indexing completed on 2024-04-21 04:43:16

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