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
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;
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>
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;
127 : base_t(ranges::exchange(that.base(), {}))
128 , copied_(that.copied_.load(std::memory_order_relaxed))
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)))
154 detail::resume(handle());
158 detail::resume(handle());
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>
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>>
279 using promise_type = detail::generator_promise<Reference>;
281 constexpr
generator() noexcept =
default;
283 : coro_{handle::from_promise(*p)}
285 RANGES_EXPECT(coro_);
291 using handle = RANGES_COROUTINES_NS::coroutine_handle<promise_type>;
296 using value_type = Value;
299 constexpr
explicit cursor(handle coro) noexcept
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 >
338 using promise_type = detail::sized_generator_promise<Reference>;
339 using handle = RANGES_COROUTINES_NS::coroutine_handle<promise_type>;
345 generator_size_t size()
const noexcept
347 return promise().size();
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
std::integral_constant< std::size_t, N > size_t
An integral constant wrapper for std::size_t.
Definition: meta.hpp:163
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
Definition: default_sentinel.hpp:26
Definition: generator.hpp:114
Definition: generator.hpp:278
Definition: generator.hpp:337
A utility for constructing a view from a (derived) type that implements begin and end cursors.
Definition: facade.hpp:66