123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- // Copyright (c) 2022 Klemens D. Morgenstern
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_COBALT_THIS_CORO_HPP
- #define BOOST_COBALT_THIS_CORO_HPP
- #include <boost/cobalt/this_thread.hpp>
- #include <boost/cobalt/detail/this_thread.hpp>
- #include <boost/asio/associated_allocator.hpp>
- #include <boost/asio/associated_cancellation_slot.hpp>
- #include <boost/asio/associated_executor.hpp>
- #include <boost/asio/this_coro.hpp>
- #include <boost/asio/cancellation_state.hpp>
- #include <coroutine>
- #include <optional>
- #include <tuple>
- namespace boost::cobalt
- {
- namespace this_coro
- {
- /* tag::outline[]
- // Awaitable type that returns the executor of the current coroutine.
- struct executor_t {}
- constexpr executor_t executor;
- // Awaitable type that returns the cancellation state of the current coroutine.
- struct cancellation_state_t {};
- constexpr cancellation_state_t cancellation_state;
- // Reset the cancellation state with custom or default filters.
- constexpr __unspecified__ reset_cancellation_state();
- template<typename Filter>
- constexpr __unspecified__ reset_cancellation_state(
- Filter && filter);
- template<typename InFilter, typename OutFilter>
- constexpr __unspecified__ reset_cancellation_state(
- InFilter && in_filter,
- OutFilter && out_filter);
- // get & set the throw_if_cancelled setting.
- __unspecified__ throw_if_cancelled();
- __unspecified__ throw_if_cancelled(bool value);
- // Set the cancellation source in a detached.
- __unspecified__ reset_cancellation_source();
- __unspecified__ reset_cancellation_source(asio::cancellation_slot slot);
- end::outline[]
- */
- using namespace asio::this_coro;
- //tag::outline[]
- // get the allocator the promise
- struct allocator_t {};
- constexpr allocator_t allocator;
- // get the current cancellation state-type
- struct cancelled_t {};
- constexpr cancelled_t cancelled;
- // set the over-eager mode of a generator
- struct initial_t {};
- constexpr initial_t initial;
- //end::outline[]
- template<typename CancellationSlot = asio::cancellation_slot>
- struct reset_cancellation_source_t
- {
- CancellationSlot source;
- };
- template<typename CancellationSlot= asio::cancellation_slot>
- reset_cancellation_source_t<CancellationSlot> reset_cancellation_source(CancellationSlot slot = {})
- {
- return reset_cancellation_source_t<CancellationSlot>{std::move(slot)};
- }
- }
- template<typename CancellationSlot = asio::cancellation_slot,
- typename DefaultFilter = asio::enable_terminal_cancellation>
- struct promise_cancellation_base
- {
- using cancellation_slot_type = asio::cancellation_slot;
- cancellation_slot_type get_cancellation_slot() const {return state_.slot();}
- template<typename InitialFilter = asio::enable_terminal_cancellation>
- promise_cancellation_base(CancellationSlot slot = {}, InitialFilter filter = {})
- : source_(slot), state_{source_, filter} {}
- // This await transformation resets the associated cancellation state.
- auto await_transform(cobalt::this_coro::cancelled_t) noexcept
- {
- return cancelled_t_awaitable{state_.cancelled()};
- }
- // This await transformation resets the associated cancellation state.
- auto await_transform(asio::this_coro::cancellation_state_t) noexcept
- {
- return cancellation_state_t_awaitable{state_};
- }
- // This await transformation resets the associated cancellation state.
- auto await_transform(asio::this_coro::reset_cancellation_state_0_t) noexcept
- {
- return reset_cancellation_state_0_t_awaitable{state_, source_};
- }
- // This await transformation resets the associated cancellation state.
- template <typename Filter>
- auto await_transform(
- asio::this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept
- {
- return reset_cancellation_state_1_t_awaitable<Filter>{state_, BOOST_ASIO_MOVE_CAST(Filter)(reset.filter), source_};
- }
- // This await transformation resets the associated cancellation state.
- template <typename InFilter, typename OutFilter>
- auto await_transform(
- asio::this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset)
- noexcept
- {
- return reset_cancellation_state_2_t_awaitable<InFilter, OutFilter>{state_,
- BOOST_ASIO_MOVE_CAST(InFilter)(reset.in_filter),
- BOOST_ASIO_MOVE_CAST(OutFilter)(reset.out_filter),
- source_};
- }
- const asio::cancellation_state & cancellation_state() const {return state_;}
- asio::cancellation_state & cancellation_state() {return state_;}
- asio::cancellation_type cancelled() const
- {
- return state_.cancelled();
- }
- cancellation_slot_type get_cancellation_slot() {return state_.slot();}
- void reset_cancellation_source(CancellationSlot source = CancellationSlot())
- {
- source_ = source;
- state_ = asio::cancellation_state{source, DefaultFilter()};
- state_.clear();
- }
- CancellationSlot & source() {return source_;}
- const CancellationSlot & source() const {return source_;}
- private:
- CancellationSlot source_;
- asio::cancellation_state state_{source_, DefaultFilter() };
- struct cancelled_t_awaitable
- {
- asio::cancellation_type state;
- bool await_ready() const noexcept
- {
- return true;
- }
- void await_suspend(std::coroutine_handle<void>) noexcept
- {
- }
- auto await_resume() const
- {
- return state;
- }
- };
- struct cancellation_state_t_awaitable
- {
- asio::cancellation_state &state;
- bool await_ready() const noexcept
- {
- return true;
- }
- void await_suspend(std::coroutine_handle<void>) noexcept
- {
- }
- auto await_resume() const
- {
- return state;
- }
- };
- struct reset_cancellation_state_0_t_awaitable
- {
- asio::cancellation_state &state;
- CancellationSlot &source;
- bool await_ready() const noexcept
- {
- return true;
- }
- void await_suspend(std::coroutine_handle<void>) noexcept
- {
- }
- auto await_resume() const
- {
- state = asio::cancellation_state(source, DefaultFilter());
- }
- };
- template<typename Filter>
- struct reset_cancellation_state_1_t_awaitable
- {
- asio::cancellation_state & state;
- Filter filter_;
- CancellationSlot &source;
- bool await_ready() const noexcept
- {
- return true;
- }
- void await_suspend(std::coroutine_handle<void>) noexcept
- {
- }
- auto await_resume()
- {
- state = asio::cancellation_state(
- source,
- BOOST_ASIO_MOVE_CAST(Filter)(filter_));
- }
- };
- template<typename InFilter, typename OutFilter>
- struct reset_cancellation_state_2_t_awaitable
- {
- asio::cancellation_state & state;
- InFilter in_filter_;
- OutFilter out_filter_;
- CancellationSlot &source;
- bool await_ready() const noexcept
- {
- return true;
- }
- void await_suspend(std::coroutine_handle<void>) noexcept
- {
- }
- auto await_resume()
- {
- state = asio::cancellation_state(
- source,
- BOOST_ASIO_MOVE_CAST(InFilter)(in_filter_),
- BOOST_ASIO_MOVE_CAST(OutFilter)(out_filter_));
- }
- };
- };
- struct promise_throw_if_cancelled_base
- {
- promise_throw_if_cancelled_base(bool throw_if_cancelled = true) : throw_if_cancelled_(throw_if_cancelled) {}
- // This await transformation determines whether cancellation is propagated as
- // an exception.
- auto await_transform(this_coro::throw_if_cancelled_0_t)
- noexcept
- {
- return throw_if_cancelled_0_awaitable_{throw_if_cancelled_};
- }
- // This await transformation sets whether cancellation is propagated as an
- // exception.
- auto await_transform(this_coro::throw_if_cancelled_1_t throw_if_cancelled)
- noexcept
- {
- return throw_if_cancelled_1_awaitable_{this, throw_if_cancelled.value};
- }
- bool throw_if_cancelled() const {return throw_if_cancelled_;}
- protected:
- bool throw_if_cancelled_{true};
- struct throw_if_cancelled_0_awaitable_
- {
- bool value_;
- bool await_ready() const noexcept
- {
- return true;
- }
- void await_suspend(std::coroutine_handle<void>) noexcept
- {
- }
- auto await_resume()
- {
- return value_;
- }
- };
- struct throw_if_cancelled_1_awaitable_
- {
- promise_throw_if_cancelled_base* this_;
- bool value_;
- bool await_ready() const noexcept
- {
- return true;
- }
- void await_suspend(std::coroutine_handle<void>) noexcept
- {
- }
- auto await_resume()
- {
- this_->throw_if_cancelled_ = value_;
- }
- };
- };
- struct promise_memory_resource_base
- {
- #if !defined(BOOST_COBALT_NO_PMR)
- using allocator_type = pmr::polymorphic_allocator<void>;
- allocator_type get_allocator() const {return allocator_type{resource};}
- template<typename ... Args>
- static void * operator new(const std::size_t size, Args & ... args)
- {
- auto res = detail::get_memory_resource_from_args(args...);
- const auto p = res->allocate(size + sizeof(pmr::memory_resource *), alignof(pmr::memory_resource *));
- auto pp = static_cast<pmr::memory_resource**>(p);
- *pp = res;
- return pp + 1;
- }
- static void operator delete(void * raw, const std::size_t size) noexcept
- {
- const auto p = static_cast<pmr::memory_resource**>(raw) - 1;
- pmr::memory_resource * res = *p;
- res->deallocate(p, size + sizeof(pmr::memory_resource *), alignof(pmr::memory_resource *));
- }
- promise_memory_resource_base(pmr::memory_resource * resource = this_thread::get_default_resource()) : resource(resource) {}
- private:
- pmr::memory_resource * resource = this_thread::get_default_resource();
- #endif
- };
- /// Allocate the memory and put the allocator behind the cobalt memory
- template<typename AllocatorType>
- void *allocate_coroutine(const std::size_t size, AllocatorType alloc_)
- {
- using alloc_type = typename std::allocator_traits<AllocatorType>::template rebind_alloc<unsigned char>;
- alloc_type alloc{alloc_};
- const std::size_t align_needed = size % alignof(alloc_type);
- const std::size_t align_offset = align_needed != 0 ? alignof(alloc_type) - align_needed : 0ull;
- const std::size_t alloc_size = size + sizeof(alloc_type) + align_offset;
- const auto raw = std::allocator_traits<alloc_type>::allocate(alloc, alloc_size);
- new(raw + size + align_offset) alloc_type(std::move(alloc));
- return raw;
- }
- /// Deallocate the memory and destroy the allocator in the cobalt memory.
- template<typename AllocatorType>
- void deallocate_coroutine(void *raw_, const std::size_t size)
- {
- using alloc_type = typename std::allocator_traits<AllocatorType>::template rebind_alloc<unsigned char>;
- const auto raw = static_cast<unsigned char *>(raw_);
- const std::size_t align_needed = size % alignof(alloc_type);
- const std::size_t align_offset = align_needed != 0 ? alignof(alloc_type) - align_needed : 0ull;
- const std::size_t alloc_size = size + sizeof(alloc_type) + align_offset;
- auto alloc_p = reinterpret_cast<alloc_type *>(raw + size + align_offset);
- auto alloc = std::move(*alloc_p);
- alloc_p->~alloc_type();
- using size_type = typename std::allocator_traits<alloc_type>::size_type;
- std::allocator_traits<alloc_type>::deallocate(alloc, raw, static_cast<size_type>(alloc_size));
- }
- template<typename Promise>
- struct enable_await_allocator
- {
- auto await_transform(this_coro::allocator_t)
- {
- return allocator_awaitable_{static_cast<Promise*>(this)->get_allocator()};
- }
- private:
- struct allocator_awaitable_
- {
- using allocator_type = typename Promise::allocator_type;
- allocator_type alloc;
- constexpr static bool await_ready() { return true; }
- bool await_suspend( std::coroutine_handle<void> ) { return false; }
- allocator_type await_resume()
- {
- return alloc;
- }
- };
- };
- template<typename Promise>
- struct enable_await_executor
- {
- auto await_transform(this_coro::executor_t)
- {
- return executor_awaitable_{static_cast<Promise*>(this)->get_executor()};
- }
- private:
- struct executor_awaitable_
- {
- using executor_type = typename Promise::executor_type;
- executor_type exec;
- constexpr static bool await_ready() { return true; }
- bool await_suspend( std::coroutine_handle<void> ) { return false; }
- executor_type await_resume()
- {
- return exec;
- }
- };
- };
- }
- #endif //BOOST_COBALT_THIS_CORO_HPP
|