userver: userver/utils/result_store.hpp Source File
Loading...
Searching...
No Matches
result_store.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/result_store.hpp
4/// @brief @copybrief utils::ResultStore
5
6#include <exception>
7#include <optional>
8#include <stdexcept>
9#include <utility>
10
11#include <userver/compiler/impl/lifetime.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace utils {
16
17/// @ingroup userver_universal userver_containers
18///
19/// Simple value/exception store
20template <typename T>
21class ResultStore final {
22public:
23 /// @brief Retrieves the stored value or rethrows the stored exception
24 /// @throws std::logic_error if no value/exception stored
25 /// @note Can be called at most once.
27
28 /// @brief Returns the stored value or rethrows the stored exception
29 /// @throws std::logic_error if no value/exception stored
30 const T& Get() const& USERVER_IMPL_LIFETIME_BOUND;
31
32 /// Stores a value
33 void SetValue(const T&);
34
35 /// Stores a value
36 void SetValue(T&&);
37
38 /// Stores an exception
39 void SetException(std::exception_ptr&&) noexcept;
40
41 // Returns the stored exception if present
42 std::exception_ptr GetException() const noexcept;
43
44private:
45 // variant here would require a specialization for exception_ptr
46 std::optional<T> value_;
47 std::exception_ptr exception_;
48};
49
50/// @ingroup userver_universal userver_containers
51///
52/// Simple void value/exception store
53template <>
54class ResultStore<void> final {
55public:
56 /// @brief Checks value availability or rethrows the stored exception
57 /// @throws std::logic_error if no value/exception stored
58 void Retrieve();
59
60 void Get() const&;
61
62 /// Marks the value as available
63 void SetValue() noexcept;
64
65 /// Stores an exception
66 void SetException(std::exception_ptr&&) noexcept;
67
68 // Returns the stored exception if present
69 std::exception_ptr GetException() const noexcept;
70
71private:
72 bool has_value_{false};
73 std::exception_ptr exception_;
74};
75
76template <typename T>
77T ResultStore<T>::Retrieve() {
78 if (value_) {
79 return std::move(*value_);
80 }
81 if (exception_) {
82 std::rethrow_exception(exception_);
83 }
84 throw std::logic_error("result store is not ready");
85}
86
87template <typename T>
88const T& ResultStore<T>::Get() const& USERVER_IMPL_LIFETIME_BOUND {
89 if (value_) {
90 return *value_;
91 }
92 if (exception_) {
93 std::rethrow_exception(exception_);
94 }
95 throw std::logic_error("result store is not ready");
96}
97
98template <typename T>
99void ResultStore<T>::SetValue(const T& value) {
100 value_ = value;
101}
102
103template <typename T>
104void ResultStore<T>::SetValue(T&& value) {
105 value_.emplace(std::move(value));
106}
107
108template <typename T>
109void ResultStore<T>::SetException(std::exception_ptr&& exception) noexcept {
110 exception_ = std::move(exception);
111}
112
113template <typename T>
114std::exception_ptr ResultStore<T>::GetException() const noexcept {
115 return exception_;
116}
117
118// NOLINTNEXTLINE(readability-make-member-function-const)
119inline void ResultStore<void>::Retrieve() { Get(); }
120
121inline void ResultStore<void>::Get() const& {
122 if (has_value_) {
123 return;
124 }
125 if (exception_) {
126 std::rethrow_exception(exception_);
127 }
128 throw std::logic_error("result store is not ready");
129}
130
131inline void ResultStore<void>::SetValue() noexcept { has_value_ = true; }
132
133inline void ResultStore<void>::SetException(std::exception_ptr&& exception) noexcept {
134 exception_ = std::move(exception);
135}
136
137inline std::exception_ptr ResultStore<void>::GetException() const noexcept { return exception_; }
138
139} // namespace utils
140
141USERVER_NAMESPACE_END