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;
220 std::shared_ptr<T> baseSharedPtr,
std::shared_ptr<
void> extraData);
229template<
typename T,
typename Func>
233 qohoscommon_p_h_detail::isStdOptional<QOhosInvokeResult<Func, T>>,
234 "func must return a std::optional");
235 return opt.has_value() ? func(*opt) : QOhosInvokeResult<Func, T>();
238template<
typename T,
typename Func>
241 using TransformedT = std::remove_cv_t<QOhosInvokeResult<Func, T>>;
242 return opt.has_value()
243 ? std::optional<TransformedT>(func(*opt))
244 : std::optional<TransformedT>();
247template<
typename Func, Func func>
248QOhosNamedFunc<Func, func>::QOhosNamedFunc(
const char *funcName)
249 : m_funcName(funcName)
253template<
typename Func, Func func>
254const char *QOhosNamedFunc<Func, func>::name()
const
259template<
typename Func, Func func>
260Func QOhosNamedFunc<Func, func>::ptr()
const
265template<
typename Func, Func func>
266QOhosNamedFunc<Func, func>::operator Func ()
const
271template<
typename ...Ts>
276template<
typename ...Ts>
279 return [](
const Ts &...) {
292template<
typename ProcessFunc>
295 std::lock_guard<
std::mutex> valueLock(m_valueMutex);
296 std::forward<ProcessFunc>(processFunc)(m_value);
300template<
typename EvalFunc>
303 std::lock_guard<
std::mutex> valueLock(m_valueMutex);
304 return std::forward<EvalFunc>(evalFunc)(m_value);
312 return std::make_shared<T>(
std::forward<T>(obj));
317 std::shared_ptr<T> baseSharedPtr,
std::shared_ptr<
void> extraData)
319 auto *baseRawPtr = baseSharedPtr.get();
320 return std::shared_ptr<T>(
323 std::move(baseSharedPtr),
324 std::move(extraData))),
336 class DestroyNotifier
339 explicit DestroyNotifier(
std::function<
void()> callOnDestroy)
340 : callOnDestroy(std::move(callOnDestroy))
344 DestroyNotifier(
const DestroyNotifier &) =
delete;
345 DestroyNotifier(DestroyNotifier &&) =
delete;
346 DestroyNotifier &operator=(
const DestroyNotifier &) =
delete;
347 DestroyNotifier &operator=(DestroyNotifier &&) =
delete;
355 std::function<
void()> callOnDestroy;
358 return std::make_shared<DestroyNotifier>(
std::move(callOnDestroy));
363template<
typename... Args>
364template<
typename F,
typename>
366 F &&callable,
std::function<
void()> optOnDestroyedWithoutCall,
std::string callerContextName)
369 std::make_shared<TrackingNode>(
370 std::move(callerContextName),
nullptr,
371 std::make_shared<TrackingUsageState>(
374 optOnDestroyedWithoutCall
375 ? std::move(optOnDestroyedWithoutCall)
376 : makeQOhosNoOpConsumer<>()))))
380template<
typename... Args>
383 if (!m_tracking || m_tracking->usage->used)
386 --m_tracking->usage->activeCount;
388 if (m_tracking->usage->activeCount == 0) {
389 m_tracking->logCallerContextChainAsErrors(Q_FUNC_INFO);
391 "%s: promise destroyed without notifying the caller: %s",
392 Q_FUNC_INFO, m_tracking->rootCallerContextOrUnknown().c_str());
393 (*m_tracking->usage->onDestroyedWithoutCall)();
397template<
typename... Args>
399 std::shared_ptr<Callable> callable,
std::shared_ptr<TrackingNode> tracking)
400 : m_callable(
std::move(callable))
401 , m_tracking(
std::move(tracking))
405template<
typename... Args>
414 m_tracking->markUsed(Q_FUNC_INFO);
416 m_callable->call(
std::forward<Args>(args)...);
419template<
typename... Args>
422 const auto funcInfo = Q_FUNC_INFO;
430 m_tracking->markUsed(funcInfo);
432 auto callable =
std::move(m_callable);
433 auto tracking =
std::move(m_tracking);
435 auto sharedCalledFlag =
std::make_shared<
bool>(
false);
436 auto destroyNotifier = QtOhos::makeDestroyNotifier(
437 [sharedCalledFlag, tracking, funcInfo]() {
438 if (!*sharedCalledFlag) {
439 tracking->logCallerContextChainAsErrors(funcInfo);
441 "%s: promise (as std::function) destroyed without notifying the caller: %s",
442 funcInfo, tracking->rootCallerContextOrUnknown().c_str());
443 (*tracking->usage->onDestroyedWithoutCall)();
447 return [callable, sharedCalledFlag, tracking, funcInfo, destroyNotifier](Args... args) {
448 if (*sharedCalledFlag) {
450 "%s: promise (as std::function) called more than once for: %s",
451 funcInfo, tracking->rootCallerContextOrUnknown().c_str());
453 *sharedCalledFlag =
true;
454 callable->call(
std::forward<Args>(args)...);
458template<
typename... Args>
464 m_tracking->markUsed(Q_FUNC_INFO);
466 auto newUsage =
std::make_shared<TrackingUsageState>(1, m_tracking->usage->onDestroyedWithoutCall);
469 std::move(m_callable),
470 std::make_shared<TrackingNode>(
471 std::move(callerContextName),
std::move(m_tracking), newUsage));
474template<
typename... Args>
475template<
typename... ContextNames>
482 m_tracking->markUsed(Q_FUNC_INFO);
484 auto sharedUsage =
std::make_shared<TrackingUsageState>(
485 sizeof...(ContextNames), m_tracking->usage->onDestroyedWithoutCall);
489 std::make_shared<TrackingNode>(
490 std::forward<ContextNames>(branchContextNames),
491 m_tracking, sharedUsage))...
495template<
typename... Args>
499 auto branches =
std::move(*
this).makeChained(
std::move(callerContextName)).makeBranched(
"then",
"catch");
500 return {
std::move(branches[0]),
std::move(branches[1])};
503template<
typename... Args>
504template<
typename Func>
507 : m_func(
std::forward<F>(f))
511template<
typename... Args>
512template<
typename Func>
515 m_func(
std::forward<Args>(args)...);
518template<
typename... Args>
520 std::size_t activeCount,
std::shared_ptr<
std::function<
void()>> onDestroyedWithoutCall)
521 : onDestroyedWithoutCall(onDestroyedWithoutCall)
522 , activeCount(activeCount)
526template<
typename... Args>
528 std::string callerContext,
std::shared_ptr<TrackingNode> optParent,
529 std::shared_ptr<TrackingUsageState> usage)
530 : callerContext(
std::move(callerContext))
531 , optParent(
std::move(optParent))
532 , usage(
std::move(usage))
536template<
typename... Args>
537void QOhosTaskPromise<Args...>::TrackingNode::markUsed(
const char *callerContextString)
540 logCallerContextChainAsErrors(callerContextString);
542 "%s: using a dead promise branch (%s) from this caller: %s",
543 callerContextString, callerContext.c_str(), rootCallerContextOrUnknown().c_str());
548template<
typename... Args>
551 const TrackingNode *rootContextNode =
nullptr;
552 for (
auto currentNode =
this; currentNode !=
nullptr; currentNode = currentNode->optParent.get()) {
553 if (!currentNode->callerContext.empty())
554 rootContextNode = currentNode;
556 return rootContextNode !=
nullptr ? rootContextNode->callerContext :
"<unknown>";
559template<
typename... Args>
560void QOhosTaskPromise<Args...>::TrackingNode::logCallerContextChainAsErrors(
const char *messagePrefix)
const
563 for (
auto currentNode =
this; currentNode; currentNode = currentNode->optParent.get()) {
564 if (!currentNode->callerContext.empty()) {
566 "%s [caller context #%d]: %s",
567 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)
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)