Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-12 09:21:48

0001 // Copyright (C) 2018 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 // Qt-Security score:significant reason:default
0004 
0005 #ifndef QTESTSUPPORT_CORE_H
0006 #define QTESTSUPPORT_CORE_H
0007 
0008 #include <QtCore/qcoreapplication.h>
0009 #include <QtCore/qdeadlinetimer.h>
0010 
0011 #include <chrono>
0012 
0013 QT_BEGIN_NAMESPACE
0014 
0015 namespace QTest {
0016 
0017 Q_CORE_EXPORT void qSleep(int ms);
0018 Q_CORE_EXPORT void qSleep(std::chrono::milliseconds msecs);
0019 
0020 extern Q_CORE_EXPORT std::atomic<std::chrono::milliseconds> defaultTryTimeout;
0021 
0022 namespace Internal {
0023 enum class WaitForResult {
0024     Failed = -1,
0025     NotYet = 0,
0026     Done = 1,
0027 };
0028 
0029 inline bool waitForMore(bool) { return true; }
0030 inline bool waitForMore(WaitForResult value) { return value == WaitForResult::NotYet; }
0031 
0032 inline bool waitForSucceeded(bool value) { return value; }
0033 inline bool waitForSucceeded(WaitForResult value) { return value >= WaitForResult::Done; }
0034 }
0035 
0036 template <typename Functor>
0037 [[nodiscard]] bool
0038 qWaitFor(Functor predicate, QDeadlineTimer deadline = QDeadlineTimer(
0039     defaultTryTimeout.load(std::memory_order_relaxed)))
0040 {
0041     using Internal::waitForMore; // customization point
0042     using Internal::waitForSucceeded; // customization point
0043 
0044     // We should not spin the event loop in case the predicate is already true,
0045     // otherwise we might send new events that invalidate the predicate.
0046     if (waitForSucceeded(predicate()))
0047         return true;
0048 
0049     // qWait() is expected to spin the event loop at least once, even when
0050     // called with a small timeout like 1ns.
0051 
0052     do {
0053         // We explicitly do not pass the remaining time to processEvents, as
0054         // that would keep spinning processEvents for the whole duration if
0055         // new events were posted as part of processing events, and we need
0056         // to return back to this function to check the predicate between
0057         // each pass of processEvents. Our own timer will take care of the
0058         // timeout.
0059         QCoreApplication::processEvents(QEventLoop::AllEvents);
0060         QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
0061 
0062         if (auto predresult = predicate(); waitForSucceeded(predresult))
0063             return true;
0064         else if (!waitForMore(predresult))
0065             return false;
0066 
0067         using namespace std::chrono;
0068 
0069         if (const auto remaining = deadline.remainingTimeAsDuration(); remaining > 0ns)
0070             qSleep((std::min)(10ms, ceil<milliseconds>(remaining)));
0071 
0072     } while (!deadline.hasExpired());
0073 
0074     return waitForSucceeded(predicate()); // Last chance
0075 }
0076 
0077 template <typename Functor>
0078 [[nodiscard]] bool qWaitFor(Functor predicate, int timeout)
0079 {
0080     return qWaitFor(predicate, QDeadlineTimer{timeout, Qt::PreciseTimer});
0081 }
0082 
0083 Q_CORE_EXPORT void qWait(int ms);
0084 
0085 Q_CORE_EXPORT void qWait(std::chrono::milliseconds msecs);
0086 
0087 } // namespace QTest
0088 
0089 QT_END_NAMESPACE
0090 
0091 #endif