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