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 [ - - - - ]: 16772 : 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 [ + - ]: 15080 : Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {} // constructor for void
57 [ - + ]: 6971420 : Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
58 : 8433 : Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}
59 : 24668 : Result(Result&&) = default;
60 [ + - + - ]: 7016740 : ~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 [ + + ][ + - : 67590 : bool has_value() const noexcept { return m_variant.index() == 1; }
+ - + - +
- + - + -
+ - + - +
- ][ + - +
- + - ]
65 [ - + ]: 1322 : const T& value() const LIFETIMEBOUND
66 : : {
67 [ - + ]: 1322 : assert(has_value());
68 : 1322 : return std::get<1>(m_variant);
69 : : }
70 [ - + ]: 6987059 : T& value() LIFETIMEBOUND
71 : : {
72 [ - + ]: 6987059 : assert(has_value());
73 : 6987059 : 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 [ + - ][ + + : 6892749 : T value_or(U&& default_value) &&
+ - - + +
- - + ]
82 : : {
83 [ + - ][ + + : 6892749 : return has_value() ? std::move(value()) : std::forward<U>(default_value);
+ - - + +
- - + ]
84 : : }
85 [ + + ][ + + : 7016277 : explicit operator bool() const noexcept { return has_value(); }
+ + + + +
+ + + +
+ ][ + + +
+ # # # #
# # # # #
# # # ][ -
+ + + - +
+ + + + +
+ + + +
+ ][ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ ][ + + +
+ + + # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ - - +
- + - +
- ][ - - +
- + - + -
+ - # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ][ -
+ - + + -
+ - + - +
+ + - + -
+ - + - +
- + - + -
+ - + - +
- + + +
+ ]
86 : 129 : const T* operator->() const LIFETIMEBOUND { return &value(); }
87 : 1109 : const T& operator*() const LIFETIMEBOUND { return value(); }
88 : 5023 : T* operator->() LIFETIMEBOUND { return &value(); }
89 : 89290 : T& operator*() LIFETIMEBOUND { return value(); }
90 : : };
91 : :
92 : : template <typename T>
93 [ + + ]: 11531 : bilingual_str ErrorString(const Result<T>& result)
94 : : {
95 [ + + - + ]: 11531 : return result ? bilingual_str{} : std::get<0>(result.m_variant);
96 : 3800 : }
97 : : } // namespace util
98 : :
99 : : #endif // BITCOIN_UTIL_RESULT_H
|