aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/utils/singleton.h
blob: db114e4d48397ace700a32e75667de7ca586c467 (plain)
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
75
76
77
78
79
80
81
82
83
84
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#pragma once

#include "utils_global.h"

#include <QMutex>
#include <QMutexLocker>

#include <type_traits>
#include <typeindex>

namespace Utils {

class Singleton;

struct SingletonStaticData
{
    Singleton *m_instance = nullptr;
    QMutex m_mutex;
};

class QTCREATOR_UTILS_EXPORT Singleton
{
    Q_DISABLE_COPY_MOVE(Singleton)
public:
    static void deleteAll();

private:
    template <typename SingletonSubClass, typename ...Dependencies>
    friend class SingletonWithOptionalDependencies;

    Singleton() = default;
    virtual ~Singleton();
    static void addSingleton(Singleton *singleton);
    static SingletonStaticData &staticData(std::type_index index);
};

template <typename SingletonSubClass, typename ...Dependencies>
class SingletonWithOptionalDependencies : public Singleton
{
public:
    Q_DISABLE_COPY_MOVE(SingletonWithOptionalDependencies)
    static SingletonSubClass *instance()
    {
        SingletonStaticData &data = staticData();
        QMutexLocker locker(&data.m_mutex);
        if (data.m_instance == nullptr) {
            // instantiate all dependencies first
            if constexpr (sizeof...(Dependencies))
                instantiateDependencies<Dependencies...>();
            data.m_instance = new SingletonSubClass;
            // put instance into static list of registered instances
            addSingleton(data.m_instance);
        }
        return static_cast<SingletonSubClass *>(data.m_instance);
    }

protected:
    SingletonWithOptionalDependencies() = default;
    ~SingletonWithOptionalDependencies() override
    {
        SingletonStaticData &data = staticData();
        QMutexLocker locker(&data.m_mutex);
        if (data.m_instance == this)
            data.m_instance = nullptr;
    }

private:
    template <typename ...Dependency> static void instantiateDependencies()
    {
        static_assert ((... && std::is_base_of_v<Singleton, Dependency>),
                "All Dependencies must derive from SingletonWithOptionalDependencies class.");
        (..., Dependency::instance());
    }
    static SingletonStaticData &staticData()
    {
        static SingletonStaticData &data = Singleton::staticData(std::type_index(typeid(SingletonSubClass)));
        return data;
    }
};

} // namespace Utils