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 [ - - - - ]: 16894 : 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 [ + - ]: 15528 : Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {} // constructor for void
57 [ - + ]: 9961788 : Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
58 : 8494 : Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}
59 : 82915 : Result(Result&&) = default;
60 [ + - + - : 10065786 : ~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 [ + + + - : 69283 : bool has_value() const noexcept { return m_variant.index() == 1; }
+ - # # #
# # # # #
# # # # ]
[ + + # #
# # ][ + -
+ - + - +
- + - + -
+ - + - +
- ]
65 [ - + ]: 1466 : const T& value() const LIFETIMEBOUND
66 : : {
67 [ - + ]: 1466 : assert(has_value());
68 : 1466 : return std::get<1>(m_variant);
69 : : }
70 [ - + ]: 10035329 : T& value() LIFETIMEBOUND
71 : : {
72 [ - + ]: 10035329 : assert(has_value());
73 : 10035329 : 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 [ + + + - : 9831043 : T value_or(U&& default_value) &&
- + + - -
+ ][ + - ]
82 : : {
83 [ + + + - : 9831043 : return has_value() ? std::move(value()) : std::forward<U>(default_value);
- + + - -
+ ][ + - ]
84 : : }
85 [ + + + + : 10015048 : explicit operator bool() const noexcept { return has_value(); }
+ + ][ + +
+ + + + +
+ + + + +
+ + + + ]
[ + + - +
+ - + - +
- + + + -
+ - + - +
- + - + -
+ - + - +
- + - + +
+ + ][ + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ ][ + + +
+ + - + -
+ - # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ][ +
+ + + + +
+ + + + +
- ][ - - -
- - - - +
- + - + +
+ - + # #
# # # # #
# # # #
# ][ - - +
+ + - - +
- + + + -
+ + + + +
+ + + + -
- + + +
- ][ - + +
- # # # #
# # # # #
# # # ]
86 : 129 : const T* operator->() const LIFETIMEBOUND { return &value(); }
87 : 1251 : const T& operator*() const LIFETIMEBOUND { return value(); }
88 : 5207 : T* operator->() LIFETIMEBOUND { return &value(); }
89 : 199082 : T& operator*() LIFETIMEBOUND { return value(); }
90 : : };
91 : :
92 : : template <typename T>
93 [ + + ]: 11706 : bilingual_str ErrorString(const Result<T>& result)
94 : : {
95 [ + + - + ]: 11706 : return result ? bilingual_str{} : std::get<0>(result.m_variant);
96 : 3918 : }
97 : : } // namespace util
98 : :
99 : : #endif // BITCOIN_UTIL_RESULT_H
|