Commit 28c9ae3f authored by Mirko Bonadei's avatar Mirko Bonadei Committed by Commit Bot

Roll abseil_revision 930fbec75b..3c8b5d7587

Change Log:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+log/930fbec75b..3c8b5d7587
Full diff:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+/930fbec75b..3c8b5d7587

No changes required to .def files.

Bug: None
Change-Id: I9ec81aafc9986662f47ebd0425d0984fcb95ce9e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2401465Reviewed-by: default avatarDanil Chapovalov <danilchap@chromium.org>
Commit-Queue: Mirko Bonadei <mbonadei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#805678}
parent 1067ee44
......@@ -4,7 +4,7 @@ URL: https://github.com/abseil/abseil-cpp
License: Apache 2.0
License File: LICENSE
Version: 0
Revision: 930fbec75b452af8bb8c796f5bb754e953e29cf5
Revision: 3c8b5d7587dc8ecf730ce9996c89e156e408c3ed
Security Critical: yes
Description:
......
......@@ -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
......@@ -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));
......
......@@ -20,14 +20,15 @@
//
// * An `absl::Status` class for holding error handling information
// * A set of canonical `absl::StatusCode` error codes, and associated
// utilities for generating and propogating status codes.
// utilities for generating and propagating status codes.
// * 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 that 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;
// // Propagate 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<<()
......
......@@ -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;
// absl::StatusOr<T>
//
// The `absl::StatusOr<T>` class template is a union of an `absl::Status` object
// and an object of type `T`. The `absl::StatusOr<T>` models an object that is
// either a usable object, or an error (of type `absl::Status`) explaining why
// such an object is not present. An `absl::StatusOr<T>` is typically the return
// value of a function which may fail.
//
// An `absl::StatusOr<T>` can never hold an "OK" status (an
// `absl::StatusCode::kOk` value); instead, the presence of an object of type
// `T` indicates success. Instead of checking for a `kOk` value, use the
// `absl::StatusOr<T>::ok()` member function. (It is for this reason, and code
// readability, that using the `ok()` function is preferred for `absl::Status`
// as well.)
//
// Example:
//
// StatusOr<Foo> result = DoBigCalculationThatCouldFail();
// if (result.ok()) {
// result->DoSomethingCool();
// } else {
// LOG(ERROR) << result.status();
// }
//
// Accessing the object held by an `absl::StatusOr<T>` should be performed via
// `operator*` or `operator->`, after a call to `ok()` confirms that the
// `absl::StatusOr<T>` holds an object of type `T`:
//
// Example:
//
// absl::StatusOr<int> i = GetCount();
// if (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>
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment