2 // Copyright 2017 Asylo authors
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
24 #include <type_traits>
27 #include "arrow/status.h"
28 #include "arrow/util/aligned_storage.h"
29 #include "arrow/util/compare.h"
38 ARROW_EXPORT
void DieWithMessage(const std::string
& msg
);
40 ARROW_EXPORT
void InvalidValueOrDie(const Status
& st
);
42 } // namespace internal
44 /// A class for representing either a usable value, or an error.
46 /// A Result object either contains a value of type `T` or a Status object
47 /// explaining why such a value is not present. The type `T` must be
48 /// copy-constructible and/or move-constructible.
50 /// The state of a Result object may be determined by calling ok() or
51 /// status(). The ok() method returns true if the object contains a valid value.
52 /// The status() method returns the internal Status object. A Result object
53 /// that contains a valid value will return an OK Status for a call to status().
55 /// A value of type `T` may be extracted from a Result object through a call
56 /// to ValueOrDie(). This function should only be called if a call to ok()
57 /// returns true. Sample usage:
60 /// arrow::Result<Foo> result = CalculateFoo();
61 /// if (result.ok()) {
62 /// Foo foo = result.ValueOrDie();
63 /// foo.DoSomethingCool();
65 /// ARROW_LOG(ERROR) << result.status();
69 /// If `T` is a move-only type, like `std::unique_ptr<>`, then the value should
70 /// only be extracted after invoking `std::move()` on the Result object.
74 /// arrow::Result<std::unique_ptr<Foo>> result = CalculateFoo();
75 /// if (result.ok()) {
76 /// std::unique_ptr<Foo> foo = std::move(result).ValueOrDie();
77 /// foo->DoSomethingCool();
79 /// ARROW_LOG(ERROR) << result.status();
83 /// Result is provided for the convenience of implementing functions that
84 /// return some value but may fail during execution. For instance, consider a
85 /// function with the following signature:
88 /// arrow::Status CalculateFoo(int *output);
91 /// This function may instead be written as:
94 /// arrow::Result<int> CalculateFoo();
97 class ARROW_MUST_USE_TYPE Result
: public util::EqualityComparable
<Result
<T
>> {
101 static_assert(!std::is_same
<T
, Status
>::value
,
102 "this assert indicates you have probably made a metaprogramming error");
107 /// Constructs a Result object that contains a non-OK status.
109 /// This constructor is marked `explicit` to prevent attempts to `return {}`
110 /// from a function with a return type of, for example,
111 /// `Result<std::vector<int>>`. While `return {}` seems like it would return
112 /// an empty vector, it will actually invoke the default constructor of
114 explicit Result() noexcept
// NOLINT(runtime/explicit)
115 : status_(Status::UnknownError("Uninitialized Result<T>")) {}
117 ~Result() noexcept
{ Destroy(); }
119 /// Constructs a Result object with the given non-OK Status object. All
120 /// calls to ValueOrDie() on this object will abort. The given `status` must
121 /// not be an OK status, otherwise this constructor will abort.
123 /// This constructor is not declared explicit so that a function with a return
124 /// type of `Result<T>` can return a Status object, and the status will be
125 /// implicitly converted to the appropriate return type as a matter of
128 /// \param status The non-OK Status object to initialize to.
129 Result(const Status
& status
) noexcept
// NOLINT(runtime/explicit)
131 if (ARROW_PREDICT_FALSE(status
.ok())) {
132 internal::DieWithMessage(std::string("Constructed with a non-error status: ") +
137 /// Constructs a Result object that contains `value`. The resulting object
138 /// is considered to have an OK status. The wrapped element can be accessed
139 /// with ValueOrDie().
141 /// This constructor is made implicit so that a function with a return type of
142 /// `Result<T>` can return an object of type `U &&`, implicitly converting
143 /// it to a `Result<T>` object.
145 /// Note that `T` must be implicitly constructible from `U`, and `U` must not
146 /// be a (cv-qualified) Status or Status-reference type. Due to C++
147 /// reference-collapsing rules and perfect-forwarding semantics, this
148 /// constructor matches invocations that pass `value` either as a const
149 /// reference or as an rvalue reference. Since Result needs to work for both
150 /// reference and rvalue-reference types, the constructor uses perfect
151 /// forwarding to avoid invalidating arguments that were passed by reference.
152 /// See http://thbecker.net/articles/rvalue_references/section_08.html for
153 /// additional details.
155 /// \param value The value to initialize to.
156 template <typename U
,
157 typename E
= typename
std::enable_if
<
158 std::is_constructible
<T
, U
>::value
&& std::is_convertible
<U
, T
>::value
&&
159 !std::is_same
<typename
std::remove_reference
<
160 typename
std::remove_cv
<U
>::type
>::type
,
161 Status
>::value
>::type
>
162 Result(U
&& value
) noexcept
{ // NOLINT(runtime/explicit)
163 ConstructValue(std::forward
<U
>(value
));
166 /// Constructs a Result object that contains `value`. The resulting object
167 /// is considered to have an OK status. The wrapped element can be accessed
168 /// with ValueOrDie().
170 /// This constructor is made implicit so that a function with a return type of
171 /// `Result<T>` can return an object of type `T`, implicitly converting
172 /// it to a `Result<T>` object.
174 /// \param value The value to initialize to.
175 // NOTE `Result(U&& value)` above should be sufficient, but some compilers
177 Result(T
&& value
) noexcept
{ // NOLINT(runtime/explicit)
178 ConstructValue(std::move(value
));
181 /// Copy constructor.
183 /// This constructor needs to be explicitly defined because the presence of
184 /// the move-assignment operator deletes the default copy constructor. In such
185 /// a scenario, since the deleted copy constructor has stricter binding rules
186 /// than the templated copy constructor, the templated constructor cannot act
187 /// as a copy constructor, and any attempt to copy-construct a `Result`
188 /// object results in a compilation error.
190 /// \param other The value to copy from.
191 Result(const Result
& other
) noexcept
: status_(other
.status_
) {
192 if (ARROW_PREDICT_TRUE(status_
.ok())) {
193 ConstructValue(other
.ValueUnsafe());
197 /// Templatized constructor that constructs a `Result<T>` from a const
198 /// reference to a `Result<U>`.
200 /// `T` must be implicitly constructible from `const U &`.
202 /// \param other The value to copy from.
203 template <typename U
, typename E
= typename
std::enable_if
<
204 std::is_constructible
<T
, const U
&>::value
&&
205 std::is_convertible
<U
, T
>::value
>::type
>
206 Result(const Result
<U
>& other
) noexcept
: status_(other
.status_
) {
207 if (ARROW_PREDICT_TRUE(status_
.ok())) {
208 ConstructValue(other
.ValueUnsafe());
212 /// Copy-assignment operator.
214 /// \param other The Result object to copy.
215 Result
& operator=(const Result
& other
) noexcept
{
216 // Check for self-assignment.
217 if (ARROW_PREDICT_FALSE(this == &other
)) {
221 status_
= other
.status_
;
222 if (ARROW_PREDICT_TRUE(status_
.ok())) {
223 ConstructValue(other
.ValueUnsafe());
228 /// Templatized constructor which constructs a `Result<T>` by moving the
229 /// contents of a `Result<U>`. `T` must be implicitly constructible from `U
232 /// Sets `other` to contain a non-OK status with a`StatusError::Invalid`
235 /// \param other The Result object to move from and set to a non-OK status.
236 template <typename U
,
237 typename E
= typename
std::enable_if
<std::is_constructible
<T
, U
&&>::value
&&
238 std::is_convertible
<U
, T
>::value
>::type
>
239 Result(Result
<U
>&& other
) noexcept
{
240 if (ARROW_PREDICT_TRUE(other
.status_
.ok())) {
241 status_
= std::move(other
.status_
);
242 ConstructValue(other
.MoveValueUnsafe());
244 // If we moved the status, the other status may become ok but the other
245 // value hasn't been constructed => crash on other destructor.
246 status_
= other
.status_
;
250 /// Move-assignment operator.
252 /// Sets `other` to an invalid state..
254 /// \param other The Result object to assign from and set to a non-OK
256 Result
& operator=(Result
&& other
) noexcept
{
257 // Check for self-assignment.
258 if (ARROW_PREDICT_FALSE(this == &other
)) {
262 if (ARROW_PREDICT_TRUE(other
.status_
.ok())) {
263 status_
= std::move(other
.status_
);
264 ConstructValue(other
.MoveValueUnsafe());
266 // If we moved the status, the other status may become ok but the other
267 // value hasn't been constructed => crash on other destructor.
268 status_
= other
.status_
;
273 /// Compare to another Result.
274 bool Equals(const Result
& other
) const {
275 if (ARROW_PREDICT_TRUE(status_
.ok())) {
276 return other
.status_
.ok() && ValueUnsafe() == other
.ValueUnsafe();
278 return status_
== other
.status_
;
281 /// Indicates whether the object contains a `T` value. Generally instead
282 /// of accessing this directly you will want to use ASSIGN_OR_RAISE defined
285 /// \return True if this Result object's status is OK (i.e. a call to ok()
286 /// returns true). If this function returns true, then it is safe to access
287 /// the wrapped element through a call to ValueOrDie().
288 constexpr bool ok() const { return status_
.ok(); }
290 /// \brief Equivalent to ok().
291 // operator bool() const { return ok(); }
293 /// Gets the stored status object, or an OK status if a `T` value is stored.
295 /// \return The stored non-OK status object, or an OK status if this object
297 constexpr const Status
& status() const { return status_
; }
299 /// Gets the stored `T` value.
301 /// This method should only be called if this Result object's status is OK
302 /// (i.e. a call to ok() returns true), otherwise this call will abort.
304 /// \return The stored `T` value.
305 const T
& ValueOrDie() const& {
306 if (ARROW_PREDICT_FALSE(!ok())) {
307 internal::InvalidValueOrDie(status_
);
309 return ValueUnsafe();
311 const T
& operator*() const& { return ValueOrDie(); }
312 const T
* operator->() const { return &ValueOrDie(); }
314 /// Gets a mutable reference to the stored `T` value.
316 /// This method should only be called if this Result object's status is OK
317 /// (i.e. a call to ok() returns true), otherwise this call will abort.
319 /// \return The stored `T` value.
321 if (ARROW_PREDICT_FALSE(!ok())) {
322 internal::InvalidValueOrDie(status_
);
324 return ValueUnsafe();
326 T
& operator*() & { return ValueOrDie(); }
327 T
* operator->() { return &ValueOrDie(); }
329 /// Moves and returns the internally-stored `T` value.
331 /// This method should only be called if this Result object's status is OK
332 /// (i.e. a call to ok() returns true), otherwise this call will abort. The
333 /// Result object is invalidated after this call and will be updated to
334 /// contain a non-OK status.
336 /// \return The stored `T` value.
338 if (ARROW_PREDICT_FALSE(!ok())) {
339 internal::InvalidValueOrDie(status_
);
341 return MoveValueUnsafe();
343 T
operator*() && { return std::move(*this).ValueOrDie(); }
345 /// Helper method for implementing Status returning functions in terms of semantically
346 /// equivalent Result returning functions. For example:
348 /// Status GetInt(int *out) { return GetInt().Value(out); }
349 template <typename U
, typename E
= typename
std::enable_if
<
350 std::is_constructible
<U
, T
>::value
>::type
>
351 Status
Value(U
* out
) && {
355 *out
= U(MoveValueUnsafe());
359 /// Move and return the internally stored value or alternative if an error is stored.
360 T
ValueOr(T alternative
) && {
364 return MoveValueUnsafe();
367 /// Retrieve the value if ok(), falling back to an alternative generated by the provided
369 template <typename G
>
370 T
ValueOrElse(G
&& generate_alternative
) && {
372 return MoveValueUnsafe();
374 return generate_alternative();
377 /// Apply a function to the internally stored value to produce a new result or propagate
378 /// the stored error.
379 template <typename M
>
380 typename EnsureResult
<decltype(std::declval
<M
&&>()(std::declval
<T
&&>()))>::type
Map(
385 return std::forward
<M
>(m
)(MoveValueUnsafe());
388 /// Apply a function to the internally stored value to produce a new result or propagate
389 /// the stored error.
390 template <typename M
>
391 typename EnsureResult
<decltype(std::declval
<M
&&>()(std::declval
<const T
&>()))>::type
396 return std::forward
<M
>(m
)(ValueUnsafe());
399 /// Cast the internally stored value to produce a new result or propagate the stored
401 template <typename U
, typename E
= typename
std::enable_if
<
402 std::is_constructible
<U
, T
>::value
>::type
>
407 return U(MoveValueUnsafe());
410 /// Cast the internally stored value to produce a new result or propagate the stored
412 template <typename U
, typename E
= typename
std::enable_if
<
413 std::is_constructible
<U
, const T
&>::value
>::type
>
414 Result
<U
> As() const& {
418 return U(ValueUnsafe());
421 constexpr const T
& ValueUnsafe() const& { return *storage_
.get(); }
423 #if __cpp_constexpr >= 201304L // non-const constexpr
424 constexpr T
& ValueUnsafe() & { return *storage_
.get(); }
426 T
& ValueUnsafe() & { return *storage_
.get(); }
429 T
ValueUnsafe() && { return MoveValueUnsafe(); }
431 T
MoveValueUnsafe() { return std::move(*storage_
.get()); }
434 Status status_
; // pointer-sized
435 internal::AlignedStorage
<T
> storage_
;
437 template <typename U
>
438 void ConstructValue(U
&& u
) noexcept
{
439 storage_
.construct(std::forward
<U
>(u
));
442 void Destroy() noexcept
{
443 if (ARROW_PREDICT_TRUE(status_
.ok())) {
444 static_assert(offsetof(Result
<T
>, status_
) == 0,
445 "Status is guaranteed to be at the start of Result<>");
451 #define ARROW_ASSIGN_OR_RAISE_IMPL(result_name, lhs, rexpr) \
452 auto&& result_name = (rexpr); \
453 ARROW_RETURN_IF_(!(result_name).ok(), (result_name).status(), ARROW_STRINGIFY(rexpr)); \
454 lhs = std::move(result_name).ValueUnsafe();
456 #define ARROW_ASSIGN_OR_RAISE_NAME(x, y) ARROW_CONCAT(x, y)
458 /// \brief Execute an expression that returns a Result, extracting its value
459 /// into the variable defined by `lhs` (or returning a Status on error).
461 /// Example: Assigning to a new value:
462 /// ARROW_ASSIGN_OR_RAISE(auto value, MaybeGetValue(arg));
464 /// Example: Assigning to an existing value:
466 /// ARROW_ASSIGN_OR_RAISE(value, MaybeGetValue(arg));
468 /// WARNING: ARROW_ASSIGN_OR_RAISE expands into multiple statements;
469 /// it cannot be used in a single statement (e.g. as the body of an if
470 /// statement without {})!
472 /// WARNING: ARROW_ASSIGN_OR_RAISE `std::move`s its right operand. If you have
473 /// an lvalue Result which you *don't* want to move out of cast appropriately.
475 /// WARNING: ARROW_ASSIGN_OR_RAISE is not a single expression; it will not
476 /// maintain lifetimes of all temporaries in `rexpr` (e.g.
477 /// `ARROW_ASSIGN_OR_RAISE(auto x, MakeTemp().GetResultRef());`
478 /// will most likely segfault)!
479 #define ARROW_ASSIGN_OR_RAISE(lhs, rexpr) \
480 ARROW_ASSIGN_OR_RAISE_IMPL(ARROW_ASSIGN_OR_RAISE_NAME(_error_or_value, __COUNTER__), \
485 template <typename T
>
486 inline const Status
& GenericToStatus(const Result
<T
>& res
) {
490 template <typename T
>
491 inline Status
GenericToStatus(Result
<T
>&& res
) {
492 return std::move(res
).status();
495 } // namespace internal
497 template <typename T
, typename R
= typename EnsureResult
<T
>::type
>
499 return R(std::move(t
));
502 template <typename T
>
503 struct EnsureResult
{
504 using type
= Result
<T
>;
507 template <typename T
>
508 struct EnsureResult
<Result
<T
>> {
509 using type
= Result
<T
>;