Warning, file /include/range/v3/experimental/utility/generator.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef RANGES_V3_EXPERIMENTAL_UTILITY_GENERATOR_HPP
0014 #define RANGES_V3_EXPERIMENTAL_UTILITY_GENERATOR_HPP
0015
0016 #include <range/v3/detail/config.hpp>
0017 #if RANGES_CXX_COROUTINES >= RANGES_CXX_COROUTINES_TS1
0018 #include <atomic>
0019 #include <cstddef>
0020 #include <exception>
0021 #include RANGES_COROUTINES_HEADER
0022 #include <utility>
0023
0024 #include <meta/meta.hpp>
0025
0026 #include <concepts/concepts.hpp>
0027
0028 #include <range/v3/range_fwd.hpp>
0029
0030 #include <range/v3/iterator/default_sentinel.hpp>
0031 #include <range/v3/range/traits.hpp>
0032 #include <range/v3/utility/box.hpp>
0033 #include <range/v3/utility/semiregular_box.hpp>
0034 #include <range/v3/utility/swap.hpp>
0035 #include <range/v3/view/all.hpp>
0036 #include <range/v3/view/facade.hpp>
0037
0038 #if defined(_MSC_VER) && !defined(RANGES_SILENCE_COROUTINE_WARNING)
0039 #ifdef __clang__
0040 #pragma message( \
0041 "DANGER: clang doesn't (yet?) grok the MSVC coroutine ABI. " \
0042 "Use at your own risk. " \
0043 "(RANGES_SILENCE_COROUTINE_WARNING will silence this message.)")
0044 #elif defined RANGES_WORKAROUND_MSVC_835948
0045 #pragma message( \
0046 "DANGER: ranges::experimental::generator is fine, but this " \
0047 "version of MSVC likely miscompiles ranges::experimental::sized_generator. " \
0048 "Use the latter at your own risk. " \
0049 "(RANGES_SILENCE_COROUTINE_WARNING will silence this message.)")
0050 #endif
0051 #endif
0052
0053 #include <range/v3/detail/prologue.hpp>
0054
0055 namespace ranges
0056 {
0057
0058
0059 namespace experimental
0060 {
0061
0062 using generator_size_t = std::size_t;
0063
0064
0065 enum struct generator_size : generator_size_t
0066 {
0067 invalid = ~generator_size_t(0)
0068 };
0069
0070 template<typename Promise = void>
0071 struct RANGES_EMPTY_BASES coroutine_owner;
0072
0073 class enable_coroutine_owner
0074 {
0075 template<class>
0076 friend struct coroutine_owner;
0077 std::atomic<unsigned int> refcount_{1};
0078 };
0079 }
0080
0081
0082 namespace detail
0083 {
0084 inline void resume(RANGES_COROUTINES_NS::coroutine_handle<> coro)
0085 {
0086
0087 RANGES_EXPECT(coro);
0088 RANGES_EXPECT(!coro.done());
0089 coro.resume();
0090 }
0091
0092 namespace coroutine_owner_
0093 {
0094 struct adl_hook
0095 {};
0096
0097 template<typename Promise>
0098 void swap(experimental::coroutine_owner<Promise> & x,
0099 experimental::coroutine_owner<Promise> & y) noexcept
0100 {
0101 x.swap(y);
0102 }
0103 }
0104 }
0105
0106
0107 namespace experimental
0108 {
0109
0110 template<typename Promise>
0111 struct RANGES_EMPTY_BASES coroutine_owner
0112 : private RANGES_COROUTINES_NS::coroutine_handle<Promise>
0113 , private detail::coroutine_owner_::adl_hook
0114 {
0115 CPP_assert(derived_from<Promise, enable_coroutine_owner>);
0116 using base_t = RANGES_COROUTINES_NS::coroutine_handle<Promise>;
0117
0118 using base_t::operator bool;
0119 using base_t::done;
0120 using base_t::promise;
0121
0122 coroutine_owner() = default;
0123 constexpr explicit coroutine_owner(base_t coro) noexcept
0124 : base_t(coro)
0125 {}
0126 coroutine_owner(coroutine_owner && that) noexcept
0127 : base_t(ranges::exchange(that.base(), {}))
0128 , copied_(that.copied_.load(std::memory_order_relaxed))
0129 {}
0130 coroutine_owner(coroutine_owner const & that) noexcept
0131 : base_t(that.handle())
0132 , copied_(that.handle() != nullptr)
0133 {
0134 if(*this)
0135 {
0136 that.copied_.store(true, std::memory_order_relaxed);
0137 base().promise().refcount_.fetch_add(1, std::memory_order_relaxed);
0138 }
0139 }
0140 ~coroutine_owner()
0141 {
0142 if(base() && (!copied_.load(std::memory_order_relaxed) ||
0143 1 == base().promise().refcount_.fetch_sub(
0144 1, std::memory_order_acq_rel)))
0145 base().destroy();
0146 }
0147 coroutine_owner & operator=(coroutine_owner that) noexcept
0148 {
0149 swap(that);
0150 return *this;
0151 }
0152 void resume()
0153 {
0154 detail::resume(handle());
0155 }
0156 void operator()()
0157 {
0158 detail::resume(handle());
0159 }
0160 void swap(coroutine_owner & that) noexcept
0161 {
0162 bool tmp = copied_.load(std::memory_order_relaxed);
0163 copied_.store(that.copied_.load(std::memory_order_relaxed),
0164 std::memory_order_relaxed);
0165 that.copied_.store(tmp, std::memory_order_relaxed);
0166 std::swap(base(), that.base());
0167 }
0168 base_t handle() const noexcept
0169 {
0170 return *this;
0171 }
0172
0173 private:
0174 mutable std::atomic<bool> copied_{false};
0175
0176 base_t & base() noexcept
0177 {
0178 return *this;
0179 }
0180 };
0181 }
0182
0183
0184 namespace detail
0185 {
0186 template<typename Reference>
0187 struct generator_promise : experimental::enable_coroutine_owner
0188 {
0189 std::exception_ptr except_ = nullptr;
0190
0191 CPP_assert(std::is_reference<Reference>::value ||
0192 copy_constructible<Reference>);
0193
0194 generator_promise * get_return_object() noexcept
0195 {
0196 return this;
0197 }
0198 RANGES_COROUTINES_NS::suspend_always initial_suspend() const noexcept
0199 {
0200 return {};
0201 }
0202 RANGES_COROUTINES_NS::suspend_always final_suspend() const noexcept
0203 {
0204 return {};
0205 }
0206 void return_void() const noexcept
0207 {}
0208 void unhandled_exception() noexcept
0209 {
0210 except_ = std::current_exception();
0211 RANGES_EXPECT(except_);
0212 }
0213 template(typename Arg)(
0214 requires convertible_to<Arg, Reference> AND
0215 std::is_assignable<semiregular_box_t<Reference> &, Arg>::value)
0216 RANGES_COROUTINES_NS::suspend_always yield_value(Arg && arg) noexcept(
0217 std::is_nothrow_assignable<semiregular_box_t<Reference> &, Arg>::value)
0218 {
0219 ref_ = std::forward<Arg>(arg);
0220 return {};
0221 }
0222 RANGES_COROUTINES_NS::suspend_never await_transform(
0223 experimental::generator_size) const noexcept
0224 {
0225 RANGES_ENSURE_MSG(false,
0226 "Invalid size request for a non-sized generator");
0227 return {};
0228 }
0229 meta::if_<std::is_reference<Reference>, Reference, Reference const &> read()
0230 const noexcept
0231 {
0232 return ref_;
0233 }
0234
0235 private:
0236 semiregular_box_t<Reference> ref_;
0237 };
0238
0239 template<typename Reference>
0240 struct sized_generator_promise : generator_promise<Reference>
0241 {
0242 sized_generator_promise * get_return_object() noexcept
0243 {
0244 return this;
0245 }
0246 RANGES_COROUTINES_NS::suspend_never initial_suspend() const noexcept
0247 {
0248
0249 return {};
0250 }
0251 RANGES_COROUTINES_NS::suspend_always await_transform(
0252 experimental::generator_size size) noexcept
0253 {
0254
0255
0256 size_ = size;
0257 return {};
0258 }
0259 experimental::generator_size_t size() const noexcept
0260 {
0261 RANGES_EXPECT(size_ != experimental::generator_size::invalid);
0262 return static_cast<experimental::generator_size_t>(size_);
0263 }
0264
0265 private:
0266 experimental::generator_size size_ = experimental::generator_size::invalid;
0267 };
0268 }
0269
0270
0271 namespace experimental
0272 {
0273 template<typename Reference, typename Value = uncvref_t<Reference>>
0274 struct sized_generator;
0275
0276 template<typename Reference, typename Value = uncvref_t<Reference>>
0277 struct generator : view_facade<generator<Reference, Value>>
0278 {
0279 using promise_type = detail::generator_promise<Reference>;
0280
0281 constexpr generator() noexcept = default;
0282 generator(promise_type * p)
0283 : coro_{handle::from_promise(*p)}
0284 {
0285 RANGES_EXPECT(coro_);
0286 }
0287
0288 private:
0289 friend range_access;
0290 friend struct sized_generator<Reference, Value>;
0291 using handle = RANGES_COROUTINES_NS::coroutine_handle<promise_type>;
0292 coroutine_owner<promise_type> coro_;
0293
0294 struct cursor
0295 {
0296 using value_type = Value;
0297
0298 cursor() = default;
0299 constexpr explicit cursor(handle coro) noexcept
0300 : coro_{coro}
0301 {}
0302 bool equal(default_sentinel_t) const
0303 {
0304 RANGES_EXPECT(coro_);
0305 if(coro_.done())
0306 {
0307 auto & e = coro_.promise().except_;
0308 if(e)
0309 std::rethrow_exception(std::move(e));
0310 return true;
0311 }
0312 return false;
0313 }
0314 void next()
0315 {
0316 detail::resume(coro_);
0317 }
0318 Reference read() const
0319 {
0320 RANGES_EXPECT(coro_);
0321 return coro_.promise().read();
0322 }
0323
0324 private:
0325 handle coro_ = nullptr;
0326 };
0327
0328 cursor begin_cursor()
0329 {
0330 detail::resume(coro_.handle());
0331 return cursor{coro_.handle()};
0332 }
0333 };
0334
0335 template<typename Reference, typename Value >
0336 struct sized_generator : generator<Reference, Value>
0337 {
0338 using promise_type = detail::sized_generator_promise<Reference>;
0339 using handle = RANGES_COROUTINES_NS::coroutine_handle<promise_type>;
0340
0341 constexpr sized_generator() noexcept = default;
0342 sized_generator(promise_type * p)
0343 : generator<Reference, Value>{p}
0344 {}
0345 generator_size_t size() const noexcept
0346 {
0347 return promise().size();
0348 }
0349
0350 private:
0351 using generator<Reference, Value>::coro_;
0352
0353 promise_type const & promise() const noexcept
0354 {
0355 RANGES_EXPECT(coro_);
0356 return static_cast<promise_type const &>(coro_.promise());
0357 }
0358 };
0359 }
0360
0361
0362 }
0363
0364 #include <range/v3/detail/epilogue.hpp>
0365
0366 #endif
0367
0368 #endif