summaryrefslogtreecommitdiff
path: root/abseil-cpp/absl/status/status.cc
diff options
context:
space:
mode:
Diffstat (limited to 'abseil-cpp/absl/status/status.cc')
-rw-r--r--abseil-cpp/absl/status/status.cc266
1 files changed, 224 insertions, 42 deletions
diff --git a/abseil-cpp/absl/status/status.cc b/abseil-cpp/absl/status/status.cc
index a27fd8b..26e6829 100644
--- a/abseil-cpp/absl/status/status.cc
+++ b/abseil-cpp/absl/status/status.cc
@@ -13,9 +13,14 @@
// limitations under the License.
#include "absl/status/status.h"
+#include <errno.h>
+
#include <cassert>
+#include <utility>
#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/strerror.h"
+#include "absl/base/macros.h"
#include "absl/debugging/stacktrace.h"
#include "absl/debugging/symbolize.h"
#include "absl/status/status_payload_printer.h"
@@ -74,15 +79,15 @@ std::ostream& operator<<(std::ostream& os, StatusCode code) {
namespace status_internal {
-static int FindPayloadIndexByUrl(const Payloads* payloads,
- absl::string_view type_url) {
- if (payloads == nullptr) return -1;
+static absl::optional<size_t> FindPayloadIndexByUrl(
+ const Payloads* payloads, absl::string_view type_url) {
+ if (payloads == nullptr) return absl::nullopt;
for (size_t i = 0; i < payloads->size(); ++i) {
if ((*payloads)[i].type_url == type_url) return i;
}
- return -1;
+ return absl::nullopt;
}
// Convert canonical code to a value known to this binary.
@@ -116,8 +121,9 @@ absl::StatusCode MapToLocalCode(int value) {
absl::optional<absl::Cord> Status::GetPayload(
absl::string_view type_url) const {
const auto* payloads = GetPayloads();
- int index = status_internal::FindPayloadIndexByUrl(payloads, type_url);
- if (index != -1) return (*payloads)[index].payload;
+ absl::optional<size_t> index =
+ status_internal::FindPayloadIndexByUrl(payloads, type_url);
+ if (index.has_value()) return (*payloads)[index.value()].payload;
return absl::nullopt;
}
@@ -132,10 +138,10 @@ void Status::SetPayload(absl::string_view type_url, absl::Cord payload) {
rep->payloads = absl::make_unique<status_internal::Payloads>();
}
- int index =
+ absl::optional<size_t> index =
status_internal::FindPayloadIndexByUrl(rep->payloads.get(), type_url);
- if (index != -1) {
- (*rep->payloads)[index].payload = std::move(payload);
+ if (index.has_value()) {
+ (*rep->payloads)[index.value()].payload = std::move(payload);
return;
}
@@ -143,10 +149,11 @@ void Status::SetPayload(absl::string_view type_url, absl::Cord payload) {
}
bool Status::ErasePayload(absl::string_view type_url) {
- int index = status_internal::FindPayloadIndexByUrl(GetPayloads(), type_url);
- if (index != -1) {
+ absl::optional<size_t> index =
+ status_internal::FindPayloadIndexByUrl(GetPayloads(), type_url);
+ if (index.has_value()) {
PrepareToModify();
- GetPayloads()->erase(GetPayloads()->begin() + index);
+ GetPayloads()->erase(GetPayloads()->begin() + index.value());
if (GetPayloads()->empty() && message().empty()) {
// Special case: If this can be represented inlined, it MUST be
// inlined (EqualsSlow depends on this behavior).
@@ -161,7 +168,7 @@ bool Status::ErasePayload(absl::string_view type_url) {
}
void Status::ForEachPayload(
- const std::function<void(absl::string_view, const absl::Cord&)>& visitor)
+ absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor)
const {
if (auto* payloads = GetPayloads()) {
bool in_reverse =
@@ -185,11 +192,16 @@ void Status::ForEachPayload(
}
const std::string* Status::EmptyString() {
- static std::string* empty_string = new std::string();
- return empty_string;
+ static union EmptyString {
+ std::string str;
+ ~EmptyString() {}
+ } empty = {{}};
+ return &empty.str;
}
+#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
constexpr const char Status::kMovedFromString[];
+#endif
const std::string* Status::MovedFromString() {
static std::string* moved_from_string = new std::string(kMovedFromString);
@@ -207,20 +219,10 @@ void Status::UnrefNonInlined(uintptr_t rep) {
}
}
-uintptr_t Status::NewRep(absl::StatusCode code, absl::string_view msg,
- std::unique_ptr<status_internal::Payloads> payloads) {
- status_internal::StatusRep* rep = new status_internal::StatusRep;
- rep->ref.store(1, std::memory_order_relaxed);
- rep->code = code;
- rep->message.assign(msg.data(), msg.size());
- rep->payloads = std::move(payloads);
- return PointerToRep(rep);
-}
-
Status::Status(absl::StatusCode code, absl::string_view msg)
: rep_(CodeToInlinedRep(code)) {
if (code != absl::StatusCode::kOk && !msg.empty()) {
- rep_ = NewRep(code, msg, nullptr);
+ rep_ = PointerToRep(new status_internal::StatusRep(code, msg, nullptr));
}
}
@@ -239,8 +241,9 @@ absl::StatusCode Status::code() const {
void Status::PrepareToModify() {
ABSL_RAW_CHECK(!ok(), "PrepareToModify shouldn't be called on OK status.");
if (IsInlined(rep_)) {
- rep_ = NewRep(static_cast<absl::StatusCode>(raw_code()),
- absl::string_view(), nullptr);
+ rep_ = PointerToRep(new status_internal::StatusRep(
+ static_cast<absl::StatusCode>(raw_code()), absl::string_view(),
+ nullptr));
return;
}
@@ -251,7 +254,9 @@ void Status::PrepareToModify() {
if (rep->payloads) {
payloads = absl::make_unique<status_internal::Payloads>(*rep->payloads);
}
- rep_ = NewRep(rep->code, message(), std::move(payloads));
+ status_internal::StatusRep* const new_rep = new status_internal::StatusRep(
+ rep->code, message(), std::move(payloads));
+ rep_ = PointerToRep(new_rep);
UnrefNonInlined(rep_i);
}
}
@@ -290,26 +295,32 @@ bool Status::EqualsSlow(const absl::Status& a, const absl::Status& b) {
return true;
}
-std::string Status::ToStringSlow() const {
+std::string Status::ToStringSlow(StatusToStringMode mode) const {
std::string text;
absl::StrAppend(&text, absl::StatusCodeToString(code()), ": ", message());
- status_internal::StatusPayloadPrinter printer =
- status_internal::GetStatusPayloadPrinter();
- this->ForEachPayload([&](absl::string_view type_url,
- const absl::Cord& payload) {
- absl::optional<std::string> result;
- if (printer) result = printer(type_url, payload);
- absl::StrAppend(
- &text, " [", type_url, "='",
- result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
- "']");
- });
+
+ const bool with_payload = (mode & StatusToStringMode::kWithPayload) ==
+ StatusToStringMode::kWithPayload;
+
+ if (with_payload) {
+ status_internal::StatusPayloadPrinter printer =
+ status_internal::GetStatusPayloadPrinter();
+ this->ForEachPayload([&](absl::string_view type_url,
+ const absl::Cord& payload) {
+ absl::optional<std::string> result;
+ if (printer) result = printer(type_url, payload);
+ absl::StrAppend(
+ &text, " [", type_url, "='",
+ result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
+ "']");
+ });
+ }
return text;
}
std::ostream& operator<<(std::ostream& os, const Status& x) {
- os << x.ToString();
+ os << x.ToString(StatusToStringMode::kWithEverything);
return os;
}
@@ -441,5 +452,176 @@ bool IsUnknown(const Status& status) {
return status.code() == absl::StatusCode::kUnknown;
}
+StatusCode ErrnoToStatusCode(int error_number) {
+ switch (error_number) {
+ case 0:
+ return StatusCode::kOk;
+ case EINVAL: // Invalid argument
+ case ENAMETOOLONG: // Filename too long
+ case E2BIG: // Argument list too long
+ case EDESTADDRREQ: // Destination address required
+ case EDOM: // Mathematics argument out of domain of function
+ case EFAULT: // Bad address
+ case EILSEQ: // Illegal byte sequence
+ case ENOPROTOOPT: // Protocol not available
+ case ENOSTR: // Not a STREAM
+ case ENOTSOCK: // Not a socket
+ case ENOTTY: // Inappropriate I/O control operation
+ case EPROTOTYPE: // Protocol wrong type for socket
+ case ESPIPE: // Invalid seek
+ return StatusCode::kInvalidArgument;
+ case ETIMEDOUT: // Connection timed out
+ case ETIME: // Timer expired
+ return StatusCode::kDeadlineExceeded;
+ case ENODEV: // No such device
+ case ENOENT: // No such file or directory
+#ifdef ENOMEDIUM
+ case ENOMEDIUM: // No medium found
+#endif
+ case ENXIO: // No such device or address
+ case ESRCH: // No such process
+ return StatusCode::kNotFound;
+ case EEXIST: // File exists
+ case EADDRNOTAVAIL: // Address not available
+ case EALREADY: // Connection already in progress
+#ifdef ENOTUNIQ
+ case ENOTUNIQ: // Name not unique on network
+#endif
+ return StatusCode::kAlreadyExists;
+ case EPERM: // Operation not permitted
+ case EACCES: // Permission denied
+#ifdef ENOKEY
+ case ENOKEY: // Required key not available
+#endif
+ case EROFS: // Read only file system
+ return StatusCode::kPermissionDenied;
+ case ENOTEMPTY: // Directory not empty
+ case EISDIR: // Is a directory
+ case ENOTDIR: // Not a directory
+ case EADDRINUSE: // Address already in use
+ case EBADF: // Invalid file descriptor
+#ifdef EBADFD
+ case EBADFD: // File descriptor in bad state
+#endif
+ case EBUSY: // Device or resource busy
+ case ECHILD: // No child processes
+ case EISCONN: // Socket is connected
+#ifdef EISNAM
+ case EISNAM: // Is a named type file
+#endif
+#ifdef ENOTBLK
+ case ENOTBLK: // Block device required
+#endif
+ case ENOTCONN: // The socket is not connected
+ case EPIPE: // Broken pipe
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: // Cannot send after transport endpoint shutdown
+#endif
+ case ETXTBSY: // Text file busy
+#ifdef EUNATCH
+ case EUNATCH: // Protocol driver not attached
+#endif
+ return StatusCode::kFailedPrecondition;
+ case ENOSPC: // No space left on device
+#ifdef EDQUOT
+ case EDQUOT: // Disk quota exceeded
+#endif
+ case EMFILE: // Too many open files
+ case EMLINK: // Too many links
+ case ENFILE: // Too many open files in system
+ case ENOBUFS: // No buffer space available
+ case ENODATA: // No message is available on the STREAM read queue
+ case ENOMEM: // Not enough space
+ case ENOSR: // No STREAM resources
+#ifdef EUSERS
+ case EUSERS: // Too many users
+#endif
+ return StatusCode::kResourceExhausted;
+#ifdef ECHRNG
+ case ECHRNG: // Channel number out of range
+#endif
+ case EFBIG: // File too large
+ case EOVERFLOW: // Value too large to be stored in data type
+ case ERANGE: // Result too large
+ return StatusCode::kOutOfRange;
+#ifdef ENOPKG
+ case ENOPKG: // Package not installed
+#endif
+ case ENOSYS: // Function not implemented
+ case ENOTSUP: // Operation not supported
+ case EAFNOSUPPORT: // Address family not supported
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT: // Protocol family not supported
+#endif
+ case EPROTONOSUPPORT: // Protocol not supported
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT: // Socket type not supported
+#endif
+ case EXDEV: // Improper link
+ return StatusCode::kUnimplemented;
+ case EAGAIN: // Resource temporarily unavailable
+#ifdef ECOMM
+ case ECOMM: // Communication error on send
+#endif
+ case ECONNREFUSED: // Connection refused
+ case ECONNABORTED: // Connection aborted
+ case ECONNRESET: // Connection reset
+ case EINTR: // Interrupted function call
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: // Host is down
+#endif
+ case EHOSTUNREACH: // Host is unreachable
+ case ENETDOWN: // Network is down
+ case ENETRESET: // Connection aborted by network
+ case ENETUNREACH: // Network unreachable
+ case ENOLCK: // No locks available
+ case ENOLINK: // Link has been severed
+#ifdef ENONET
+ case ENONET: // Machine is not on the network
+#endif
+ return StatusCode::kUnavailable;
+ case EDEADLK: // Resource deadlock avoided
+#ifdef ESTALE
+ case ESTALE: // Stale file handle
+#endif
+ return StatusCode::kAborted;
+ case ECANCELED: // Operation cancelled
+ return StatusCode::kCancelled;
+ default:
+ return StatusCode::kUnknown;
+ }
+}
+
+namespace {
+std::string MessageForErrnoToStatus(int error_number,
+ absl::string_view message) {
+ return absl::StrCat(message, ": ",
+ absl::base_internal::StrError(error_number));
+}
+} // namespace
+
+Status ErrnoToStatus(int error_number, absl::string_view message) {
+ return Status(ErrnoToStatusCode(error_number),
+ MessageForErrnoToStatus(error_number, message));
+}
+
+namespace status_internal {
+
+std::string* MakeCheckFailString(const absl::Status* status,
+ const char* prefix) {
+ return new std::string(
+ absl::StrCat(prefix, " (",
+ status->ToString(StatusToStringMode::kWithEverything), ")"));
+}
+
+} // namespace status_internal
+
+const char* StatusMessageAsCStr(const Status& status) {
+ // As an internal implementation detail, we guarantee that if status.message()
+ // is non-empty, then the resulting string_view is null terminated.
+ auto sv_message = status.message();
+ return sv_message.empty() ? "" : sv_message.data();
+}
+
ABSL_NAMESPACE_END
} // namespace absl