// Copyright 2020 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: statusor.h // ----------------------------------------------------------------------------- // // An `absl::StatusOr<T>` represents a union of an `absl::Status` object // and an object of type `T`. The `absl::StatusOr<T>` will either contain an // object of type `T` (indicating a successful operation), or an error (of type // `absl::Status`) explaining why such a value is not present. // // In general, check the success of an operation returning an // `absl::StatusOr<T>` like you would an `absl::Status` by using the `ok()` // member function. // // Example: // // StatusOr<Foo> result = Calculation(); // if (result.ok()) { // result->DoSomethingCool(); // } else { // LOG(ERROR) << result.status(); // } #ifndef ABSL_STATUS_STATUSOR_H_ #define ABSL_STATUS_STATUSOR_H_ #include <exception> #include <initializer_list> #include <new> #include <ostream> #include <string> #include <type_traits> #include <utility> #include "absl/base/attributes.h" #include "absl/base/nullability.h" #include "absl/base/call_once.h" #include "absl/meta/type_traits.h" #include "absl/status/internal/statusor_internal.h" #include "absl/status/status.h" #include "absl/strings/has_absl_stringify.h" #include "absl/strings/has_ostream_operator.h" #include "absl/strings/str_format.h" #include "absl/types/variant.h" #include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN // BadStatusOrAccess // // This class defines the type of object to throw (if exceptions are enabled), // when accessing the value of an `absl::StatusOr<T>` object that does not // contain a value. This behavior is analogous to that of // `std::bad_optional_access` in the case of accessing an invalid // `std::optional` value. // // Example: // // try { // absl::StatusOr<int> v = FetchInt(); // DoWork(v.value()); // Accessing value() when not "OK" may throw // } catch (absl::BadStatusOrAccess& ex) { // LOG(ERROR) << ex.status(); // } class BadStatusOrAccess : public std::exception { … }; // Returned StatusOr objects may not be ignored. template <typename T> #if ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) // TODO(b/176172494): ABSL_MUST_USE_RESULT should expand to the more strict // [[nodiscard]]. For now, just use [[nodiscard]] directly when it is available. class [[nodiscard]] StatusOr; #else class ABSL_MUST_USE_RESULT StatusOr; #endif // ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) // absl::StatusOr<T> // // The `absl::StatusOr<T>` class template is a union of an `absl::Status` object // and an object of type `T`. The `absl::StatusOr<T>` models an object that is // either a usable object, or an error (of type `absl::Status`) explaining why // such an object is not present. An `absl::StatusOr<T>` is typically the return // value of a function which may fail. // // An `absl::StatusOr<T>` can never hold an "OK" status (an // `absl::StatusCode::kOk` value); instead, the presence of an object of type // `T` indicates success. Instead of checking for a `kOk` value, use the // `absl::StatusOr<T>::ok()` member function. (It is for this reason, and code // readability, that using the `ok()` function is preferred for `absl::Status` // as well.) // // Example: // // StatusOr<Foo> result = DoBigCalculationThatCouldFail(); // if (result.ok()) { // result->DoSomethingCool(); // } else { // LOG(ERROR) << result.status(); // } // // Accessing the object held by an `absl::StatusOr<T>` should be performed via // `operator*` or `operator->`, after a call to `ok()` confirms that the // `absl::StatusOr<T>` holds an object of type `T`: // // Example: // // absl::StatusOr<int> i = GetCount(); // if (i.ok()) { // updated_total += *i; // } // // NOTE: using `absl::StatusOr<T>::value()` when no valid value is present will // throw an exception if exceptions are enabled or terminate the process when // exceptions are not enabled. // // Example: // // StatusOr<Foo> result = DoBigCalculationThatCouldFail(); // const Foo& foo = result.value(); // Crash/exception if no value present // foo.DoSomethingCool(); // // A `absl::StatusOr<T*>` can be constructed from a null pointer like any other // pointer value, and the result will be that `ok()` returns `true` and // `value()` returns `nullptr`. Checking the value of pointer in an // `absl::StatusOr<T*>` generally requires a bit more care, to ensure both that // a value is present and that value is not null: // // StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg); // if (!result.ok()) { // LOG(ERROR) << result.status(); // } else if (*result == nullptr) { // LOG(ERROR) << "Unexpected null pointer"; // } else { // (*result)->DoSomethingCool(); // } // // Example factory implementation returning StatusOr<T>: // // StatusOr<Foo> FooFactory::MakeFoo(int arg) { // if (arg <= 0) { // return absl::Status(absl::StatusCode::kInvalidArgument, // "Arg must be positive"); // } // return Foo(arg); // } template <typename T> class StatusOr : private internal_statusor::StatusOrData<T>, private internal_statusor::CopyCtorBase<T>, private internal_statusor::MoveCtorBase<T>, private internal_statusor::CopyAssignBase<T>, private internal_statusor::MoveAssignBase<T> { … }; // operator==() // // This operator checks the equality of two `absl::StatusOr<T>` objects. template <typename T> bool operator==(const StatusOr<T>& lhs, const StatusOr<T>& rhs) { … } // operator!=() // // This operator checks the inequality of two `absl::StatusOr<T>` objects. template <typename T> bool operator!=(const StatusOr<T>& lhs, const StatusOr<T>& rhs) { … } // Prints the `value` or the status in brackets to `os`. // // Requires `T` supports `operator<<`. Do not rely on the output format which // may change without notice. template <typename T, typename std::enable_if< absl::HasOstreamOperator<T>::value, int>::type = 0> std::ostream& operator<<(std::ostream& os, const StatusOr<T>& status_or) { … } // As above, but supports `StrCat`, `StrFormat`, etc. // // Requires `T` has `AbslStringify`. Do not rely on the output format which // may change without notice. template < typename Sink, typename T, typename std::enable_if<absl::HasAbslStringify<T>::value, int>::type = 0> void AbslStringify(Sink& sink, const StatusOr<T>& status_or) { … } //------------------------------------------------------------------------------ // Implementation details for StatusOr<T> //------------------------------------------------------------------------------ // TODO(sbenza): avoid the string here completely. template <typename T> StatusOr<T>::StatusOr() : … { … } template <typename T> template <typename U> inline void StatusOr<T>::Assign(const StatusOr<U>& other) { … } template <typename T> template <typename U> inline void StatusOr<T>::Assign(StatusOr<U>&& other) { … } template <typename T> template <typename... Args> StatusOr<T>::StatusOr(absl::in_place_t, Args&&... args) : Base(absl::in_place, std::forward<Args>(args)...) { … } template <typename T> template <typename U, typename... Args> StatusOr<T>::StatusOr(absl::in_place_t, std::initializer_list<U> ilist, Args&&... args) : Base(absl::in_place, ilist, std::forward<Args>(args)...) { … } template <typename T> const Status& StatusOr<T>::status() const& { … } template <typename T> Status StatusOr<T>::status() && { … } template <typename T> const T& StatusOr<T>::value() const& { … } template <typename T> T& StatusOr<T>::value() & { … } template <typename T> const T&& StatusOr<T>::value() const&& { … } template <typename T> T&& StatusOr<T>::value() && { … } template <typename T> const T& StatusOr<T>::operator*() const& { … } template <typename T> T& StatusOr<T>::operator*() & { … } template <typename T> const T&& StatusOr<T>::operator*() const&& { … } template <typename T> T&& StatusOr<T>::operator*() && { … } template <typename T> absl::Nonnull<const T*> StatusOr<T>::operator->() const { … } template <typename T> absl::Nonnull<T*> StatusOr<T>::operator->() { … } template <typename T> template <typename U> T StatusOr<T>::value_or(U&& default_value) const& { … } template <typename T> template <typename U> T StatusOr<T>::value_or(U&& default_value) && { … } template <typename T> void StatusOr<T>::IgnoreError() const { … } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STATUS_STATUSOR_H_