diff options
author | Benjamin Barenblat <bbaren@google.com> | 2021-04-08 10:23:55 -0400 |
---|---|---|
committer | Benjamin Barenblat <bbaren@google.com> | 2021-04-08 10:23:55 -0400 |
commit | feac56827dd1f0d159ea0bcf2ce37ef1990ac743 (patch) | |
tree | bc8ca767be02a5b22118108f9712b72ec64064c3 /absl/status | |
parent | 2b91b17d526b464840a3f45504c594cdb50152c5 (diff) | |
parent | 997aaf3a28308eba1b9156aa35ab7bca9688e9f6 (diff) |
Merge new upstream LTS 20210324.0
Diffstat (limited to 'absl/status')
-rw-r--r-- | absl/status/internal/status_internal.h | 18 | ||||
-rw-r--r-- | absl/status/internal/statusor_internal.h | 11 | ||||
-rw-r--r-- | absl/status/status.cc | 51 | ||||
-rw-r--r-- | absl/status/status.h | 101 | ||||
-rw-r--r-- | absl/status/status_test.cc | 28 | ||||
-rw-r--r-- | absl/status/statusor.h | 6 | ||||
-rw-r--r-- | absl/status/statusor_test.cc | 11 |
7 files changed, 173 insertions, 53 deletions
diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h index 1f82b8e4..99a2d964 100644 --- a/absl/status/internal/status_internal.h +++ b/absl/status/internal/status_internal.h @@ -19,6 +19,17 @@ #include "absl/container/inlined_vector.h" #include "absl/strings/cord.h" +#ifndef SWIG +// Disabled for SWIG as it doesn't parse attributes correctly. +namespace absl { +ABSL_NAMESPACE_BEGIN +// Returned Status objects may not be ignored. Codesearch doesn't handle ifdefs +// as part of a class definitions (b/6995610), so we use a forward declaration. +class ABSL_MUST_USE_RESULT Status; +ABSL_NAMESPACE_END +} // namespace absl +#endif // !SWIG + namespace absl { ABSL_NAMESPACE_BEGIN @@ -36,6 +47,13 @@ using Payloads = absl::InlinedVector<Payload, 1>; // Reference-counted representation of Status data. struct StatusRep { + StatusRep(absl::StatusCode code, std::string message, + std::unique_ptr<status_internal::Payloads> payloads) + : ref(int32_t{1}), + code(code), + message(std::move(message)), + payloads(std::move(payloads)) {} + std::atomic<int32_t> ref; absl::StatusCode code; std::string message; diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h index 96e41da5..eaac2c0b 100644 --- a/absl/status/internal/statusor_internal.h +++ b/absl/status/internal/statusor_internal.h @@ -17,6 +17,7 @@ #include <type_traits> #include <utility> +#include "absl/base/attributes.h" #include "absl/meta/type_traits.h" #include "absl/status/status.h" #include "absl/utility/utility.h" @@ -135,18 +136,14 @@ class Helper { public: // Move type-agnostic error handling to the .cc. static void HandleInvalidStatusCtorArg(Status*); - static void Crash(const absl::Status& status); + ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status); }; // Construct an instance of T in `p` through placement new, passing Args... to // the constructor. // This abstraction is here mostly for the gcc performance fix. template <typename T, typename... Args> -void PlacementNew(void* p, Args&&... args) { -#if defined(__GNUC__) && !defined(__clang__) - // Teach gcc that 'p' cannot be null, fixing code size issues. - if (p == nullptr) __builtin_unreachable(); -#endif +ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(void* p, Args&&... args) { new (p) T(std::forward<Args>(args)...); } @@ -215,7 +212,7 @@ class StatusOrData { template <typename U, absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value, int> = 0> - explicit StatusOrData(U&& v) : status_(v) { + explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) { EnsureNotOk(); } diff --git a/absl/status/status.cc b/absl/status/status.cc index a27fd8b3..51a0d268 100644 --- a/absl/status/status.cc +++ b/absl/status/status.cc @@ -207,13 +207,12 @@ 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); +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( + code, std::string(msg.data(), msg.size()), + std::move(payloads)); return PointerToRep(rep); } @@ -239,8 +238,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_ = + NewRep(static_cast<absl::StatusCode>(raw_code()), absl::string_view(), + nullptr); return; } @@ -251,7 +251,8 @@ void Status::PrepareToModify() { if (rep->payloads) { payloads = absl::make_unique<status_internal::Payloads>(*rep->payloads); } - rep_ = NewRep(rep->code, message(), std::move(payloads)); + rep_ = NewRep(rep->code, message(), + std::move(payloads)); UnrefNonInlined(rep_i); } } @@ -290,20 +291,26 @@ 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; } diff --git a/absl/status/status.h b/absl/status/status.h index 42f634e0..61486fee 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -57,6 +57,7 @@ #include "absl/container/inlined_vector.h" #include "absl/status/internal/status_internal.h" #include "absl/strings/cord.h" +#include "absl/strings/string_view.h" #include "absl/types/optional.h" namespace absl { @@ -98,7 +99,7 @@ enum class StatusCode : int { // StatusCode::kCancelled // - // kCanelled (gRPC code "CANCELLED") indicates the operation was cancelled, + // kCancelled (gRPC code "CANCELLED") indicates the operation was cancelled, // typically by the caller. kCancelled = 1, @@ -198,9 +199,9 @@ enum class StatusCode : int { // `kAborted`, and `kUnavailable`. kAborted = 10, - // StatusCode::kOutofRange + // StatusCode::kOutOfRange // - // kOutofRange (gRPC code "OUT_OF_RANGE") indicates the operation was + // kOutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was // attempted past the valid range, such as seeking or reading past an // end-of-file. // @@ -279,6 +280,57 @@ std::string StatusCodeToString(StatusCode code); // Streams StatusCodeToString(code) to `os`. std::ostream& operator<<(std::ostream& os, StatusCode code); +// absl::StatusToStringMode +// +// An `absl::StatusToStringMode` is an enumerated type indicating how +// `absl::Status::ToString()` should construct the output string for an non-ok +// status. +enum class StatusToStringMode : int { + // ToString will not contain any extra data (such as payloads). It will only + // contain the error code and message, if any. + kWithNoExtraData = 0, + // ToString will contain the payloads. + kWithPayload = 1 << 0, + // ToString will include all the extra data this Status has. + kWithEverything = ~kWithNoExtraData, +}; + +// absl::StatusToStringMode is specified as a bitmask type, which means the +// following operations must be provided: +inline constexpr StatusToStringMode operator&(StatusToStringMode lhs, + StatusToStringMode rhs) { + return static_cast<StatusToStringMode>(static_cast<int>(lhs) & + static_cast<int>(rhs)); +} +inline constexpr StatusToStringMode operator|(StatusToStringMode lhs, + StatusToStringMode rhs) { + return static_cast<StatusToStringMode>(static_cast<int>(lhs) | + static_cast<int>(rhs)); +} +inline constexpr StatusToStringMode operator^(StatusToStringMode lhs, + StatusToStringMode rhs) { + return static_cast<StatusToStringMode>(static_cast<int>(lhs) ^ + static_cast<int>(rhs)); +} +inline constexpr StatusToStringMode operator~(StatusToStringMode arg) { + return static_cast<StatusToStringMode>(~static_cast<int>(arg)); +} +inline StatusToStringMode& operator&=(StatusToStringMode& lhs, + StatusToStringMode rhs) { + lhs = lhs & rhs; + return lhs; +} +inline StatusToStringMode& operator|=(StatusToStringMode& lhs, + StatusToStringMode rhs) { + lhs = lhs | rhs; + return lhs; +} +inline StatusToStringMode& operator^=(StatusToStringMode& lhs, + StatusToStringMode rhs) { + lhs = lhs ^ rhs; + return lhs; +} + // absl::Status // // The `absl::Status` class is generally used to gracefully handle errors @@ -360,7 +412,12 @@ std::ostream& operator<<(std::ostream& os, StatusCode code); // return result; // } // -class ABSL_MUST_USE_RESULT Status final { +// For documentation see https://abseil.io/docs/cpp/guides/status. +// +// Returned Status objects may not be ignored. status_internal.h has a forward +// declaration of the form +// class ABSL_MUST_USE_RESULT Status; +class Status final { public: // Constructors @@ -370,10 +427,10 @@ class ABSL_MUST_USE_RESULT Status final { Status(); // Creates a status in the canonical error space with the specified - // `absl::StatusCode` and error message. If `code == absl::StatusCode::kOk`, + // `absl::StatusCode` and error message. If `code == absl::StatusCode::kOk`, // NOLINT // `msg` is ignored and an object identical to an OK status is constructed. // - // The `msg` string 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., // NOLINT // by printing a warning) if it is not. Status(absl::StatusCode code, absl::string_view msg); @@ -442,15 +499,17 @@ class ABSL_MUST_USE_RESULT Status final { // Status::ToString() // - // 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. + // Returns a string based on the `mode`. By default, it returns 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; + std::string ToString( + StatusToStringMode mode = StatusToStringMode::kWithPayload) const; // Status::IgnoreError() // @@ -550,8 +609,9 @@ class ABSL_MUST_USE_RESULT Status final { status_internal::Payloads* GetPayloads(); // Takes ownership of payload. - static uintptr_t NewRep(absl::StatusCode code, absl::string_view msg, - std::unique_ptr<status_internal::Payloads> payload); + static uintptr_t NewRep( + absl::StatusCode code, absl::string_view msg, + std::unique_ptr<status_internal::Payloads> payload); static bool EqualsSlow(const absl::Status& a, const absl::Status& b); // MSVC 14.0 limitation requires the const. @@ -580,8 +640,7 @@ class ABSL_MUST_USE_RESULT Status final { static uintptr_t PointerToRep(status_internal::StatusRep* r); static status_internal::StatusRep* RepToPointer(uintptr_t r); - // Returns string for non-ok Status. - std::string ToStringSlow() const; + std::string ToStringSlow(StatusToStringMode mode) const; // Status supports two different representations. // - When the low bit is off it is an inlined representation. @@ -704,9 +763,11 @@ inline Status::Status(Status&& x) noexcept : rep_(x.rep_) { inline Status& Status::operator=(Status&& x) { uintptr_t old_rep = rep_; - rep_ = x.rep_; - x.rep_ = MovedFromRep(); - Unref(old_rep); + if (x.rep_ != old_rep) { + rep_ = x.rep_; + x.rep_ = MovedFromRep(); + Unref(old_rep); + } return *this; } @@ -743,8 +804,8 @@ inline bool operator!=(const Status& lhs, const Status& rhs) { return !(lhs == rhs); } -inline std::string Status::ToString() const { - return ok() ? "OK" : ToStringSlow(); +inline std::string Status::ToString(StatusToStringMode mode) const { + return ok() ? "OK" : ToStringSlow(mode); } inline void Status::IgnoreError() const { diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc index ca9488ad..0e1a43ce 100644 --- a/absl/status/status_test.cc +++ b/absl/status/status_test.cc @@ -280,6 +280,27 @@ TEST(Status, ToString) { HasSubstr("[bar='\\xff']"))); } +TEST(Status, ToStringMode) { + absl::Status s(absl::StatusCode::kInternal, "fail"); + s.SetPayload("foo", absl::Cord("bar")); + s.SetPayload("bar", absl::Cord("\377")); + + EXPECT_EQ("INTERNAL: fail", + s.ToString(absl::StatusToStringMode::kWithNoExtraData)); + + EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithPayload), + AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"), + HasSubstr("[bar='\\xff']"))); + + EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithEverything), + AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"), + HasSubstr("[bar='\\xff']"))); + + EXPECT_THAT(s.ToString(~absl::StatusToStringMode::kWithPayload), + AllOf(HasSubstr("INTERNAL: fail"), Not(HasSubstr("[foo='bar']")), + Not(HasSubstr("[bar='\\xff']")))); +} + absl::Status EraseAndReturn(const absl::Status& base) { absl::Status copy = base; EXPECT_TRUE(copy.ErasePayload(kUrl1)); @@ -397,6 +418,12 @@ TEST(Status, MoveAssignment) { assignee = std::move(status); EXPECT_EQ(assignee, copy); } + { + absl::Status status(absl::StatusCode::kInvalidArgument, "message"); + absl::Status copy(status); + status = static_cast<absl::Status&&>(status); + EXPECT_EQ(status, copy); + } } TEST(Status, Update) { @@ -454,5 +481,4 @@ TEST(Status, Swap) { test_swap(no_payload, with_payload); test_swap(with_payload, no_payload); } - } // namespace diff --git a/absl/status/statusor.h b/absl/status/statusor.h index bdf6039d..b7c55cc8 100644 --- a/absl/status/statusor.h +++ b/absl/status/statusor.h @@ -129,13 +129,13 @@ class ABSL_MUST_USE_RESULT StatusOr; // Example: // // absl::StatusOr<int> i = GetCount(); -// if (foo.ok()) { +// if (i.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. +// exceptions are not enabled. // // Example: // @@ -542,7 +542,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>, // StatusOr<T>::value_or() // - // Returns the current value of `this->ok() == true`. Otherwise constructs a + // Returns the current value if `this->ok() == true`. Otherwise constructs a // value using the provided `default_value`. // // Unlike `value`, this function returns by value, copying the current value diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc index 5e4b2687..c2e8fb7e 100644 --- a/absl/status/statusor_test.cc +++ b/absl/status/statusor_test.cc @@ -292,6 +292,17 @@ TEST(StatusOr, TestDefaultCtor) { EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown); } +TEST(StatusOr, StatusCtorForwards) { + absl::Status status(absl::StatusCode::kInternal, "Some error"); + + EXPECT_EQ(absl::StatusOr<int>(status).status().message(), "Some error"); + EXPECT_EQ(status.message(), "Some error"); + + EXPECT_EQ(absl::StatusOr<int>(std::move(status)).status().message(), + "Some error"); + EXPECT_NE(status.message(), "Some error"); +} + // Define `EXPECT_DEATH_OR_THROW` to test the behavior of `StatusOr::value`, // which either throws `BadStatusOrAccess` or `LOG(FATAL)` based on whether // exceptions are enabled. |