Line data Source code
1 : #pragma once 2 : 3 : // This component provides a class template, `Expected<T>`, that is either an 4 : // instance of `T` or an instance of `Error`. `Expected<void>` is either 5 : // `nullopt` or an instance of `Error`. 6 : // 7 : // `Expected` is inspired by, but incompatible with, C++23's `std::expected`. 8 : // 9 : // Example Usage 10 : // ------------- 11 : // The following excerpt demonstrates the intended usage of `Expected<T>`: 12 : // 13 : // Expected<int> parse_integer(StringView name); 14 : // 15 : // 16 : // int main() { 17 : // auto maybe_int = parse_integer("the answer"); 18 : // // using the `if_error` method 19 : // if (auto *error = maybe_int.if_error()) { 20 : // std::cerr << "parse_integer returned error: " << *error << '\n'; 21 : // return int(error->code); 22 : // } 23 : // 24 : // assert(*maybe_int == 42); 25 : // 26 : // maybe_int = parse_integer("one hundred twenty-three"); 27 : // // use the `error` method. 28 : // if (!maybe_int) { 29 : // std::cerr << "parse_integer returned error: " << maybe_int.error() << 30 : // '\n'; return int(maybe_int.error().code); 31 : // } 32 : // 33 : // assert(maybe_int == 123); 34 : // } 35 : // 36 : // `Expected<void>` is like `Expected<T>`, except that if the value is not an 37 : // error then it cannot be "dereferenced" with `operator*`, i.e. it is analogous 38 : // to `Optional<Error>` (and is implemented as such). 39 : 40 : #include <variant> 41 : 42 : #include "error.h" 43 : #include "optional.h" 44 : 45 : namespace datadog { 46 : namespace tracing { 47 : 48 : template <typename Value> 49 : class Expected { 50 : std::variant<Value, Error> data_; 51 : 52 : public: 53 : Expected() = default; 54 : Expected(const Expected&) = default; 55 : Expected(Expected&) = default; 56 142 : Expected(Expected&&) = default; 57 : Expected& operator=(const Expected&) = default; 58 63 : Expected& operator=(Expected&&) = default; 59 : 60 : template <typename Other> 61 : Expected(Other&&); 62 : template <typename Other> 63 : Expected& operator=(Other&&); 64 : 65 : // Return whether this object holds a `Value` (as opposed to an `Error`). 66 : bool has_value() const noexcept; 67 : explicit operator bool() const noexcept; 68 : 69 : // Return a reference to the `Value` held by this object. If this object is 70 : // an `Error`, throw a `std::bad_variant_access`. 71 : Value& value() &; 72 : const Value& value() const&; 73 : Value&& value() &&; 74 : const Value&& value() const&&; 75 : Value& operator*() &; 76 : const Value& operator*() const&; 77 : Value&& operator*() &&; 78 : const Value&& operator*() const&&; 79 : 80 : // Return a pointer to the `Value` held by this object. If this object is an 81 : // `Error`, throw a `std::bad_variant_access`. 82 : Value* operator->(); 83 : const Value* operator->() const; 84 : 85 : // Return a reference to the `Error` held by this object. If this object is 86 : // not an `Error`, throw a `std::bad_variant_access`. 87 : Error& error() &; 88 : const Error& error() const&; 89 : Error&& error() &&; 90 : const Error&& error() const&&; 91 : 92 : // Return a pointer to the `Error` value held by this object, or return 93 : // `nullptr` if this object is not an `Error`. 94 : Error* if_error() &; 95 : const Error* if_error() const&; 96 : // Don't use `if_error` on an rvalue (temporary). 97 : Error* if_error() && = delete; 98 : const Error* if_error() const&& = delete; 99 : }; 100 : 101 : template <typename Value> 102 : template <typename Other> 103 31323 : Expected<Value>::Expected(Other&& other) : data_(std::forward<Other>(other)) {} 104 : 105 : template <typename Value> 106 : template <typename Other> 107 : Expected<Value>& Expected<Value>::operator=(Other&& other) { 108 : data_ = std::forward<Other>(other); 109 : return *this; 110 : } 111 : 112 : template <typename Value> 113 2546 : bool Expected<Value>::has_value() const noexcept { 114 2546 : return std::holds_alternative<Value>(data_); 115 : } 116 : template <typename Value> 117 2546 : Expected<Value>::operator bool() const noexcept { 118 2546 : return has_value(); 119 : } 120 : 121 : template <typename Value> 122 30857 : Value& Expected<Value>::value() & { 123 30857 : return std::get<0>(data_); 124 : } 125 : template <typename Value> 126 211 : const Value& Expected<Value>::value() const& { 127 211 : return std::get<0>(data_); 128 : } 129 : template <typename Value> 130 : Value&& Expected<Value>::value() && { 131 : return std::move(std::get<0>(data_)); 132 : } 133 : template <typename Value> 134 : const Value&& Expected<Value>::value() const&& { 135 : return std::move(std::get<0>(data_)); 136 : } 137 : 138 : template <typename Value> 139 4215 : Value& Expected<Value>::operator*() & { 140 4215 : return value(); 141 : } 142 : template <typename Value> 143 74 : const Value& Expected<Value>::operator*() const& { 144 74 : return value(); 145 : } 146 : template <typename Value> 147 26529 : Value&& Expected<Value>::operator*() && { 148 26529 : return std::move(value()); 149 : } 150 : template <typename Value> 151 : const Value&& Expected<Value>::operator*() const&& { 152 : return std::move(value()); 153 : } 154 : 155 : template <typename Value> 156 113 : Value* Expected<Value>::operator->() { 157 113 : return &value(); 158 : } 159 : template <typename Value> 160 137 : const Value* Expected<Value>::operator->() const { 161 137 : return &value(); 162 : } 163 : 164 : template <typename Value> 165 187 : Error& Expected<Value>::error() & { 166 187 : return std::get<1>(data_); 167 : } 168 : template <typename Value> 169 48 : const Error& Expected<Value>::error() const& { 170 48 : return std::get<1>(data_); 171 : } 172 : template <typename Value> 173 : Error&& Expected<Value>::error() && { 174 : return std::move(std::get<1>(data_)); 175 : } 176 : template <typename Value> 177 : const Error&& Expected<Value>::error() const&& { 178 : return std::move(std::get<1>(data_)); 179 : } 180 : 181 : template <typename Value> 182 2385 : Error* Expected<Value>::if_error() & { 183 2385 : return std::get_if<1>(&data_); 184 : } 185 : template <typename Value> 186 : const Error* Expected<Value>::if_error() const& { 187 : return std::get_if<1>(&data_); 188 : } 189 : 190 : template <> 191 : class Expected<void> { 192 : Optional<Error> data_; 193 : 194 : public: 195 130740 : Expected() = default; 196 : Expected(const Expected&) = default; 197 : Expected(Expected&) = default; 198 : Expected(Expected&&) = default; 199 : Expected& operator=(const Expected&) = default; 200 23439 : Expected& operator=(Expected&&) = default; 201 : 202 : template <typename Other> 203 : Expected(Other&&); 204 : template <typename Other> 205 : Expected& operator=(Other&&); 206 : 207 : void swap(Expected& other); 208 : 209 : bool has_value() const; 210 : explicit operator bool() const; 211 : 212 : Error& error() &; 213 : const Error& error() const&; 214 : Error&& error() &&; 215 : const Error&& error() const&&; 216 : 217 : Error* if_error() &; 218 : const Error* if_error() const&; 219 : // Don't use `if_error` on an rvalue (temporary). 220 : Error* if_error() && = delete; 221 : const Error* if_error() const&& = delete; 222 : }; 223 : 224 : template <typename Other> 225 11367 : Expected<void>::Expected(Other&& other) : data_(std::forward<Other>(other)) {} 226 : 227 : template <typename Other> 228 4 : Expected<void>& Expected<void>::operator=(Other&& other) { 229 4 : data_ = std::forward<Other>(other); 230 4 : return *this; 231 : } 232 : 233 : inline void Expected<void>::swap(Expected& other) { data_.swap(other.data_); } 234 : 235 19160 : inline bool Expected<void>::has_value() const { return !data_.has_value(); } 236 19160 : inline Expected<void>::operator bool() const { return has_value(); } 237 : 238 8 : inline Error& Expected<void>::error() & { return *data_; } 239 23 : inline const Error& Expected<void>::error() const& { return *data_; } 240 : inline Error&& Expected<void>::error() && { return std::move(*data_); } 241 : inline const Error&& Expected<void>::error() const&& { 242 : return std::move(*data_); 243 : } 244 : 245 10914 : inline Error* Expected<void>::if_error() & { return data_ ? &*data_ : nullptr; } 246 82875 : inline const Error* Expected<void>::if_error() const& { 247 82875 : return data_ ? &*data_ : nullptr; 248 : } 249 : 250 : } // namespace tracing 251 : } // namespace datadog