librf
generator.h
1 /*
2 * Modify from <experimental/generator_t.h>
3 * Purpose: Library support of coroutines. generator_t class
4 * http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0057r0.pdf
5 */
6 #pragma once
7 
8 #pragma pack(push,_CRT_PACKING)
9 #pragma push_macro("new")
10 #undef new
11 
12 namespace resumef
13 {
14  template <typename _Ty, typename promise_type>
15  struct generator_iterator;
16 
17 #ifndef DOXYGEN_SKIP_PROPERTY
18 
19  template<typename promise_type>
20  struct generator_iterator<void, promise_type>
21  {
22  typedef std::input_iterator_tag iterator_category;
23  typedef ptrdiff_t difference_type;
24 
25  coroutine_handle<promise_type> _Coro;
26 
27  generator_iterator(std::nullptr_t) : _Coro(nullptr)
28  {
29  }
30 
31  generator_iterator(coroutine_handle<promise_type> _CoroArg) : _Coro(_CoroArg)
32  {
33  }
34 
35  generator_iterator& operator++()
36  {
37  if (_Coro.done())
38  _Coro = nullptr;
39  else
40  _Coro.resume();
41  return *this;
42  }
43 
44  void operator++(int)
45  {
46  // This postincrement operator meets the requirements of the Ranges TS
47  // InputIterator concept, but not those of Standard C++ InputIterator.
48  ++* this;
49  }
50 
51  bool operator==(generator_iterator const& right_) const
52  {
53  return _Coro == right_._Coro;
54  }
55 
56  bool operator!=(generator_iterator const& right_) const
57  {
58  return !(*this == right_);
59  }
60  };
61 
62  template <typename promise_type>
63  struct generator_iterator<std::nullptr_t, promise_type> : public generator_iterator<void, promise_type>
64  {
65  generator_iterator(std::nullptr_t) : generator_iterator<void, promise_type>(nullptr)
66  {
67  }
68  generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg)
69  {
70  }
71  };
72 
73  template <typename _Ty, typename promise_type>
74  struct generator_iterator : public generator_iterator<void, promise_type>
75  {
76  using value_type = _Ty;
77  using reference = _Ty const&;
78  using pointer = _Ty const*;
79 
80  generator_iterator(std::nullptr_t) : generator_iterator<void, promise_type>(nullptr)
81  {
82  }
83  generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg)
84  {
85  }
86 
87  reference operator*() const
88  {
89  return *this->_Coro.promise()._CurrentValue;
90  }
91 
92  pointer operator->() const
93  {
94  return this->_Coro.promise()._CurrentValue;
95  }
96  };
97 #endif //DOXYGEN_SKIP_PROPERTY
98 
102  template <typename _Ty, typename _Alloc>
103  struct generator_t
104  {
105  using value_type = _Ty;
107 
108 #ifndef DOXYGEN_SKIP_PROPERTY
109  struct promise_type
110  {
111  using value_type = _Ty;
113  using future_type = generator_t<value_type>;
114 
115  _Ty const* _CurrentValue;
116 
117  promise_type()
118  {
119  get_state()->set_initial_suspend(coroutine_handle<promise_type>::from_promise(*this));
120  }
121  promise_type(promise_type&& _Right) noexcept = default;
122  promise_type& operator = (promise_type&& _Right) noexcept = default;
123  promise_type(const promise_type&) = default;
124  promise_type& operator = (const promise_type&) = default;
125 
126  generator_t get_return_object()
127  {
128  return generator_t{ *this };
129  }
130 
131  suspend_always initial_suspend() noexcept
132  {
133  return {};
134  }
135 
136  suspend_always final_suspend() noexcept
137  {
138  return {};
139  }
140 
141  suspend_always yield_value(_Ty const& _Value) noexcept
142  {
143  _CurrentValue = std::addressof(_Value);
144  return {};
145  }
146 
147  //template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>>
148  void return_value(_Ty const& _Value) noexcept
149  {
150  _CurrentValue = std::addressof(_Value);
151  }
152  //template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>>
153  void return_value() noexcept
154  {
155  _CurrentValue = nullptr;
156  }
157 
158  void set_exception(std::exception_ptr e)
159  {
160  (void)e;
161  std::terminate();
162  }
163 #ifdef __clang__
164  void unhandled_exception()
165  {
166  std::terminate();
167  }
168 #endif
169 
170  template <typename _Uty>
171  _Uty&& await_transform(_Uty&& _Whatever) noexcept
172  {
173  static_assert(std::is_same_v<_Uty, void>,
174  "co_await is not supported in coroutines of type std::experiemental::generator_t");
175  return std::forward<_Uty>(_Whatever);
176  }
177 
178  state_type* get_state() noexcept
179  {
180 #if RESUMEF_INLINE_STATE
181  size_t _State_size = _Align_size<state_type>();
182 #if defined(__clang__)
183  auto h = coroutine_handle<promise_type>::from_promise(*this);
184  char* ptr = reinterpret_cast<char*>(h.address()) - _State_size;
185  return reinterpret_cast<state_type*>(ptr);
186 #elif defined(_MSC_VER)
187  char* ptr = reinterpret_cast<char*>(this) - _State_size;
188  return reinterpret_cast<state_type*>(ptr);
189 #else
190 #error "Unknown compiler"
191 #endif
192 #else
193  return _state.get();
194 #endif
195  }
196 
197  using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>;
198  static_assert(std::is_same_v<char*, typename std::allocator_traits<_Alloc_char>::pointer>,
199  "generator_t does not support allocators with fancy pointer types");
200  static_assert(std::allocator_traits<_Alloc_char>::is_always_equal::value,
201  "generator_t only supports stateless allocators");
202 
203  void* operator new(size_t _Size)
204  {
205  _Alloc_char _Al;
206 #if RESUMEF_INLINE_STATE
207  size_t _State_size = _Align_size<state_type>();
208  assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
209 
210  char* ptr = _Al.allocate(_Size + _State_size);
211  char* _Rptr = ptr + _State_size;
212 #if RESUMEF_DEBUG_COUNTER
213  std::cout << " generator_promise::new, alloc size=" << (_Size + _State_size) << std::endl;
214  std::cout << " generator_promise::new, alloc ptr=" << (void*)ptr << std::endl;
215  std::cout << " generator_promise::new, return ptr=" << (void*)_Rptr << std::endl;
216 #endif
217 
218  //在初始地址上构造state
219  {
220  state_type* st = state_type::_Construct(ptr);
221  st->lock();
222  }
223 
224  return _Rptr;
225 #else
226  char* ptr = _Al.allocate(_Size);
227 #if RESUMEF_DEBUG_COUNTER
228  std::cout << " generator_promise::new, alloc size=" << _Size << std::endl;
229  std::cout << " generator_promise::new, alloc ptr=" << (void*)ptr << std::endl;
230  std::cout << " generator_promise::new, return ptr=" << (void*)ptr << std::endl;
231 #endif
232 
233  return ptr;
234 #endif
235  }
236 
237  void operator delete(void* _Ptr, size_t _Size)
238  {
239 #if RESUMEF_INLINE_STATE
240  size_t _State_size = _Align_size<state_type>();
241  assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
242 
243  *reinterpret_cast<uint32_t*>(_Ptr) = static_cast<uint32_t>(_Size + _State_size);
244 
245  state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size);
246  st->unlock();
247 #else
248  _Alloc_char _Al;
249  return _Al.deallocate(reinterpret_cast<char *>(_Ptr), _Size);
250 #endif
251  }
252 #if !RESUMEF_INLINE_STATE
253  private:
254  counted_ptr<state_type> _state = state_generator_t::_Alloc_state();
255 #endif
256  };
257 #endif //DOXYGEN_SKIP_PROPERTY
258 
259  using iterator = generator_iterator<_Ty, promise_type>;
260 
261  iterator begin()
262  {
263  if (_Coro)
264  {
265  _Coro.resume();
266  if (_Coro.done())
267  return{ nullptr };
268  }
269  return { _Coro };
270  }
271 
272  iterator end()
273  {
274  return{ nullptr };
275  }
276 
277  explicit generator_t(promise_type& _Prom)
278  : _Coro(coroutine_handle<promise_type>::from_promise(_Prom))
279  {
280  }
281 
282  generator_t() = default;
283 
284  generator_t(generator_t const&) = delete;
285  generator_t& operator=(generator_t const&) = delete;
286 
287  generator_t(generator_t&& right_) noexcept
288  : _Coro(right_._Coro)
289  {
290  right_._Coro = nullptr;
291  }
292 
293  generator_t& operator=(generator_t&& right_) noexcept
294  {
295  if (this != std::addressof(right_)) {
296  _Coro = right_._Coro;
297  right_._Coro = nullptr;
298  }
299  return *this;
300  }
301 
302  ~generator_t()
303  {
304  if (_Coro) {
305  _Coro.destroy();
306  }
307  }
308 
309  state_type* detach_state()
310  {
311  auto t = _Coro;
312  _Coro = nullptr;
313  return t.promise().get_state();
314  }
315 
316  private:
317  coroutine_handle<promise_type> _Coro = nullptr;
318  };
319 
320 } // namespace resumef
321 
322 #pragma pop_macro("new")
323 #pragma pack(pop)
324 
325 #ifndef DOXYGEN_SKIP_PROPERTY
326 
327 namespace std {
328  namespace experimental {
329 
330  template <typename _Ty, typename _Alloc, typename... Args>
331  struct coroutine_traits<resumef::generator_t<_Ty, _Alloc>, Args...>
332  {
333  typedef typename resumef::generator_t<_Ty, _Alloc>::promise_type promise_type;
334  };
335  }
336 } // namespace std::experimental
337 
338 #endif //DOXYGEN_SKIP_PROPERTY
resumef::counted_ptr< state_type >
resumef::state_generator_t
专用于generator_t<>的state类。
Definition: state.h:70
resumef::generator_t
专用于co_yield函数。
Definition: generator.h:103