18#include <QtCore/private/qohoslogger_p.h>
19#include <QtCore/qglobal.h>
20#include <QtCore/qlogging.h>
21#include <QtCore/qdebug.h>
29#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>
66template<
typename T,
typename Func>
69template<
typename T,
typename Func>
72template<
typename... Args>
78 F &&callable,
std::function<
void()> optOnDestroyedWithoutCall,
79 std::string callerContextName = {});
93 template<
typename... ContextNames>
104 virtual ~Callable() =
default;
105 virtual void call(Args &&...args) = 0;
108 template<
typename Func>
109 class CallableImpl :
public Callable
113 explicit CallableImpl(F &&f);
115 void call(Args &&...args)
override;
121 struct TrackingUsageState
124 std::size_t activeCount,
125 std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall);
127 std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall;
129 std::size_t activeCount = 1;
135 std::string callerContext,
std::shared_ptr<TrackingNode> optParent,
136 std::shared_ptr<TrackingUsageState> usage);
138 void markUsed(
const char *callerContextString);
139 std::string rootCallerContextOrUnknown()
const;
140 void logCallerContextChainAsErrors(
const char *messagePrefix)
const;
142 std::string callerContext;
143 std::shared_ptr<TrackingNode> optParent;
144 std::shared_ptr<TrackingUsageState> usage;
147 QOhosTaskPromise(
std::shared_ptr<Callable> callable,
std::shared_ptr<TrackingNode> tracking);
149 std::shared_ptr<Callable> m_callable;
150 std::shared_ptr<TrackingNode> m_tracking;
153template<
typename Func, Func func>
161 const char *
name()
const;
169 const char *m_funcName;
172template<
typename Func, Func func>
181 template<
typename ...Ts>
182 void operator()(
const Ts &...)
const;
185template<
typename ...Ts>
202 template<
typename ProcessFunc>
205 template<
typename EvalFunc>
206 auto evalWithValue(EvalFunc &&evalFunc)
const ->
decltype(evalFunc(
std::declval<
const T &>()));
209 mutable std::mutex m_valueMutex;
219template<
typename Signature>
224 std::shared_ptr<T> baseSharedPtr,
std::shared_ptr<
void> extraData);
233template<
typename T,
typename Func>
237 qohoscommon_p_h_detail::isStdOptional<QOhosInvokeResult<Func, T>>,
238 "func must return a std::optional");
239 return opt.has_value() ? func(*opt) : QOhosInvokeResult<Func, T>();
242template<
typename T,
typename Func>
245 using TransformedT = std::remove_cv_t<QOhosInvokeResult<Func, T>>;
246 return opt.has_value()
247 ? std::optional<TransformedT>(func(*opt))
248 : std::optional<TransformedT>();
251template<
typename Func, Func func>
252QOhosNamedFunc<Func, func>::QOhosNamedFunc(
const char *funcName)
253 : m_funcName(funcName)
257template<
typename Func, Func func>
258const char *QOhosNamedFunc<Func, func>::name()
const
263template<
typename Func, Func func>
264Func QOhosNamedFunc<Func, func>::ptr()
const
269template<
typename Func, Func func>
270QOhosNamedFunc<Func, func>::operator Func ()
const
275template<
typename ...Ts>
280template<
typename ...Ts>
283 return [](
const Ts &...) {
296template<
typename ProcessFunc>
299 std::lock_guard<
std::mutex> valueLock(m_valueMutex);
300 std::forward<ProcessFunc>(processFunc)(m_value);
304template<
typename EvalFunc>
307 std::lock_guard<
std::mutex> valueLock(m_valueMutex);
308 return std::forward<EvalFunc>(evalFunc)(m_value);
316 return std::make_shared<T>(
std::forward<T>(obj));
319template<
typename Signature>
322 return std::make_shared<
std::function<Signature>>(std::exchange(func,
nullptr));
327 std::shared_ptr<T> baseSharedPtr,
std::shared_ptr<
void> extraData)
329 auto *baseRawPtr = baseSharedPtr.get();
330 return std::shared_ptr<T>(
333 std::move(baseSharedPtr),
334 std::move(extraData))),
346 class DestroyNotifier
349 explicit DestroyNotifier(
std::function<
void()> callOnDestroy)
350 : callOnDestroy(std::move(callOnDestroy))
354 DestroyNotifier(
const DestroyNotifier &) =
delete;
355 DestroyNotifier(DestroyNotifier &&) =
delete;
356 DestroyNotifier &operator=(
const DestroyNotifier &) =
delete;
357 DestroyNotifier &operator=(DestroyNotifier &&) =
delete;
365 std::function<
void()> callOnDestroy;
368 return std::make_shared<DestroyNotifier>(
std::move(callOnDestroy));
373template<
typename... Args>
374template<
typename F,
typename>
376 F &&callable,
std::function<
void()> optOnDestroyedWithoutCall,
std::string callerContextName)
379 std::make_shared<TrackingNode>(
380 std::move(callerContextName),
nullptr,
381 std::make_shared<TrackingUsageState>(
384 optOnDestroyedWithoutCall
385 ? std::move(optOnDestroyedWithoutCall)
386 : makeQOhosNoOpConsumer<>()))))
390template<
typename... Args>
393 if (!m_tracking || m_tracking->usage->used)
396 --m_tracking->usage->activeCount;
398 if (m_tracking->usage->activeCount == 0) {
399 m_tracking->logCallerContextChainAsErrors(Q_FUNC_INFO);
401 "%s: promise destroyed without notifying the caller: %s",
402 Q_FUNC_INFO, m_tracking->rootCallerContextOrUnknown().c_str());
403 (*m_tracking->usage->onDestroyedWithoutCall)();
407template<
typename... Args>
409 std::shared_ptr<Callable> callable,
std::shared_ptr<TrackingNode> tracking)
410 : m_callable(
std::move(callable))
411 , m_tracking(
std::move(tracking))
415template<
typename... Args>
424 m_tracking->markUsed(Q_FUNC_INFO);
426 m_callable->call(
std::forward<Args>(args)...);
429template<
typename... Args>
432 const auto funcInfo = Q_FUNC_INFO;
440 m_tracking->markUsed(funcInfo);
442 auto callable =
std::move(m_callable);
443 auto tracking =
std::move(m_tracking);
445 auto sharedCalledFlag =
std::make_shared<
bool>(
false);
446 auto destroyNotifier = QtOhos::makeDestroyNotifier(
447 [sharedCalledFlag, tracking, funcInfo]() {
448 if (!*sharedCalledFlag) {
449 tracking->logCallerContextChainAsErrors(funcInfo);
451 "%s: promise (as std::function) destroyed without notifying the caller: %s",
452 funcInfo, tracking->rootCallerContextOrUnknown().c_str());
453 (*tracking->usage->onDestroyedWithoutCall)();
457 return [callable, sharedCalledFlag, tracking, funcInfo, destroyNotifier](Args... args) {
458 if (*sharedCalledFlag) {
460 "%s: promise (as std::function) called more than once for: %s",
461 funcInfo, tracking->rootCallerContextOrUnknown().c_str());
463 *sharedCalledFlag =
true;
464 callable->call(
std::forward<Args>(args)...);
468template<
typename... Args>
474 m_tracking->markUsed(Q_FUNC_INFO);
476 auto newUsage =
std::make_shared<TrackingUsageState>(1, m_tracking->usage->onDestroyedWithoutCall);
479 std::move(m_callable),
480 std::make_shared<TrackingNode>(
481 std::move(callerContextName),
std::move(m_tracking), newUsage));
484template<
typename... Args>
485template<
typename... ContextNames>
492 m_tracking->markUsed(Q_FUNC_INFO);
494 auto sharedUsage =
std::make_shared<TrackingUsageState>(
495 sizeof...(ContextNames), m_tracking->usage->onDestroyedWithoutCall);
499 std::make_shared<TrackingNode>(
500 std::forward<ContextNames>(branchContextNames),
501 m_tracking, sharedUsage))...
505template<
typename... Args>
509 auto branches =
std::move(*
this).makeChained(
std::move(callerContextName)).makeBranched(
"then",
"catch");
510 return {
std::move(branches[0]),
std::move(branches[1])};
513template<
typename... Args>
514template<
typename Func>
517 : m_func(
std::forward<F>(f))
521template<
typename... Args>
522template<
typename Func>
525 m_func(
std::forward<Args>(args)...);
528template<
typename... Args>
530 std::size_t activeCount,
std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall)
531 : onDestroyedWithoutCall(onDestroyedWithoutCall)
532 , activeCount(activeCount)
536template<
typename... Args>
538 std::string callerContext,
std::shared_ptr<TrackingNode> optParent,
539 std::shared_ptr<TrackingUsageState> usage)
540 : callerContext(
std::move(callerContext))
541 , optParent(
std::move(optParent))
542 , usage(
std::move(usage))
546template<
typename... Args>
547void QOhosTaskPromise<Args...>::TrackingNode::markUsed(
const char *callerContextString)
550 logCallerContextChainAsErrors(callerContextString);
552 "%s: using a dead promise branch (%s) from this caller: %s",
553 callerContextString, callerContext.c_str(), rootCallerContextOrUnknown().c_str());
558template<
typename... Args>
561 const TrackingNode *rootContextNode =
nullptr;
562 for (
auto currentNode =
this; currentNode !=
nullptr; currentNode = currentNode->optParent.get()) {
563 if (!currentNode->callerContext.empty())
564 rootContextNode = currentNode;
566 return rootContextNode !=
nullptr ? rootContextNode->callerContext :
"<unknown>";
569template<
typename... Args>
570void QOhosTaskPromise<Args...>::TrackingNode::logCallerContextChainAsErrors(
const char *messagePrefix)
const
573 for (
auto currentNode =
this; currentNode; currentNode = currentNode->optParent.get()) {
574 if (!currentNode->callerContext.empty()) {
576 "%s [caller context #%d]: %s",
577 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< std::function< Signature > > takeFunctionToSharedPtr(std::function< Signature > &func)
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)
constexpr bool isStdOptional
QOhosInvokeResult< Func, T > qAndThen(const std::optional< T > &opt, Func &&func)
#define qOhosReportFatalErrorAndAbort(...)
std::optional< std::remove_cv_t< QOhosInvokeResult< Func, T > > > qTransform(const std::optional< T > &opt, Func &&func)
QOhosNoOpConsumer makeQOhosNoOpConsumer()
std::function< T()> QOhosSupplier
std::function< void(Ts...)> QOhosConsumer
QOhosConsumer< Ts... > makeQOhosNoOpConsumer()
QOhosNamedFunc< Func, func > makeQOhosNamedFunc(const char *funcName)