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