#pragma once #include #include #include #include #include namespace basiccoro { namespace detail { template class AwaiterBase { public: AwaiterBase(Event& event) : event_(event) {} bool await_ready() { if (event_.isSet()) { // unset already set event, then continue coroutine event_.isSet_ = false; return true; } return false; } void await_suspend(std::coroutine_handle<> handle) { event_.waiting_.push_back(handle); } typename Event::value_type await_resume() { if constexpr (!std::is_same_v) { if (!event_.result) { throw std::runtime_error("AwaiterBase: no value in event_.result"); } return *event_.result; } } private: Event& event_; }; class SingleEventBase { public: SingleEventBase() = default; SingleEventBase(const SingleEventBase&) = delete; SingleEventBase(SingleEventBase&&); SingleEventBase& operator=(const SingleEventBase&) = delete; SingleEventBase& operator=(SingleEventBase&&); ~SingleEventBase(); bool isSet() const { return isSet_; } protected: void set_common(); private: template friend class AwaiterBase; std::vector> waiting_; bool isSet_ = false; }; } // namespace detail template class SingleEvent : public detail::SingleEventBase { public: using value_type = T; using awaiter = detail::AwaiterBase>; void set(T t) { result = std::move(t); set_common(); } awaiter operator co_await() { return awaiter{*this}; } private: friend awaiter; std::optional result; }; template<> class SingleEvent : public detail::SingleEventBase { public: using value_type = void; using awaiter = detail::AwaiterBase>; void set() { set_common(); } awaiter operator co_await(); }; } // namespace basiccoro