AusweisApp
Lade ...
Suche ...
Keine Treffer
Env.h
gehe zur Dokumentation dieser Datei
1
5#pragma once
6
7#include <functional>
8#include <type_traits>
9
10#include <QCoreApplication>
11#include <QDebug>
12#include <QMap>
13#include <QMetaObject>
14#include <QMetaType>
15#include <QObject>
16#include <QObjectCleanupHandler>
17#include <QPointer>
18#include <QReadLocker>
19#include <QReadWriteLock>
20#include <QSharedPointer>
21#include <QThread>
22#include <QWeakPointer>
23#include <QWriteLocker>
24
25#ifndef QT_NO_DEBUG
26 #include <QList>
27#endif
28
29
30class test_Env;
31
32
33namespace governikus
34{
35
36template<typename T> T* singleton();
37template<typename T, typename ... Args> T createNewObject(Args && ... pArgs);
38
39class Env
40{
41 Q_DISABLE_COPY(Env)
42 friend class ::test_Env;
43
44 public:
45 struct ThreadSafe {};
46
47 private:
48 using Identifier = const char*;
49
50#ifndef QT_NO_DEBUG
51 class FuncWrapperBase
52 {
53 int mCounter = 0;
54
55 public:
56 [[nodiscard]] inline int getCounter() const
57 {
58 return mCounter;
59 }
60
61
62 inline void reset()
63 {
64 mCounter = 0;
65 }
66
67
68 inline void increaseCounter()
69 {
70 ++mCounter;
71 }
72
73
74 virtual ~FuncWrapperBase();
75 };
76
77 template<typename T, typename ... Args>
78 class FuncWrapper final
79 : public FuncWrapperBase
80 {
81 private:
82 const std::function<T(Args ...)> mFunc;
83
84 public:
85 explicit FuncWrapper(std::function<T(Args ...)> pFunc)
86 : mFunc(std::move(pFunc))
87 {
88 }
89
90
91 T operator()(Args&& ... pArgs)
92 {
93 increaseCounter();
94 return mFunc(pArgs ...);
95 }
96
97
98 };
99
100 using Wrapper = QSharedPointer<FuncWrapperBase>;
101 QList<Wrapper> mInstancesCreator;
102 QMap<Identifier, void*> mInstancesSingleton;
103 mutable QReadWriteLock mLock;
104#endif
105
106 QPointer<QObjectCleanupHandler> mSingletonHandler;
107 QList<std::function<void* (bool)>> mSingletonCreator;
108
109 QMap<Identifier, QWeakPointer<QObject>> mSharedInstances;
110 mutable QReadWriteLock mSharedInstancesLock;
111
112 static Env& getInstance();
113
114 template<typename T>
115 T* createSingleton()
116 {
117 Q_ASSERT(!mSingletonHandler.isNull());
118#ifndef QT_NO_DEBUG
119 if (!QCoreApplication::startingUp() && !QCoreApplication::applicationName().startsWith(QLatin1String("Test_")))
120 {
121 Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("MainThread"));
122 }
123#endif
124
125 qDebug() << "Create singleton:" << T::staticMetaObject.className();
126
127 T* ptr = nullptr;
128 if constexpr (std::is_abstract_v<T>&& std::is_destructible_v<T>)
129 {
130 ptr = createNewObject<T*>();
131 }
132 else
133 {
134 ptr = new T();
135 }
136
137 QObject::connect(ptr, &QObject::destroyed, ptr, [] {
138 qDebug() << "Destroy singleton:" << T::staticMetaObject.className();
139 });
140 mSingletonHandler->add(ptr);
141 mSingletonCreator << std::bind(&Env::getOrCreateSingleton<T>, this, std::placeholders::_1);
142
143 return ptr;
144 }
145
146
147 template<typename T>
148 T* getOrCreateSingleton(bool pCreate = false)
149 {
150 static QPointer<T> instance = createSingleton<T>();
151
152 if (Q_UNLIKELY(pCreate))
153 {
154 // It's not thread-safe! So Env::init() should be the only one!
155 Q_ASSERT(instance.isNull());
156 instance = createSingleton<T>();
157 }
158
159 return instance;
160 }
161
162
163 template<typename T>
164 inline T* fetchRealSingleton()
165 {
166 if constexpr (QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value)
167 {
168 return getOrCreateSingleton<T>();
169 }
170 else
171 {
172 if constexpr (std::is_abstract_v<T>&& std::is_destructible_v<T>)
173 {
174 static_assert(std::has_virtual_destructor_v<T>, "Destructor must be virtual");
175 return singleton<T>();
176 }
177 else
178 {
179 return &T::getInstance();
180 }
181 }
182 }
183
184
185 template<typename T>
186 inline T* checkObjectInfo(Identifier pId, T* pObject) const
187 {
188 static_assert(QtPrivate::IsGadgetHelper<T>::IsRealGadget || QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value,
189 "Object needs to be a Q_GADGET or an QObject/Q_OBJECT");
190
191 if constexpr (QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value)
192 {
193 if (!std::is_base_of<ThreadSafe, T>() && pObject->thread() != QThread::currentThread())
194 {
195 qWarning() << pId << "was created in" << pObject->thread()->objectName() << "but is requested by" << QThread::currentThread()->objectName();
196#ifndef QT_NO_DEBUG
197 Q_ASSERT(QCoreApplication::applicationName().startsWith(QLatin1String("Test_global_Env")));
198#endif
199 }
200 }
201
202 return pObject;
203 }
204
205
206 template<typename T>
207 inline T* fetchSingleton()
208 {
209 static_assert(QtPrivate::IsGadgetHelper<T>::IsRealGadget || QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value,
210 "Singletons needs to be a Q_GADGET or an QObject/Q_OBJECT");
211
212 const Identifier id = T::staticMetaObject.className();
213 void* obj = nullptr;
214#ifndef QT_NO_DEBUG
215 const QReadLocker locker(&mLock);
216 obj = mInstancesSingleton.value(id);
217 if (!obj)
218#endif
219 obj = fetchRealSingleton<T>();
220 Q_ASSERT(obj);
221 return checkObjectInfo(id, static_cast<T*>(obj));
222 }
223
224
225 template<typename T, typename ... Args>
226 inline T newObject(Args&& ... pArgs) const
227 {
228 if constexpr (std::is_constructible_v<std::remove_pointer_t<T>, Args ...>)
229 {
230 if constexpr (std::is_pointer_v<T>)
231 {
232 using t = std::remove_pointer_t<T>;
233 return new t(std::forward<Args>(pArgs) ...);
234 }
235 else
236 {
237 return T(std::forward<Args>(pArgs) ...);
238 }
239 }
240 else
241 {
242 static_assert(std::is_pointer_v<T>, "It is impossible to return implementation of interface by value. Use pointer or add constructor!");
243 auto obj = createNewObject<T>(std::forward<Args>(pArgs) ...);
244 Q_ASSERT(obj);
245 return obj;
246 }
247 }
248
249
250 template<typename T, typename ... Args>
251 T createObject(Args&& ... pArgs) const
252 {
253#ifndef QT_NO_DEBUG
254 {
255 QReadLocker locker(&mLock);
256
257 // copy QSharedPointer "mock" to increase ref-counter. Otherwise
258 // unlock would allow to delete the wrapper.
259 for (auto mock : std::as_const(mInstancesCreator)) // clazy:exclude=range-loop,range-loop-reference
260 {
261 auto creator = mock.dynamicCast<FuncWrapper<T, Args ...>>();
262 if (creator)
263 {
264 locker.unlock();
265 return (*creator)(std::forward<Args>(pArgs) ...);
266 }
267 }
268 }
269#endif
270
271 return newObject<T>(std::forward<Args>(pArgs) ...);
272 }
273
274
275 void initialize()
276 {
277 Q_ASSERT(mSingletonHandler.isNull());
278 mSingletonHandler = new QObjectCleanupHandler();
279 QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, mSingletonHandler.data(), &QObject::deleteLater);
280
281 const auto copy = mSingletonCreator;
282 mSingletonCreator.clear();
283 for (const auto& func : copy)
284 {
285 func(true);
286 }
287 }
288
289 protected:
290 Env();
291 ~Env() = default;
292
293 public:
294 static void init()
295 {
296 getInstance().initialize();
297 }
298
299
300 template<typename T>
301 static T* getSingleton()
302 {
303 return getInstance().fetchSingleton<T>();
304 }
305
306
307 template<typename T, typename ... Args>
308 static T create(Args&& ... pArgs)
309 {
310 return getInstance().createObject<T>(std::forward<Args>(pArgs) ...);
311 }
312
313
314 template<typename T>
315 static QSharedPointer<T> getShared(bool pSpawn = true)
316 {
317 static_assert(QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, "Shared class needs to be an QObject/Q_OBJECT");
318
319 const Identifier className = T::staticMetaObject.className();
320
321 auto& holder = getInstance();
322 holder.mSharedInstancesLock.lockForRead();
323 QSharedPointer<T> shared = qSharedPointerCast<T>(holder.mSharedInstances.value(className));
324 holder.mSharedInstancesLock.unlock();
325
326 if (!shared && pSpawn)
327 {
328 const QWriteLocker locker(&holder.mSharedInstancesLock);
329 shared = qSharedPointerCast<T>(holder.mSharedInstances.value(className));
330 if (!shared)
331 {
332 qDebug() << "Spawn shared instance:" << className;
333 shared = QSharedPointer<T>::create();
334 holder.mSharedInstances.insert(className, shared.toWeakRef());
335 }
336 }
337
338 return shared;
339 }
340
341
342#ifndef QT_NO_DEBUG
343 static void resetCounter();
344 static void clear();
345 static void set(const QMetaObject& pMetaObject, void* pObject = nullptr);
346
347 template<typename T, typename ... Args>
348 static int getCounter()
349 {
350 auto& holder = getInstance();
351 const QReadLocker locker(&holder.mLock);
352
353 for (const auto& mock : std::as_const(holder.mInstancesCreator))
354 {
355 if (mock.dynamicCast<FuncWrapper<T, Args ...>>())
356 {
357 return mock->getCounter();
358 }
359 }
360
361 return -1; // There is no mock... use setCreator!
362 }
363
364
365 template<typename T, typename ... Args>
366 static void setCreator(std::function<T(Args ...)> pFunc)
367 {
368 Q_ASSERT(pFunc);
369
370 const auto& value = QSharedPointer<FuncWrapper<T, Args ...>>::create(std::move(pFunc));
371
372 auto& holder = getInstance();
373 const QWriteLocker locker(&holder.mLock);
374
375 QMutableListIterator<Wrapper> iter(holder.mInstancesCreator);
376 while (iter.hasNext())
377 {
378 iter.next();
379 if (iter.value().dynamicCast<FuncWrapper<T, Args ...>>())
380 {
381 iter.setValue(value);
382 return;
383 }
384 }
385
386 holder.mInstancesCreator << value;
387 }
388
389
390 static void setShared(const QMetaObject& pMetaObject, const QSharedPointer<QObject>& pObject);
391#endif
392
393};
394
395} // namespace governikus
Definition Env.h:40
static void setCreator(std::function< T(Args ...)> pFunc)
Definition Env.h:366
friend class ::test_Env
Definition Env.h:42
static int getCounter()
Definition Env.h:348
static void set(const QMetaObject &pMetaObject, void *pObject=nullptr)
Definition Env.cpp:59
static void clear()
Definition Env.cpp:46
Env()
Definition Env.cpp:27
static T * getSingleton()
Definition Env.h:301
static void resetCounter()
Definition Env.cpp:37
static T create(Args &&... pArgs)
Definition Env.h:308
static void init()
Definition Env.h:294
~Env()=default
static QSharedPointer< T > getShared(bool pSpawn=true)
Definition Env.h:315
static void setShared(const QMetaObject &pMetaObject, const QSharedPointer< QObject > &pObject)
Definition Env.cpp:80
#define T(v)
Definition http_parser.cpp:237
Defines the AccessRight and AccessRole enum.
Definition CommandApdu.h:17
T * singleton()
T createNewObject(Args &&... pArgs)
Definition Env.h:45