qa: Replace deprecated qVariantFromValue() by QVariant::fromValue()
[quassel.git] / src / common / singleton.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2019 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #pragma once
22
23 #include <iostream>
24
25 // For Windows DLLs, we must not export the template function.
26 // For other systems, we must, otherwise the local static variables won't work across library boundaries...
27 #ifndef Q_OS_WIN
28 #    include "common-export.h"
29 #    define QUASSEL_SINGLETON_EXPORT COMMON_EXPORT
30 #else
31 #    define QUASSEL_SINGLETON_EXPORT
32 #endif
33
34 namespace detail {
35
36 // This needs to be a free function instead of a member function of Singleton, because
37 // - MSVC can't deal with static attributes in an exported template class
38 // - Clang produces weird and unreliable results for local static variables in static member functions
39 //
40 // We need to export the function on anything not using Windows DLLs, otherwise local static members don't
41 // work across library boundaries.
42 template<typename T>
43 QUASSEL_SINGLETON_EXPORT T* getOrSetInstance(T* instance = nullptr, bool destroyed = false)
44 {
45     static T* _instance = instance;
46     static bool _destroyed = destroyed;
47
48     if (destroyed) {
49         _destroyed = true;
50         return _instance = nullptr;
51     }
52     if (instance) {
53         if (_destroyed) {
54             std::cerr << "Trying to reinstantiate a destroyed singleton, this must not happen!\n";
55             abort();  // This produces a backtrace, which is highly useful for finding the culprit
56         }
57         if (_instance != instance) {
58             std::cerr << "Trying to reinstantiate a singleton that is already instantiated, this must not happen!\n";
59             abort();
60         }
61     }
62     if (!_instance) {
63         std::cerr << "Trying to access a singleton that has not been instantiated yet!\n";
64         abort();
65     }
66     return _instance;
67 }
68
69 }  // detail
70
71 /**
72  * Mixin class for "pseudo" singletons.
73  *
74  * Classes inheriting from this mixin become "pseudo" singletons that can still be constructed
75  * and destroyed in a controlled manner, but also gain an instance() method for static access.
76  * This is very similar to the behavior of e.g. QCoreApplication.
77  *
78  * The mixin protects against multiple instantiation, use-before-instantiation and use-after-destruction
79  * by aborting the program. This is intended to find lifetime issues during development; abort()
80  * produces a backtrace that makes it easy to find the culprit.
81  *
82  * The Curiously Recurring Template Pattern (CRTP) is used for the mixin to be able to provide a
83  * correctly typed instance pointer.
84  */
85 template<typename T>
86 class Singleton
87 {
88 public:
89     /**
90      * Constructs the mixin.
91      *
92      * The constructor can only be called once; subsequent invocations abort the program.
93      *
94      * @param instance Pointer to the instance being created, i.e. the 'this' pointer of the parent class
95      */
96     Singleton(T* instance)
97     {
98         detail::getOrSetInstance<T>(instance);
99     }
100
101     // Satisfy Rule of Five
102     Singleton(const Singleton&) = delete;
103     Singleton(Singleton&&) = delete;
104     Singleton& operator=(const Singleton&) = delete;
105     Singleton& operator=(Singleton&&) = delete;
106
107     /**
108      * Destructor.
109      *
110      * Sets the instance pointer to null and flags the destruction, so a subsequent reinstantiation will fail.
111      */
112     ~Singleton()
113     {
114         detail::getOrSetInstance<T>(nullptr, true);
115     }
116
117     /**
118      * Accesses the instance pointer.
119      *
120      * If the singleton hasn't been instantiated yet, the program is aborted. No lazy instantiation takes place,
121      * because the singleton's lifetime shall be explicitly controlled.
122      *
123      * @returns A pointer to the instance
124      */
125     static T* instance()
126     {
127         return detail::getOrSetInstance<T>();
128     }
129 };