Branch data Line data Source code
1 : : // Copyright (c) 2022 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_UTIL_RESULT_H
6 : : #define BITCOIN_UTIL_RESULT_H
7 : :
8 : : #include <attributes.h>
9 : : #include <util/translation.h>
10 : :
11 : : #include <variant>
12 : :
13 : : namespace util {
14 : :
15 [ # # # # ]: 388571 : struct Error {
16 : : bilingual_str message;
17 : : };
18 : :
19 : : //! The util::Result class provides a standard way for functions to return
20 : : //! either error messages or result values.
21 : : //!
22 : : //! It is intended for high-level functions that need to report error strings to
23 : : //! end users. Lower-level functions that don't need this error-reporting and
24 : : //! only need error-handling should avoid util::Result and instead use standard
25 : : //! classes like std::optional, std::variant, and std::tuple, or custom structs
26 : : //! and enum types to return function results.
27 : : //!
28 : : //! Usage examples can be found in \example ../test/result_tests.cpp, but in
29 : : //! general code returning `util::Result<T>` values is very similar to code
30 : : //! returning `std::optional<T>` values. Existing functions returning
31 : : //! `std::optional<T>` can be updated to return `util::Result<T>` and return
32 : : //! error strings usually just replacing `return std::nullopt;` with `return
33 : : //! util::Error{error_string};`.
34 : : template <class M>
35 : : class Result
36 : : {
37 : : private:
38 : : using T = std::conditional_t<std::is_same_v<M, void>, std::monostate, M>;
39 : :
40 : : std::variant<bilingual_str, T> m_variant;
41 : :
42 : : //! Disallow copy constructor, require Result to be moved for efficiency.
43 : : Result(const Result&) = delete;
44 : :
45 : : //! Disallow operator= to avoid confusion in the future when the Result
46 : : //! class gains support for richer error reporting, and callers should have
47 : : //! ability to set a new result value without clearing existing error
48 : : //! messages.
49 : : Result& operator=(const Result&) = delete;
50 : : Result& operator=(Result&&) = delete;
51 : :
52 : : template <typename FT>
53 : : friend bilingual_str ErrorString(const Result<FT>& result);
54 : :
55 : : public:
56 [ + - ]: 48549 : Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {} // constructor for void
57 [ - + ]: 1824961 : Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
58 : 194663 : Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}
59 : 1097408 : Result(Result&&) = default;
60 [ - - - - : 3155393 : ~Result() = default;
- - + - +
- ][ + - #
# # # # #
# # ][ + -
+ + + + ]
61 : :
62 : : //! std::optional methods, so functions returning optional<T> can change to
63 : : //! return Result<T> with minimal changes to existing code, and vice versa.
64 [ + - - + ]: 1593420 : bool has_value() const noexcept { return m_variant.index() == 1; }
[ + + ]
65 [ - + ]: 4286 : const T& value() const LIFETIMEBOUND
66 : : {
67 [ - + ]: 4286 : assert(has_value());
68 : 4286 : return std::get<1>(m_variant);
69 : : }
70 [ - + ]: 3199812 : T& value() LIFETIMEBOUND
71 : : {
72 [ - + ]: 3199812 : assert(has_value());
73 : 3199812 : return std::get<1>(m_variant);
74 : : }
75 : : template <class U>
76 : : T value_or(U&& default_value) const&
77 : : {
78 : : return has_value() ? value() : std::forward<U>(default_value);
79 : : }
80 : : template <class U>
81 [ + - ]: 313762 : T value_or(U&& default_value) &&
82 : : {
83 [ + - ]: 313762 : return has_value() ? std::move(value()) : std::forward<U>(default_value);
84 : : }
85 [ + + ][ + + : 3450200 : explicit operator bool() const noexcept { return has_value(); }
+ + + + -
+ + + + +
- + - + -
+ + + +
+ ][ - - -
- - - - +
- + + + +
+ - + ][ -
+ - + - +
+ + # # #
# # # #
# ][ - - +
+ + + + +
+ + - - ]
[ + + + +
+ + - + -
+ + + - +
+ + - + +
+ + + + +
+ + + + ]
[ # # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
86 : : const T* operator->() const LIFETIMEBOUND { return &value(); }
87 : 0 : const T& operator*() const LIFETIMEBOUND { return value(); }
88 : 471052 : T* operator->() LIFETIMEBOUND { return &value(); }
89 : 2412997 : T& operator*() LIFETIMEBOUND { return value(); }
90 : : };
91 : :
92 : : template <typename T>
93 [ + + ]: 155450 : bilingual_str ErrorString(const Result<T>& result)
94 : : {
95 [ + + - + ]: 155450 : return result ? bilingual_str{} : std::get<0>(result.m_variant);
96 : 44085 : }
97 : : } // namespace util
98 : :
99 : : #endif // BITCOIN_UTIL_RESULT_H
|