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