mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Export of internal Abseil changes
-- 8ae3cb636b81b6498ef30fbe59cc102a4098cad2 by Tom Manshreck <shreck@google.com>: Upgrade absl::StatusOr<T> docs to Abseil standards PiperOrigin-RevId: 329975341 -- 7c7baf586c7380497a751f1a186a4ef0e650161a by Tom Manshreck <shreck@google.com>: Update absl::Status to Abseil documentation standards PiperOrigin-RevId: 329942967 -- 6710d022ba987dbae7a5d83045a6697afeb972c4 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 329775111 -- fd182dc699e18522ef16d269731c57669c5487d2 by Abseil Team <absl-team@google.com>: Google-internal change. PiperOrigin-RevId: 329737362 -- c0df5e27ffb48d9c784e7019267580fcb4a3f92e by Xiaoyi Zhang <zhangxy@google.com>: Remove obsolete `static_assert`. PiperOrigin-RevId: 329727604 GitOrigin-RevId: 8ae3cb636b81b6498ef30fbe59cc102a4098cad2 Change-Id: Ic9dede0ab97f799e7f4093fae75ae0ec6cc21437
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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`.
|
||||
//
|
||||
// Convenient way of keeping track of the first error encountered.
|
||||
// Instead of:
|
||||
// if (overall_status.ok()) overall_status = new_status
|
||||
// Use:
|
||||
// `Update()` provides a convenient way of keeping track of the first error
|
||||
// encountered.
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// 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 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>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user