18#include <QtCore/private/qohoslogger_p.h>
19#include <QtCore/qglobal.h>
20#include <QtCore/qlogging.h>
21#include <QtCore/qdebug.h>
28#ifndef QT_NO_EXCEPTIONS
33#define Q_OHOS_NAMED_FUNC(func) (QT_PREPEND_NAMESPACE(makeQOhosNamedFunc)<decltype(func)*, func>)(QT_STRINGIFY(func))
35#define qOhosReportFatalErrorAndAbort(...)
37 QT_PREPEND_NAMESPACE(QMessageLogger)(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).fatal(__VA_ARGS__);
43template<
typename Func,
typename... FuncArgs>
44using QOhosInvokeResult =
decltype(std::declval<Func>()(std::declval<FuncArgs>()...));
46template<
typename ...Ts>
52template<
typename... Args>
58 F &&callable,
std::function<
void()> optOnDestroyedWithoutCall,
59 std::string callerContextName = {});
73 template<
typename... ContextNames>
84 virtual ~Callable() =
default;
85 virtual void call(Args &&...args) = 0;
88 template<
typename Func>
89 class CallableImpl :
public Callable
93 explicit CallableImpl(F &&f);
95 void call(Args &&...args)
override;
101 struct TrackingUsageState
104 std::size_t activeCount,
105 std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall);
107 std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall;
109 std::size_t activeCount = 1;
115 std::string callerContext,
std::shared_ptr<TrackingNode> optParent,
116 std::shared_ptr<TrackingUsageState> usage);
118 void markUsed(
const char *callerContextString);
119 std::string rootCallerContextOrUnknown()
const;
120 void logCallerContextChainAsErrors(
const char *messagePrefix)
const;
122 std::string callerContext;
123 std::shared_ptr<TrackingNode> optParent;
124 std::shared_ptr<TrackingUsageState> usage;
127 QOhosTaskPromise(
std::shared_ptr<Callable> callable,
std::shared_ptr<TrackingNode> tracking);
129 std::shared_ptr<Callable> m_callable;
130 std::shared_ptr<TrackingNode> m_tracking;
133template<
typename Func, Func func>
141 const char *
name()
const;
149 const char *m_funcName;
152template<
typename Func, Func func>
161 template<
typename ...Ts>
162 void operator()(
const Ts &...)
const;
165template<
typename ...Ts>
182 template<
typename ProcessFunc>
185 template<
typename EvalFunc>
186 auto evalWithValue(EvalFunc &&evalFunc)
const ->
decltype(evalFunc(
std::declval<
const T &>()));
189 mutable std::mutex m_valueMutex;
200 std::shared_ptr<T> baseSharedPtr,
std::shared_ptr<
void> extraData);
209template<
typename Func, Func func>
210QOhosNamedFunc<Func, func>::QOhosNamedFunc(
const char *funcName)
211 : m_funcName(funcName)
215template<
typename Func, Func func>
216const char *QOhosNamedFunc<Func, func>::name()
const
221template<
typename Func, Func func>
222Func QOhosNamedFunc<Func, func>::ptr()
const
227template<
typename Func, Func func>
228QOhosNamedFunc<Func, func>::operator Func ()
const
233template<
typename ...Ts>
238template<
typename ...Ts>
241 return [](
const Ts &...) {
254template<
typename ProcessFunc>
257 std::lock_guard<
std::mutex> valueLock(m_valueMutex);
258 std::forward<ProcessFunc>(processFunc)(m_value);
262template<
typename EvalFunc>
265 std::lock_guard<
std::mutex> valueLock(m_valueMutex);
266 return std::forward<EvalFunc>(evalFunc)(m_value);
274 return std::make_shared<T>(
std::forward<T>(obj));
279 std::shared_ptr<T> baseSharedPtr,
std::shared_ptr<
void> extraData)
281 auto *baseRawPtr = baseSharedPtr.get();
282 return std::shared_ptr<T>(
285 std::move(baseSharedPtr),
286 std::move(extraData))),
298 class DestroyNotifier
301 explicit DestroyNotifier(
std::function<
void()> callOnDestroy)
302 : callOnDestroy(std::move(callOnDestroy))
306 DestroyNotifier(
const DestroyNotifier &) =
delete;
307 DestroyNotifier(DestroyNotifier &&) =
delete;
308 DestroyNotifier &operator=(
const DestroyNotifier &) =
delete;
309 DestroyNotifier &operator=(DestroyNotifier &&) =
delete;
317 std::function<
void()> callOnDestroy;
320 return std::make_shared<DestroyNotifier>(
std::move(callOnDestroy));
325template<
typename... Args>
326template<
typename F,
typename>
328 F &&callable,
std::function<
void()> optOnDestroyedWithoutCall,
std::string callerContextName)
331 std::make_shared<TrackingNode>(
332 std::move(callerContextName),
nullptr,
333 std::make_shared<TrackingUsageState>(
336 optOnDestroyedWithoutCall
337 ? std::move(optOnDestroyedWithoutCall)
338 : makeQOhosNoOpConsumer<>()))))
342template<
typename... Args>
345 if (!m_tracking || m_tracking->usage->used)
348 --m_tracking->usage->activeCount;
350 if (m_tracking->usage->activeCount == 0) {
351 m_tracking->logCallerContextChainAsErrors(Q_FUNC_INFO);
353 "%s: promise destroyed without notifying the caller: %s",
354 Q_FUNC_INFO, m_tracking->rootCallerContextOrUnknown().c_str());
355 (*m_tracking->usage->onDestroyedWithoutCall)();
359template<
typename... Args>
361 std::shared_ptr<Callable> callable,
std::shared_ptr<TrackingNode> tracking)
362 : m_callable(
std::move(callable))
363 , m_tracking(
std::move(tracking))
367template<
typename... Args>
376 m_tracking->markUsed(Q_FUNC_INFO);
378 m_callable->call(
std::forward<Args>(args)...);
381template<
typename... Args>
384 const auto funcInfo = Q_FUNC_INFO;
392 m_tracking->markUsed(funcInfo);
394 auto callable =
std::move(m_callable);
395 auto tracking =
std::move(m_tracking);
397 auto sharedCalledFlag =
std::make_shared<
bool>(
false);
398 auto destroyNotifier = QtOhos::makeDestroyNotifier(
399 [sharedCalledFlag, tracking, funcInfo]() {
400 if (!*sharedCalledFlag) {
401 tracking->logCallerContextChainAsErrors(funcInfo);
403 "%s: promise (as std::function) destroyed without notifying the caller: %s",
404 funcInfo, tracking->rootCallerContextOrUnknown().c_str());
405 (*tracking->usage->onDestroyedWithoutCall)();
409 return [callable, sharedCalledFlag, tracking, funcInfo, destroyNotifier](Args... args) {
410 if (*sharedCalledFlag) {
412 "%s: promise (as std::function) called more than once for: %s",
413 funcInfo, tracking->rootCallerContextOrUnknown().c_str());
415 *sharedCalledFlag =
true;
416 callable->call(
std::forward<Args>(args)...);
420template<
typename... Args>
426 m_tracking->markUsed(Q_FUNC_INFO);
428 auto newUsage =
std::make_shared<TrackingUsageState>(1, m_tracking->usage->onDestroyedWithoutCall);
431 std::move(m_callable),
432 std::make_shared<TrackingNode>(
433 std::move(callerContextName),
std::move(m_tracking), newUsage));
436template<
typename... Args>
437template<
typename... ContextNames>
444 m_tracking->markUsed(Q_FUNC_INFO);
446 auto sharedUsage =
std::make_shared<TrackingUsageState>(
447 sizeof...(ContextNames), m_tracking->usage->onDestroyedWithoutCall);
451 std::make_shared<TrackingNode>(
452 std::forward<ContextNames>(branchContextNames),
453 m_tracking, sharedUsage))...
457template<
typename... Args>
461 auto branches =
std::move(*
this).makeChained(
std::move(callerContextName)).makeBranched(
"then",
"catch");
462 return {
std::move(branches[0]),
std::move(branches[1])};
465template<
typename... Args>
466template<
typename Func>
469 : m_func(
std::forward<F>(f))
473template<
typename... Args>
474template<
typename Func>
477 m_func(
std::forward<Args>(args)...);
480template<
typename... Args>
482 std::size_t activeCount,
std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall)
483 : onDestroyedWithoutCall(onDestroyedWithoutCall)
484 , activeCount(activeCount)
488template<
typename... Args>
490 std::string callerContext,
std::shared_ptr<TrackingNode> optParent,
491 std::shared_ptr<TrackingUsageState> usage)
492 : callerContext(
std::move(callerContext))
493 , optParent(
std::move(optParent))
494 , usage(
std::move(usage))
498template<
typename... Args>
499void QOhosTaskPromise<Args...>::TrackingNode::markUsed(
const char *callerContextString)
502 logCallerContextChainAsErrors(callerContextString);
504 "%s: using a dead promise branch (%s) from this caller: %s",
505 callerContextString, callerContext.c_str(), rootCallerContextOrUnknown().c_str());
510template<
typename... Args>
513 const TrackingNode *rootContextNode =
nullptr;
514 for (
auto currentNode =
this; currentNode !=
nullptr; currentNode = currentNode->optParent.get()) {
515 if (!currentNode->callerContext.empty())
516 rootContextNode = currentNode;
518 return rootContextNode !=
nullptr ? rootContextNode->callerContext :
"<unknown>";
521template<
typename... Args>
522void QOhosTaskPromise<Args...>::TrackingNode::logCallerContextChainAsErrors(
const char *messagePrefix)
const
525 for (
auto currentNode =
this; currentNode; currentNode = currentNode->optParent.get()) {
526 if (!currentNode->callerContext.empty()) {
528 "%s [caller context #%d]: %s",
529 messagePrefix, index, currentNode->callerContext.c_str());
auto evalWithValue(EvalFunc &&evalFunc) const -> decltype(evalFunc(std::declval< const T & >()))
QOhosMutexProtectedValue()
QOhosMutexProtectedValue & operator=(const QOhosMutexProtectedValue< T > &other)=delete
void processValue(ProcessFunc &&processFunc)
QOhosMutexProtectedValue & operator=(QOhosMutexProtectedValue< T > &&other)=delete
QOhosMutexProtectedValue(const QOhosMutexProtectedValue< T > &other)=delete
QOhosMutexProtectedValue(QOhosMutexProtectedValue< T > &&other)=delete
QOhosNamedFunc(const char *funcName)
const char * name() const
static constexpr Func funcPtr
void operator()(const Ts &...) const
std::array< QOhosTaskPromise, sizeof...(ContextNames)> makeBranched(ContextNames &&...branchContextNames) &&
void operator()(Args... args) const
QOhosTaskPromise(F &&callable, std::function< void()> optOnDestroyedWithoutCall, std::string callerContextName={})
QOhosTaskPromise makeChained(std::string callerContextName) &&
operator std::function< void(Args...)>() &&
QOhosTaskPromise & operator=(const QOhosTaskPromise &)=delete
QOhosTaskPromise & operator=(QOhosTaskPromise &&)=default
std::pair< QOhosTaskPromise, QOhosTaskPromise > makeThenCatchBranches(std::string callerContextName) &&
QOhosTaskPromise(const QOhosTaskPromise &)=delete
QOhosTaskPromise(QOhosTaskPromise &&)=default
std::shared_ptr< T > makeSharedPtrWithAttachedExtraData(std::shared_ptr< T > baseSharedPtr, std::shared_ptr< void > extraData)
std::shared_ptr< T > moveToSharedPtr(T &&obj)
std::weak_ptr< T > makeWeakPtr(const std::shared_ptr< T > &obj)
std::shared_ptr< void > makeDestroyNotifier(std::function< void()> callOnDestroy)
#define qOhosReportFatalErrorAndAbort(...)
QOhosNoOpConsumer makeQOhosNoOpConsumer()
std::function< T()> QOhosSupplier
std::function< void(Ts...)> QOhosConsumer
QOhosConsumer< Ts... > makeQOhosNoOpConsumer()
QOhosNamedFunc< Func, func > makeQOhosNamedFunc(const char *funcName)