comparison dep/toml11/toml/result.hpp @ 318:3b355fa948c7

config: use TOML instead of INI unfortunately, INI is not enough, and causes some paths including semicolons to break with our current storage of the library folders. so, I decided to switch to TOML which does support real arrays...
author Paper <paper@paper.us.eu.org>
date Wed, 12 Jun 2024 05:25:41 -0400
parents
children
comparison
equal deleted inserted replaced
317:b1f4d1867ab1 318:3b355fa948c7
1 // Copyright Toru Niina 2017.
2 // Distributed under the MIT License.
3 #ifndef TOML11_RESULT_HPP
4 #define TOML11_RESULT_HPP
5 #include "traits.hpp"
6 #include <type_traits>
7 #include <stdexcept>
8 #include <utility>
9 #include <new>
10 #include <string>
11 #include <sstream>
12 #include <cassert>
13
14 namespace toml
15 {
16
17 template<typename T>
18 struct success
19 {
20 using value_type = T;
21 value_type value;
22
23 explicit success(const value_type& v)
24 noexcept(std::is_nothrow_copy_constructible<value_type>::value)
25 : value(v)
26 {}
27 explicit success(value_type&& v)
28 noexcept(std::is_nothrow_move_constructible<value_type>::value)
29 : value(std::move(v))
30 {}
31
32 template<typename U>
33 explicit success(U&& v): value(std::forward<U>(v)) {}
34
35 template<typename U>
36 explicit success(const success<U>& v): value(v.value) {}
37 template<typename U>
38 explicit success(success<U>&& v): value(std::move(v.value)) {}
39
40 ~success() = default;
41 success(const success&) = default;
42 success(success&&) = default;
43 success& operator=(const success&) = default;
44 success& operator=(success&&) = default;
45 };
46
47 template<typename T>
48 struct failure
49 {
50 using value_type = T;
51 value_type value;
52
53 explicit failure(const value_type& v)
54 noexcept(std::is_nothrow_copy_constructible<value_type>::value)
55 : value(v)
56 {}
57 explicit failure(value_type&& v)
58 noexcept(std::is_nothrow_move_constructible<value_type>::value)
59 : value(std::move(v))
60 {}
61
62 template<typename U>
63 explicit failure(U&& v): value(std::forward<U>(v)) {}
64
65 template<typename U>
66 explicit failure(const failure<U>& v): value(v.value) {}
67 template<typename U>
68 explicit failure(failure<U>&& v): value(std::move(v.value)) {}
69
70 ~failure() = default;
71 failure(const failure&) = default;
72 failure(failure&&) = default;
73 failure& operator=(const failure&) = default;
74 failure& operator=(failure&&) = default;
75 };
76
77 template<typename T>
78 success<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
79 ok(T&& v)
80 {
81 return success<
82 typename std::remove_cv<typename std::remove_reference<T>::type>::type
83 >(std::forward<T>(v));
84 }
85 template<typename T>
86 failure<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
87 err(T&& v)
88 {
89 return failure<
90 typename std::remove_cv<typename std::remove_reference<T>::type>::type
91 >(std::forward<T>(v));
92 }
93
94 inline success<std::string> ok(const char* literal)
95 {
96 return success<std::string>(std::string(literal));
97 }
98 inline failure<std::string> err(const char* literal)
99 {
100 return failure<std::string>(std::string(literal));
101 }
102
103
104 template<typename T, typename E>
105 struct result
106 {
107 using value_type = T;
108 using error_type = E;
109 using success_type = success<value_type>;
110 using failure_type = failure<error_type>;
111
112 result(const success_type& s): is_ok_(true)
113 {
114 auto tmp = ::new(std::addressof(this->succ)) success_type(s);
115 assert(tmp == std::addressof(this->succ));
116 (void)tmp;
117 }
118 result(const failure_type& f): is_ok_(false)
119 {
120 auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
121 assert(tmp == std::addressof(this->fail));
122 (void)tmp;
123 }
124 result(success_type&& s): is_ok_(true)
125 {
126 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
127 assert(tmp == std::addressof(this->succ));
128 (void)tmp;
129 }
130 result(failure_type&& f): is_ok_(false)
131 {
132 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
133 assert(tmp == std::addressof(this->fail));
134 (void)tmp;
135 }
136
137 template<typename U>
138 result(const success<U>& s): is_ok_(true)
139 {
140 auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
141 assert(tmp == std::addressof(this->succ));
142 (void)tmp;
143 }
144 template<typename U>
145 result(const failure<U>& f): is_ok_(false)
146 {
147 auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
148 assert(tmp == std::addressof(this->fail));
149 (void)tmp;
150 }
151 template<typename U>
152 result(success<U>&& s): is_ok_(true)
153 {
154 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
155 assert(tmp == std::addressof(this->succ));
156 (void)tmp;
157 }
158 template<typename U>
159 result(failure<U>&& f): is_ok_(false)
160 {
161 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
162 assert(tmp == std::addressof(this->fail));
163 (void)tmp;
164 }
165
166 result& operator=(const success_type& s)
167 {
168 this->cleanup();
169 this->is_ok_ = true;
170 auto tmp = ::new(std::addressof(this->succ)) success_type(s);
171 assert(tmp == std::addressof(this->succ));
172 (void)tmp;
173 return *this;
174 }
175 result& operator=(const failure_type& f)
176 {
177 this->cleanup();
178 this->is_ok_ = false;
179 auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
180 assert(tmp == std::addressof(this->fail));
181 (void)tmp;
182 return *this;
183 }
184 result& operator=(success_type&& s)
185 {
186 this->cleanup();
187 this->is_ok_ = true;
188 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
189 assert(tmp == std::addressof(this->succ));
190 (void)tmp;
191 return *this;
192 }
193 result& operator=(failure_type&& f)
194 {
195 this->cleanup();
196 this->is_ok_ = false;
197 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
198 assert(tmp == std::addressof(this->fail));
199 (void)tmp;
200 return *this;
201 }
202
203 template<typename U>
204 result& operator=(const success<U>& s)
205 {
206 this->cleanup();
207 this->is_ok_ = true;
208 auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
209 assert(tmp == std::addressof(this->succ));
210 (void)tmp;
211 return *this;
212 }
213 template<typename U>
214 result& operator=(const failure<U>& f)
215 {
216 this->cleanup();
217 this->is_ok_ = false;
218 auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
219 assert(tmp == std::addressof(this->fail));
220 (void)tmp;
221 return *this;
222 }
223 template<typename U>
224 result& operator=(success<U>&& s)
225 {
226 this->cleanup();
227 this->is_ok_ = true;
228 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
229 assert(tmp == std::addressof(this->succ));
230 (void)tmp;
231 return *this;
232 }
233 template<typename U>
234 result& operator=(failure<U>&& f)
235 {
236 this->cleanup();
237 this->is_ok_ = false;
238 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
239 assert(tmp == std::addressof(this->fail));
240 (void)tmp;
241 return *this;
242 }
243
244 ~result() noexcept {this->cleanup();}
245
246 result(const result& other): is_ok_(other.is_ok())
247 {
248 if(other.is_ok())
249 {
250 auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
251 assert(tmp == std::addressof(this->succ));
252 (void)tmp;
253 }
254 else
255 {
256 auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
257 assert(tmp == std::addressof(this->fail));
258 (void)tmp;
259 }
260 }
261 result(result&& other): is_ok_(other.is_ok())
262 {
263 if(other.is_ok())
264 {
265 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
266 assert(tmp == std::addressof(this->succ));
267 (void)tmp;
268 }
269 else
270 {
271 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
272 assert(tmp == std::addressof(this->fail));
273 (void)tmp;
274 }
275 }
276
277 template<typename U, typename F>
278 result(const result<U, F>& other): is_ok_(other.is_ok())
279 {
280 if(other.is_ok())
281 {
282 auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
283 assert(tmp == std::addressof(this->succ));
284 (void)tmp;
285 }
286 else
287 {
288 auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
289 assert(tmp == std::addressof(this->fail));
290 (void)tmp;
291 }
292 }
293 template<typename U, typename F>
294 result(result<U, F>&& other): is_ok_(other.is_ok())
295 {
296 if(other.is_ok())
297 {
298 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
299 assert(tmp == std::addressof(this->succ));
300 (void)tmp;
301 }
302 else
303 {
304 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
305 assert(tmp == std::addressof(this->fail));
306 (void)tmp;
307 }
308 }
309
310 result& operator=(const result& other)
311 {
312 this->cleanup();
313 if(other.is_ok())
314 {
315 auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
316 assert(tmp == std::addressof(this->succ));
317 (void)tmp;
318 }
319 else
320 {
321 auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
322 assert(tmp == std::addressof(this->fail));
323 (void)tmp;
324 }
325 is_ok_ = other.is_ok();
326 return *this;
327 }
328 result& operator=(result&& other)
329 {
330 this->cleanup();
331 if(other.is_ok())
332 {
333 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
334 assert(tmp == std::addressof(this->succ));
335 (void)tmp;
336 }
337 else
338 {
339 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
340 assert(tmp == std::addressof(this->fail));
341 (void)tmp;
342 }
343 is_ok_ = other.is_ok();
344 return *this;
345 }
346
347 template<typename U, typename F>
348 result& operator=(const result<U, F>& other)
349 {
350 this->cleanup();
351 if(other.is_ok())
352 {
353 auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
354 assert(tmp == std::addressof(this->succ));
355 (void)tmp;
356 }
357 else
358 {
359 auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
360 assert(tmp == std::addressof(this->fail));
361 (void)tmp;
362 }
363 is_ok_ = other.is_ok();
364 return *this;
365 }
366 template<typename U, typename F>
367 result& operator=(result<U, F>&& other)
368 {
369 this->cleanup();
370 if(other.is_ok())
371 {
372 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
373 assert(tmp == std::addressof(this->succ));
374 (void)tmp;
375 }
376 else
377 {
378 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
379 assert(tmp == std::addressof(this->fail));
380 (void)tmp;
381 }
382 is_ok_ = other.is_ok();
383 return *this;
384 }
385
386 bool is_ok() const noexcept {return is_ok_;}
387 bool is_err() const noexcept {return !is_ok_;}
388
389 operator bool() const noexcept {return is_ok_;}
390
391 value_type& unwrap() &
392 {
393 if(is_err())
394 {
395 throw std::runtime_error("toml::result: bad unwrap: " +
396 format_error(this->as_err()));
397 }
398 return this->succ.value;
399 }
400 value_type const& unwrap() const&
401 {
402 if(is_err())
403 {
404 throw std::runtime_error("toml::result: bad unwrap: " +
405 format_error(this->as_err()));
406 }
407 return this->succ.value;
408 }
409 value_type&& unwrap() &&
410 {
411 if(is_err())
412 {
413 throw std::runtime_error("toml::result: bad unwrap: " +
414 format_error(this->as_err()));
415 }
416 return std::move(this->succ.value);
417 }
418
419 value_type& unwrap_or(value_type& opt) &
420 {
421 if(is_err()) {return opt;}
422 return this->succ.value;
423 }
424 value_type const& unwrap_or(value_type const& opt) const&
425 {
426 if(is_err()) {return opt;}
427 return this->succ.value;
428 }
429 value_type unwrap_or(value_type opt) &&
430 {
431 if(is_err()) {return opt;}
432 return this->succ.value;
433 }
434
435 error_type& unwrap_err() &
436 {
437 if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
438 return this->fail.value;
439 }
440 error_type const& unwrap_err() const&
441 {
442 if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
443 return this->fail.value;
444 }
445 error_type&& unwrap_err() &&
446 {
447 if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
448 return std::move(this->fail.value);
449 }
450
451 value_type& as_ok() & noexcept {return this->succ.value;}
452 value_type const& as_ok() const& noexcept {return this->succ.value;}
453 value_type&& as_ok() && noexcept {return std::move(this->succ.value);}
454
455 error_type& as_err() & noexcept {return this->fail.value;}
456 error_type const& as_err() const& noexcept {return this->fail.value;}
457 error_type&& as_err() && noexcept {return std::move(this->fail.value);}
458
459
460 // prerequisities
461 // F: T -> U
462 // retval: result<U, E>
463 template<typename F>
464 result<detail::return_type_of_t<F, value_type&>, error_type>
465 map(F&& f) &
466 {
467 if(this->is_ok()){return ok(f(this->as_ok()));}
468 return err(this->as_err());
469 }
470 template<typename F>
471 result<detail::return_type_of_t<F, value_type const&>, error_type>
472 map(F&& f) const&
473 {
474 if(this->is_ok()){return ok(f(this->as_ok()));}
475 return err(this->as_err());
476 }
477 template<typename F>
478 result<detail::return_type_of_t<F, value_type &&>, error_type>
479 map(F&& f) &&
480 {
481 if(this->is_ok()){return ok(f(std::move(this->as_ok())));}
482 return err(std::move(this->as_err()));
483 }
484
485 // prerequisities
486 // F: E -> F
487 // retval: result<T, F>
488 template<typename F>
489 result<value_type, detail::return_type_of_t<F, error_type&>>
490 map_err(F&& f) &
491 {
492 if(this->is_err()){return err(f(this->as_err()));}
493 return ok(this->as_ok());
494 }
495 template<typename F>
496 result<value_type, detail::return_type_of_t<F, error_type const&>>
497 map_err(F&& f) const&
498 {
499 if(this->is_err()){return err(f(this->as_err()));}
500 return ok(this->as_ok());
501 }
502 template<typename F>
503 result<value_type, detail::return_type_of_t<F, error_type&&>>
504 map_err(F&& f) &&
505 {
506 if(this->is_err()){return err(f(std::move(this->as_err())));}
507 return ok(std::move(this->as_ok()));
508 }
509
510 // prerequisities
511 // F: T -> U
512 // retval: U
513 template<typename F, typename U>
514 detail::return_type_of_t<F, value_type&>
515 map_or_else(F&& f, U&& opt) &
516 {
517 if(this->is_err()){return std::forward<U>(opt);}
518 return f(this->as_ok());
519 }
520 template<typename F, typename U>
521 detail::return_type_of_t<F, value_type const&>
522 map_or_else(F&& f, U&& opt) const&
523 {
524 if(this->is_err()){return std::forward<U>(opt);}
525 return f(this->as_ok());
526 }
527 template<typename F, typename U>
528 detail::return_type_of_t<F, value_type&&>
529 map_or_else(F&& f, U&& opt) &&
530 {
531 if(this->is_err()){return std::forward<U>(opt);}
532 return f(std::move(this->as_ok()));
533 }
534
535 // prerequisities
536 // F: E -> U
537 // retval: U
538 template<typename F, typename U>
539 detail::return_type_of_t<F, error_type&>
540 map_err_or_else(F&& f, U&& opt) &
541 {
542 if(this->is_ok()){return std::forward<U>(opt);}
543 return f(this->as_err());
544 }
545 template<typename F, typename U>
546 detail::return_type_of_t<F, error_type const&>
547 map_err_or_else(F&& f, U&& opt) const&
548 {
549 if(this->is_ok()){return std::forward<U>(opt);}
550 return f(this->as_err());
551 }
552 template<typename F, typename U>
553 detail::return_type_of_t<F, error_type&&>
554 map_err_or_else(F&& f, U&& opt) &&
555 {
556 if(this->is_ok()){return std::forward<U>(opt);}
557 return f(std::move(this->as_err()));
558 }
559
560 // prerequisities:
561 // F: func T -> U
562 // toml::err(error_type) should be convertible to U.
563 // normally, type U is another result<S, F> and E is convertible to F
564 template<typename F>
565 detail::return_type_of_t<F, value_type&>
566 and_then(F&& f) &
567 {
568 if(this->is_ok()){return f(this->as_ok());}
569 return err(this->as_err());
570 }
571 template<typename F>
572 detail::return_type_of_t<F, value_type const&>
573 and_then(F&& f) const&
574 {
575 if(this->is_ok()){return f(this->as_ok());}
576 return err(this->as_err());
577 }
578 template<typename F>
579 detail::return_type_of_t<F, value_type&&>
580 and_then(F&& f) &&
581 {
582 if(this->is_ok()){return f(std::move(this->as_ok()));}
583 return err(std::move(this->as_err()));
584 }
585
586 // prerequisities:
587 // F: func E -> U
588 // toml::ok(value_type) should be convertible to U.
589 // normally, type U is another result<S, F> and T is convertible to S
590 template<typename F>
591 detail::return_type_of_t<F, error_type&>
592 or_else(F&& f) &
593 {
594 if(this->is_err()){return f(this->as_err());}
595 return ok(this->as_ok());
596 }
597 template<typename F>
598 detail::return_type_of_t<F, error_type const&>
599 or_else(F&& f) const&
600 {
601 if(this->is_err()){return f(this->as_err());}
602 return ok(this->as_ok());
603 }
604 template<typename F>
605 detail::return_type_of_t<F, error_type&&>
606 or_else(F&& f) &&
607 {
608 if(this->is_err()){return f(std::move(this->as_err()));}
609 return ok(std::move(this->as_ok()));
610 }
611
612 // if *this is error, returns *this. otherwise, returns other.
613 result and_other(const result& other) const&
614 {
615 return this->is_err() ? *this : other;
616 }
617 result and_other(result&& other) &&
618 {
619 return this->is_err() ? std::move(*this) : std::move(other);
620 }
621
622 // if *this is okay, returns *this. otherwise, returns other.
623 result or_other(const result& other) const&
624 {
625 return this->is_ok() ? *this : other;
626 }
627 result or_other(result&& other) &&
628 {
629 return this->is_ok() ? std::move(*this) : std::move(other);
630 }
631
632 void swap(result<T, E>& other)
633 {
634 result<T, E> tmp(std::move(*this));
635 *this = std::move(other);
636 other = std::move(tmp);
637 return ;
638 }
639
640 private:
641
642 static std::string format_error(std::exception const& excpt)
643 {
644 return std::string(excpt.what());
645 }
646 template<typename U, typename std::enable_if<!std::is_base_of<
647 std::exception, U>::value, std::nullptr_t>::type = nullptr>
648 static std::string format_error(U const& others)
649 {
650 std::ostringstream oss; oss << others;
651 return oss.str();
652 }
653
654 void cleanup() noexcept
655 {
656 if(this->is_ok_) {this->succ.~success_type();}
657 else {this->fail.~failure_type();}
658 return;
659 }
660
661 private:
662
663 bool is_ok_;
664 union
665 {
666 success_type succ;
667 failure_type fail;
668 };
669 };
670
671 template<typename T, typename E>
672 void swap(result<T, E>& lhs, result<T, E>& rhs)
673 {
674 lhs.swap(rhs);
675 return;
676 }
677
678 // this might be confusing because it eagerly evaluated, while in the other
679 // cases operator && and || are short-circuited.
680 //
681 // template<typename T, typename E>
682 // inline result<T, E>
683 // operator&&(const result<T, E>& lhs, const result<T, E>& rhs) noexcept
684 // {
685 // return lhs.is_ok() ? rhs : lhs;
686 // }
687 //
688 // template<typename T, typename E>
689 // inline result<T, E>
690 // operator||(const result<T, E>& lhs, const result<T, E>& rhs) noexcept
691 // {
692 // return lhs.is_ok() ? lhs : rhs;
693 // }
694
695 // ----------------------------------------------------------------------------
696 // re-use result<T, E> as a optional<T> with none_t
697
698 namespace detail
699 {
700 struct none_t {};
701 inline bool operator==(const none_t&, const none_t&) noexcept {return true;}
702 inline bool operator!=(const none_t&, const none_t&) noexcept {return false;}
703 inline bool operator< (const none_t&, const none_t&) noexcept {return false;}
704 inline bool operator<=(const none_t&, const none_t&) noexcept {return true;}
705 inline bool operator> (const none_t&, const none_t&) noexcept {return false;}
706 inline bool operator>=(const none_t&, const none_t&) noexcept {return true;}
707 template<typename charT, typename traitsT>
708 std::basic_ostream<charT, traitsT>&
709 operator<<(std::basic_ostream<charT, traitsT>& os, const none_t&)
710 {
711 os << "none";
712 return os;
713 }
714 inline failure<none_t> none() noexcept {return failure<none_t>{none_t{}};}
715 } // detail
716 } // toml11
717 #endif// TOML11_RESULT_H