summaryrefslogtreecommitdiffstats
path: root/core/singleton.h
blob: 9573b07e84310b32638f010c05b355ea19ee8ead (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// SPDX-License-Identifier: GPL-2.0
/*
 * We use singletons in numerous places. In combination with QML this gives
 * us a very fundamental problem, because QML likes to allocate objects by
 * itself. There are known workarounds, but currently we use idiosyncratic
 * singleton classes, which initialize the global instance pointer in the
 * constructor. Things get even more complicated if the same singleton is used
 * on mobile and on desktop. The latter might want to simply use the classical
 * instance() function without having to initialize the singleton first, as
 * that would beat the purpose of the instance() method.
 *
 * The template defined here, SillySingleton, codifies all this. Simply derive
 * a class from this template:
 *	class X : public SillySingleton<X> {
 *		...
 *	};
 * This will generate an instance() method. This will do the right thing for
 * both methods: explicit construction of the singleton via new or implicit
 * by calling the instance() method. It will also generate warnings if a
 * singleton class is generated more than once (i.e. first instance() is called
 * and _then_ new).
 *
 * In the long run we should get rid of all users of this class.
 */
#ifndef SINGLETON_H
#define SINGLETON_H

#include <typeinfo>
#include <QtGlobal>

// 1) Declaration
template<typename T>
class SillySingleton {
	static T *self;
protected:
	SillySingleton();
	~SillySingleton();
public:
	static T *instance();
};

template<typename T>
T *SillySingleton<T>::self = nullptr;

// 2) Implementation

template<typename T>
SillySingleton<T>::SillySingleton()
{
	if (self)
		qWarning("Generating second instance of singleton %s", typeid(T).name());
	self = static_cast<T *>(this);
	qDebug("Generated singleton %s", typeid(T).name());
}

template<typename T>
SillySingleton<T>::~SillySingleton()
{
	if (self == this)
		self = nullptr;
	else
		qWarning("Destroying unknown instance of singleton %s", typeid(T).name());
	qDebug("Destroyed singleton %s", typeid(T).name());
}

template<typename T>
T *SillySingleton<T>::instance()
{
	if (!self)
		new T;
	return self;
}

#endif