Back to home page

EIC code displayed by LXR

 
 

    


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 /// \file
0002 // Range v3 library
0003 //
0004 //  Copyright Casey Carter 2017
0005 //
0006 //  Use, modification and distribution is subject to the
0007 //  Boost Software License, Version 1.0. (See accompanying
0008 //  file LICENSE_1_0.txt or copy at
0009 //  http://www.boost.org/LICENSE_1_0.txt)
0010 //
0011 // Project home: https://github.com/ericniebler/range-v3
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 // RANGES_SILENCE_COROUTINE_WARNINGS
0052 
0053 #include <range/v3/detail/prologue.hpp>
0054 
0055 namespace ranges
0056 {
0057     /// \addtogroup group-view
0058     /// @{
0059     namespace experimental
0060     {
0061         // The type of size() for a sized_generator
0062         using generator_size_t = std::size_t;
0063 
0064         // Type upon which to co_await to set the size of a sized_generator
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     } // namespace experimental
0080 
0081     /// \cond
0082     namespace detail
0083     {
0084         inline void resume(RANGES_COROUTINES_NS::coroutine_handle<> coro)
0085         {
0086             // Pre: coro refers to a suspended coroutine.
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         } // namespace coroutine_owner_
0104     }     // namespace detail
0105     /// \endcond
0106 
0107     namespace experimental
0108     {
0109         // An owning coroutine_handle
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     } // namespace experimental
0182 
0183     /// \cond
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                 // sized_generator doesn't suspend at its initial suspend point because...
0249                 return {};
0250             }
0251             RANGES_COROUTINES_NS::suspend_always await_transform(
0252                 experimental::generator_size size) noexcept
0253             {
0254                 // ...we need the coroutine set the size of the range first by
0255                 // co_awaiting on a generator_size.
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     } // namespace detail
0269     /// \endcond
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 /* = uncvref_t<Reference>*/>
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     } // namespace experimental
0360 
0361     /// @}
0362 } // namespace ranges
0363 
0364 #include <range/v3/detail/epilogue.hpp>
0365 
0366 #endif // RANGES_CXX_COROUTINES >= RANGES_CXX_COROUTINES_TS1
0367 
0368 #endif // RANGES_V3_EXPERIMENTAL_UTILITY_GENERATOR_HPP