diff options
author | Abseil Team <absl-team@google.com> | 2020-09-03 12:54:45 -0700 |
---|---|---|
committer | Derek Mauro <dmauro@google.com> | 2020-09-04 12:59:29 -0400 |
commit | 7ba8cdb56df3bf4fe4ab4606f3fe4b2ab825afac (patch) | |
tree | 058d9db0e1acfd979929ab48e9bfe9e802c94741 /absl/status/statusor.h | |
parent | 930fbec75b452af8bb8c796f5bb754e953e29cf5 (diff) |
Export of internal Abseil changes
--
8ae3cb636b81b6498ef30fbe59cc102a4098cad2 by Tom Manshreck <shreck@google.com>:
Upgrade absl::StatusOr<T> docs to Abseil standards
PiperOrigin-RevId: 329975341
--
7c7baf586c7380497a751f1a186a4ef0e650161a by Tom Manshreck <shreck@google.com>:
Update absl::Status to Abseil documentation standards
PiperOrigin-RevId: 329942967
--
6710d022ba987dbae7a5d83045a6697afeb972c4 by Derek Mauro <dmauro@google.com>:
Internal change
PiperOrigin-RevId: 329775111
--
fd182dc699e18522ef16d269731c57669c5487d2 by Abseil Team <absl-team@google.com>:
Google-internal change.
PiperOrigin-RevId: 329737362
--
c0df5e27ffb48d9c784e7019267580fcb4a3f92e by Xiaoyi Zhang <zhangxy@google.com>:
Remove obsolete `static_assert`.
PiperOrigin-RevId: 329727604
GitOrigin-RevId: 8ae3cb636b81b6498ef30fbe59cc102a4098cad2
Change-Id: Ic9dede0ab97f799e7f4093fae75ae0ec6cc21437
Diffstat (limited to 'absl/status/statusor.h')
-rw-r--r-- | absl/status/statusor.h | 368 |
1 files changed, 229 insertions, 139 deletions
diff --git a/absl/status/statusor.h b/absl/status/statusor.h index 95f99f4d..ff0dab65 100644 --- a/absl/status/statusor.h +++ b/absl/status/statusor.h @@ -12,58 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// StatusOr<T> is the union of a Status object and a T -// object. StatusOr models the concept of an object that is either a -// usable value, or an error Status explaining why such a value is -// not present. To this end, StatusOr<T> does not allow its Status -// value to be absl::OkStatus(). +// ----------------------------------------------------------------------------- +// File: statusor.h +// ----------------------------------------------------------------------------- // -// The primary use-case for StatusOr<T> is as the return value of a -// function which may fail. +// 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. // -// Example usage of a StatusOr<T>: +// 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. // -// StatusOr<Foo> result = DoBigCalculationThatCouldFail(); -// if (result.ok()) { -// result->DoSomethingCool(); -// } else { -// LOG(ERROR) << result.status(); -// } -// -// Example that is guaranteed to crash if the result holds no value: -// -// StatusOr<Foo> result = DoBigCalculationThatCouldFail(); -// const Foo& foo = result.value(); -// foo.DoSomethingCool(); -// -// Example usage of a StatusOr<std::unique_ptr<T>>: -// -// StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg); -// if (!result.ok()) { // Don't omit .ok() -// LOG(ERROR) << result.status(); -// } else if (*result == nullptr) { -// LOG(ERROR) << "Unexpected null pointer"; -// } else { -// (*result)->DoSomethingCool(); -// } +// Example: // -// 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); -// } -// -// NULL POINTERS -// -// Historically StatusOr<T*> treated null pointers specially. This is no longer -// true -- a 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 null. - +// StatusOr<Foo> result = Calculation(); +// if (result.ok()) { +// result->DoSomethingCool(); +// } else { +// LOG(ERROR) << result.status(); +// } #ifndef ABSL_STATUS_STATUSOR_H_ #define ABSL_STATUS_STATUSOR_H_ @@ -83,11 +52,42 @@ 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 { public: explicit BadStatusOrAccess(absl::Status status); ~BadStatusOrAccess() override; + + // BadStatusOrAccess::what() + // + // Returns the associated explanatory string of the `absl::StatusOr<T>` + // object's error code. This function only returns the string literal "Bad + // StatusOr Access" for cases when evaluating general exceptions. + // + // The pointer of this string is guaranteed to be valid until any non-const + // function is invoked on the exception object. const char* what() const noexcept override; + + // BadStatusOrAccess::status() + // + // Returns the associated `absl::Status` of the `absl::StatusOr<T>` object's + // error. const absl::Status& status() const; private: @@ -98,6 +98,75 @@ class BadStatusOrAccess : public std::exception { template <typename T> class ABSL_MUST_USE_RESULT StatusOr; +// abls::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 (foo.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 +// execeptions 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>, @@ -110,30 +179,42 @@ class StatusOr : private internal_statusor::StatusOrData<T>, typedef internal_statusor::StatusOrData<T> Base; public: + // StatusOr<T>::value_type + // + // This instance data provides a generic `value_type` member for use within + // generic programming. This usage is analogous to that of + // `optional::value_type` in the case of `std::optional`. typedef T value_type; - // Constructs a new StatusOr with Status::UNKNOWN status. This is marked - // 'explicit' to try to catch cases like 'return {};', where people think - // absl::StatusOr<std::vector<int>> will be initialized with an empty vector, - // instead of a Status::UNKNOWN status. + // Constructors + + // Constructs a new `absl::StatusOr` with an `absl::StatusCode::kUnknown` + // status. This constructor is marked 'explicit' to prevent usages in return + // values such as 'return {};', under the misconception that + // `absl::StatusOr<std::vector<int>>` will be initialized with an empty + // vector, instead of an `absl::StatusCode::kUnknown` error code. explicit StatusOr(); - // StatusOr<T> is copy constructible if T is copy constructible. + // `StatusOr<T>` is copy constructible if `T` is copy constructible. StatusOr(const StatusOr&) = default; - // StatusOr<T> is copy assignable if T is copy constructible and copy + // `StatusOr<T>` is copy assignable if `T` is copy constructible and copy // assignable. StatusOr& operator=(const StatusOr&) = default; - // StatusOr<T> is move constructible if T is move constructible. + // `StatusOr<T>` is move constructible if `T` is move constructible. StatusOr(StatusOr&&) = default; - // StatusOr<T> is moveAssignable if T is move constructible and move + // `StatusOr<T>` is moveAssignable if `T` is move constructible and move // assignable. StatusOr& operator=(StatusOr&&) = default; - // Converting constructors from StatusOr<U>, when T is constructible from U. - // To avoid ambiguity, they are disabled if T is also constructible from - // StatusOr<U>. Explicit iff the corresponding construction of T from U is - // explicit. + // Converting Constructors + + // Constructs a new `absl::StatusOr<T>` from an `absl::StatusOr<U>`, when `T` + // is constructible from `U`. To avoid ambiguity, these constructors are + // disabled if `T` is also constructible from `StatusOr<U>.`. This constructor + // is explicit if and only if the corresponding construction of `T` from `U` + // is explicit. (This constructor inherits its explicitness from the + // underlying constructor.) template < typename U, absl::enable_if_t< @@ -186,9 +267,25 @@ class StatusOr : private internal_statusor::StatusOrData<T>, explicit StatusOr(StatusOr<U>&& other) : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {} - // Conversion copy/move assignment operator, T must be constructible and - // assignable from U. Only enable if T cannot be directly assigned from - // StatusOr<U>. + // Converting Assignment Operators + + // Creates an `absl::StatusOr<T>` through assignment from an + // `absl::StatusOr<U>` when: + // + // * Both `absl::StatusOr<T>` and `absl::StatusOr<U>` are OK by assigning + // `U` to `T` directly. + // * `absl::StatusOr<T>` is OK and `absl::StatusOr<U>` contains an error + // code by destroying `absl::StatusOr<T>`'s value and assigning from + // `absl::StatusOr<U>' + // * `absl::StatusOr<T>` contains an error code and `absl::StatusOr<U>` is + // OK by directly initializing `T` from `U`. + // * Both `absl::StatusOr<T>` and `absl::StatusOr<U>` contain an error + // code by assigning the `Status` in `absl::StatusOr<U>` to + // `absl::StatusOr<T>` + // + // These overloads only apply if `absl::StatusOr<T>` is constructible and + // assignable from `absl::StatusOr<U>` and `StatusOr<T>` cannot be directly + // assigned from `StatusOr<U>`. template < typename U, absl::enable_if_t< @@ -221,14 +318,13 @@ class StatusOr : private internal_statusor::StatusOrData<T>, return *this; } - // Constructs a new StatusOr with a non-ok status. After calling this - // constructor, this->ok() will be false and calls to value() will CHECK-fail. - // The constructor also takes any type `U` that is convertible to `Status`. + // Constructs a new `absl::StatusOr<T>` with a non-ok status. After calling + // this constructor, `this->ok()` will be `false` and calls to `value()` will + // crash, or produce an exception if exceptions are enabled. // - // NOTE: Not explicit - we want to use StatusOr<T> as a return - // value, so it is convenient and sensible to be able to do - // `return Status()` or `return ConvertibleToStatus()` when the return type - // is `StatusOr<T>`. + // The constructor also takes any type `U` that is convertible to + // `absl::Status`. This constructor is explicit if an only if `U` is not of + // type `absl::Status` and the conversion from `U` to `Status` is explicit. // // REQUIRES: !Status(std::forward<U>(v)).ok(). This requirement is DCHECKed. // In optimized builds, passing absl::OkStatus() here will have the effect @@ -279,6 +375,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>, } // Perfect-forwarding value assignment operator. + // If `*this` contains a `T` value before the call, the contained value is // assigned from `std::forward<U>(v)`; Otherwise, it is directly-initialized // from `std::forward<U>(v)`. @@ -305,39 +402,25 @@ class StatusOr : private internal_statusor::StatusOrData<T>, HasConversionOperatorToStatusOr<T, U&&>>>>, internal_statusor::IsForwardingAssignmentValid<T, U&&>>::value>::type> StatusOr& operator=(U&& v) { - static_assert( - !absl::conjunction< - std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>, - std::is_constructible<absl::Status, U&&>, - std::is_assignable<absl::Status&, U&&>, - absl::negation<std::is_same< - T, absl::remove_cv_t<absl::remove_reference_t<U>>>>>::value, - "U can assign to both T and Status, will result in semantic change"); - static_assert( - !absl::conjunction< - std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>, - internal_statusor::HasConversionOperatorToStatusOr<T, U&&>, - absl::negation<std::is_same< - T, absl::remove_cv_t<absl::remove_reference_t<U>>>>>::value, - "U can assign to T and convert to StatusOr<T>, will result in semantic " - "change"); this->Assign(std::forward<U>(v)); return *this; } - // Constructs the inner value T in-place using the provided args, using the - // T(args...) constructor. + // Constructs the inner value `T` in-place using the provided args, using the + // `T(args...)` constructor. template <typename... Args> explicit StatusOr(absl::in_place_t, Args&&... args); template <typename U, typename... Args> explicit StatusOr(absl::in_place_t, std::initializer_list<U> ilist, Args&&... args); - // Constructs the inner value T in-place using the provided args, using the - // T(U) (direct-initialization) constructor. Only valid if T can be - // constructed from a U. Can accept move or copy constructors. Explicit if - // U is not convertible to T. To avoid ambiguity, this is disabled if U is - // a StatusOr<J>, where J is convertible to T. + // Constructs the inner value `T` in-place using the provided args, using the + // `T(U)` (direct-initialization) constructor. This constructor is only valid + // if `T` can be constructed from a `U`. Can accept move or copy constructors. + // + // This constructor is explicit if `U` is not convertible to `T`. To avoid + // ambiguity, this constuctor is disabled if `U` is a `StatusOr<J>`, where `J` + // is convertible to `T`. template < typename U = T, absl::enable_if_t< @@ -355,21 +438,6 @@ class StatusOr : private internal_statusor::StatusOrData<T>, int> = 0> StatusOr(U&& u) // NOLINT : StatusOr(absl::in_place, std::forward<U>(u)) { - static_assert( - !absl::conjunction< - std::is_convertible<U&&, T>, std::is_convertible<U&&, absl::Status>, - absl::negation<std::is_same< - T, absl::remove_cv_t<absl::remove_reference_t<U>>>>>::value, - "U is convertible to both T and Status, will result in semantic " - "change"); - static_assert( - !absl::conjunction< - std::is_convertible<U&&, T>, - internal_statusor::HasConversionOperatorToStatusOr<T, U&&>, - absl::negation<std::is_same< - T, absl::remove_cv_t<absl::remove_reference_t<U>>>>>::value, - "U can construct T and convert to StatusOr<T>, will result in semantic " - "change"); } template < @@ -390,38 +458,42 @@ class StatusOr : private internal_statusor::StatusOrData<T>, int> = 0> explicit StatusOr(U&& u) // NOLINT : StatusOr(absl::in_place, std::forward<U>(u)) { - static_assert( - !absl::conjunction< - std::is_constructible<T, U&&>, - std::is_constructible<absl::Status, U&&>, - absl::negation<std::is_same< - T, absl::remove_cv_t<absl::remove_reference_t<U>>>>>::value, - "U can construct both T and Status, will result in semantic " - "change"); - static_assert( - !absl::conjunction< - std::is_constructible<T, U&&>, - internal_statusor::HasConversionOperatorToStatusOr<T, U&&>, - absl::negation<std::is_same< - T, absl::remove_cv_t<absl::remove_reference_t<U>>>>>::value, - "U can construct T and convert to StatusOr<T>, will result in semantic " - "change"); } - // Returns this->status().ok() + // StatusOr<T>::ok() + // + // Returns whether or not this `absl::StatusOr<T>` holds a `T` value. This + // member function is analagous to `absl::Status::ok()` and should be used + // similarly to check the status of return values. + // + // Example: + // + // StatusOr<Foo> result = DoBigCalculationThatCouldFail(); + // if (result.ok()) { + // // Handle result + // else { + // // Handle error + // } ABSL_MUST_USE_RESULT bool ok() const { return this->status_.ok(); } - // Returns a reference to our status. If this contains a T, then - // returns absl::OkStatus(). + // StatusOr<T>::status() + // + // Returns a reference to the current `absl::Status` contained within the + // `absl::StatusOr<T>`. If `absl::StatusOr<T>` contains a `T`, then this + // function returns `absl::OkStatus()`. const Status& status() const &; Status status() &&; + // StatusOr<T>::value() + // // Returns a reference to the held value if `this->ok()`. Otherwise, throws - // `absl::BadStatusOrAccess` if exception is enabled, or `LOG(FATAL)` if - // exception is disabled. + // `absl::BadStatusOrAccess` if exceptions are enabled, or is guaranteed to + // terminate the process if exceptions are disabled. + // // If you have already checked the status using `this->ok()`, you probably // want to use `operator*()` or `operator->()` to access the value instead of // `value`. + // // Note: for value types that are cheap to copy, prefer simple code: // // T value = statusor.value(); @@ -443,28 +515,35 @@ class StatusOr : private internal_statusor::StatusOrData<T>, const T&& value() const&&; T&& value() &&; + // StatusOr<T>:: operator*() + // // Returns a reference to the current value. // - // REQUIRES: this->ok() == true, otherwise the behavior is undefined. + // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined. // - // Use this->ok() to verify that there is a current value. - // Alternatively, see value() for a similar API that guarantees - // CHECK-failing if there is no current value. + // Use `this->ok()` to verify that there is a current value within the + // `absl::StatusOr<T>`. Alternatively, see the `value()` member function for a + // similar API that guarantees crashing or throwing an exception if there is + // no current value. const T& operator*() const&; T& operator*() &; const T&& operator*() const&&; T&& operator*() &&; + // StatusOr<T>::operator->() + // // Returns a pointer to the current value. // - // REQUIRES: this->ok() == true, otherwise the behavior is undefined. + // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined. // - // Use this->ok() to verify that there is a current value. + // Use `this->ok()` to verify that there is a current value. const T* operator->() const; T* operator->(); - // Returns the current value this->ok() == true. Otherwise constructs a value - // using `default_value`. + // StatusOr<T>::value_or() + // + // Returns the current value of `this->ok() == true`. Otherwise constructs a + // value using the provided `default_value`. // // Unlike `value`, this function returns by value, copying the current value // if necessary. If the value type supports an efficient move, it can be used @@ -472,18 +551,22 @@ class StatusOr : private internal_statusor::StatusOrData<T>, // // T value = std::move(statusor).value_or(def); // - // Unlike with `value`, calling `std::move` on the result of `value_or` will + // Unlike with `value`, calling `std::move()` on the result of `value_or` will // still trigger a copy. template <typename U> T value_or(U&& default_value) const&; template <typename U> T value_or(U&& default_value) &&; + // StatusOr<T>::IgnoreError() + // // Ignores any errors. This method does nothing except potentially suppress // complaints from any tools that are checking that errors are not dropped on // the floor. void IgnoreError() const; + // StatusOr<T>::emplace() + // // Reconstructs the inner value T in-place using the provided args, using the // T(args...) constructor. Returns reference to the reconstructed `T`. template <typename... Args> @@ -522,19 +605,26 @@ class StatusOr : private internal_statusor::StatusOrData<T>, void Assign(absl::StatusOr<U>&& other); }; +// 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) { if (lhs.ok() && rhs.ok()) return *lhs == *rhs; return lhs.status() == rhs.status(); } +// 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) { return !(lhs == rhs); } -//////////////////////////////////////////////////////////////////////////////// +//------------------------------------------------------------------------------ // Implementation details for StatusOr<T> +//------------------------------------------------------------------------------ // TODO(sbenza): avoid the string here completely. template <typename T> |