54 using Identifier =
const char*;
62 [[nodiscard]]
inline int getCounter()
const
74 inline void increaseCounter()
80 virtual ~FuncWrapperBase();
83 template<
typename T,
typename ... Args>
84 class FuncWrapper final
85 :
public FuncWrapperBase
88 const std::function<
T(Args ...)> mFunc;
91 explicit FuncWrapper(std::function<
T(Args ...)> pFunc)
92 : mFunc(std::move(pFunc))
97 T operator()(Args&& ... pArgs)
100 return mFunc(pArgs ...);
106 using Wrapper = QSharedPointer<FuncWrapperBase>;
107 QVector<Wrapper> mInstancesCreator;
108 QMap<Identifier, void*> mInstancesSingleton;
109 mutable QReadWriteLock mLock;
112 QPointer<QObjectCleanupHandler> mSingletonHandler;
113 QVector<std::function<
void* (bool)>> mSingletonCreator;
115 QMap<Identifier, QWeakPointer<QObject>> mSharedInstances;
116 mutable QReadWriteLock mSharedInstancesLock;
118 static Env& getInstance();
123 Q_ASSERT(!mSingletonHandler.isNull());
125 if (!QCoreApplication::startingUp() && !QCoreApplication::applicationName().startsWith(QLatin1String(
"Test_")))
127 Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String(
"MainThread"));
131 qDebug() <<
"Create singleton:" << T::staticMetaObject.className();
134 if constexpr (std::is_abstract_v<T> && std::is_destructible_v<T>)
136 ptr = createNewObject<T*>();
143 QObject::connect(ptr, &QObject::destroyed, ptr, [] {
144 qDebug() <<
"Destroy singleton:" << T::staticMetaObject.className();
146 mSingletonHandler->add(ptr);
147 mSingletonCreator << std::bind(&Env::getOrCreateSingleton<T>,
this, std::placeholders::_1);
154 T* getOrCreateSingleton(
bool pCreate =
false)
156 static QPointer<T> instance = createSingleton<T>();
158 if (Q_UNLIKELY(pCreate))
161 Q_ASSERT(instance.isNull());
162 instance = createSingleton<T>();
170 inline T* fetchRealSingleton()
172 if constexpr (QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value)
174 return getOrCreateSingleton<T>();
178 if constexpr (std::is_abstract_v<T> && std::is_destructible_v<T>)
180 static_assert(std::has_virtual_destructor_v<T>,
"Destructor must be virtual");
181 return singleton<T>();
185 return &T::getInstance();
192 inline std::enable_if_t<QtPrivate::IsGadgetHelper<T>::IsRealGadget,
T*> checkObjectInfo(Identifier pId,
T* pObject)
const
200 inline std::enable_if_t<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value,
T*> checkObjectInfo(Identifier pId,
T* pObject)
const
202 if (!std::is_base_of<ThreadSafe, T>() && pObject->thread() != QThread::currentThread())
204 qWarning() << pId <<
"was created in" << pObject->thread()->objectName() <<
"but is requested by" << QThread::currentThread()->objectName();
206 Q_ASSERT(QCoreApplication::applicationName().startsWith(QLatin1String(
"Test_global_Env")));
215 inline T* fetchSingleton()
217 static_assert(QtPrivate::IsGadgetHelper<T>::IsRealGadget || QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value,
218 "Singletons needs to be a Q_GADGET or an QObject/Q_OBJECT");
220 const Identifier
id = T::staticMetaObject.className();
223 const QReadLocker locker(&mLock);
224 obj = mInstancesSingleton.value(
id);
227 obj = fetchRealSingleton<T>();
229 return checkObjectInfo(
id,
static_cast<T*
>(obj));
233 template<
typename T,
typename ... Args>
234 inline T newObject(Args&& ... pArgs)
const
236 if constexpr (std::is_constructible_v<std::remove_pointer_t<T>, Args ...>)
238 if constexpr (std::is_pointer_v<T>)
240 using t = std::remove_pointer_t<T>;
241 return new t(std::forward<Args>(pArgs) ...);
245 return T(std::forward<Args>(pArgs) ...);
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) ...);
258 template<
typename T,
typename ... Args>
259 T createObject(Args&& ... pArgs)
const
263 QReadLocker locker(&mLock);
267 for (
auto mock : std::as_const(mInstancesCreator))
269 auto creator = mock.dynamicCast<FuncWrapper<
T, Args ...>>();
273 return (*creator)(std::forward<Args>(pArgs) ...);
279 return newObject<T>(std::forward<Args>(pArgs) ...);
285 Q_ASSERT(mSingletonHandler.isNull());
286 mSingletonHandler =
new QObjectCleanupHandler();
287 QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, mSingletonHandler.data(), &QObject::deleteLater);
289 const auto copy = mSingletonCreator;
290 mSingletonCreator.clear();
291 for (
const auto& func : copy)
304 getInstance().initialize();
311 return getInstance().fetchSingleton<
T>();
315 template<
typename T,
typename ... Args>
318 return getInstance().createObject<
T>(std::forward<Args>(pArgs) ...);
325 static_assert(QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value,
"Shared class needs to be an QObject/Q_OBJECT");
327 const Identifier className = T::staticMetaObject.className();
329 auto& holder = getInstance();
330 holder.mSharedInstancesLock.lockForRead();
331 QSharedPointer<T> shared = qSharedPointerCast<T>(holder.mSharedInstances.value(className));
332 holder.mSharedInstancesLock.unlock();
334 if (!shared && pSpawn)
336 const QWriteLocker locker(&holder.mSharedInstancesLock);
337 shared = qSharedPointerCast<T>(holder.mSharedInstances.value(className));
340 qDebug() <<
"Spawn shared instance:" << className;
341 shared = QSharedPointer<T>::create();
342 holder.mSharedInstances.insert(className, shared.toWeakRef());
353 static void set(
const QMetaObject& pMetaObject,
void* pObject =
nullptr);
355 template<
typename T,
typename ... Args>
358 auto& holder = getInstance();
359 const QReadLocker locker(&holder.mLock);
361 for (
const auto& mock : std::as_const(holder.mInstancesCreator))
363 if (mock.dynamicCast<FuncWrapper<T, Args ...>>())
365 return mock->getCounter();
373 template<
typename T,
typename ... Args>
378 const auto& value = QSharedPointer<FuncWrapper<
T, Args ...>>
::create(std::move(pFunc));
380 auto& holder = getInstance();
381 const QWriteLocker locker(&holder.mLock);
383 QMutableVectorIterator<Wrapper> iter(holder.mInstancesCreator);
384 while (iter.hasNext())
387 if (iter.value().dynamicCast<FuncWrapper<T, Args ...>>())
389 iter.setValue(value);
394 holder.mInstancesCreator << value;
398 static void setShared(
const QMetaObject& pMetaObject,
const QSharedPointer<QObject>& pObject);