1
+ #include < coroutine>
2
+ #include < cstdlib>
3
+ #include < iostream>
4
+ #include < utility>
5
+ #include < variant>
6
+
7
+ template <typename T, typename E>
8
+ struct result
9
+ {
10
+ private:
11
+ std::variant<std::monostate, T, E> m_data;
12
+
13
+ public:
14
+ result () = default ;
15
+ result (result const &) = default ;
16
+ result (result&&) noexcept = default ;
17
+ ~result () noexcept = default ;
18
+
19
+ result (T const & value)
20
+ : m_data{ value }
21
+ {
22
+ }
23
+ result (E const & err)
24
+ : m_data{ err }
25
+ {
26
+ }
27
+
28
+ auto operator =(result const &) -> result& = default ;
29
+ auto operator =(result&&) noexcept -> result& = default ;
30
+
31
+ auto operator =(T const & value)
32
+ {
33
+ m_data = value;
34
+ return *this ;
35
+ }
36
+
37
+ auto operator =(E const & err) -> result&
38
+ {
39
+ m_data = err;
40
+ return *this ;
41
+ }
42
+
43
+ [[nodiscard]] auto value_or (T& fallback) -> T&
44
+ {
45
+ if (auto * p = std::get_if<T>(&m_data)) {
46
+ return *p;
47
+ }
48
+
49
+ return fallback;
50
+ }
51
+
52
+ [[nodiscard]] auto value_or (T const & fallback) const -> T const &
53
+ {
54
+ if (auto * p = std::get_if<T>(&m_data)) {
55
+ return *p;
56
+ }
57
+
58
+ return fallback;
59
+ }
60
+
61
+ [[nodiscard]] auto value () const -> T const &
62
+ {
63
+ if (auto * p = std::get_if<T>(&m_data)) {
64
+ return *p;
65
+ }
66
+
67
+ // Ugly solution, but we don't really care
68
+ std::cout << " Tried to access either value even though it's in error state!" << std::endl;
69
+ std::exit (EXIT_FAILURE);
70
+ }
71
+
72
+ [[nodiscard]] auto get_underlying () noexcept -> std::variant<std::monostate, T, E>&
73
+ {
74
+ return m_data;
75
+ }
76
+
77
+ [[nodiscard]] auto get_underlying () const noexcept -> std::variant<std::monostate, T, E>
78
+ {
79
+ return m_data;
80
+ }
81
+
82
+ [[nodiscard]] inline auto is_error () const noexcept -> bool
83
+ {
84
+ return std::get_if<E>(&m_data);
85
+ }
86
+
87
+ [[nodiscard]] auto get_error () noexcept -> E&
88
+ {
89
+ return *std::get_if<E>(&m_data);
90
+ }
91
+
92
+ [[nodiscard]] auto get_error () const noexcept -> E const &
93
+ {
94
+ return *std::get_if<E>(&m_data);
95
+ }
96
+
97
+ struct promise_type
98
+ {
99
+ result* res = nullptr ;
100
+
101
+ auto get_return_object () -> result
102
+ {
103
+ return { *this };
104
+ }
105
+
106
+ auto return_value (result val) -> void
107
+ {
108
+ *res = std::move (val);
109
+ }
110
+
111
+ auto initial_suspend () const noexcept -> std::suspend_never
112
+ {
113
+ return {};
114
+ }
115
+
116
+ auto final_suspend () const noexcept -> std::suspend_never
117
+ {
118
+ return {};
119
+ }
120
+
121
+ auto unhandled_exception () noexcept -> void
122
+ {
123
+ }
124
+ };
125
+
126
+ struct awaiter
127
+ {
128
+ result& res;
129
+
130
+ auto await_ready () -> bool
131
+ {
132
+ return !res.is_error ();
133
+ }
134
+
135
+ auto await_resume () -> T const
136
+ {
137
+ return res.value ();
138
+ }
139
+
140
+ auto await_suspend (std::coroutine_handle<promise_type> h) -> void
141
+ {
142
+ *(h.promise ().res ) = res;
143
+ h.destroy ();
144
+ }
145
+ };
146
+
147
+ auto operator co_await () -> awaiter
148
+ {
149
+ return awaiter{ *this };
150
+ }
151
+
152
+ private:
153
+ result (promise_type& promise)
154
+ {
155
+ promise.res = this ;
156
+ }
157
+ };
158
+
159
+ template <typename T, typename E>
160
+ auto operator <<(std::ostream& os, result<T, E> const & res) -> std::ostream&
161
+ {
162
+ if (res.is_error ()) {
163
+ os << res.get_error ();
164
+ }
165
+ else {
166
+ os << res.value ();
167
+ }
168
+ return os;
169
+ }
0 commit comments