18class ConditionVariable {
20 ConditionVariable& cv;
21 bool (*pred)(Waiter&);
23 std::coroutine_handle<> handle;
24 std::shared_ptr<data::CancellableCallback> timer;
28 Waiter(ConditionVariable& cv,
bool (*pred)(Waiter&)) noexcept : cv(cv), pred(pred) {}
32 std::lock_guard lock{cv.mutex};
34 if (timer) timer->cancel();
38 bool satisfied() {
return pred && pred(*
this); }
41 std::unique_lock lock{cv.mutex};
42 bool linked = is_linked();
47 if (linked) handle.resume();
50 bool suspend(std::coroutine_handle<> h, std::optional<Duration> dur) {
52 if (dur) timer = exec->executeAfter([
this] { onTimeout(); }, *dur);
53 std::lock_guard lock{cv.mutex};
54 if (fired)
return false;
55 if (satisfied() && (!timer || timer->cancel()))
return false;
56 cv.waiters.push_back(*
this);
62 class Awaiter : Waiter {
63 static constexpr bool hasPred = !std::is_same_v<Pred, std::monostate>;
65 std::optional<Duration> dur;
66 LL_NO_UNIQUE_ADDRESS Pred pred;
68 static bool test(Waiter& w) {
69 if constexpr (hasPred)
return std::invoke(
static_cast<Awaiter&
>(w).pred);
74 Awaiter(ConditionVariable& cv, Pred pred, std::optional<Duration> dur)
75 : Waiter(cv, hasPred ? &test :
nullptr),
77 pred(std::move(pred)) {}
79 void setExecutor(ExecutorRef ex) { this->exec = ex; }
82 if (this->satisfied())
return true;
83 if (!dur || *dur > Duration{0})
return false;
87 bool await_suspend(std::coroutine_handle<> h) {
return this->suspend(h, dur); }
88 bool await_resume()
const noexcept {
return this->result; }
95 auto make(Pred&& pred, std::optional<Duration> dur = {}) {
96 return Awaiter<std::decay_t<Pred>>{*
this, std::forward<Pred>(pred), dur};
99 size_t notify(
size_t limit,
bool inplace) {
103 std::lock_guard lock{mutex};
104 for (
auto it = waiters.begin(); it != waiters.end() && count < limit;) {
107 if (w.pred && !w.pred(w))
continue;
108 if (w.timer && !w.timer->cancel())
continue;
113 while (!woken.empty()) {
114 auto& w = woken.front();
116 if (inplace) w.handle.resume();
117 else w.exec->execute(w.handle);
123 ConditionVariable() =
default;
125 ConditionVariable(ConditionVariable
const&) =
delete;
126 ConditionVariable& operator=(ConditionVariable
const&) =
delete;
128 [[nodiscard]]
auto wait() {
return make(std::monostate{}); }
130 template <std::predicate Pred>
131 [[nodiscard]]
auto wait(Pred&& pred) {
132 return make(std::forward<Pred>(pred));
135 template <
class R,
class P>
136 [[nodiscard]]
auto waitFor(std::chrono::duration<R, P> dur) {
137 return make(std::monostate{}, std::chrono::duration_cast<Duration>(dur));
140 template <
class R,
class P, std::predicate Pred>
141 [[nodiscard]]
auto waitFor(std::chrono::duration<R, P> dur, Pred&& pred) {
142 return make(std::forward<Pred>(pred), std::chrono::duration_cast<Duration>(dur));
145 template <
class C,
class D,
class... Pred>
146 [[nodiscard]]
auto waitUntil(std::chrono::time_point<C, D> time, Pred&&... pred) {
147 return waitFor(time - C::now(), std::forward<Pred>(pred)...);
150 bool notifyOne(
bool inplace =
false) {
return notify(1, inplace) != 0; }
152 size_t notifyAll(
bool inplace =
false) {
return notify(std::numeric_limits<size_t>::max(), inplace); }