mp-coro main
Coroutine support tools
generator.h
Go to the documentation of this file.
1// The MIT License (MIT)
2//
3// Copyright (c) 2021 Mateusz Pusz
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#pragma once
24
26#include <mp-coro/coro_ptr.h>
27#include <mp-coro/trace.h>
28#include <cassert>
29#include <concepts>
30#include <coroutine>
31#include <optional>
32#include <ranges>
33#include <utility>
34
35namespace mp_coro {
36
37/// @ingroup coro_ret_types
38template <typename T>
39class [[nodiscard]] generator {
40 public:
41 using value_type = std::remove_reference_t<T>;
42 using reference = std::conditional_t<std::is_reference_v<T>, T, const value_type &>;
43 using pointer = std::add_pointer_t<reference>;
44
47
48 static std::suspend_always initial_suspend() noexcept {
49 TRACE_FUNC();
50 return {};
51 }
52 static std::suspend_always final_suspend() noexcept {
53 TRACE_FUNC();
54 return {};
55 }
56 static void return_void() noexcept { TRACE_FUNC(); }
57
59 TRACE_FUNC();
60 return this;
61 }
62 std::suspend_always yield_value(reference v) noexcept {
63 TRACE_FUNC();
64 value = std::addressof(v);
65 return {};
66 }
68 TRACE_FUNC();
69 throw;
70 }
71
72 // disallow co_await in generator coroutines
73 void await_transform() = delete;
74 };
75
76 class iterator {
77 std::coroutine_handle<promise_type> handle_;
78 friend generator;
79 explicit iterator(std::coroutine_handle<promise_type> h) noexcept : handle_(h) {}
80
81 public:
83 using difference_type = std::ptrdiff_t;
84
85 iterator() = default; // TODO Remove when gcc is fixed
86
87 iterator(iterator &&other) noexcept : handle_(std::exchange(other.handle_, {})) {}
88 iterator &operator=(iterator &&other) noexcept {
89 handle_ = std::exchange(other.handle_, {});
90 return *this;
91 }
92
94 TRACE_FUNC();
95 assert(!handle_.done() && "Can't increment generator end iterator");
96 handle_.resume();
97 return *this;
98 }
99 void operator++(int) {
100 TRACE_FUNC();
101 ++*this;
102 }
103
104 [[nodiscard]] reference operator*() const noexcept {
105 TRACE_FUNC();
106 assert(!handle_.done() && "Can't dereference generator end iterator");
107 return *handle_.promise().value;
108 }
109 [[nodiscard]] pointer operator->() const noexcept {
110 TRACE_FUNC();
111 return std::addressof(operator*());
112 }
113
114 [[nodiscard]] bool operator==(std::default_sentinel_t) const noexcept {
115 TRACE_FUNC();
116 return !handle_ // TODO Remove when gcc is fixed
117 // (default-construction will not be available and user should
118 // not compare with a moved-from iterator)
119 || handle_.done();
120 }
121 };
122 static_assert(std::input_iterator<iterator>);
123
124 generator() = default; // TODO Remove when gcc is fixed
125
126 [[nodiscard]] iterator begin() {
127 TRACE_FUNC();
128 // Pre: Coroutine is suspended at its initial suspend point
129 assert(promise_ && "Can't call begin on moved-from generator");
130 auto handle = std::coroutine_handle<promise_type>::from_promise(*promise_);
131 handle.resume();
132 return iterator(handle);
133 }
134 [[nodiscard]] std::default_sentinel_t end() const noexcept {
135 TRACE_FUNC();
136 return std::default_sentinel;
137 }
138
139 private:
141 generator(promise_type *promise) : promise_(promise) {}
142};
143
144} // namespace mp_coro
145
146template <typename T>
147inline constexpr bool std::ranges::enable_view<mp_coro::generator<T>> = true;
iterator(iterator &&other) noexcept
Definition: generator.h:87
iterator(std::coroutine_handle< promise_type > h) noexcept
Definition: generator.h:79
iterator & operator=(iterator &&other) noexcept
Definition: generator.h:88
reference operator*() const noexcept
Definition: generator.h:104
generator::value_type value_type
Definition: generator.h:82
pointer operator->() const noexcept
Definition: generator.h:109
std::ptrdiff_t difference_type
Definition: generator.h:83
bool operator==(std::default_sentinel_t) const noexcept
Definition: generator.h:114
std::coroutine_handle< promise_type > handle_
Definition: generator.h:77
promise_ptr< promise_type > promise_
Definition: generator.h:140
std::remove_reference_t< T > value_type
Definition: generator.h:41
std::conditional_t< std::is_reference_v< T >, T, const value_type & > reference
Definition: generator.h:42
generator(promise_type *promise)
Definition: generator.h:141
std::add_pointer_t< reference > pointer
Definition: generator.h:43
std::default_sentinel_t end() const noexcept
Definition: generator.h:134
iterator begin()
Definition: generator.h:126
Definition: async.h:31
std::unique_ptr< T, coro_deleter > promise_ptr
RAII wrapper that destroys promise object's associated coroutine.
Definition: coro_ptr.h:44
Base class with deleted copy constructor and copy assignment operator.
Definition: noncopyable.h:28
generator get_return_object() noexcept
Definition: generator.h:58
static void return_void() noexcept
Definition: generator.h:56
std::suspend_always yield_value(reference v) noexcept
Definition: generator.h:62
static std::suspend_always final_suspend() noexcept
Definition: generator.h:52
static std::suspend_always initial_suspend() noexcept
Definition: generator.h:48
#define TRACE_FUNC()
Definition: trace.h:27