Joos1W Compiler Framework
All Classes Functions Typedefs Pages
Generator.h
1 // Source: https://en.cppreference.com/w/cpp/coroutine/coroutine_handle
2 
3 #pragma once
4 
5 #include <coroutine>
6 #include <optional>
7 
8 namespace utils {
9 
10 template <std::movable T>
11 class Generator {
12 public:
13  struct promise_type {
14  Generator<T> get_return_object() {
15  return Generator{Handle::from_promise(*this)};
16  }
17  static std::suspend_always initial_suspend() noexcept { return {}; }
18  static std::suspend_always final_suspend() noexcept { return {}; }
19  std::suspend_always yield_value(T value) noexcept {
20  current_value = std::move(value);
21  return {};
22  }
23  // Disallow co_await in generator coroutines.
24  void await_transform() = delete;
25  [[noreturn]] static void unhandled_exception() { throw; }
26 
27  std::optional<T> current_value;
28  };
29 
30  using Handle = std::coroutine_handle<promise_type>;
31 
32  explicit Generator(const Handle coroutine) : m_coroutine{coroutine} {}
33 
34  Generator() = default;
35  ~Generator() {
36  if(m_coroutine) m_coroutine.destroy();
37  }
38 
39  Generator(const Generator&) = delete;
40  Generator& operator=(const Generator&) = delete;
41 
42  Generator(Generator&& other) noexcept : m_coroutine{other.m_coroutine} {
43  other.m_coroutine = {};
44  }
45  Generator& operator=(Generator&& other) noexcept {
46  if(this != &other) {
47  if(m_coroutine) m_coroutine.destroy();
48  m_coroutine = other.m_coroutine;
49  other.m_coroutine = {};
50  }
51  return *this;
52  }
53 
54  // Range-based for loop support.
55  class Iter {
56  public:
57  void operator++() { m_coroutine.resume(); }
58  const T& operator*() const { return *m_coroutine.promise().current_value; }
59  bool operator==(std::default_sentinel_t) const {
60  return !m_coroutine || m_coroutine.done();
61  }
62 
63  explicit Iter(const Handle coroutine) : m_coroutine{coroutine} {}
64 
65  private:
66  Handle m_coroutine;
67  };
68 
69  Iter begin() {
70  if(m_coroutine) m_coroutine.resume();
71  return Iter{m_coroutine};
72  }
73 
74  std::default_sentinel_t end() { return {}; }
75 
76 private:
77  Handle m_coroutine;
78 };
79 
80 template <std::integral T>
81 Generator<T> range(T first, const T last) {
82  while(first < last) co_yield first++;
83 }
84 
85 } // namespace utils