13#ifndef RANGES_V3_EXPERIMENTAL_UTILITY_GENERATOR_HPP
14#define RANGES_V3_EXPERIMENTAL_UTILITY_GENERATOR_HPP
16#include <range/v3/detail/config.hpp>
17#if RANGES_CXX_COROUTINES >= RANGES_CXX_COROUTINES_TS1
21#include RANGES_COROUTINES_HEADER
38#if defined(_MSC_VER) && !defined(RANGES_SILENCE_COROUTINE_WARNING)
41 "DANGER: clang doesn't (yet?) grok the MSVC coroutine ABI. " \
42 "Use at your own risk. " \
43 "(RANGES_SILENCE_COROUTINE_WARNING will silence this message.)")
44#elif defined RANGES_WORKAROUND_MSVC_835948
46 "DANGER: ranges::experimental::generator is fine, but this " \
47 "version of MSVC likely miscompiles ranges::experimental::sized_generator. " \
48 "Use the latter at your own risk. " \
49 "(RANGES_SILENCE_COROUTINE_WARNING will silence this message.)")
53#include <range/v3/detail/prologue.hpp>
59 namespace experimental
62 using generator_size_t = std::size_t;
65 enum struct generator_size : generator_size_t
67 invalid = ~generator_size_t(0)
70 template<
typename Promise =
void>
71 struct RANGES_EMPTY_BASES coroutine_owner;
76 friend struct coroutine_owner;
77 std::atomic<unsigned int> refcount_{1};
84 inline void resume(RANGES_COROUTINES_NS::coroutine_handle<> coro)
88 RANGES_EXPECT(!coro.done());
92 namespace coroutine_owner_
97 template<
typename Promise>
98 void swap(experimental::coroutine_owner<Promise> & x,
99 experimental::coroutine_owner<Promise> & y)
noexcept
107 namespace experimental
110 template<
typename Promise>
111 struct RANGES_EMPTY_BASES coroutine_owner
112 :
private RANGES_COROUTINES_NS::coroutine_handle<Promise>
113 ,
private detail::coroutine_owner_::adl_hook
115 CPP_assert(derived_from<Promise, enable_coroutine_owner>);
116 using base_t = RANGES_COROUTINES_NS::coroutine_handle<Promise>;
118 using base_t::operator bool;
120 using base_t::promise;
122 coroutine_owner() =
default;
123 constexpr explicit coroutine_owner(base_t coro) noexcept
126 coroutine_owner(coroutine_owner && that) noexcept
127 : base_t(ranges::exchange(that.base(), {}))
128 , copied_(that.copied_.load(std::memory_order_relaxed))
130 coroutine_owner(coroutine_owner
const & that) noexcept
131 : base_t(that.handle())
132 , copied_(that.handle() !=
nullptr)
136 that.copied_.store(
true, std::memory_order_relaxed);
137 base().promise().refcount_.fetch_add(1, std::memory_order_relaxed);
142 if(base() && (!copied_.load(std::memory_order_relaxed) ||
143 1 == base().promise().refcount_.fetch_sub(
144 1, std::memory_order_acq_rel)))
147 coroutine_owner & operator=(coroutine_owner that)
noexcept
154 detail::resume(handle());
158 detail::resume(handle());
160 void swap(coroutine_owner & that)
noexcept
162 bool tmp = copied_.load(std::memory_order_relaxed);
163 copied_.store(that.copied_.load(std::memory_order_relaxed),
164 std::memory_order_relaxed);
165 that.copied_.store(tmp, std::memory_order_relaxed);
166 std::swap(base(), that.base());
168 base_t handle() const noexcept
174 mutable std::atomic<bool> copied_{
false};
176 base_t & base() noexcept
186 template<
typename Reference>
187 struct generator_promise : experimental::enable_coroutine_owner
189 std::exception_ptr except_ =
nullptr;
191 CPP_assert(std::is_reference<Reference>::value ||
192 copy_constructible<Reference>);
194 generator_promise * get_return_object() noexcept
198 RANGES_COROUTINES_NS::suspend_always initial_suspend() const noexcept
202 RANGES_COROUTINES_NS::suspend_always final_suspend() const noexcept
206 void return_void() const noexcept
208 void unhandled_exception() noexcept
210 except_ = std::current_exception();
211 RANGES_EXPECT(except_);
213 template(
typename Arg)(
214 requires convertible_to<Arg, Reference> AND
215 std::is_assignable<semiregular_box_t<Reference> &, Arg>::value)
216 RANGES_COROUTINES_NS::suspend_always yield_value(Arg && arg)
noexcept(
217 std::is_nothrow_assignable<semiregular_box_t<Reference> &, Arg>::value)
219 ref_ = std::forward<Arg>(arg);
222 RANGES_COROUTINES_NS::suspend_never await_transform(
223 experimental::generator_size)
const noexcept
225 RANGES_ENSURE_MSG(
false,
226 "Invalid size request for a non-sized generator");
236 semiregular_box_t<Reference> ref_;
239 template<
typename Reference>
240 struct sized_generator_promise : generator_promise<Reference>
242 sized_generator_promise * get_return_object() noexcept
246 RANGES_COROUTINES_NS::suspend_never initial_suspend() const noexcept
251 RANGES_COROUTINES_NS::suspend_always await_transform(
252 experimental::generator_size size)
noexcept
259 experimental::generator_size_t
size() const noexcept
261 RANGES_EXPECT(size_ != experimental::generator_size::invalid);
262 return static_cast<experimental::generator_size_t
>(size_);
266 experimental::generator_size size_ = experimental::generator_size::invalid;
271 namespace experimental
273 template<
typename Reference,
typename Value = uncvref_t<Reference>>
274 struct sized_generator;
276 template<
typename Reference,
typename Value = uncvref_t<Reference>>
277 struct generator : view_facade<generator<Reference, Value>>
279 using promise_type = detail::generator_promise<Reference>;
281 constexpr generator() noexcept = default;
282 generator(promise_type * p)
283 : coro_{handle::from_promise(*p)}
285 RANGES_EXPECT(coro_);
290 friend struct sized_generator<Reference, Value>;
291 using handle = RANGES_COROUTINES_NS::coroutine_handle<promise_type>;
292 coroutine_owner<promise_type> coro_;
296 using value_type = Value;
299 constexpr explicit cursor(handle coro) noexcept
302 bool equal(default_sentinel_t)
const
304 RANGES_EXPECT(coro_);
307 auto & e = coro_.promise().except_;
309 std::rethrow_exception(std::move(e));
316 detail::resume(coro_);
318 Reference read()
const
320 RANGES_EXPECT(coro_);
321 return coro_.promise().read();
325 handle coro_ =
nullptr;
328 cursor begin_cursor()
330 detail::resume(coro_.handle());
331 return cursor{coro_.handle()};
335 template<
typename Reference,
typename Value >
336 struct sized_generator : generator<Reference, Value>
338 using promise_type = detail::sized_generator_promise<Reference>;
339 using handle = RANGES_COROUTINES_NS::coroutine_handle<promise_type>;
341 constexpr sized_generator() noexcept = default;
342 sized_generator(promise_type * p)
343 : generator<Reference, Value>{p}
345 generator_size_t
size() const noexcept
347 return promise().size();
351 using generator<Reference, Value>::coro_;
353 promise_type
const & promise() const noexcept
355 RANGES_EXPECT(coro_);
356 return static_cast<promise_type
const &
>(coro_.promise());
364#include <range/v3/detail/epilogue.hpp>
Definition generator.hpp:74
meta::size_t< L::size()> size
An integral constant wrapper that is the size of the meta::list L.
Definition meta.hpp:1696
_t< detail::_if_< list< Args... > > > if_
Select one type or another depending on a compile-time Boolean.
Definition meta.hpp:1247