MathUtils
A library of mathematical utilities.
Loading...
Searching...
No Matches
simple_generator.hpp
Go to the documentation of this file.
1#pragma once
2
13
14#include <coroutine>
15#include <stdexcept>
16#include <unordered_set> // std::unordered_set
17#include <vector>
18
19namespace mathutils {
24
25template <typename T> class SimpleGenerator {
26public:
27 struct promise_type;
28 using handle_type = std::coroutine_handle<promise_type>;
29
30private:
31 handle_type mCoro;
32
33public:
34 explicit SimpleGenerator(handle_type h) : mCoro(h) {}
35
36 SimpleGenerator(SimpleGenerator &&other_sg) noexcept : mCoro(other_sg.mCoro) {
37 other_sg.mCoro = nullptr;
38 }
39 SimpleGenerator &operator=(SimpleGenerator &&other) noexcept {
40 if (this != other) {
41 mCoro = other.mCoro;
42 other.mCoro = nullptr;
43 return *this;
44 }
45 }
46 SimpleGenerator(const SimpleGenerator &) = delete;
47 SimpleGenerator &operator=(const SimpleGenerator &) = delete;
48 ~SimpleGenerator() {
49 if (mCoro) {
50 mCoro.destroy();
51 }
52 }
53
54 // Implementation of the external API called by the user to actually use the
55 // generator
56 void start() { try_next(); }
57 bool running() { return not mCoro.done(); }
58 void try_next() {
59 mCoro.resume();
60 if (mCoro.promise().m_latest_exception) {
61 std::rethrow_exception(mCoro.promise().m_latest_exception);
62 }
63 }
64 T take() { return std::move(mCoro.promise().m_current_value); }
65
66 // Implementation of the internal API called when co_yield/etc are triggered
67 // inside the coroutine
69 T m_current_value;
70 std::exception_ptr m_latest_exception;
71 friend SimpleGenerator;
72
73 public:
74 auto get_return_object() {
75 return SimpleGenerator{handle_type::from_promise(*this)};
76 }
77 auto yield_value(T some_value) {
78 m_current_value = some_value; // Capture the yielded value
79 return std::suspend_always{};
80 }
81 auto unhandled_exception() {
82 m_latest_exception = std::current_exception();
83 }
84 auto initial_suspend() { return std::suspend_always{}; }
85 auto final_suspend() noexcept { return std::suspend_always{}; }
86 auto return_void() { return std::suspend_never{}; }
87 };
88
89private:
90 // Implementation of the iterator protocol
91 class iterator {
92 SimpleGenerator<T> &owner;
93 bool done;
94 void iter_next() {
95 owner.try_next();
96 done = not owner.running();
97 }
98
99 public:
100 bool operator!=(const iterator &r) const { return done != r.done; }
101 auto operator*() const { return owner.take(); }
102 iterator &operator++() {
103 iter_next();
104 return *this;
105 }
106 iterator(SimpleGenerator<T> &o, bool d) : owner(o), done(d) {
107 if (not done)
108 iter_next();
109 }
110 };
111
112public:
113 // Public access to the internal iterator protocol
114
115 iterator begin() { return iterator{*this, false}; }
116 iterator end() { return iterator{*this, true}; }
117
118public:
119 // Convert generator to a unordered_set
120 std::unordered_set<T> to_unordered_set() {
121 std::unordered_set<T> result;
122 for (auto &value : *this) {
123 result.insert(value);
124 }
125 return result;
126 }
127
128 // Convert generator to a vector
129 std::vector<T> to_vector() {
130 std::vector<T> result;
131 for (auto &value : *this) {
132 result.push_back(value);
133 }
134 return result;
135 }
136};
137
138} // namespace mathutils
139
Definition simple_generator.hpp:68