From 7ba8cdb56df3bf4fe4ab4606f3fe4b2ab825afac Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 3 Sep 2020 12:54:45 -0700 Subject: Export of internal Abseil changes -- 8ae3cb636b81b6498ef30fbe59cc102a4098cad2 by Tom Manshreck : Upgrade absl::StatusOr docs to Abseil standards PiperOrigin-RevId: 329975341 -- 7c7baf586c7380497a751f1a186a4ef0e650161a by Tom Manshreck : Update absl::Status to Abseil documentation standards PiperOrigin-RevId: 329942967 -- 6710d022ba987dbae7a5d83045a6697afeb972c4 by Derek Mauro : Internal change PiperOrigin-RevId: 329775111 -- fd182dc699e18522ef16d269731c57669c5487d2 by Abseil Team : Google-internal change. PiperOrigin-RevId: 329737362 -- c0df5e27ffb48d9c784e7019267580fcb4a3f92e by Xiaoyi Zhang : Remove obsolete `static_assert`. PiperOrigin-RevId: 329727604 GitOrigin-RevId: 8ae3cb636b81b6498ef30fbe59cc102a4098cad2 Change-Id: Ic9dede0ab97f799e7f4093fae75ae0ec6cc21437 --- absl/status/status.h | 227 +++++++++++++++++++++--------- absl/status/statusor.h | 368 ++++++++++++++++++++++++++++++------------------- 2 files changed, 394 insertions(+), 201 deletions(-) (limited to 'absl/status') diff --git a/absl/status/status.h b/absl/status/status.h index 8e1974c..530f580 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -24,10 +24,11 @@ // * A set of helper functions for creating status codes and checking their // values // -// Within Google, `absl::Status` is the primary mechanism for indicating -// recoverable errors across API boundaries (and in particular across RPC -// boundaries). Most functions which can produce a recoverable error should -// be designed to return an `absl::Status` (or `absl::StatusOr`). +// Within Google, `absl::Status` is the primary mechanism for gracefully +// handling errors across API boundaries (and in particular across RPC +// boundaries). Some of these errors may be recoverable, but others may not. +// Most functions which can produce a recoverable error should be designed to +// return an `absl::Status` (or `absl::StatusOr`). // // Example: // @@ -47,16 +48,6 @@ // error codes (of type `absl::StatusCode`) enumerated in this header file. // These canonical codes are understood across the codebase and will be // accepted across all API and RPC boundaries. -// -// An `absl::Status` can optionally include a payload with more information -// about the error. Typically, this payload serves one of several purposes: -// -// * It may provide more fine-grained semantic information about the error to -// facilitate actionable remedies. -// * It may provide human-readable contexual information that is more -// appropriate -// to display to an end user. -// #ifndef ABSL_STATUS_STATUS_H_ #define ABSL_STATUS_STATUS_H_ @@ -290,18 +281,99 @@ std::ostream& operator<<(std::ostream& os, StatusCode code); // absl::Status // +// The `absl::Status` class is generally used to gracefully handle errors +// across API boundaries (and in particular across RPC boundaries). Some of +// these errors may be recoverable, but others may not. Most +// functions which can produce a recoverable error should be designed to return +// either an `absl::Status` (or the similar `absl::StatusOr`, which holds +// either an object of type `T` or an error). +// +// API developers should construct their functions to return `absl::OkStatus()` +// upon success, or an `absl::StatusCode` upon another type of error (e.g +// an `absl::StatusCode::kInvalidArgument` error). The API provides convenience +// functions to constuct each status code. +// +// Example: +// +// absl::Status myFunction(absl::string_view fname, ...) { +// ... +// // encounter error +// if (error condition) { +// // Construct an absl::StatusCode::kInvalidArgument error +// return absl::InvalidArgumentError("bad mode"); +// } +// // else, return OK +// return absl::OkStatus(); +// } +// +// Users handling status error codes should prefer checking for an OK status +// using the `ok()` member function. Handling multiple error codes may justify +// use of switch statement, but only check for error codes you know how to +// handle; do not try to exhaustively match against all canonical error codes. +// Errors that cannot be handled should be logged and/or propagated for higher +// levels to deal with. If you do use a switch statement, make sure that you +// also provide a `default:` switch case, so that code does not break as other +// canonical codes are added to the API. +// +// Example: +// +// absl::Status result = DoSomething(); +// if (!result.ok()) { +// LOG(ERROR) << result; +// } +// +// // Provide a default if switching on multiple error codes +// switch (result.code()) { +// // The user hasn't authenticated. Ask them to reauth +// case absl::StatusCode::kUnauthenticated: +// DoReAuth(); +// break; +// // The user does not have permission. Log an error. +// case absl::StatusCode::kPermissionDenied: +// LOG(ERROR) << result; +// break; +// // Propogate the error otherwise +// default: +// return true; +// } +// +// An `absl::Status` can optionally include a payload with more information +// about the error. Typically, this payload serves one of several purposes: +// +// * It may provide more fine-grained semantic information about the error to +// facilitate actionable remedies. +// * It may provide human-readable contexual information that is more +// appropriate to display to an end user. +// +// Example: +// +// absl::Status result = DoSomething(); +// // Inform user to retry after 30 seconds +// // See more error details in googleapis/google/rpc/error_details.proto +// if (absl::IsResourceExhausted(result)) { +// google::rpc::RetryInfo info; +// info.retry_delay().seconds() = 30; +// // Payloads require a unique key (a URL to ensure no collisions with +// // other payloads), and an `absl::Cord` to hold the encoded data. +// absl::string_view url = "type.googleapis.com/google.rpc.RetryInfo"; +// result.SetPayload(url, info.SerializeAsCord()); +// return result; +// } +// class ABSL_MUST_USE_RESULT Status final { public: // Constructors - // Creates an OK status with no message or payload. + // This default constructor creates an OK status with no message or payload. + // Avoid this constructor and pefer explicit construction of an OK status with + // `absl::OkStatus()`. Status(); - // Create a status in the canonical error space with the specified code and - // error message. If `code == absl::StatusCode::kOk`, `msg` is ignored and an - // object identical to an OK status is constructed. + // Creates a status in the canonical error space with the specified + // `absl::StatusCode` and error message. If `code == absl::StatusCode::kOk`, + // `msg` is ignored and an object identical to an OK status is constructed. // - // `msg` must be in UTF-8. The implementation may complain (e.g., + // The `msg` string must be in UTF-8. The implementation may complain (e.g., // by printing a warning) if it is not. Status(absl::StatusCode code, absl::string_view msg); @@ -318,42 +390,51 @@ class ABSL_MUST_USE_RESULT Status final { // Status::Update() // - // If `this->ok()`, stores `new_status` into *this. If `!this->ok()`, - // preserves the current data. May, in the future, augment the current status - // with additional information about `new_status`. + // Updates the existing status with `new_status` provided that `this->ok()`. + // If the existing status already contains a non-OK error, this update has no + // effect and preserves the current data. Note that this behavior may change + // in the future to augment a current non-ok status with additional + // information about `new_status`. + // + // `Update()` provides a convenient way of keeping track of the first error + // encountered. // - // Convenient way of keeping track of the first error encountered. - // Instead of: - // if (overall_status.ok()) overall_status = new_status - // Use: + // Example: + // // Instead of "if (overall_status.ok()) overall_status = new_status" // overall_status.Update(new_status); // - // Style guide exception for rvalue reference granted in CL 153567220. void Update(const Status& new_status); void Update(Status&& new_status); // Status::ok() // - // Returns true if the Status is OK. + // Returns `true` if `this->ok()`. Prefer checking for an OK status using this + // member function. ABSL_MUST_USE_RESULT bool ok() const; // Status::code() // - // Returns the (canonical) error code. + // Returns the canonical error code of type `absl::StatusCode` of this status. absl::StatusCode code() const; // Status::raw_code() // - // Returns the raw (canonical) error code which could be out of the range of - // the local `absl::StatusCode` enum. NOTE: This should only be called when - // converting to wire format. Use `code` for error handling. + // Returns a raw (canonical) error code corresponding to the enum value of + // `google.rpc.Code` definitions within + // https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto. + // These values could be out of the range of canonical `absl::StatusCode` + // enum values. + // + // NOTE: This function should only be called when converting to an associated + // wire format. Use `Status::code()` for error handling. int raw_code() const; // Status::message() // - // Returns the error message. Note: prefer ToString() for debug logging. - // This message rarely describes the error code. It is not unusual for the - // error message to be the empty string. + // Returns the error message associated with this error code, if available. + // Note that this message rarely describes the error code. It is not unusual + // for the error message to be the empty string. As a result, prefer + // `Status::ToString()` for debug logging. absl::string_view message() const; friend bool operator==(const Status&, const Status&); @@ -361,12 +442,14 @@ class ABSL_MUST_USE_RESULT Status final { // Status::ToString() // - // Returns a combination of the error code name, the message and the payloads. - // You can expect the code name and the message to be substrings of the - // result, and the payloads to be printed by the registered printer extensions - // if they are recognized. - // WARNING: Do not depend on the exact format of the result of `ToString()` - // which is subject to change. + // Returns a combination of the error code name, the message and any + // associated payload messages. This string is designed simply to be human + // readable and its exact format should not be load bearing. Do not depend on + // the exact format of the result of `ToString()` which is subject to change. + // + // The printed code name and the message are generally substrings of the + // result, and the payloads to be printed use the status payload printer + // mechanism (which is internal). std::string ToString() const; // Status::IgnoreError() @@ -378,52 +461,71 @@ class ABSL_MUST_USE_RESULT Status final { // swap() // - // Swap the contents of `a` with `b` + // Swap the contents of one status with another. friend void swap(Status& a, Status& b); //---------------------------------------------------------------------------- - // Payload management APIs + // Payload Management APIs //---------------------------------------------------------------------------- - // Type URL should be unique and follow the naming convention below: - // The idea of type URL comes from `google.protobuf.Any` - // (https://developers.google.com/protocol-buffers/docs/proto3#any). The - // type URL should be globally unique and follow the format of URL - // (https://en.wikipedia.org/wiki/URL). The default type URL for a given - // protobuf message type is "type.googleapis.com/packagename.messagename". For - // other custom wire formats, users should define the format of type URL in a - // similar practice so as to minimize the chance of conflict between type - // URLs. Users should make sure that the type URL can be mapped to a concrete + // A payload may be attached to a status to provide additional context to an + // error that may not be satisifed by an existing `absl::StatusCode`. + // Typically, this payload serves one of several purposes: + // + // * It may provide more fine-grained semantic information about the error + // to facilitate actionable remedies. + // * It may provide human-readable contexual information that is more + // appropriate to display to an end user. + // + // A payload consists of a [key,value] pair, where the key is a string + // referring to a unique "type URL" and the value is an object of type + // `absl::Cord` to hold the contextual data. + // + // The "type URL" should be unique and follow the format of a URL + // (https://en.wikipedia.org/wiki/URL) and, ideally, provide some + // documentation or schema on how to interpret its associated data. For + // example, the default type URL for a protobuf message type is + // "type.googleapis.com/packagename.messagename". Other custom wire formats + // should define the format of type URL in a similar practice so as to + // minimize the chance of conflict between type URLs. + // Users should ensure that the type URL can be mapped to a concrete // C++ type if they want to deserialize the payload and read it effectively. + // + // To attach a payload to a status object, call `Status::SetPayload()`, + // passing it the type URL and an `absl::Cord` of associated data. Similarly, + // to extract the payload from a status, call `Status::GetPayload()`. You + // may attach multiple payloads (with differing type URLs) to any given + // status object, provided that the status is currently exhibiting an error + // code (i.e. is not OK). // Status::GetPayload() // - // Gets the payload based for `type_url` key, if it is present. + // Gets the payload of a status given its unique `type_url` key, if present. absl::optional GetPayload(absl::string_view type_url) const; // Status::SetPayload() // - // Sets the payload for `type_url` key for a non-ok status, overwriting any - // existing payload for `type_url`. + // Sets the payload for a non-ok status using a `type_url` key, overwriting + // any existing payload for that `type_url`. // - // NOTE: Does nothing if the Status is ok. + // NOTE: This function does nothing if the Status is ok. void SetPayload(absl::string_view type_url, absl::Cord payload); // Status::ErasePayload() // - // Erases the payload corresponding to the `type_url` key. Returns true if + // Erases the payload corresponding to the `type_url` key. Returns `true` if // the payload was present. bool ErasePayload(absl::string_view type_url); // Status::ForEachPayload() // - // Iterates over the stored payloads and calls `visitor(type_key, payload)` - // for each one. + // Iterates over the stored payloads and calls the + // `visitor(type_key, payload)` callable for each one. // - // NOTE: The order of calls to `visitor` is not specified and may change at + // NOTE: The order of calls to `visitor()` is not specified and may change at // any time. // - // NOTE: Any mutation on the same 'Status' object during visitation is + // NOTE: Any mutation on the same 'absl::Status' object during visitation is // forbidden and could result in undefined behavior. void ForEachPayload( const std::function& visitor) @@ -494,7 +596,8 @@ class ABSL_MUST_USE_RESULT Status final { // OkStatus() // -// Returns an OK status, equivalent to a default constructed instance. +// Returns an OK status, equivalent to a default constructed instance. Prefer +// usage of `absl::OkStatus()` when constructing such an OK status. Status OkStatus(); // operator<<() diff --git a/absl/status/statusor.h b/absl/status/statusor.h index 95f99f4..ff0dab6 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 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 does not allow its Status -// value to be absl::OkStatus(). +// ----------------------------------------------------------------------------- +// File: statusor.h +// ----------------------------------------------------------------------------- // -// The primary use-case for StatusOr is as the return value of a -// function which may fail. +// An `absl::StatusOr` represents a union of an `absl::Status` object +// and an object of type `T`. The `absl::StatusOr` 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: +// In general, check the success of an operation returning an +// `absl::StatusOr` like you would an `absl::Status` by using the `ok()` +// member function. // -// StatusOr 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 result = DoBigCalculationThatCouldFail(); -// const Foo& foo = result.value(); -// foo.DoSomethingCool(); -// -// Example usage of a StatusOr>: -// -// StatusOr> 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: -// -// StatusOr FooFactory::MakeFoo(int arg) { -// if (arg <= 0) { -// return absl::Status(absl::StatusCode::kInvalidArgument, -// "Arg must be positive"); -// } -// return Foo(arg); -// } -// -// NULL POINTERS -// -// Historically StatusOr treated null pointers specially. This is no longer -// true -- a StatusOr 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 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` 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 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` + // 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` object's + // error. const absl::Status& status() const; private: @@ -98,6 +98,75 @@ class BadStatusOrAccess : public std::exception { template class ABSL_MUST_USE_RESULT StatusOr; +// abls::StatusOr +// +// The `absl::StatusOr` class template is a union of an `absl::Status` object +// and an object of type `T`. The `absl::StatusOr` 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` is typically the return +// value of a function which may fail. +// +// An `absl::StatusOr` 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::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 result = DoBigCalculationThatCouldFail(); +// if (result.ok()) { +// result->DoSomethingCool(); +// } else { +// LOG(ERROR) << result.status(); +// } +// +// Accessing the object held by an `absl::StatusOr` should be performed via +// `operator*` or `operator->`, after a call to `ok()` confirms that the +// `absl::StatusOr` holds an object of type `T`: +// +// Example: +// +// absl::StatusOr i = GetCount(); +// if (foo.ok()) { +// updated_total += *i +// } +// +// NOTE: using `absl::StatusOr::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 result = DoBigCalculationThatCouldFail(); +// const Foo& foo = result.value(); // Crash/exception if no value present +// foo.DoSomethingCool(); +// +// A `absl::StatusOr` 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` generally requires a bit more care, to ensure both that a +// value is present and that value is not null: +// +// StatusOr> 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: +// +// StatusOr FooFactory::MakeFoo(int arg) { +// if (arg <= 0) { +// return absl::Status(absl::StatusCode::kInvalidArgument, +// "Arg must be positive"); +// } +// return Foo(arg); +// } template class StatusOr : private internal_statusor::StatusOrData, private internal_statusor::CopyCtorBase, @@ -110,30 +179,42 @@ class StatusOr : private internal_statusor::StatusOrData, typedef internal_statusor::StatusOrData Base; public: + // StatusOr::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> 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>` will be initialized with an empty + // vector, instead of an `absl::StatusCode::kUnknown` error code. explicit StatusOr(); - // StatusOr is copy constructible if T is copy constructible. + // `StatusOr` is copy constructible if `T` is copy constructible. StatusOr(const StatusOr&) = default; - // StatusOr is copy assignable if T is copy constructible and copy + // `StatusOr` is copy assignable if `T` is copy constructible and copy // assignable. StatusOr& operator=(const StatusOr&) = default; - // StatusOr is move constructible if T is move constructible. + // `StatusOr` is move constructible if `T` is move constructible. StatusOr(StatusOr&&) = default; - // StatusOr is moveAssignable if T is move constructible and move + // `StatusOr` is moveAssignable if `T` is move constructible and move // assignable. StatusOr& operator=(StatusOr&&) = default; - // Converting constructors from StatusOr, when T is constructible from U. - // To avoid ambiguity, they are disabled if T is also constructible from - // StatusOr. Explicit iff the corresponding construction of T from U is - // explicit. + // Converting Constructors + + // Constructs a new `absl::StatusOr` from an `absl::StatusOr`, when `T` + // is constructible from `U`. To avoid ambiguity, these constructors are + // disabled if `T` is also constructible from `StatusOr.`. 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, explicit StatusOr(StatusOr&& other) : Base(static_cast::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. + // Converting Assignment Operators + + // Creates an `absl::StatusOr` through assignment from an + // `absl::StatusOr` when: + // + // * Both `absl::StatusOr` and `absl::StatusOr` are OK by assigning + // `U` to `T` directly. + // * `absl::StatusOr` is OK and `absl::StatusOr` contains an error + // code by destroying `absl::StatusOr`'s value and assigning from + // `absl::StatusOr' + // * `absl::StatusOr` contains an error code and `absl::StatusOr` is + // OK by directly initializing `T` from `U`. + // * Both `absl::StatusOr` and `absl::StatusOr` contain an error + // code by assigning the `Status` in `absl::StatusOr` to + // `absl::StatusOr` + // + // These overloads only apply if `absl::StatusOr` is constructible and + // assignable from `absl::StatusOr` and `StatusOr` cannot be directly + // assigned from `StatusOr`. template < typename U, absl::enable_if_t< @@ -221,14 +318,13 @@ class StatusOr : private internal_statusor::StatusOrData, 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` 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 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`. + // 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(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, } // Perfect-forwarding value assignment operator. + // If `*this` contains a `T` value before the call, the contained value is // assigned from `std::forward(v)`; Otherwise, it is directly-initialized // from `std::forward(v)`. @@ -305,39 +402,25 @@ class StatusOr : private internal_statusor::StatusOrData, HasConversionOperatorToStatusOr>>>, internal_statusor::IsForwardingAssignmentValid>::value>::type> StatusOr& operator=(U&& v) { - static_assert( - !absl::conjunction< - std::is_constructible, std::is_assignable, - std::is_constructible, - std::is_assignable, - absl::negation>>>>::value, - "U can assign to both T and Status, will result in semantic change"); - static_assert( - !absl::conjunction< - std::is_constructible, std::is_assignable, - internal_statusor::HasConversionOperatorToStatusOr, - absl::negation>>>>::value, - "U can assign to T and convert to StatusOr, will result in semantic " - "change"); this->Assign(std::forward(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 explicit StatusOr(absl::in_place_t, Args&&... args); template explicit StatusOr(absl::in_place_t, std::initializer_list 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, 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`, where `J` + // is convertible to `T`. template < typename U = T, absl::enable_if_t< @@ -355,21 +438,6 @@ class StatusOr : private internal_statusor::StatusOrData, int> = 0> StatusOr(U&& u) // NOLINT : StatusOr(absl::in_place, std::forward(u)) { - static_assert( - !absl::conjunction< - std::is_convertible, std::is_convertible, - absl::negation>>>>::value, - "U is convertible to both T and Status, will result in semantic " - "change"); - static_assert( - !absl::conjunction< - std::is_convertible, - internal_statusor::HasConversionOperatorToStatusOr, - absl::negation>>>>::value, - "U can construct T and convert to StatusOr, will result in semantic " - "change"); } template < @@ -390,38 +458,42 @@ class StatusOr : private internal_statusor::StatusOrData, int> = 0> explicit StatusOr(U&& u) // NOLINT : StatusOr(absl::in_place, std::forward(u)) { - static_assert( - !absl::conjunction< - std::is_constructible, - std::is_constructible, - absl::negation>>>>::value, - "U can construct both T and Status, will result in semantic " - "change"); - static_assert( - !absl::conjunction< - std::is_constructible, - internal_statusor::HasConversionOperatorToStatusOr, - absl::negation>>>>::value, - "U can construct T and convert to StatusOr, will result in semantic " - "change"); } - // Returns this->status().ok() + // StatusOr::ok() + // + // Returns whether or not this `absl::StatusOr` 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 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::status() + // + // Returns a reference to the current `absl::Status` contained within the + // `absl::StatusOr`. If `absl::StatusOr` contains a `T`, then this + // function returns `absl::OkStatus()`. const Status& status() const &; Status status() &&; + // StatusOr::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, const T&& value() const&&; T&& value() &&; + // StatusOr:: 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`. 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::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::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 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 T value_or(U&& default_value) const&; template T value_or(U&& default_value) &&; + // StatusOr::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::emplace() + // // Reconstructs the inner value T in-place using the provided args, using the // T(args...) constructor. Returns reference to the reconstructed `T`. template @@ -522,19 +605,26 @@ class StatusOr : private internal_statusor::StatusOrData, void Assign(absl::StatusOr&& other); }; +// operator==() +// +// This operator checks the equality of two `absl::StatusOr` objects. template bool operator==(const StatusOr& lhs, const StatusOr& rhs) { if (lhs.ok() && rhs.ok()) return *lhs == *rhs; return lhs.status() == rhs.status(); } +// operator!=() +// +// This operator checks the inequality of two `absl::StatusOr` objects. template bool operator!=(const StatusOr& lhs, const StatusOr& rhs) { return !(lhs == rhs); } -//////////////////////////////////////////////////////////////////////////////// +//------------------------------------------------------------------------------ // Implementation details for StatusOr +//------------------------------------------------------------------------------ // TODO(sbenza): avoid the string here completely. template -- cgit v1.2.3