summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/base/internal/strerror.cc37
-rw-r--r--absl/base/internal/strerror_benchmark.cc9
-rw-r--r--absl/status/status.h227
-rw-r--r--absl/status/statusor.h368
-rw-r--r--absl/synchronization/internal/kernel_timeout.h56
5 files changed, 447 insertions, 250 deletions
diff --git a/absl/base/internal/strerror.cc b/absl/base/internal/strerror.cc
index af181513..d66ba120 100644
--- a/absl/base/internal/strerror.cc
+++ b/absl/base/internal/strerror.cc
@@ -14,6 +14,7 @@
#include "absl/base/internal/strerror.h"
+#include <array>
#include <cerrno>
#include <cstddef>
#include <cstdio>
@@ -21,13 +22,13 @@
#include <string>
#include <type_traits>
-#include "absl/base/attributes.h"
#include "absl/base/internal/errno_saver.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
namespace {
+
const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
#if defined(_WIN32)
int rc = strerror_s(buf, buflen, errnum);
@@ -35,15 +36,6 @@ const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
if (rc == 0 && strncmp(buf, "Unknown error", buflen) == 0) *buf = '\0';
return buf;
#else
-#if defined(__GLIBC__) || defined(__APPLE__)
- // Use the BSD sys_errlist API provided by GNU glibc and others to
- // avoid any need to copy the message into the local buffer first.
- if (0 <= errnum && errnum < sys_nerr) {
- if (const char* p = sys_errlist[errnum]) {
- return p;
- }
- }
-#endif
// The type of `ret` is platform-specific; both of these branches must compile
// either way but only one will execute on any given platform:
auto ret = strerror_r(errnum, buf, buflen);
@@ -57,9 +49,8 @@ const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
}
#endif
}
-} // namespace
-std::string StrError(int errnum) {
+std::string StrErrorInternal(int errnum) {
absl::base_internal::ErrnoSaver errno_saver;
char buf[100];
const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
@@ -70,6 +61,28 @@ std::string StrError(int errnum) {
return str;
}
+// kSysNerr is the number of errors from a recent glibc. `StrError()` falls back
+// to `StrErrorAdaptor()` if the value is larger than this.
+constexpr int kSysNerr = 135;
+
+std::array<std::string, kSysNerr>* NewStrErrorTable() {
+ auto* table = new std::array<std::string, kSysNerr>;
+ for (int i = 0; i < static_cast<int>(table->size()); ++i) {
+ (*table)[i] = StrErrorInternal(i);
+ }
+ return table;
+}
+
+} // namespace
+
+std::string StrError(int errnum) {
+ static const auto* table = NewStrErrorTable();
+ if (errnum >= 0 && errnum < static_cast<int>(table->size())) {
+ return (*table)[errnum];
+ }
+ return StrErrorInternal(errnum);
+}
+
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/base/internal/strerror_benchmark.cc b/absl/base/internal/strerror_benchmark.cc
index d8ca86b9..c9ab14a8 100644
--- a/absl/base/internal/strerror_benchmark.cc
+++ b/absl/base/internal/strerror_benchmark.cc
@@ -20,15 +20,6 @@
#include "benchmark/benchmark.h"
namespace {
-#if defined(__GLIBC__) || defined(__APPLE__)
-void BM_SysErrList(benchmark::State& state) {
- for (auto _ : state) {
- benchmark::DoNotOptimize(std::string(sys_errlist[ERANGE]));
- }
-}
-BENCHMARK(BM_SysErrList);
-#endif
-
void BM_AbslStrError(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(absl::base_internal::StrError(ERANGE));
diff --git a/absl/status/status.h b/absl/status/status.h
index 8e1974c9..530f5807 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<T>`, 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<absl::Cord> 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<void(absl::string_view, const absl::Cord&)>& 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 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>
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h
index d6ac5db0..1084e1e6 100644
--- a/absl/synchronization/internal/kernel_timeout.h
+++ b/absl/synchronization/internal/kernel_timeout.h
@@ -57,6 +57,10 @@ class KernelTimeout {
bool has_timeout() const { return ns_ != 0; }
+ // Convert to parameter for sem_timedwait/futex/similar. Only for approved
+ // users. Do not call if !has_timeout.
+ struct timespec MakeAbsTimespec();
+
private:
// internal rep, not user visible: ns after unix epoch.
// zero = no timeout.
@@ -82,34 +86,6 @@ class KernelTimeout {
return x;
}
- // Convert to parameter for sem_timedwait/futex/similar. Only for approved
- // users. Do not call if !has_timeout.
- struct timespec MakeAbsTimespec() {
- int64_t n = ns_;
- static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
- if (n == 0) {
- ABSL_RAW_LOG(
- ERROR,
- "Tried to create a timespec from a non-timeout; never do this.");
- // But we'll try to continue sanely. no-timeout ~= saturated timeout.
- n = (std::numeric_limits<int64_t>::max)();
- }
-
- // Kernel APIs validate timespecs as being at or after the epoch,
- // despite the kernel time type being signed. However, no one can
- // tell the difference between a timeout at or before the epoch (since
- // all such timeouts have expired!)
- if (n < 0) n = 0;
-
- struct timespec abstime;
- int64_t seconds = (std::min)(n / kNanosPerSecond,
- int64_t{(std::numeric_limits<time_t>::max)()});
- abstime.tv_sec = static_cast<time_t>(seconds);
- abstime.tv_nsec =
- static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
- return abstime;
- }
-
#ifdef _WIN32
// Converts to milliseconds from now, or INFINITE when
// !has_timeout(). For use by SleepConditionVariableSRW on
@@ -148,6 +124,30 @@ class KernelTimeout {
friend class Waiter;
};
+inline struct timespec KernelTimeout::MakeAbsTimespec() {
+ int64_t n = ns_;
+ static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+ if (n == 0) {
+ ABSL_RAW_LOG(
+ ERROR, "Tried to create a timespec from a non-timeout; never do this.");
+ // But we'll try to continue sanely. no-timeout ~= saturated timeout.
+ n = (std::numeric_limits<int64_t>::max)();
+ }
+
+ // Kernel APIs validate timespecs as being at or after the epoch,
+ // despite the kernel time type being signed. However, no one can
+ // tell the difference between a timeout at or before the epoch (since
+ // all such timeouts have expired!)
+ if (n < 0) n = 0;
+
+ struct timespec abstime;
+ int64_t seconds = (std::min)(n / kNanosPerSecond,
+ int64_t{(std::numeric_limits<time_t>::max)()});
+ abstime.tv_sec = static_cast<time_t>(seconds);
+ abstime.tv_nsec = static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
+ return abstime;
+}
+
} // namespace synchronization_internal
ABSL_NAMESPACE_END
} // namespace absl