Woman, Life, Freedom


Adaptive AUTOSAR
ARA public interface header documentation
result.h
1#ifndef RESULT_H
2#define RESULT_H
3
4#include "./error_code.h"
5#include "./optional.h"
6
7namespace ara
8{
9 namespace core
10 {
14 template <typename T, typename E = ErrorCode>
15 class Result final
16 {
17 private:
18 Optional<T> mValue;
19 Optional<E> mError;
20
21 public:
23 using value_type = T;
25 using error_type = E;
26
27 Result() = delete;
28
29 Result(const T &t) noexcept(
30 std::is_nothrow_copy_constructible<T>::value) : mValue{t}
31 {
32 }
33
34 Result(T &&t) noexcept(
35 std::is_nothrow_move_constructible<T>::value) : mValue{std::move(t)}
36 {
37 }
38
39 explicit Result(const E &e) noexcept(
40 std::is_nothrow_copy_constructible<E>::value) : mError{e}
41 {
42 }
43
44 explicit Result(E &&e) noexcept(
45 std::is_nothrow_move_constructible<E>::value) : mError{std::move(e)}
46 {
47 }
48
49 Result(const Result &other) noexcept(
50 std::is_nothrow_copy_assignable<T>::value &&
51 std::is_nothrow_copy_assignable<E>::value)
52 {
53 // Copy the value if it exists, otherwise copy the error
54 if (other.HasValue())
55 {
56 mValue = other.mValue;
57 }
58 else
59 {
60 mError = other.mError;
61 }
62 }
63
64 Result(Result &&other) noexcept(
65 std::is_nothrow_move_assignable<T>::value &&
66 std::is_nothrow_move_assignable<E>::value)
67 {
68 // Move the value if it exists, otherwise move the error
69 if (other.HasValue())
70 {
71 mValue = std::move(other.mValue);
72 }
73 else
74 {
75 mError = std::move(other.mError);
76 }
77 }
78
79 ~Result() noexcept = default;
80
84 static Result FromValue(const T &t) noexcept(
85 std::is_nothrow_copy_constructible<T>::value);
86
90 static Result FromValue(T &&t) noexcept(
91 std::is_nothrow_move_constructible<T>::value);
92
96 static Result FromError(const E &e) noexcept(
97 std::is_nothrow_copy_constructible<E>::value);
98
102 static Result FromError(E &&e) noexcept(
103 std::is_nothrow_move_constructible<E>::value);
104
105 Result &operator=(Result const &other) noexcept(
106 std::is_nothrow_copy_assignable<T>::value &&
107 std::is_nothrow_copy_assignable<E>::value)
108 {
109 // Copy the value if it exists and reset the error, otherwise copy the error and reset the value
110 if (other.HasValue())
111 {
112 mValue = other.mValue;
113 mError.Reset();
114 }
115 else
116 {
117 mError = other.mError;
118 mValue.Reset();
119 }
120
121 return *this;
122 }
123
124 Result &operator=(Result &&other) noexcept(
125 std::is_nothrow_move_assignable<T>::value &&
126 std::is_nothrow_move_assignable<E>::value)
127 {
128 // Move the value if it exists and reset the error, otherwise move the error and reset the value
129 if (other.HasValue())
130 {
131 mValue = std::move(other.mValue);
132 mError.Reset();
133 }
134 else
135 {
136 mError = std::move(other.mError);
137 mValue.Reset();
138 }
139
140 return *this;
141 }
142
145 template <typename... Args>
146 void EmplaceValue(Args &&...args)
147 {
148 mValue = T{std::move(args...)};
149 mError.Reset();
150 }
151
154 template <typename... Args>
155 void EmplaceError(Args &&...args)
156 {
157 mError = E{std::move(args...)};
158 mValue.Reset();
159 }
160
163 void Swap(Result &other) noexcept(
164 std::is_nothrow_move_assignable<T>::value &&
165 std::is_nothrow_move_assignable<E>::value)
166 {
167 if (HasValue() && other.HasValue())
168 {
169 std::swap(mValue, other.mValue);
170 }
171 else if (HasValue() && !other.HasValue())
172 {
173 mError = std::move(other.mError);
174 other.mValue = std::move(mValue);
175 }
176 else if (!HasValue() && other.HasValue())
177 {
178 mValue = std::move(other.mValue);
179 other.mError = std::move(mError);
180 }
181 else // Both instances contain error
182 {
183 std::swap(mError, other.mError);
184 }
185 }
186
189 bool HasValue() const noexcept
190 {
191 return mValue.HasValue();
192 }
193
195 explicit operator bool() const noexcept
196 {
197 return HasValue();
198 }
199
202 const T &operator*() const &
203 {
204 return mValue.Value();
205 }
206
209 T &&operator*() &&
210 {
211 return std::move(mValue).Value();
212 }
213
216 const T *operator->() const
217 {
218 return &mValue.Value();
219 }
220
224 const T &Value() const &
225 {
226 return mValue.Value();
227 }
228
232 T &&Value() &&
233 {
234 return std::move(mValue).Value();
235 }
236
240 const E &Error() const &
241 {
242 return mError.Value();
243 }
244
248 E &&Error() &&
249 {
250 return std::move(mError).Value();
251 }
252
255 Optional<T> Ok() const &
256 {
257 return mValue;
258 }
259
263 {
264 return std::move(mValue);
265 }
266
269 Optional<E> Err() const &
270 {
271 return mError;
272 }
273
277 {
278 return std::move(mError);
279 }
280
285 template <typename U>
286 T ValueOr(U &&defaultValue) const &
287 {
288 return mValue.ValueOr(defaultValue);
289 }
290
295 template <typename U>
296 T ValueOr(U &&defaultValue) &&
297 {
298 return std::move(mValue).ValueOr(defaultValue);
299 }
300
305 template <typename G>
306 E ErrorOr(G &&defaultError) const &
307 {
308 return mError.ValueOr(defaultError);
309 }
310
315 template <typename G>
316 E ErrorOr(G &&defaultError) &&
317 {
318 return std::move(mError).ValueOr(defaultError);
319 }
320
324 template <typename G>
325 bool CheckError(G &&error) const
326 {
327 if (HasValue())
328 {
329 // No error exists for comparison
330 return false;
331 }
332 else
333 {
334 E _error = static_cast<E>(error);
335 return mError.Value() == _error;
336 }
337 }
338
342 const T &ValueOrThrow() const &noexcept(false)
343 {
344 return mValue.Value();
345 }
346
350 T &&ValueOrThrow() &&noexcept(false)
351 {
352 return std::move(mValue).Value();
353 }
354
359 template <typename F>
360 T Resolve(F &&f) const
361 {
362 return HasValue() ? Value() : f(Error());
363 }
364
369 template <typename F>
370 auto Bind(F &&f) const -> Result<decltype(f(Value())), E>
371 {
372 if (HasValue())
373 {
374 Result<decltype(f(Value())), E> _result{f(Value())};
375 return _result;
376 }
377 else
378 {
379 Result<decltype(f(Value())), E> _result{Error()};
380 return _result;
381 }
382 }
383 };
384
385 template <typename T, typename E>
387 std::is_nothrow_copy_constructible<T>::value)
388 {
389 Result _result{t};
390 return _result;
391 }
392
393 template <typename T, typename E>
395 std::is_nothrow_move_constructible<T>::value)
396 {
397 Result _result{std::move(t)};
398 return _result;
399 }
400
401 template <typename T, typename E>
403 std::is_nothrow_copy_constructible<E>::value)
404 {
405 Result _result{e};
406 return _result;
407 }
408
409 template <typename T, typename E>
411 std::is_nothrow_move_constructible<E>::value)
412 {
413 Result _result{std::move(e)};
414 return _result;
415 }
416
418 template <typename T, typename E>
419 inline bool operator==(const Result<T, E> &lhs, const Result<T, E> &rhs)
420 {
421 bool _result;
422
423 if (lhs.HasValue() && rhs.HasValue())
424 {
425 _result = lhs.Value() == rhs.Value();
426 }
427 else if (!lhs.HasValue() && !rhs.HasValue())
428 {
429 _result = lhs.Error() == rhs.Error();
430 }
431 else
432 {
433 _result = false;
434 }
435
436 return _result;
437 }
438
440 template <typename T, typename E>
441 inline bool operator!=(const Result<T, E> &lhs, const Result<T, E> &rhs)
442 {
443 bool _result;
444
445 if (lhs.HasValue() && rhs.HasValue())
446 {
447 _result = lhs.Value() != rhs.Value();
448 }
449 else if (!lhs.HasValue() && !rhs.HasValue())
450 {
451 _result = lhs.Error() != rhs.Error();
452 }
453 else
454 {
455 _result = true;
456 }
457
458 return _result;
459 }
460
461 template <typename T, typename E>
462 inline bool operator==(const Result<T, E> &lhs, const T &rhs)
463 {
464 bool _result = lhs.HasValue() ? lhs.Value() == rhs : false;
465 return _result;
466 }
467
468 template <typename T, typename E>
469 inline bool operator==(const T &lhs, const Result<T, E> &rhs)
470 {
471 bool _result = rhs.HasValue() ? lhs == rhs.Value() : false;
472 return _result;
473 }
474
475 template <typename T, typename E>
476 inline bool operator!=(const Result<T, E> &lhs, const T &rhs)
477 {
478 bool _result = lhs.HasValue() ? lhs.Value() != rhs : true;
479 return _result;
480 }
481
482 template <typename T, typename E>
483 inline bool operator!=(const T &lhs, const Result<T, E> &rhs)
484 {
485 bool _result = rhs.HasValue() ? lhs != rhs.Value() : true;
486 return _result;
487 }
488
489 template <typename T, typename E>
490 inline bool operator==(const Result<T, E> &lhs, const E &rhs)
491 {
492 bool _result = lhs.HasValue() ? false : lhs.Error() == rhs;
493 return _result;
494 }
495
496 template <typename T, typename E>
497 inline bool operator==(const E &lhs, const Result<T, E> &rhs)
498 {
499 bool _result = rhs.HasValue() ? false : lhs == rhs.Error();
500 return _result;
501 }
502
503 template <typename T, typename E>
504 inline bool operator!=(const Result<T, E> &lhs, const E &rhs)
505 {
506 bool _result = lhs.HasValue() ? true : lhs.Error() != rhs;
507 return _result;
508 }
509
510 template <typename T, typename E>
511 inline bool operator!=(const E &lhs, const Result<T, E> &rhs)
512 {
513 bool _result = rhs.HasValue() ? true : lhs != rhs.Error();
514 return _result;
515 }
516
519 template <typename E>
520 class Result<void, E> final
521 {
522 private:
523 Optional<E> mError;
524
525 bool hasError() const noexcept
526 {
527 return mError.HasValue();
528 }
529
530 public:
532 using value_type = void;
534 using error_type = E;
535
536 Result() noexcept = default;
537
538 explicit Result(const E &e) noexcept(
539 std::is_nothrow_copy_constructible<E>::value) : mError{e}
540 {
541 }
542
543 explicit Result(E &&e) noexcept(
544 std::is_nothrow_move_constructible<E>::value) : mError{std::move(e)}
545 {
546 }
547
548 Result(const Result &other) noexcept(
549 std::is_nothrow_copy_assignable<E>::value)
550 {
551 if (other.hasError())
552 {
553 mError = other.mError;
554 }
555 }
556
557 Result(Result &&other) noexcept(
558 std::is_nothrow_move_assignable<E>::value)
559 {
560 if (other.hasError())
561 {
562 mError = std::move(other.mError);
563 }
564 }
565
566 ~Result() noexcept = default;
567
570 static Result FromValue() noexcept;
571
575 static Result FromError(const E &e) noexcept(
576 std::is_nothrow_copy_constructible<E>::value);
577
581 static Result FromError(E &&e) noexcept(
582 std::is_nothrow_move_constructible<E>::value);
583
586 template <typename... Args>
587 static Result FromError(Args &&...args);
588
589 Result &operator=(Result const &other) noexcept(
590 std::is_nothrow_copy_assignable<E>::value)
591 {
592 if (other.hasError())
593 {
594 mError = other.mError;
595 }
596 else
597 {
598 mError.Reset();
599 }
600
601 return *this;
602 }
603
604 Result &operator=(Result &&other) noexcept(
605 std::is_nothrow_move_assignable<E>::value)
606 {
607 if (other.mHasError)
608 {
609 mError = std::move(other.mError);
610 }
611 else
612 {
613 mError.Reset();
614 }
615
616 return *this;
617 }
618
621 template <typename... Args>
622 void EmplaceError(Args &&...args)
623 {
624 mError = E{args...};
625 }
626
629 void Swap(Result &other) noexcept(
630 std::is_nothrow_move_assignable<E>::value)
631 {
632 if (hasError() && other.hasError())
633 {
634 std::swap(mError, other.mError);
635 }
636 else if (hasError() && !other.hasError())
637 {
638 other.mError = std::move(mError);
639 }
640 else if (!hasError() && other.hasError())
641 {
642 mError = std::move(other.mError);
643 }
644 }
645
648 constexpr bool HasValue() const noexcept
649 {
650 return !hasError();
651 }
652
654 constexpr explicit operator bool() const noexcept
655 {
656 return HasValue();
657 }
658
659 constexpr void operator*() const noexcept
660 {
661 // The function does nothing and it is implemented to help with generic programming.
662 }
663
664 constexpr void operator->() const noexcept
665 {
666 // The function does nothing and it is implemented to help with generic programming.
667 }
668
670 constexpr void Value() const noexcept
671 {
672 // The function does nothing and it is implemented to help with generic programming.
673 }
674
678 const E &Error() const &
679 {
680 return mError.Value();
681 }
682
686 E &&Error() &&
687 {
688 return std::move(mError).Value();
689 }
690
693 Optional<E> Err() const &
694 {
695 return mError;
696 }
697
701 {
702 return std::move(mError);
703 }
704
706 template <typename U>
707 void ValueOr(U &&defaultValue) const noexcept
708 {
709 // The function does nothing and it is implemented to help with generic programming.
710 }
711
716 template <typename G>
717 E ErrorOr(G &&defaultError) const &
718 {
719 return mError.ValueOr(defaultError);
720 }
721
726 template <typename G>
727 E ErrorOr(G &&defaultError) &&
728 {
729 return std::move(mError).ValueOr(defaultError);
730 }
731
735 template <typename G>
736 bool CheckError(G &&error) const
737 {
738 if (hasError())
739 {
740 E _error = static_cast<E>(error);
741 return mError.Value() == _error;
742 }
743 else
744 {
745 // No error exists for comparison
746 return false;
747 }
748 }
749
752 void ValueOrThrow() const noexcept(false)
753 {
754 throw std::runtime_error("Result contains no value.");
755 }
756
760 template <typename F>
761 void Resolve(F &&f) const
762 {
763 if (hasError())
764 {
765 f(Error());
766 }
767 }
768
773 template <typename F>
774 auto Bind(F &&f) const -> Result<decltype(f()), E>
775 {
776 if (hasError())
777 {
778 Result<decltype(f()), E> _result{Error()};
779 return _result;
780 }
781 else
782 {
783 Result<decltype(f()), E> _result{f()};
784 return _result;
785 }
786 }
787 };
788
789 template <typename E>
791 {
792 Result _result;
793 return _result;
794 }
795
796 template <typename E>
798 std::is_nothrow_copy_constructible<E>::value)
799 {
800 Result _result{e};
801 return _result;
802 }
803
804 template <typename E>
806 std::is_nothrow_move_constructible<E>::value)
807 {
808 Result _result{std::move(e)};
809 return _result;
810 }
811
812 template <typename E>
813 template <typename... Args>
815 {
816 E _error{std::move(args...)};
817 Result _result{_error};
818
819 return _result;
820 }
821
823 template <typename E>
824 inline bool operator==(const Result<void, E> &lhs, const Result<void, E> &rhs)
825 {
826 bool _result;
827
828 if (lhs.HasValue() && rhs.HasValue())
829 {
830 _result = true;
831 }
832 else if (!lhs.HasValue() && !rhs.HasValue())
833 {
834 _result = lhs.Error() == rhs.Error();
835 }
836 else
837 {
838 _result = false;
839 }
840
841 return _result;
842 }
843
845 template <typename E>
846 inline bool operator!=(const Result<void, E> &lhs, const Result<void, E> &rhs)
847 {
848 bool _result;
849
850 if (lhs.HasValue() && rhs.HasValue())
851 {
852 _result = false;
853 }
854 else if (!lhs.HasValue() && !rhs.HasValue())
855 {
856 _result = lhs.Error() != rhs.Error();
857 }
858 else
859 {
860 _result = true;
861 }
862
863 return _result;
864 }
865 }
866}
867
868#endif
A wrapper around a possible value.
Definition: optional.h:16
void Reset() noexcept
Reset the instance value.
Definition: optional.h:134
constexpr bool HasValue() const noexcept
Indicate whether the instance has a value or not.
Definition: optional.h:145
T ValueOr(U &&defaultValue) const &
Get the instance value or the default value.
Definition: optional.h:236
const T & Value() const &
Get instance possible value.
Definition: optional.h:201
A wrapper around the callee's possible error.
Definition: result.h:521
constexpr bool HasValue() const noexcept
Indicate whether the instance contains an error or not.
Definition: result.h:648
Optional< E > Err() &&
Get optional instance error.
Definition: result.h:700
auto Bind(F &&f) const -> Result< decltype(f()), E >
Create a new Result by invoking a callable.
Definition: result.h:774
E error_type
Result error type alias.
Definition: result.h:534
Optional< E > Err() const &
Get optional instance error.
Definition: result.h:693
void Swap(Result &other) noexcept(std::is_nothrow_move_assignable< E >::value)
Swap the current instance with another one.
Definition: result.h:629
bool CheckError(G &&error) const
Check an error with the instance error.
Definition: result.h:736
const E & Error() const &
Get instance possible error.
Definition: result.h:678
E ErrorOr(G &&defaultError) const &
Get the instance error or the default error.
Definition: result.h:717
E ErrorOr(G &&defaultError) &&
Get the instance error or the default error.
Definition: result.h:727
void Resolve(F &&f) const
Invoke a callable.
Definition: result.h:761
E && Error() &&
Get instance possible error.
Definition: result.h:686
void EmplaceError(Args &&...args)
Construct a new error from the give argument(s) and assign it to the instance error.
Definition: result.h:622
constexpr void Value() const noexcept
The function does nothing.
Definition: result.h:670
void ValueOrThrow() const noexcept(false)
Throw an exception.
Definition: result.h:752
void ValueOr(U &&defaultValue) const noexcept
The function does nothing.
Definition: result.h:707
void value_type
Void value type alias.
Definition: result.h:532
A wrapper around the callee's return value and its possible error.
Definition: result.h:16
static Result FromError(const E &e) noexcept(std::is_nothrow_copy_constructible< E >::value)
Result factory by copying its error.
Definition: result.h:402
Optional< T > Ok() const &
Get optional instance value.
Definition: result.h:255
Optional< E > Err() &&
Get optional instance error.
Definition: result.h:276
const T & ValueOrThrow() const &noexcept(false)
Get instance possible value or throw an exception.
Definition: result.h:342
const T & operator*() const &
Definition: result.h:202
void EmplaceError(Args &&...args)
Construct a new error from the give argument(s) and assign it to the instance error.
Definition: result.h:155
T ValueOr(U &&defaultValue) const &
Get the instance value or the default value.
Definition: result.h:286
bool CheckError(G &&error) const
Check an error with the instance error.
Definition: result.h:325
auto Bind(F &&f) const -> Result< decltype(f(Value())), E >
Create a new Result by passing the instance value (if exists) to a callable.
Definition: result.h:370
T Resolve(F &&f) const
Get the instance value or a callable result.
Definition: result.h:360
T value_type
Result value type alias.
Definition: result.h:23
T && operator*() &&
Definition: result.h:209
const T * operator->() const
Definition: result.h:216
void EmplaceValue(Args &&...args)
Construct a new value from the give argument(s) and assign it to the instance value.
Definition: result.h:146
bool HasValue() const noexcept
Indicate whether the instance has a value or not.
Definition: result.h:189
static Result FromValue(const T &t) noexcept(std::is_nothrow_copy_constructible< T >::value)
Result factory by copying its value.
Definition: result.h:386
E ErrorOr(G &&defaultError) const &
Get the instance error or the default error.
Definition: result.h:306
const T & Value() const &
Get instance possible value.
Definition: result.h:224
void Swap(Result &other) noexcept(std::is_nothrow_move_assignable< T >::value &&std::is_nothrow_move_assignable< E >::value)
Swap the current instance with another one.
Definition: result.h:163
E ErrorOr(G &&defaultError) &&
Get the instance error or the default error.
Definition: result.h:316
T && Value() &&
Get instance possible value.
Definition: result.h:232
Optional< E > Err() const &
Get optional instance error.
Definition: result.h:269
E && Error() &&
Get instance possible error.
Definition: result.h:248
const E & Error() const &
Get instance possible error.
Definition: result.h:240
E error_type
Result error type alias.
Definition: result.h:25
T && ValueOrThrow() &&noexcept(false)
Get instance possible value or throw an exception.
Definition: result.h:350
T ValueOr(U &&defaultValue) &&
Get the instance value or the default value.
Definition: result.h:296
Optional< T > Ok() &&
Get optional instance value.
Definition: result.h:262
bool operator==(Ipv4Address address1, Ipv4Address address2)
Ipv4Address equality operator override.
Definition: ipv4_address.h:63
bool operator!=(Ipv4Address address1, Ipv4Address address2)
Ipv4Address inequality operator override.
Definition: ipv4_address.h:78