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
34#define Q_OHOS_NAMED_FUNC(func) (QT_PREPEND_NAMESPACE(makeQOhosNamedFunc)<decltype(func)*, func>)(QT_STRINGIFY(func))
36#define qOhosReportFatalErrorAndAbort(...)
38 QT_PREPEND_NAMESPACE(QMessageLogger)(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).fatal(__VA_ARGS__);
44template<
typename Func,
typename... FuncArgs>
45using QOhosInvokeResult =
decltype(std::declval<Func>()(std::declval<FuncArgs>()...));
47template<
typename ...Ts>
53template<
typename... Args>
59 F &&callable,
std::function<
void()> optOnDestroyedWithoutCall,
60 std::string callerContextName = {});
74 template<
typename... ContextNames>
85 virtual ~Callable() =
default;
86 virtual void call(Args &&...args) = 0;
89 template<
typename Func>
90 class CallableImpl :
public Callable
94 explicit CallableImpl(F &&f);
96 void call(Args &&...args)
override;
102 struct TrackingUsageState
105 std::size_t activeCount,
106 std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall);
108 std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall;
110 std::size_t activeCount = 1;
116 std::string callerContext,
std::shared_ptr<TrackingNode> optParent,
117 std::shared_ptr<TrackingUsageState> usage);
119 void markUsed(
const char *callerContextString);
120 std::string rootCallerContextOrUnknown()
const;
121 void logCallerContextChainAsErrors(
const char *messagePrefix)
const;
123 std::string callerContext;
124 std::shared_ptr<TrackingNode> optParent;
125 std::shared_ptr<TrackingUsageState> usage;
128 QOhosTaskPromise(
std::shared_ptr<Callable> callable,
std::shared_ptr<TrackingNode> tracking);
130 std::shared_ptr<Callable> m_callable;
131 std::shared_ptr<TrackingNode> m_tracking;
134template<
typename Func, Func func>
142 const char *
name()
const;
150 const char *m_funcName;
153template<
typename Func, Func func>
162 template<
typename ...Ts>
163 void operator()(
const Ts &...)
const;
166template<
typename ...Ts>
183 template<
typename ProcessFunc>
186 template<
typename EvalFunc>
187 auto evalWithValue(EvalFunc &&evalFunc)
const ->
decltype(evalFunc(
std::declval<
const T &>()));
190 mutable std::mutex m_valueMutex;
201 std::shared_ptr<T> baseSharedPtr,
std::shared_ptr<
void> extraData);
210template<
typename Func, Func func>
211QOhosNamedFunc<Func, func>::QOhosNamedFunc(
const char *funcName)
212 : m_funcName(funcName)
216template<
typename Func, Func func>
217const char *QOhosNamedFunc<Func, func>::name()
const
222template<
typename Func, Func func>
223Func QOhosNamedFunc<Func, func>::ptr()
const
228template<
typename Func, Func func>
229QOhosNamedFunc<Func, func>::operator Func ()
const
234template<
typename ...Ts>
239template<
typename ...Ts>
242 return [](
const Ts &...) {
255template<
typename ProcessFunc>
258 std::lock_guard<
std::mutex> valueLock(m_valueMutex);
259 std::forward<ProcessFunc>(processFunc)(m_value);
263template<
typename EvalFunc>
266 std::lock_guard<
std::mutex> valueLock(m_valueMutex);
267 return std::forward<EvalFunc>(evalFunc)(m_value);
275 return std::make_shared<T>(
std::forward<T>(obj));
280 std::shared_ptr<T> baseSharedPtr,
std::shared_ptr<
void> extraData)
282 auto *baseRawPtr = baseSharedPtr.get();
283 return std::shared_ptr<T>(
286 std::move(baseSharedPtr),
287 std::move(extraData))),
299 class DestroyNotifier
302 explicit DestroyNotifier(
std::function<
void()> callOnDestroy)
303 : callOnDestroy(std::move(callOnDestroy))
307 DestroyNotifier(
const DestroyNotifier &) =
delete;
308 DestroyNotifier(DestroyNotifier &&) =
delete;
309 DestroyNotifier &operator=(
const DestroyNotifier &) =
delete;
310 DestroyNotifier &operator=(DestroyNotifier &&) =
delete;
318 std::function<
void()> callOnDestroy;
321 return std::make_shared<DestroyNotifier>(
std::move(callOnDestroy));
326template<
typename... Args>
327template<
typename F,
typename>
329 F &&callable,
std::function<
void()> optOnDestroyedWithoutCall,
std::string callerContextName)
332 std::make_shared<TrackingNode>(
333 std::move(callerContextName),
nullptr,
334 std::make_shared<TrackingUsageState>(
337 optOnDestroyedWithoutCall
338 ? std::move(optOnDestroyedWithoutCall)
339 : makeQOhosNoOpConsumer<>()))))
343template<
typename... Args>
346 if (!m_tracking || m_tracking->usage->used)
349 --m_tracking->usage->activeCount;
351 if (m_tracking->usage->activeCount == 0) {
352 m_tracking->logCallerContextChainAsErrors(Q_FUNC_INFO);
354 "%s: promise destroyed without notifying the caller: %s",
355 Q_FUNC_INFO, m_tracking->rootCallerContextOrUnknown().c_str());
356 (*m_tracking->usage->onDestroyedWithoutCall)();
360template<
typename... Args>
362 std::shared_ptr<Callable> callable,
std::shared_ptr<TrackingNode> tracking)
363 : m_callable(
std::move(callable))
364 , m_tracking(
std::move(tracking))
368template<
typename... Args>
377 m_tracking->markUsed(Q_FUNC_INFO);
379 m_callable->call(
std::forward<Args>(args)...);
382template<
typename... Args>
385 const auto funcInfo = Q_FUNC_INFO;
393 m_tracking->markUsed(funcInfo);
395 auto callable =
std::move(m_callable);
396 auto tracking =
std::move(m_tracking);
398 auto sharedCalledFlag =
std::make_shared<
bool>(
false);
399 auto destroyNotifier = QtOhos::makeDestroyNotifier(
400 [sharedCalledFlag, tracking, funcInfo]() {
401 if (!*sharedCalledFlag) {
402 tracking->logCallerContextChainAsErrors(funcInfo);
404 "%s: promise (as std::function) destroyed without notifying the caller: %s",
405 funcInfo, tracking->rootCallerContextOrUnknown().c_str());
406 (*tracking->usage->onDestroyedWithoutCall)();
410 return [callable, sharedCalledFlag, tracking, funcInfo, destroyNotifier](Args... args) {
411 if (*sharedCalledFlag) {
413 "%s: promise (as std::function) called more than once for: %s",
414 funcInfo, tracking->rootCallerContextOrUnknown().c_str());
416 *sharedCalledFlag =
true;
417 callable->call(
std::forward<Args>(args)...);
421template<
typename... Args>
427 m_tracking->markUsed(Q_FUNC_INFO);
429 auto newUsage =
std::make_shared<TrackingUsageState>(1, m_tracking->usage->onDestroyedWithoutCall);
432 std::move(m_callable),
433 std::make_shared<TrackingNode>(
434 std::move(callerContextName),
std::move(m_tracking), newUsage));
437template<
typename... Args>
438template<
typename... ContextNames>
445 m_tracking->markUsed(Q_FUNC_INFO);
447 auto sharedUsage =
std::make_shared<TrackingUsageState>(
448 sizeof...(ContextNames), m_tracking->usage->onDestroyedWithoutCall);
452 std::make_shared<TrackingNode>(
453 std::forward<ContextNames>(branchContextNames),
454 m_tracking, sharedUsage))...
458template<
typename... Args>
462 auto branches =
std::move(*
this).makeChained(
std::move(callerContextName)).makeBranched(
"then",
"catch");
463 return {
std::move(branches[0]),
std::move(branches[1])};
466template<
typename... Args>
467template<
typename Func>
470 : m_func(
std::forward<F>(f))
474template<
typename... Args>
475template<
typename Func>
478 m_func(
std::forward<Args>(args)...);
481template<
typename... Args>
483 std::size_t activeCount,
std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall)
484 : onDestroyedWithoutCall(onDestroyedWithoutCall)
485 , activeCount(activeCount)
489template<
typename... Args>
491 std::string callerContext,
std::shared_ptr<TrackingNode> optParent,
492 std::shared_ptr<TrackingUsageState> usage)
493 : callerContext(
std::move(callerContext))
494 , optParent(
std::move(optParent))
495 , usage(
std::move(usage))
499template<
typename... Args>
500void QOhosTaskPromise<Args...>::TrackingNode::markUsed(
const char *callerContextString)
503 logCallerContextChainAsErrors(callerContextString);
505 "%s: using a dead promise branch (%s) from this caller: %s",
506 callerContextString, callerContext.c_str(), rootCallerContextOrUnknown().c_str());
511template<
typename... Args>
514 const TrackingNode *rootContextNode =
nullptr;
515 for (
auto currentNode =
this; currentNode !=
nullptr; currentNode = currentNode->optParent.get()) {
516 if (!currentNode->callerContext.empty())
517 rootContextNode = currentNode;
519 return rootContextNode !=
nullptr ? rootContextNode->callerContext :
"<unknown>";
522template<
typename... Args>
523void QOhosTaskPromise<Args...>::TrackingNode::logCallerContextChainAsErrors(
const char *messagePrefix)
const
526 for (
auto currentNode =
this; currentNode; currentNode = currentNode->optParent.get()) {
527 if (!currentNode->callerContext.empty()) {
529 "%s [caller context #%d]: %s",
530 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)