File Coverage

src/panda/expected.h
Criterion Covered Total %
statement 0 3 0.0
branch 0 2 0.0
condition n/a
subroutine n/a
pod n/a
total 0 5 0.0


line stmt bran cond sub pod time code
1             #pragma once
2             #include
3             #include
4              
5             namespace panda {
6              
7             template
8             struct unexpected {
9             static_assert(!std::is_same::value, "E must not be void");
10              
11             unexpected () = delete;
12             constexpr explicit unexpected (const E& e) : _val(e) {}
13             constexpr explicit unexpected (E&& e) : _val(std::move(e)) {}
14              
15             constexpr const E& value () const & { return _val; }
16             constexpr const E&& value () const && { return std::move(_val); }
17              
18             E& value () & { return _val; }
19             E&& value () && { return std::move(_val); }
20              
21             private:
22             E _val;
23             };
24              
25             template
26             inline unexpected::type> make_unexpected (E &&e) {
27             return unexpected::type>(std::forward(e));
28             }
29              
30             template
31 0 0         struct bad_expected_access : std::exception {
32 0           explicit bad_expected_access (E e) : _val(std::move(e)) {}
33              
34 0           virtual const char* what () const noexcept override { return "Bad expected access"; }
35              
36             const E& error () const & { return _val; }
37             const E&& error () const && { return std::move(_val); }
38              
39             E& error () & { return _val; }
40             E&& error () && { return std::move(_val); }
41              
42             private:
43             E _val;
44             };
45              
46             /// A tag to tell expected to construct the unexpected value
47             struct unexpect_t { unexpect_t() = default; };
48             static constexpr unexpect_t unexpect {};
49              
50              
51             template
52             struct expected {
53             using value_type = T;
54             using error_type = E;
55             using unexpected_type = unexpected;
56              
57             template ::value>::type>
58             expected () {
59             _has_val = true;
60             ::new (&_val) T();
61             }
62              
63             expected (const expected& ex) {
64             if (ex._has_val) construct_val(ex._val);
65             else construct_err(ex._err);
66             }
67              
68             expected (expected&& ex) {
69             if (ex._has_val) construct_val(std::move(ex._val));
70             else construct_err(std::move(ex._err));
71             }
72              
73             template
74             explicit expected (const expected& ex) {
75             if (ex._has_val) construct_val(ex._val);
76             else construct_err(ex._err);
77             }
78              
79             template
80             explicit expected (expected&& ex) {
81             if (ex._has_val) construct_val(std::move(ex._val));
82             else construct_err(std::move(ex._err));
83             }
84              
85             template ::value>::type>
86             expected (T2&& v) {
87             construct_val(std::forward(v));
88             }
89              
90             template
91             expected (const unexpected& uex) {
92             construct_err(uex.value());
93             }
94              
95             template
96             expected (unexpected&& uex) {
97             construct_err(std::move(uex.value()));
98             }
99              
100             ~expected () {
101             if (_has_val) _val.~T();
102             else _err.~E();
103             }
104              
105             expected& operator= (const expected& ex) {
106             if (ex._has_val) set_val(ex._val);
107             else set_err(ex._err);
108             return *this;
109             }
110              
111             expected& operator= (expected&& ex) {
112             if (ex._has_val) set_val(std::move(ex._val));
113             else set_err(std::move(ex._err));
114             return *this;
115             }
116              
117             template
118             expected& operator= (T2&& v) {
119             set_val(std::forward(v));
120             }
121              
122             template
123             expected& operator= (const unexpected& uex) {
124             set_err(uex.value());
125             }
126              
127             template
128             expected& operator= (unexpected&& uex) {
129             set_err(std::move(uex.value()));
130             }
131              
132             constexpr bool has_value () const noexcept { return _has_val; }
133             constexpr explicit operator bool () const noexcept { return _has_val; }
134              
135             const T& value () const & { if (!_has_val) throw bad_expected_access(_err); return _val; }
136             T& value () & { if (!_has_val) throw bad_expected_access(_err); return _val; }
137             const T&& value () const && { if (!_has_val) throw bad_expected_access(_err); return std::move(_val); }
138             T&& value () && { if (!_has_val) throw bad_expected_access(_err); return std::move(_val); }
139              
140             template constexpr T value_or (T2&& v) const & { return bool(*this) ? this->_val : static_cast(std::forward(v)); }
141             template constexpr T value_or (T2&& v) && { return bool(*this) ? std::move(this->_val) : static_cast(std::forward(v)); }
142              
143             const E& error () const & { return _err; }
144             E& error () & { return _err; }
145             const E&& error () const && { return std::move(_err); }
146             E&& error () && { return std::move(_err); }
147              
148             const T* operator-> () const { return &_val; }
149             T* operator-> () { return &_val; }
150              
151             const T& operator* () const & { return _val; }
152             T& operator* () & { return _val; }
153             const T&& operator* () const && { return std::move(_val); }
154             T&& operator* () && { return std::move(_val); }
155              
156             template
157             void emplace (Args&&... args) {
158             if (_has_val) _val = T(std::forward(args)...);
159             else {
160             auto tmp = std::move(_err);
161             _err.~E();
162             try {
163             ::new (&_val) T(std::forward(args)...);
164             _has_val = true;
165             } catch (...) {
166             new (&_err) E(std::move(tmp));
167             throw;
168             }
169             }
170             }
171              
172             template
173             auto and_then (F&& f) const & -> decltype(f(std::declval())) {
174             if (!_has_val) return unexpected_type(_err);
175             return f(_val);
176             }
177              
178             template
179             auto and_then (F&& f) const && -> decltype(f(std::declval())) {
180             if (!_has_val) return unexpected_type(std::move(_err));
181             return f(std::move(_val));
182             }
183              
184             template
185             auto or_else (F&& f) const & -> decltype(f(std::declval())) {
186             if (_has_val) return *this;
187             return f(_err);
188             }
189              
190             template
191             auto or_else (F&& f) const && -> decltype(f(std::declval())) {
192             if (_has_val) return std::move(*this);
193             return f(std::move(_err));
194             }
195              
196             template
197             auto map (F&& f) const & -> expected())), E> {
198             if (!_has_val) return unexpected_type(_err);
199             return f(_val);
200             }
201              
202             template
203             auto map (F&& f) const && -> expected())), E> {
204             if (!_has_val) return unexpected_type(std::move(_err));
205             return f(std::move(_val));
206             }
207              
208             template
209             auto map_error (F&& f) const & -> expected()))> {
210             if (_has_val) return _val;
211             return make_unexpected(f(_err));
212             }
213              
214             template
215             auto map_error (F&& f) const && -> expected()))> {
216             if (_has_val) return std::move(_val);
217             return make_unexpected(f(std::move(_err)));
218             }
219              
220             template
221             void swap (expected& ex) {
222             if (_has_val) {
223             if (ex._has_val) std::swap(_val, ex._val);
224             else {
225             auto tmp = std::move(ex._err);
226             ex._err.~E();
227             ex._has_val = true;
228             new (&ex._val) T(std::move(_val));
229              
230             _val.~T();
231             _has_val = false;
232             new (&_err) E(std::move(tmp));
233             }
234             }
235             else {
236             if (ex._has_val) ex.swap(*this);
237             else std::swap(_err, ex._err);
238             }
239             }
240              
241             private:
242             template friend struct expected;
243              
244             template
245             void construct_val (T2&& v) {
246             _has_val = true;
247             ::new (&_val) T(std::forward(v));
248             }
249              
250             template
251             void construct_err (E2&& e) {
252             _has_val = false;
253             ::new (&_err) E(std::forward(e));
254             }
255              
256             template
257             void set_val (T2&& v) {
258             if (_has_val) _val = std::forward(v);
259             else {
260             _err.~E();
261             _has_val = true;
262             ::new (&_val) T(std::forward(v));
263             }
264             }
265              
266             template
267             void set_err (E2&& e) {
268             if (_has_val) {
269             _val.~T();
270             _has_val = false;
271             ::new (&_err) E(std::forward(e));
272             }
273             else _err = std::forward(e);
274             }
275              
276             union {
277             T _val;
278             E _err;
279             };
280             bool _has_val;
281             };
282              
283              
284             template
285             struct expected {
286             using value_type = void;
287             using error_type = E;
288             using unexpected_type = unexpected;
289              
290             expected () { _has_val = true; }
291              
292             expected (const expected& ex) {
293             if (ex._has_val) _has_val = true;
294             else construct_err(ex._err);
295             }
296              
297             expected (expected&& ex) {
298             if (ex._has_val) _has_val = true;
299             else construct_err(std::move(ex._err));
300             }
301              
302             template
303             explicit expected (const expected& ex) {
304             if (ex._has_val) _has_val = true;
305             else construct_err(ex._err);
306             }
307              
308             template
309             explicit expected (expected&& ex) {
310             if (ex._has_val) _has_val = true;
311             else construct_err(std::move(ex._err));
312             }
313              
314             template
315             expected (const unexpected& uex) {
316             construct_err(uex.value());
317             }
318              
319             template
320             expected (unexpected&& uex) {
321             construct_err(std::move(uex.value()));
322             }
323              
324             ~expected () {
325             if (!_has_val) _err.~E();
326             }
327              
328             expected& operator= (const expected& ex) {
329             if (ex._has_val) set_val();
330             else set_err(ex._err);
331             return *this;
332             }
333              
334             expected& operator= (expected&& ex) {
335             if (ex._has_val) set_val();
336             else set_err(std::move(ex._err));
337             return *this;
338             }
339              
340             template
341             expected& operator= (const unexpected& uex) {
342             set_err(uex.value());
343             }
344              
345             template
346             expected& operator= (unexpected&& uex) {
347             set_err(std::move(uex.value()));
348             }
349              
350             constexpr bool has_value () const noexcept { return _has_val; }
351             constexpr explicit operator bool () const noexcept { return _has_val; }
352              
353             const E& error () const & { return _err; }
354             E& error () & { return _err; }
355             const E&& error () const && { return std::move(_err); }
356             E&& error () && { return std::move(_err); }
357              
358             template
359             auto and_then (F&& f) const & -> decltype(f()) {
360             if (!_has_val) return unexpected_type(_err);
361             return f();
362             }
363              
364             template
365             auto and_then (F&& f) const && -> decltype(f()) {
366             if (!_has_val) return unexpected_type(std::move(_err));
367             return f();
368             }
369              
370             template
371             auto or_else (F&& f) const & -> decltype(f(std::declval())) {
372             if (_has_val) return *this;
373             return f(_err);
374             }
375              
376             template
377             auto or_else (F&& f) const && -> decltype(f(std::declval())) {
378             if (_has_val) return std::move(*this);
379             return f(std::move(_err));
380             }
381              
382             template
383             auto map (F&& f) const & -> expected {
384             if (!_has_val) return unexpected_type(_err);
385             return f();
386             }
387              
388             template
389             auto map (F&& f) const && -> expected {
390             if (!_has_val) return unexpected_type(std::move(_err));
391             return f();
392             }
393              
394             template
395             auto map_error (F&& f) const & -> expected()))> {
396             if (_has_val) return {};
397             return make_unexpected(f(_err));
398             }
399              
400             template
401             auto map_error (F&& f) const && -> expected()))> {
402             if (_has_val) return {};
403             return make_unexpected(f(std::move(_err)));
404             }
405              
406             template
407             void swap (expected& ex) {
408             if (_has_val) {
409             if (!ex._has_val) {
410             new (&_err) E(std::move(ex._err));
411             ex._err.~E();
412             std::swap(_has_val, ex._has_val);
413             }
414             }
415             else {
416             if (ex._has_val) ex.swap(*this);
417             else std::swap(_err, ex._err);
418             }
419             }
420              
421             private:
422             template friend struct expected;
423              
424             template
425             void construct_err (E2&& e) {
426             _has_val = false;
427             ::new (&_err) E(std::forward(e));
428             }
429              
430             void set_val () {
431             if (_has_val) return;
432             _err.~E();
433             _has_val = true;
434             }
435              
436             template
437             void set_err (E2&& e) {
438             if (_has_val) {
439             _has_val = false;
440             ::new (&_err) E(std::forward(e));
441             }
442             else _err = std::forward(e);
443             }
444              
445             union {
446             E _err;
447             };
448             bool _has_val;
449             };
450              
451             template
452             bool operator== (const expected& lhs, const expected& rhs) {
453             if (lhs.has_value() != rhs.has_value()) return false;
454             return lhs.has_value() ? *lhs == *rhs : lhs.error() == rhs.error();
455             }
456              
457             template
458             bool operator== (const expected& lhs, const expected& rhs) {
459             if (lhs.has_value() != rhs.has_value()) return false;
460             return lhs.has_value() ? true : lhs.error() == rhs.error();
461             }
462              
463             template
464             bool operator!= (const expected& lhs, const expected& rhs) { return !operator==(lhs, rhs); }
465              
466             template
467             typename std::enable_if::value, bool>::type
468             operator== (const expected& x, const T2& v) { return x.has_value() ? *x == v : false; }
469              
470             template
471             bool operator== (const T2& v, const expected& x) { return x == v; }
472              
473             template
474             bool operator!= (const expected& x, const T2& v) { return !(x == v); }
475              
476             template
477             bool operator!= (const T2& v, const expected& x) { return !(x == v); }
478              
479             template
480             bool operator== (const expected& x, const unexpected& e) { return x.has_value() ? false : x.error() == e.value(); }
481             template
482             bool operator== (const unexpected& e, const expected& x) { return x == e; }
483             template
484             bool operator!= (const expected& x, const unexpected& e) { return !(x == e); }
485             template
486             bool operator!= (const unexpected& e, const expected& x) { return !(x == e); }
487              
488             template
489             void swap (expected& lhs, expected& rhs) { lhs.swap(rhs); }
490              
491              
492             }