// examples/demo_scope.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef INCLUDED_EXAMPLES_DEMO_SCOPE #define INCLUDED_EXAMPLES_DEMO_SCOPE #include #include #include #include // ---------------------------------------------------------------------------- namespace demo { namespace ex = ::beman::net29::detail::ex; class scope { private: static constexpr bool log_completions{false}; struct env { scope* self; auto query(ex::get_stop_token_t) const noexcept { return this->self->source.get_token(); } }; struct job_base { virtual ~job_base() = default; }; struct receiver { using receiver_concept = ex::receiver_t; scope* self; job_base* state{}; auto set_error(auto&&) noexcept -> void { ::std::cerr << "ERROR: demo::scope::job in scope completed with error!\n"; this->complete(); } auto set_value() && noexcept -> void { if (log_completions) std::cout << "demo::scope::set_value()\n"; this->complete(); } auto set_stopped() && noexcept -> void { if (log_completions) std::cout << "demo::scope::set_stopped()\n"; this->complete(); } auto complete() -> void { scope* self{this->self}; delete this->state; if (0u == --self->count) { self->complete(); } } auto get_env() const noexcept -> env { return {this->self}; } }; template struct job : job_base { using state_t = decltype(ex::connect(std::declval(), std::declval())); state_t state; template job(scope* self, S&& sender) : state(ex::connect(::std::forward(sender), receiver{self, this})) { ex::start(this->state); } }; std::atomic count{}; ex::inplace_stop_source source; auto complete() -> void {} public: ~scope() { if (0u < this->count) std::cerr << "ERROR: scope destroyed with live jobs: " << this->count << "\n"; } template auto spawn(Sender&& sender) { ++this->count; new job(this, std::forward(sender)); } auto stop() { this->source.request_stop(); } }; } // ---------------------------------------------------------------------------- #endif