diff options
Diffstat (limited to 'third_party/abseil-cpp/absl/status')
-rw-r--r-- | third_party/abseil-cpp/absl/status/BUILD.bazel | 44 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/CMakeLists.txt | 40 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/internal/status_internal.h | 69 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/internal/statusor_internal.h | 396 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/status.cc | 65 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/status.h | 696 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/status_payload_printer.cc | 15 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/status_test.cc | 36 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/statusor.cc | 103 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/statusor.h | 770 | ||||
-rw-r--r-- | third_party/abseil-cpp/absl/status/statusor_test.cc | 1847 |
11 files changed, 171 insertions, 3910 deletions
diff --git a/third_party/abseil-cpp/absl/status/BUILD.bazel b/third_party/abseil-cpp/absl/status/BUILD.bazel index bae5156f4a..2b83077def 100644 --- a/third_party/abseil-cpp/absl/status/BUILD.bazel +++ b/third_party/abseil-cpp/absl/status/BUILD.bazel @@ -17,6 +17,7 @@ # It will expand later to have utilities around `Status` like `StatusOr`, # `StatusBuilder` and macros. +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", @@ -25,12 +26,11 @@ load( package(default_visibility = ["//visibility:public"]) -licenses(["notice"]) +licenses(["notice"]) # Apache 2.0 cc_library( name = "status", srcs = [ - "internal/status_internal.h", "status.cc", "status_payload_printer.cc", ], @@ -40,14 +40,12 @@ cc_library( ], copts = ABSL_DEFAULT_COPTS, deps = [ - "//absl/base:atomic_hook", "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/container:inlined_vector", "//absl/debugging:stacktrace", "//absl/debugging:symbolize", - "//absl/functional:function_ref", "//absl/strings", "//absl/strings:cord", "//absl/strings:str_format", @@ -65,41 +63,3 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) - -cc_library( - name = "statusor", - srcs = [ - "internal/statusor_internal.h", - "statusor.cc", - ], - hdrs = [ - "statusor.h", - ], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":status", - "//absl/base", - "//absl/base:core_headers", - "//absl/base:raw_logging_internal", - "//absl/meta:type_traits", - "//absl/strings", - "//absl/types:variant", - "//absl/utility", - ], -) - -cc_test( - name = "statusor_test", - size = "small", - srcs = ["statusor_test.cc"], - deps = [ - ":status", - ":statusor", - "//absl/base", - "//absl/memory", - "//absl/strings", - "//absl/types:any", - "//absl/utility", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/third_party/abseil-cpp/absl/status/CMakeLists.txt b/third_party/abseil-cpp/absl/status/CMakeLists.txt index f107c85b1c..f05cee5e95 100644 --- a/third_party/abseil-cpp/absl/status/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/status/CMakeLists.txt @@ -19,17 +19,14 @@ absl_cc_library( HDRS "status.h" SRCS - "internal/status_internal.h" "status.cc" "status_payload_printer.h" "status_payload_printer.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS - absl::atomic_hook absl::config absl::core_headers - absl::function_ref absl::raw_logging_internal absl::inlined_vector absl::stacktrace @@ -51,40 +48,5 @@ absl_cc_test( DEPS absl::status absl::strings - GTest::gmock_main -) - -absl_cc_library( - NAME - statusor - HDRS - "statusor.h" - SRCS - "statusor.cc" - "internal/statusor_internal.h" - COPTS - ${ABSL_DEFAULT_COPTS} - DEPS - absl::base - absl::status - absl::core_headers - absl::raw_logging_internal - absl::type_traits - absl::strings - absl::utility - absl::variant - PUBLIC -) - -absl_cc_test( - NAME - statusor_test - SRCS - "statusor_test.cc" - COPTS - ${ABSL_TEST_COPTS} - DEPS - absl::status - absl::statusor - GTest::gmock_main + gmock_main ) diff --git a/third_party/abseil-cpp/absl/status/internal/status_internal.h b/third_party/abseil-cpp/absl/status/internal/status_internal.h deleted file mode 100644 index ac12940a6d..0000000000 --- a/third_party/abseil-cpp/absl/status/internal/status_internal.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_ -#define ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_ - -#include <string> - -#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 - -enum class StatusCode : int; - -namespace status_internal { - -// Container for status payloads. -struct Payload { - std::string type_url; - absl::Cord payload; -}; - -using Payloads = absl::InlinedVector<Payload, 1>; - -// Reference-counted representation of Status data. -struct StatusRep { - StatusRep(absl::StatusCode code_arg, absl::string_view message_arg, - std::unique_ptr<status_internal::Payloads> payloads_arg) - : ref(int32_t{1}), - code(code_arg), - message(message_arg), - payloads(std::move(payloads_arg)) {} - - std::atomic<int32_t> ref; - absl::StatusCode code; - std::string message; - std::unique_ptr<status_internal::Payloads> payloads; -}; - -absl::StatusCode MapToLocalCode(int value); -} // namespace status_internal - -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_ diff --git a/third_party/abseil-cpp/absl/status/internal/statusor_internal.h b/third_party/abseil-cpp/absl/status/internal/statusor_internal.h deleted file mode 100644 index eaac2c0b14..0000000000 --- a/third_party/abseil-cpp/absl/status/internal/statusor_internal.h +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ -#define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ - -#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" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -template <typename T> -class ABSL_MUST_USE_RESULT StatusOr; - -namespace internal_statusor { - -// Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator -// StatusOr<T>()`. -template <typename T, typename U, typename = void> -struct HasConversionOperatorToStatusOr : std::false_type {}; - -template <typename T, typename U> -void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]); - -template <typename T, typename U> -struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))> - : std::true_type {}; - -// Detects whether `T` is constructible or convertible from `StatusOr<U>`. -template <typename T, typename U> -using IsConstructibleOrConvertibleFromStatusOr = - absl::disjunction<std::is_constructible<T, StatusOr<U>&>, - std::is_constructible<T, const StatusOr<U>&>, - std::is_constructible<T, StatusOr<U>&&>, - std::is_constructible<T, const StatusOr<U>&&>, - std::is_convertible<StatusOr<U>&, T>, - std::is_convertible<const StatusOr<U>&, T>, - std::is_convertible<StatusOr<U>&&, T>, - std::is_convertible<const StatusOr<U>&&, T>>; - -// Detects whether `T` is constructible or convertible or assignable from -// `StatusOr<U>`. -template <typename T, typename U> -using IsConstructibleOrConvertibleOrAssignableFromStatusOr = - absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>, - std::is_assignable<T&, StatusOr<U>&>, - std::is_assignable<T&, const StatusOr<U>&>, - std::is_assignable<T&, StatusOr<U>&&>, - std::is_assignable<T&, const StatusOr<U>&&>>; - -// Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e. -// when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`. -template <typename T, typename U> -struct IsDirectInitializationAmbiguous - : public absl::conditional_t< - std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>, - U>::value, - std::false_type, - IsDirectInitializationAmbiguous< - T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {}; - -template <typename T, typename V> -struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>> - : public IsConstructibleOrConvertibleFromStatusOr<T, V> {}; - -// Checks against the constraints of the direction initialization, i.e. when -// `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution. -template <typename T, typename U> -using IsDirectInitializationValid = absl::disjunction< - // Short circuits if T is basically U. - std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>, - absl::negation<absl::disjunction< - std::is_same<absl::StatusOr<T>, - absl::remove_cv_t<absl::remove_reference_t<U>>>, - std::is_same<absl::Status, - absl::remove_cv_t<absl::remove_reference_t<U>>>, - std::is_same<absl::in_place_t, - absl::remove_cv_t<absl::remove_reference_t<U>>>, - IsDirectInitializationAmbiguous<T, U>>>>; - -// This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which -// is equivalent to whether all the following conditions are met: -// 1. `U` is `StatusOr<V>`. -// 2. `T` is constructible and assignable from `V`. -// 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`). -// For example, the following code is considered ambiguous: -// (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`) -// StatusOr<bool> s1 = true; // s1.ok() && s1.ValueOrDie() == true -// StatusOr<bool> s2 = false; // s2.ok() && s2.ValueOrDie() == false -// s1 = s2; // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`? -template <typename T, typename U> -struct IsForwardingAssignmentAmbiguous - : public absl::conditional_t< - std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>, - U>::value, - std::false_type, - IsForwardingAssignmentAmbiguous< - T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {}; - -template <typename T, typename U> -struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>> - : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {}; - -// Checks against the constraints of the forwarding assignment, i.e. whether -// `StatusOr<T>::operator(U&&)` should participate in overload resolution. -template <typename T, typename U> -using IsForwardingAssignmentValid = absl::disjunction< - // Short circuits if T is basically U. - std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>, - absl::negation<absl::disjunction< - std::is_same<absl::StatusOr<T>, - absl::remove_cv_t<absl::remove_reference_t<U>>>, - std::is_same<absl::Status, - absl::remove_cv_t<absl::remove_reference_t<U>>>, - std::is_same<absl::in_place_t, - absl::remove_cv_t<absl::remove_reference_t<U>>>, - IsForwardingAssignmentAmbiguous<T, U>>>>; - -class Helper { - public: - // Move type-agnostic error handling to the .cc. - static void HandleInvalidStatusCtorArg(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> -ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(void* p, Args&&... args) { - new (p) T(std::forward<Args>(args)...); -} - -// Helper base class to hold the data and all operations. -// We move all this to a base class to allow mixing with the appropriate -// TraitsBase specialization. -template <typename T> -class StatusOrData { - template <typename U> - friend class StatusOrData; - - public: - StatusOrData() = delete; - - StatusOrData(const StatusOrData& other) { - if (other.ok()) { - MakeValue(other.data_); - MakeStatus(); - } else { - MakeStatus(other.status_); - } - } - - StatusOrData(StatusOrData&& other) noexcept { - if (other.ok()) { - MakeValue(std::move(other.data_)); - MakeStatus(); - } else { - MakeStatus(std::move(other.status_)); - } - } - - template <typename U> - explicit StatusOrData(const StatusOrData<U>& other) { - if (other.ok()) { - MakeValue(other.data_); - MakeStatus(); - } else { - MakeStatus(other.status_); - } - } - - template <typename U> - explicit StatusOrData(StatusOrData<U>&& other) { - if (other.ok()) { - MakeValue(std::move(other.data_)); - MakeStatus(); - } else { - MakeStatus(std::move(other.status_)); - } - } - - template <typename... Args> - explicit StatusOrData(absl::in_place_t, Args&&... args) - : data_(std::forward<Args>(args)...) { - MakeStatus(); - } - - explicit StatusOrData(const T& value) : data_(value) { - MakeStatus(); - } - explicit StatusOrData(T&& value) : data_(std::move(value)) { - MakeStatus(); - } - - template <typename U, - absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value, - int> = 0> - explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) { - EnsureNotOk(); - } - - StatusOrData& operator=(const StatusOrData& other) { - if (this == &other) return *this; - if (other.ok()) - Assign(other.data_); - else - AssignStatus(other.status_); - return *this; - } - - StatusOrData& operator=(StatusOrData&& other) { - if (this == &other) return *this; - if (other.ok()) - Assign(std::move(other.data_)); - else - AssignStatus(std::move(other.status_)); - return *this; - } - - ~StatusOrData() { - if (ok()) { - status_.~Status(); - data_.~T(); - } else { - status_.~Status(); - } - } - - template <typename U> - void Assign(U&& value) { - if (ok()) { - data_ = std::forward<U>(value); - } else { - MakeValue(std::forward<U>(value)); - status_ = OkStatus(); - } - } - - template <typename U> - void AssignStatus(U&& v) { - Clear(); - status_ = static_cast<absl::Status>(std::forward<U>(v)); - EnsureNotOk(); - } - - bool ok() const { return status_.ok(); } - - protected: - // status_ will always be active after the constructor. - // We make it a union to be able to initialize exactly how we need without - // waste. - // Eg. in the copy constructor we use the default constructor of Status in - // the ok() path to avoid an extra Ref call. - union { - Status status_; - }; - - // data_ is active iff status_.ok()==true - struct Dummy {}; - union { - // When T is const, we need some non-const object we can cast to void* for - // the placement new. dummy_ is that object. - Dummy dummy_; - T data_; - }; - - void Clear() { - if (ok()) data_.~T(); - } - - void EnsureOk() const { - if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_); - } - - void EnsureNotOk() { - if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_); - } - - // Construct the value (ie. data_) through placement new with the passed - // argument. - template <typename... Arg> - void MakeValue(Arg&&... arg) { - internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...); - } - - // Construct the status (ie. status_) through placement new with the passed - // argument. - template <typename... Args> - void MakeStatus(Args&&... args) { - internal_statusor::PlacementNew<Status>(&status_, - std::forward<Args>(args)...); - } -}; - -// Helper base classes to allow implicitly deleted constructors and assignment -// operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete -// the copy constructor when T is not copy constructible and `StatusOr` will -// inherit that behavior implicitly. -template <typename T, bool = std::is_copy_constructible<T>::value> -struct CopyCtorBase { - CopyCtorBase() = default; - CopyCtorBase(const CopyCtorBase&) = default; - CopyCtorBase(CopyCtorBase&&) = default; - CopyCtorBase& operator=(const CopyCtorBase&) = default; - CopyCtorBase& operator=(CopyCtorBase&&) = default; -}; - -template <typename T> -struct CopyCtorBase<T, false> { - CopyCtorBase() = default; - CopyCtorBase(const CopyCtorBase&) = delete; - CopyCtorBase(CopyCtorBase&&) = default; - CopyCtorBase& operator=(const CopyCtorBase&) = default; - CopyCtorBase& operator=(CopyCtorBase&&) = default; -}; - -template <typename T, bool = std::is_move_constructible<T>::value> -struct MoveCtorBase { - MoveCtorBase() = default; - MoveCtorBase(const MoveCtorBase&) = default; - MoveCtorBase(MoveCtorBase&&) = default; - MoveCtorBase& operator=(const MoveCtorBase&) = default; - MoveCtorBase& operator=(MoveCtorBase&&) = default; -}; - -template <typename T> -struct MoveCtorBase<T, false> { - MoveCtorBase() = default; - MoveCtorBase(const MoveCtorBase&) = default; - MoveCtorBase(MoveCtorBase&&) = delete; - MoveCtorBase& operator=(const MoveCtorBase&) = default; - MoveCtorBase& operator=(MoveCtorBase&&) = default; -}; - -template <typename T, bool = std::is_copy_constructible<T>::value&& - std::is_copy_assignable<T>::value> -struct CopyAssignBase { - CopyAssignBase() = default; - CopyAssignBase(const CopyAssignBase&) = default; - CopyAssignBase(CopyAssignBase&&) = default; - CopyAssignBase& operator=(const CopyAssignBase&) = default; - CopyAssignBase& operator=(CopyAssignBase&&) = default; -}; - -template <typename T> -struct CopyAssignBase<T, false> { - CopyAssignBase() = default; - CopyAssignBase(const CopyAssignBase&) = default; - CopyAssignBase(CopyAssignBase&&) = default; - CopyAssignBase& operator=(const CopyAssignBase&) = delete; - CopyAssignBase& operator=(CopyAssignBase&&) = default; -}; - -template <typename T, bool = std::is_move_constructible<T>::value&& - std::is_move_assignable<T>::value> -struct MoveAssignBase { - MoveAssignBase() = default; - MoveAssignBase(const MoveAssignBase&) = default; - MoveAssignBase(MoveAssignBase&&) = default; - MoveAssignBase& operator=(const MoveAssignBase&) = default; - MoveAssignBase& operator=(MoveAssignBase&&) = default; -}; - -template <typename T> -struct MoveAssignBase<T, false> { - MoveAssignBase() = default; - MoveAssignBase(const MoveAssignBase&) = default; - MoveAssignBase(MoveAssignBase&&) = default; - MoveAssignBase& operator=(const MoveAssignBase&) = default; - MoveAssignBase& operator=(MoveAssignBase&&) = delete; -}; - -ABSL_ATTRIBUTE_NORETURN void ThrowBadStatusOrAccess(absl::Status status); - -} // namespace internal_statusor -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ diff --git a/third_party/abseil-cpp/absl/status/status.cc b/third_party/abseil-cpp/absl/status/status.cc index bcf3413e5f..df3b740f77 100644 --- a/third_party/abseil-cpp/absl/status/status.cc +++ b/third_party/abseil-cpp/absl/status/status.cc @@ -27,6 +27,8 @@ namespace absl { ABSL_NAMESPACE_BEGIN +// The implementation was intentionally kept same as util::error::Code_Name() +// to ease the migration. std::string StatusCodeToString(StatusCode code) { switch (code) { case StatusCode::kOk: @@ -78,7 +80,7 @@ static int FindPayloadIndexByUrl(const Payloads* payloads, absl::string_view type_url) { if (payloads == nullptr) return -1; - for (size_t i = 0; i < payloads->size(); ++i) { + for (int i = 0; i < payloads->size(); ++i) { if ((*payloads)[i].type_url == type_url) return i; } @@ -161,21 +163,21 @@ bool Status::ErasePayload(absl::string_view type_url) { } void Status::ForEachPayload( - absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor) + const std::function<void(absl::string_view, const absl::Cord&)>& visitor) const { if (auto* payloads = GetPayloads()) { bool in_reverse = payloads->size() > 1 && reinterpret_cast<uintptr_t>(payloads) % 13 > 6; - for (size_t index = 0; index < payloads->size(); ++index) { + for (int index = 0; index < payloads->size(); ++index) { const auto& elem = (*payloads)[in_reverse ? payloads->size() - 1 - index : index]; #ifdef NDEBUG visitor(elem.type_url, elem.payload); #else - // In debug mode invalidate the type url to prevent users from relying on - // this string lifetime. + // In debug mode invaldiate the type url to prevent users from relying on + // this std::string lifetime. // NOLINTNEXTLINE intentional extra conversion to force temporary. visitor(std::string(elem.type_url), elem.payload); @@ -207,10 +209,20 @@ 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_ = PointerToRep(new status_internal::StatusRep(code, msg, nullptr)); + rep_ = NewRep(code, msg, nullptr); } } @@ -229,9 +241,8 @@ absl::StatusCode Status::code() const { void Status::PrepareToModify() { ABSL_RAW_CHECK(!ok(), "PrepareToModify shouldn't be called on OK status."); if (IsInlined(rep_)) { - rep_ = PointerToRep(new status_internal::StatusRep( - static_cast<absl::StatusCode>(raw_code()), absl::string_view(), - nullptr)); + rep_ = NewRep(static_cast<absl::StatusCode>(raw_code()), + absl::string_view(), nullptr); return; } @@ -242,9 +253,7 @@ void Status::PrepareToModify() { if (rep->payloads) { payloads = absl::make_unique<status_internal::Payloads>(*rep->payloads); } - status_internal::StatusRep* const new_rep = new status_internal::StatusRep( - rep->code, message(), std::move(payloads)); - rep_ = PointerToRep(new_rep); + rep_ = NewRep(rep->code, message(), std::move(payloads)); UnrefNonInlined(rep_i); } } @@ -283,32 +292,26 @@ bool Status::EqualsSlow(const absl::Status& a, const absl::Status& b) { return true; } -std::string Status::ToStringSlow(StatusToStringMode mode) const { +std::string Status::ToStringSlow() const { std::string text; absl::StrAppend(&text, absl::StatusCodeToString(code()), ": ", message()); - - 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)), - "']"); - }); - } + 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(StatusToStringMode::kWithEverything); + os << x.ToString(); return os; } diff --git a/third_party/abseil-cpp/absl/status/status.h b/third_party/abseil-cpp/absl/status/status.h index 39071e5f4a..9706d4bace 100644 --- a/third_party/abseil-cpp/absl/status/status.h +++ b/third_party/abseil-cpp/absl/status/status.h @@ -11,43 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: status.h -// ----------------------------------------------------------------------------- -// -// This header file defines the Abseil `status` library, consisting of: -// -// * An `absl::Status` class for holding error handling information -// * A set of canonical `absl::StatusCode` error codes, and associated -// 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 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: -// -// absl::Status myFunction(absl::string_view fname, ...) { -// ... -// // encounter error -// if (error condition) { -// return absl::InvalidArgumentError("bad mode"); -// } -// // else, return OK -// return absl::OkStatus(); -// } -// -// An `absl::Status` is designed to either return "OK" or one of a number of -// different error codes, corresponding to typical error conditions. -// In almost all cases, when using `absl::Status` you should use the canonical -// 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. #ifndef ABSL_STATUS_STATUS_H_ #define ABSL_STATUS_STATUS_H_ @@ -55,543 +18,168 @@ #include <string> #include "absl/container/inlined_vector.h" -#include "absl/functional/function_ref.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 { ABSL_NAMESPACE_BEGIN -// absl::StatusCode -// -// An `absl::StatusCode` is an enumerated type indicating either no error ("OK") -// or an error condition. In most cases, an `absl::Status` indicates a -// recoverable error, and the purpose of signalling an error is to indicate what -// action to take in response to that error. These error codes map to the proto -// RPC error codes indicated in https://cloud.google.com/apis/design/errors. -// -// The errors listed below are the canonical errors associated with -// `absl::Status` and are used throughout the codebase. As a result, these -// error codes are somewhat generic. -// -// In general, try to return the most specific error that applies if more than -// one error may pertain. For example, prefer `kOutOfRange` over -// `kFailedPrecondition` if both codes apply. Similarly prefer `kNotFound` or -// `kAlreadyExists` over `kFailedPrecondition`. -// -// Because these errors may cross RPC boundaries, these codes are tied to the -// `google.rpc.Code` definitions within -// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto -// The string value of these RPC codes is denoted within each enum below. -// -// If your error handling code requires more context, you can attach payloads -// to your status. See `absl::Status::SetPayload()` and -// `absl::Status::GetPayload()` below. enum class StatusCode : int { - // StatusCode::kOk - // - // kOK (gRPC code "OK") does not indicate an error; this value is returned on - // success. It is typical to check for this value before proceeding on any - // given call across an API or RPC boundary. To check this value, use the - // `absl::Status::ok()` member function rather than inspecting the raw code. kOk = 0, - - // StatusCode::kCancelled - // - // kCancelled (gRPC code "CANCELLED") indicates the operation was cancelled, - // typically by the caller. kCancelled = 1, - - // StatusCode::kUnknown - // - // kUnknown (gRPC code "UNKNOWN") indicates an unknown error occurred. In - // general, more specific errors should be raised, if possible. Errors raised - // by APIs that do not return enough error information may be converted to - // this error. kUnknown = 2, - - // StatusCode::kInvalidArgument - // - // kInvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller - // specified an invalid argument, such as a malformed filename. Note that use - // of such errors should be narrowly limited to indicate the invalid nature of - // the arguments themselves. Errors with validly formed arguments that may - // cause errors with the state of the receiving system should be denoted with - // `kFailedPrecondition` instead. kInvalidArgument = 3, - - // StatusCode::kDeadlineExceeded - // - // kDeadlineExceeded (gRPC code "DEADLINE_EXCEEDED") indicates a deadline - // expired before the operation could complete. For operations that may change - // state within a system, this error may be returned even if the operation has - // completed successfully. For example, a successful response from a server - // could have been delayed long enough for the deadline to expire. kDeadlineExceeded = 4, - - // StatusCode::kNotFound - // - // kNotFound (gRPC code "NOT_FOUND") indicates some requested entity (such as - // a file or directory) was not found. - // - // `kNotFound` is useful if a request should be denied for an entire class of - // users, such as during a gradual feature rollout or undocumented allow list. - // If a request should be denied for specific sets of users, such as through - // user-based access control, use `kPermissionDenied` instead. kNotFound = 5, - - // StatusCode::kAlreadyExists - // - // kAlreadyExists (gRPC code "ALREADY_EXISTS") indicates that the entity a - // caller attempted to create (such as a file or directory) is already - // present. kAlreadyExists = 6, - - // StatusCode::kPermissionDenied - // - // kPermissionDenied (gRPC code "PERMISSION_DENIED") indicates that the caller - // does not have permission to execute the specified operation. Note that this - // error is different than an error due to an *un*authenticated user. This - // error code does not imply the request is valid or the requested entity - // exists or satisfies any other pre-conditions. - // - // `kPermissionDenied` must not be used for rejections caused by exhausting - // some resource. Instead, use `kResourceExhausted` for those errors. - // `kPermissionDenied` must not be used if the caller cannot be identified. - // Instead, use `kUnauthenticated` for those errors. kPermissionDenied = 7, - - // StatusCode::kResourceExhausted - // - // kResourceExhausted (gRPC code "RESOURCE_EXHAUSTED") indicates some resource - // has been exhausted, perhaps a per-user quota, or perhaps the entire file - // system is out of space. kResourceExhausted = 8, - - // StatusCode::kFailedPrecondition - // - // kFailedPrecondition (gRPC code "FAILED_PRECONDITION") indicates that the - // operation was rejected because the system is not in a state required for - // the operation's execution. For example, a directory to be deleted may be - // non-empty, an "rmdir" operation is applied to a non-directory, etc. - // - // Some guidelines that may help a service implementer in deciding between - // `kFailedPrecondition`, `kAborted`, and `kUnavailable`: - // - // (a) Use `kUnavailable` if the client can retry just the failing call. - // (b) Use `kAborted` if the client should retry at a higher transaction - // level (such as when a client-specified test-and-set fails, indicating - // the client should restart a read-modify-write sequence). - // (c) Use `kFailedPrecondition` if the client should not retry until - // the system state has been explicitly fixed. For example, if a "rmdir" - // fails because the directory is non-empty, `kFailedPrecondition` - // should be returned since the client should not retry unless - // the files are deleted from the directory. kFailedPrecondition = 9, - - // StatusCode::kAborted - // - // kAborted (gRPC code "ABORTED") indicates the operation was aborted, - // typically due to a concurrency issue such as a sequencer check failure or a - // failed transaction. - // - // See the guidelines above for deciding between `kFailedPrecondition`, - // `kAborted`, and `kUnavailable`. kAborted = 10, - - // StatusCode::kOutOfRange - // - // 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. - // - // Unlike `kInvalidArgument`, this error indicates a problem that may - // be fixed if the system state changes. For example, a 32-bit file - // system will generate `kInvalidArgument` if asked to read at an - // offset that is not in the range [0,2^32-1], but it will generate - // `kOutOfRange` if asked to read from an offset past the current - // file size. - // - // There is a fair bit of overlap between `kFailedPrecondition` and - // `kOutOfRange`. We recommend using `kOutOfRange` (the more specific - // error) when it applies so that callers who are iterating through - // a space can easily look for an `kOutOfRange` error to detect when - // they are done. kOutOfRange = 11, - - // StatusCode::kUnimplemented - // - // kUnimplemented (gRPC code "UNIMPLEMENTED") indicates the operation is not - // implemented or supported in this service. In this case, the operation - // should not be re-attempted. kUnimplemented = 12, - - // StatusCode::kInternal - // - // kInternal (gRPC code "INTERNAL") indicates an internal error has occurred - // and some invariants expected by the underlying system have not been - // satisfied. This error code is reserved for serious errors. kInternal = 13, - - // StatusCode::kUnavailable - // - // kUnavailable (gRPC code "UNAVAILABLE") indicates the service is currently - // unavailable and that this is most likely a transient condition. An error - // such as this can be corrected by retrying with a backoff scheme. Note that - // it is not always safe to retry non-idempotent operations. - // - // See the guidelines above for deciding between `kFailedPrecondition`, - // `kAborted`, and `kUnavailable`. kUnavailable = 14, - - // StatusCode::kDataLoss - // - // kDataLoss (gRPC code "DATA_LOSS") indicates that unrecoverable data loss or - // corruption has occurred. As this error is serious, proper alerting should - // be attached to errors such as this. kDataLoss = 15, - - // StatusCode::kUnauthenticated - // - // kUnauthenticated (gRPC code "UNAUTHENTICATED") indicates that the request - // does not have valid authentication credentials for the operation. Correct - // the authentication and try again. kUnauthenticated = 16, - - // StatusCode::DoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_ - // - // NOTE: this error code entry should not be used and you should not rely on - // its value, which may change. - // - // The purpose of this enumerated value is to force people who handle status - // codes with `switch()` statements to *not* simply enumerate all possible - // values, but instead provide a "default:" case. Providing such a default - // case ensures that code will compile when new codes are added. kDoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_ = 20 }; -// StatusCodeToString() -// // Returns the name for the status code, or "" if it is an unknown value. std::string StatusCodeToString(StatusCode code); -// operator<< -// // 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 a 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, - // Default mode used by ToString. Its exact value might change in the future. - kDefault = kWithPayload, +namespace status_internal { + +// Container for status payloads. +struct Payload { + std::string type_url; + absl::Cord payload; }; -// 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; -} +using Payloads = absl::InlinedVector<Payload, 1>; -// 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 construct 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; -// } -// -// 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 +// Reference-counted representation of Status data. +struct StatusRep { + std::atomic<int32_t> ref; + absl::StatusCode code; + std::string message; + std::unique_ptr<status_internal::Payloads> payloads; +}; + +absl::StatusCode MapToLocalCode(int value); +} // namespace status_internal - // This default constructor creates an OK status with no message or payload. - // Avoid this constructor and prefer explicit construction of an OK status - // with `absl::OkStatus()`. +class ABSL_MUST_USE_RESULT Status final { + public: + // Creates an OK status with no message or payload. Status(); - // Creates a status in the canonical error space with the specified - // `absl::StatusCode` and error message. If `code == absl::StatusCode::kOk`, // NOLINT - // `msg` is ignored and an object identical to an OK status is constructed. + // Create a status in the canonical error space with the specified code and + // error message. If `code == util::error::OK`, `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., // NOLINT + // `msg` 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); Status(const Status&); Status& operator=(const Status& x); - // Move operators - + // Move operations. // The moved-from state is valid but unspecified. Status(Status&&) noexcept; Status& operator=(Status&&); ~Status(); - // Status::Update() - // - // 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`. + // 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`. // - // `Update()` provides a convenient way of keeping track of the first error - // encountered. - // - // Example: - // // Instead of "if (overall_status.ok()) overall_status = new_status" + // Convenient way of keeping track of the first error encountered. + // Instead of: + // if (overall_status.ok()) overall_status = new_status + // Use: // 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 `this->ok()`. Prefer checking for an OK status using this - // member function. + // Returns true if the Status is OK. ABSL_MUST_USE_RESULT bool ok() const; - // Status::code() - // - // Returns the canonical error code of type `absl::StatusCode` of this status. + // Returns the (canonical) error code. absl::StatusCode code() const; - // Status::raw_code() - // - // 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. + // 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. int raw_code() const; - // Status::message() - // - // 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 - // `operator<<` or `Status::ToString()` for debug logging. + // 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 std::string. absl::string_view message() const; friend bool operator==(const Status&, const Status&); friend bool operator!=(const Status&, const Status&); - // Status::ToString() - // - // 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( - StatusToStringMode mode = StatusToStringMode::kDefault) const; + // 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. + std::string ToString() const; - // Status::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; - // swap() - // - // Swap the contents of one status with another. + // Swap the contents of `a` with `b` friend void swap(Status& a, Status& b); - //---------------------------------------------------------------------------- - // Payload Management APIs - //---------------------------------------------------------------------------- - - // 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 + // 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 // 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 of a status given its unique `type_url` key, if present. + + // Gets the payload based for `type_url` key, if it is 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: This function does nothing if the Status is ok. + // NOTE: 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 the - // `visitor(type_key, payload)` callable for each one. + // Iterates over the stored payloads and calls `visitor(type_key, payload)` + // 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 'absl::Status' object during visitation is + // NOTE: Any mutation on the same 'Status' object during visitation is // forbidden and could result in undefined behavior. void ForEachPayload( - absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor) + const std::function<void(absl::string_view, const absl::Cord&)>& visitor) const; private: @@ -613,9 +201,8 @@ class 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. @@ -644,7 +231,8 @@ class Status final { static uintptr_t PointerToRep(status_internal::StatusRep* r); static status_internal::StatusRep* RepToPointer(uintptr_t r); - std::string ToStringSlow(StatusToStringMode mode) const; + // Returns std::string for non-ok Status. + std::string ToStringSlow() const; // Status supports two different representations. // - When the low bit is off it is an inlined representation. @@ -657,93 +245,14 @@ class Status final { uintptr_t rep_; }; -// OkStatus() -// -// Returns an OK status, equivalent to a default constructed instance. Prefer -// usage of `absl::OkStatus()` when constructing such an OK status. +// Returns an OK status, equivalent to a default constructed instance. Status OkStatus(); -// operator<<() -// // Prints a human-readable representation of `x` to `os`. std::ostream& operator<<(std::ostream& os, const Status& x); -// IsAborted() -// IsAlreadyExists() -// IsCancelled() -// IsDataLoss() -// IsDeadlineExceeded() -// IsFailedPrecondition() -// IsInternal() -// IsInvalidArgument() -// IsNotFound() -// IsOutOfRange() -// IsPermissionDenied() -// IsResourceExhausted() -// IsUnauthenticated() -// IsUnavailable() -// IsUnimplemented() -// IsUnknown() -// -// These convenience functions return `true` if a given status matches the -// `absl::StatusCode` error code of its associated function. -ABSL_MUST_USE_RESULT bool IsAborted(const Status& status); -ABSL_MUST_USE_RESULT bool IsAlreadyExists(const Status& status); -ABSL_MUST_USE_RESULT bool IsCancelled(const Status& status); -ABSL_MUST_USE_RESULT bool IsDataLoss(const Status& status); -ABSL_MUST_USE_RESULT bool IsDeadlineExceeded(const Status& status); -ABSL_MUST_USE_RESULT bool IsFailedPrecondition(const Status& status); -ABSL_MUST_USE_RESULT bool IsInternal(const Status& status); -ABSL_MUST_USE_RESULT bool IsInvalidArgument(const Status& status); -ABSL_MUST_USE_RESULT bool IsNotFound(const Status& status); -ABSL_MUST_USE_RESULT bool IsOutOfRange(const Status& status); -ABSL_MUST_USE_RESULT bool IsPermissionDenied(const Status& status); -ABSL_MUST_USE_RESULT bool IsResourceExhausted(const Status& status); -ABSL_MUST_USE_RESULT bool IsUnauthenticated(const Status& status); -ABSL_MUST_USE_RESULT bool IsUnavailable(const Status& status); -ABSL_MUST_USE_RESULT bool IsUnimplemented(const Status& status); -ABSL_MUST_USE_RESULT bool IsUnknown(const Status& status); - -// AbortedError() -// AlreadyExistsError() -// CancelledError() -// DataLossError() -// DeadlineExceededError() -// FailedPreconditionError() -// InternalError() -// InvalidArgumentError() -// NotFoundError() -// OutOfRangeError() -// PermissionDeniedError() -// ResourceExhaustedError() -// UnauthenticatedError() -// UnavailableError() -// UnimplementedError() -// UnknownError() -// -// These convenience functions create an `absl::Status` object with an error -// code as indicated by the associated function name, using the error message -// passed in `message`. -Status AbortedError(absl::string_view message); -Status AlreadyExistsError(absl::string_view message); -Status CancelledError(absl::string_view message); -Status DataLossError(absl::string_view message); -Status DeadlineExceededError(absl::string_view message); -Status FailedPreconditionError(absl::string_view message); -Status InternalError(absl::string_view message); -Status InvalidArgumentError(absl::string_view message); -Status NotFoundError(absl::string_view message); -Status OutOfRangeError(absl::string_view message); -Status PermissionDeniedError(absl::string_view message); -Status ResourceExhaustedError(absl::string_view message); -Status UnauthenticatedError(absl::string_view message); -Status UnavailableError(absl::string_view message); -Status UnimplementedError(absl::string_view message); -Status UnknownError(absl::string_view message); - -//------------------------------------------------------------------------------ +// ----------------------------------------------------------------- // Implementation details follow -//------------------------------------------------------------------------------ inline Status::Status() : rep_(CodeToInlinedRep(absl::StatusCode::kOk)) {} @@ -767,11 +276,9 @@ inline Status::Status(Status&& x) noexcept : rep_(x.rep_) { inline Status& Status::operator=(Status&& x) { uintptr_t old_rep = rep_; - if (x.rep_ != old_rep) { - rep_ = x.rep_; - x.rep_ = MovedFromRep(); - Unref(old_rep); - } + rep_ = x.rep_; + x.rep_ = MovedFromRep(); + Unref(old_rep); return *this; } @@ -808,8 +315,8 @@ inline bool operator!=(const Status& lhs, const Status& rhs) { return !(lhs == rhs); } -inline std::string Status::ToString(StatusToStringMode mode) const { - return ok() ? "OK" : ToStringSlow(mode); +inline std::string Status::ToString() const { + return ok() ? "OK" : ToStringSlow(); } inline void Status::IgnoreError() const { @@ -871,11 +378,50 @@ inline void Status::Unref(uintptr_t rep) { inline Status OkStatus() { return Status(); } +// Each of the functions below creates a Status object with a particular error +// code and the given message. The error code of the returned status object +// matches the name of the function. +Status AbortedError(absl::string_view message); +Status AlreadyExistsError(absl::string_view message); +Status CancelledError(absl::string_view message); +Status DataLossError(absl::string_view message); +Status DeadlineExceededError(absl::string_view message); +Status FailedPreconditionError(absl::string_view message); +Status InternalError(absl::string_view message); +Status InvalidArgumentError(absl::string_view message); +Status NotFoundError(absl::string_view message); +Status OutOfRangeError(absl::string_view message); +Status PermissionDeniedError(absl::string_view message); +Status ResourceExhaustedError(absl::string_view message); +Status UnauthenticatedError(absl::string_view message); +Status UnavailableError(absl::string_view message); +Status UnimplementedError(absl::string_view message); +Status UnknownError(absl::string_view message); + // Creates a `Status` object with the `absl::StatusCode::kCancelled` error code // and an empty message. It is provided only for efficiency, given that // message-less kCancelled errors are common in the infrastructure. inline Status CancelledError() { return Status(absl::StatusCode::kCancelled); } +// Each of the functions below returns true if the given status matches the +// error code implied by the function's name. +ABSL_MUST_USE_RESULT bool IsAborted(const Status& status); +ABSL_MUST_USE_RESULT bool IsAlreadyExists(const Status& status); +ABSL_MUST_USE_RESULT bool IsCancelled(const Status& status); +ABSL_MUST_USE_RESULT bool IsDataLoss(const Status& status); +ABSL_MUST_USE_RESULT bool IsDeadlineExceeded(const Status& status); +ABSL_MUST_USE_RESULT bool IsFailedPrecondition(const Status& status); +ABSL_MUST_USE_RESULT bool IsInternal(const Status& status); +ABSL_MUST_USE_RESULT bool IsInvalidArgument(const Status& status); +ABSL_MUST_USE_RESULT bool IsNotFound(const Status& status); +ABSL_MUST_USE_RESULT bool IsOutOfRange(const Status& status); +ABSL_MUST_USE_RESULT bool IsPermissionDenied(const Status& status); +ABSL_MUST_USE_RESULT bool IsResourceExhausted(const Status& status); +ABSL_MUST_USE_RESULT bool IsUnauthenticated(const Status& status); +ABSL_MUST_USE_RESULT bool IsUnavailable(const Status& status); +ABSL_MUST_USE_RESULT bool IsUnimplemented(const Status& status); +ABSL_MUST_USE_RESULT bool IsUnknown(const Status& status); + ABSL_NAMESPACE_END } // namespace absl diff --git a/third_party/abseil-cpp/absl/status/status_payload_printer.cc b/third_party/abseil-cpp/absl/status/status_payload_printer.cc index a47aea11c2..ad96d76acf 100644 --- a/third_party/abseil-cpp/absl/status/status_payload_printer.cc +++ b/third_party/abseil-cpp/absl/status/status_payload_printer.cc @@ -16,21 +16,26 @@ #include <atomic> #include "absl/base/attributes.h" -#include "absl/base/internal/atomic_hook.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace status_internal { -ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES -static absl::base_internal::AtomicHook<StatusPayloadPrinter> storage; +namespace { +// Tried constant initialized global variable but it doesn't work with Lexan +// (MSVC's `std::atomic` has trouble constant initializing). +std::atomic<StatusPayloadPrinter>& GetStatusPayloadPrinterStorage() { + ABSL_CONST_INIT static std::atomic<StatusPayloadPrinter> instance{nullptr}; + return instance; +} +} // namespace void SetStatusPayloadPrinter(StatusPayloadPrinter printer) { - storage.Store(printer); + GetStatusPayloadPrinterStorage().store(printer, std::memory_order_relaxed); } StatusPayloadPrinter GetStatusPayloadPrinter() { - return storage.Load(); + return GetStatusPayloadPrinterStorage().load(std::memory_order_relaxed); } } // namespace status_internal diff --git a/third_party/abseil-cpp/absl/status/status_test.cc b/third_party/abseil-cpp/absl/status/status_test.cc index 1b038f6d98..ca9488ad22 100644 --- a/third_party/abseil-cpp/absl/status/status_test.cc +++ b/third_party/abseil-cpp/absl/status/status_test.cc @@ -36,9 +36,7 @@ TEST(StatusCode, InsertionOperator) { // its creator, and its classifier. struct ErrorTest { absl::StatusCode code; - using Creator = absl::Status (*)( - absl::string_view - ); + using Creator = absl::Status (*)(absl::string_view); using Classifier = bool (*)(const absl::Status&); Creator creator; Classifier classifier; @@ -80,9 +78,7 @@ TEST(Status, CreateAndClassify) { // expected error code and message. std::string message = absl::StrCat("error code ", test.code, " test message"); - absl::Status status = test.creator( - message - ); + absl::Status status = test.creator(message); EXPECT_EQ(test.code, status.code()); EXPECT_EQ(message, status.message()); @@ -284,27 +280,6 @@ 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)); @@ -422,12 +397,6 @@ 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) { @@ -485,4 +454,5 @@ TEST(Status, Swap) { test_swap(no_payload, with_payload); test_swap(with_payload, no_payload); } + } // namespace diff --git a/third_party/abseil-cpp/absl/status/statusor.cc b/third_party/abseil-cpp/absl/status/statusor.cc deleted file mode 100644 index 96642b340f..0000000000 --- a/third_party/abseil-cpp/absl/status/statusor.cc +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "absl/status/statusor.h" - -#include <cstdlib> -#include <utility> - -#include "absl/base/call_once.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/status/status.h" -#include "absl/strings/str_cat.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -BadStatusOrAccess::BadStatusOrAccess(absl::Status status) - : status_(std::move(status)) {} - -BadStatusOrAccess::BadStatusOrAccess(const BadStatusOrAccess& other) - : status_(other.status_) {} - -BadStatusOrAccess& BadStatusOrAccess::operator=( - const BadStatusOrAccess& other) { - // Ensure assignment is correct regardless of whether this->InitWhat() has - // already been called. - other.InitWhat(); - status_ = other.status_; - what_ = other.what_; - return *this; -} - -BadStatusOrAccess& BadStatusOrAccess::operator=(BadStatusOrAccess&& other) { - // Ensure assignment is correct regardless of whether this->InitWhat() has - // already been called. - other.InitWhat(); - status_ = std::move(other.status_); - what_ = std::move(other.what_); - return *this; -} - -BadStatusOrAccess::BadStatusOrAccess(BadStatusOrAccess&& other) - : status_(std::move(other.status_)) {} - -const char* BadStatusOrAccess::what() const noexcept { - InitWhat(); - return what_.c_str(); -} - -const absl::Status& BadStatusOrAccess::status() const { return status_; } - -void BadStatusOrAccess::InitWhat() const { - absl::call_once(init_what_, [this] { - what_ = absl::StrCat("Bad StatusOr access: ", status_.ToString()); - }); -} - -namespace internal_statusor { - -void Helper::HandleInvalidStatusCtorArg(absl::Status* status) { - const char* kMessage = - "An OK status is not a valid constructor argument to StatusOr<T>"; -#ifdef NDEBUG - ABSL_INTERNAL_LOG(ERROR, kMessage); -#else - ABSL_INTERNAL_LOG(FATAL, kMessage); -#endif - // In optimized builds, we will fall back to InternalError. - *status = absl::InternalError(kMessage); -} - -void Helper::Crash(const absl::Status& status) { - ABSL_INTERNAL_LOG( - FATAL, - absl::StrCat("Attempting to fetch value instead of handling error ", - status.ToString())); -} - -void ThrowBadStatusOrAccess(absl::Status status) { -#ifdef ABSL_HAVE_EXCEPTIONS - throw absl::BadStatusOrAccess(std::move(status)); -#else - ABSL_INTERNAL_LOG( - FATAL, - absl::StrCat("Attempting to fetch value instead of handling error ", - status.ToString())); - std::abort(); -#endif -} - -} // namespace internal_statusor -ABSL_NAMESPACE_END -} // namespace absl diff --git a/third_party/abseil-cpp/absl/status/statusor.h b/third_party/abseil-cpp/absl/status/statusor.h deleted file mode 100644 index c051fbb3aa..0000000000 --- a/third_party/abseil-cpp/absl/status/statusor.h +++ /dev/null @@ -1,770 +0,0 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: statusor.h -// ----------------------------------------------------------------------------- -// -// 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. -// -// 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. -// -// Example: -// -// StatusOr<Foo> result = Calculation(); -// if (result.ok()) { -// result->DoSomethingCool(); -// } else { -// LOG(ERROR) << result.status(); -// } -#ifndef ABSL_STATUS_STATUSOR_H_ -#define ABSL_STATUS_STATUSOR_H_ - -#include <exception> -#include <initializer_list> -#include <new> -#include <string> -#include <type_traits> -#include <utility> - -#include "absl/base/attributes.h" -#include "absl/base/call_once.h" -#include "absl/meta/type_traits.h" -#include "absl/status/internal/statusor_internal.h" -#include "absl/status/status.h" -#include "absl/types/variant.h" -#include "absl/utility/utility.h" - -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 = default; - - BadStatusOrAccess(const BadStatusOrAccess& other); - BadStatusOrAccess& operator=(const BadStatusOrAccess& other); - BadStatusOrAccess(BadStatusOrAccess&& other); - BadStatusOrAccess& operator=(BadStatusOrAccess&& other); - - // BadStatusOrAccess::what() - // - // Returns the associated explanatory string of the `absl::StatusOr<T>` - // object's error code. This function contains information about the failing - // status, but its exact formatting may change and should not be depended on. - // - // 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: - void InitWhat() const; - - absl::Status status_; - mutable absl::once_flag init_what_; - mutable std::string what_; -}; - -// Returned StatusOr objects may not be ignored. -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 (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 -// exceptions 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>, - private internal_statusor::MoveCtorBase<T>, - private internal_statusor::CopyAssignBase<T>, - private internal_statusor::MoveAssignBase<T> { - template <typename U> - friend class StatusOr; - - 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; - - // 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(const StatusOr&) = default; - // `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(StatusOr&&) = default; - // `StatusOr<T>` is moveAssignable if `T` is move constructible and move - // assignable. - StatusOr& operator=(StatusOr&&) = default; - - // 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< - absl::conjunction< - absl::negation<std::is_same<T, U>>, - std::is_constructible<T, const U&>, - std::is_convertible<const U&, T>, - absl::negation< - internal_statusor::IsConstructibleOrConvertibleFromStatusOr< - T, U>>>::value, - int> = 0> - StatusOr(const StatusOr<U>& other) // NOLINT - : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {} - template < - typename U, - absl::enable_if_t< - absl::conjunction< - absl::negation<std::is_same<T, U>>, - std::is_constructible<T, const U&>, - absl::negation<std::is_convertible<const U&, T>>, - absl::negation< - internal_statusor::IsConstructibleOrConvertibleFromStatusOr< - T, U>>>::value, - int> = 0> - explicit StatusOr(const StatusOr<U>& other) - : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {} - - template < - typename U, - absl::enable_if_t< - absl::conjunction< - absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, - std::is_convertible<U&&, T>, - absl::negation< - internal_statusor::IsConstructibleOrConvertibleFromStatusOr< - T, U>>>::value, - int> = 0> - StatusOr(StatusOr<U>&& other) // NOLINT - : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {} - template < - typename U, - absl::enable_if_t< - absl::conjunction< - absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, - absl::negation<std::is_convertible<U&&, T>>, - absl::negation< - internal_statusor::IsConstructibleOrConvertibleFromStatusOr< - T, U>>>::value, - int> = 0> - explicit StatusOr(StatusOr<U>&& other) - : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {} - - // 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< - absl::conjunction< - absl::negation<std::is_same<T, U>>, - std::is_constructible<T, const U&>, - std::is_assignable<T, const U&>, - absl::negation< - internal_statusor:: - IsConstructibleOrConvertibleOrAssignableFromStatusOr< - T, U>>>::value, - int> = 0> - StatusOr& operator=(const StatusOr<U>& other) { - this->Assign(other); - return *this; - } - template < - typename U, - absl::enable_if_t< - absl::conjunction< - absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, - std::is_assignable<T, U&&>, - absl::negation< - internal_statusor:: - IsConstructibleOrConvertibleOrAssignableFromStatusOr< - T, U>>>::value, - int> = 0> - StatusOr& operator=(StatusOr<U>&& other) { - this->Assign(std::move(other)); - return *this; - } - - // 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. - // - // 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 - // of passing absl::StatusCode::kInternal as a fallback. - template < - typename U = absl::Status, - absl::enable_if_t< - absl::conjunction< - std::is_convertible<U&&, absl::Status>, - std::is_constructible<absl::Status, U&&>, - absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>, - absl::negation<std::is_same<absl::decay_t<U>, T>>, - absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>, - absl::negation<internal_statusor::HasConversionOperatorToStatusOr< - T, U&&>>>::value, - int> = 0> - StatusOr(U&& v) : Base(std::forward<U>(v)) {} - - template < - typename U = absl::Status, - absl::enable_if_t< - absl::conjunction< - absl::negation<std::is_convertible<U&&, absl::Status>>, - std::is_constructible<absl::Status, U&&>, - absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>, - absl::negation<std::is_same<absl::decay_t<U>, T>>, - absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>, - absl::negation<internal_statusor::HasConversionOperatorToStatusOr< - T, U&&>>>::value, - int> = 0> - explicit StatusOr(U&& v) : Base(std::forward<U>(v)) {} - - template < - typename U = absl::Status, - absl::enable_if_t< - absl::conjunction< - std::is_convertible<U&&, absl::Status>, - std::is_constructible<absl::Status, U&&>, - absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>, - absl::negation<std::is_same<absl::decay_t<U>, T>>, - absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>, - absl::negation<internal_statusor::HasConversionOperatorToStatusOr< - T, U&&>>>::value, - int> = 0> - StatusOr& operator=(U&& v) { - this->AssignStatus(std::forward<U>(v)); - return *this; - } - - // 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)`. - // This function does not participate in overload unless: - // 1. `std::is_constructible_v<T, U>` is true, - // 2. `std::is_assignable_v<T&, U>` is true. - // 3. `std::is_same_v<StatusOr<T>, std::remove_cvref_t<U>>` is false. - // 4. Assigning `U` to `T` is not ambiguous: - // If `U` is `StatusOr<V>` and `T` is constructible and assignable from - // both `StatusOr<V>` and `V`, the assignment is considered bug-prone and - // ambiguous thus will fail to compile. For example: - // StatusOr<bool> s1 = true; // s1.ok() && *s1 == true - // StatusOr<bool> s2 = false; // s2.ok() && *s2 == false - // s1 = s2; // ambiguous, `s1 = *s2` or `s1 = bool(s2)`? - template < - typename U = T, - typename = typename std::enable_if<absl::conjunction< - std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>, - absl::disjunction< - std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>, T>, - absl::conjunction< - absl::negation<std::is_convertible<U&&, absl::Status>>, - absl::negation<internal_statusor:: - HasConversionOperatorToStatusOr<T, U&&>>>>, - internal_statusor::IsForwardingAssignmentValid<T, U&&>>::value>::type> - StatusOr& operator=(U&& v) { - this->Assign(std::forward<U>(v)); - return *this; - } - - // 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. 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 constructor is disabled if `U` is a `StatusOr<J>`, where - // `J` is convertible to `T`. - template < - typename U = T, - absl::enable_if_t< - absl::conjunction< - internal_statusor::IsDirectInitializationValid<T, U&&>, - std::is_constructible<T, U&&>, std::is_convertible<U&&, T>, - absl::disjunction< - std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>, - T>, - absl::conjunction< - absl::negation<std::is_convertible<U&&, absl::Status>>, - absl::negation< - internal_statusor::HasConversionOperatorToStatusOr< - T, U&&>>>>>::value, - int> = 0> - StatusOr(U&& u) // NOLINT - : StatusOr(absl::in_place, std::forward<U>(u)) {} - - template < - typename U = T, - absl::enable_if_t< - absl::conjunction< - internal_statusor::IsDirectInitializationValid<T, U&&>, - absl::disjunction< - std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>, - T>, - absl::conjunction< - absl::negation<std::is_constructible<absl::Status, U&&>>, - absl::negation< - internal_statusor::HasConversionOperatorToStatusOr< - T, U&&>>>>, - std::is_constructible<T, U&&>, - absl::negation<std::is_convertible<U&&, T>>>::value, - int> = 0> - explicit StatusOr(U&& u) // NOLINT - : StatusOr(absl::in_place, std::forward<U>(u)) {} - - // 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(); } - - // 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 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(); - // - // Otherwise, if the value type is expensive to copy, but can be left - // in the StatusOr, simply assign to a reference: - // - // T& value = statusor.value(); // or `const T&` - // - // Otherwise, if the value type supports an efficient move, it can be - // used as follows: - // - // T value = std::move(statusor).value(); - // - // The `std::move` on statusor instead of on the whole expression enables - // warnings about possible uses of the statusor object after the move. - const T& value() const& ABSL_ATTRIBUTE_LIFETIME_BOUND; - T& value() & ABSL_ATTRIBUTE_LIFETIME_BOUND; - const T&& value() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND; - T&& value() && ABSL_ATTRIBUTE_LIFETIME_BOUND; - - // StatusOr<T>:: operator*() - // - // Returns a reference to the current value. - // - // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined. - // - // 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& ABSL_ATTRIBUTE_LIFETIME_BOUND; - T& operator*() & ABSL_ATTRIBUTE_LIFETIME_BOUND; - const T&& operator*() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND; - T&& operator*() && ABSL_ATTRIBUTE_LIFETIME_BOUND; - - // StatusOr<T>::operator->() - // - // Returns a pointer to the current value. - // - // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined. - // - // Use `this->ok()` to verify that there is a current value. - const T* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND; - T* operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND; - - // StatusOr<T>::value_or() - // - // 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 - // if necessary. If the value type supports an efficient move, it can be used - // as follows: - // - // T value = std::move(statusor).value_or(def); - // - // 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> - T& emplace(Args&&... args) { - if (ok()) { - this->Clear(); - this->MakeValue(std::forward<Args>(args)...); - } else { - this->MakeValue(std::forward<Args>(args)...); - this->status_ = absl::OkStatus(); - } - return this->data_; - } - - template < - typename U, typename... Args, - absl::enable_if_t< - std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, - int> = 0> - T& emplace(std::initializer_list<U> ilist, Args&&... args) { - if (ok()) { - this->Clear(); - this->MakeValue(ilist, std::forward<Args>(args)...); - } else { - this->MakeValue(ilist, std::forward<Args>(args)...); - this->status_ = absl::OkStatus(); - } - return this->data_; - } - - private: - using internal_statusor::StatusOrData<T>::Assign; - template <typename U> - void Assign(const absl::StatusOr<U>& other); - template <typename U> - 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> -StatusOr<T>::StatusOr() : Base(Status(absl::StatusCode::kUnknown, "")) {} - -template <typename T> -template <typename U> -inline void StatusOr<T>::Assign(const StatusOr<U>& other) { - if (other.ok()) { - this->Assign(*other); - } else { - this->AssignStatus(other.status()); - } -} - -template <typename T> -template <typename U> -inline void StatusOr<T>::Assign(StatusOr<U>&& other) { - if (other.ok()) { - this->Assign(*std::move(other)); - } else { - this->AssignStatus(std::move(other).status()); - } -} -template <typename T> -template <typename... Args> -StatusOr<T>::StatusOr(absl::in_place_t, Args&&... args) - : Base(absl::in_place, std::forward<Args>(args)...) {} - -template <typename T> -template <typename U, typename... Args> -StatusOr<T>::StatusOr(absl::in_place_t, std::initializer_list<U> ilist, - Args&&... args) - : Base(absl::in_place, ilist, std::forward<Args>(args)...) {} - -template <typename T> -const Status& StatusOr<T>::status() const& { - return this->status_; -} -template <typename T> -Status StatusOr<T>::status() && { - return ok() ? OkStatus() : std::move(this->status_); -} - -template <typename T> -const T& StatusOr<T>::value() const& { - if (!this->ok()) internal_statusor::ThrowBadStatusOrAccess(this->status_); - return this->data_; -} - -template <typename T> -T& StatusOr<T>::value() & { - if (!this->ok()) internal_statusor::ThrowBadStatusOrAccess(this->status_); - return this->data_; -} - -template <typename T> -const T&& StatusOr<T>::value() const&& { - if (!this->ok()) { - internal_statusor::ThrowBadStatusOrAccess(std::move(this->status_)); - } - return std::move(this->data_); -} - -template <typename T> -T&& StatusOr<T>::value() && { - if (!this->ok()) { - internal_statusor::ThrowBadStatusOrAccess(std::move(this->status_)); - } - return std::move(this->data_); -} - -template <typename T> -const T& StatusOr<T>::operator*() const& { - this->EnsureOk(); - return this->data_; -} - -template <typename T> -T& StatusOr<T>::operator*() & { - this->EnsureOk(); - return this->data_; -} - -template <typename T> -const T&& StatusOr<T>::operator*() const&& { - this->EnsureOk(); - return std::move(this->data_); -} - -template <typename T> -T&& StatusOr<T>::operator*() && { - this->EnsureOk(); - return std::move(this->data_); -} - -template <typename T> -const T* StatusOr<T>::operator->() const { - this->EnsureOk(); - return &this->data_; -} - -template <typename T> -T* StatusOr<T>::operator->() { - this->EnsureOk(); - return &this->data_; -} - -template <typename T> -template <typename U> -T StatusOr<T>::value_or(U&& default_value) const& { - if (ok()) { - return this->data_; - } - return std::forward<U>(default_value); -} - -template <typename T> -template <typename U> -T StatusOr<T>::value_or(U&& default_value) && { - if (ok()) { - return std::move(this->data_); - } - return std::forward<U>(default_value); -} - -template <typename T> -void StatusOr<T>::IgnoreError() const { - // no-op -} - -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_STATUS_STATUSOR_H_ diff --git a/third_party/abseil-cpp/absl/status/statusor_test.cc b/third_party/abseil-cpp/absl/status/statusor_test.cc deleted file mode 100644 index 7cae90e185..0000000000 --- a/third_party/abseil-cpp/absl/status/statusor_test.cc +++ /dev/null @@ -1,1847 +0,0 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/status/statusor.h" - -#include <array> -#include <initializer_list> -#include <memory> -#include <string> -#include <type_traits> -#include <utility> - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/casts.h" -#include "absl/memory/memory.h" -#include "absl/status/status.h" -#include "absl/strings/string_view.h" -#include "absl/types/any.h" -#include "absl/utility/utility.h" - -namespace { - -using ::testing::AllOf; -using ::testing::AnyWith; -using ::testing::ElementsAre; -using ::testing::Field; -using ::testing::HasSubstr; -using ::testing::Ne; -using ::testing::Not; -using ::testing::Pointee; -using ::testing::VariantWith; - -#ifdef GTEST_HAS_STATUS_MATCHERS -using ::testing::status::IsOk; -using ::testing::status::IsOkAndHolds; -#else // GTEST_HAS_STATUS_MATCHERS -inline const ::absl::Status& GetStatus(const ::absl::Status& status) { - return status; -} - -template <typename T> -inline const ::absl::Status& GetStatus(const ::absl::StatusOr<T>& status) { - return status.status(); -} - -// Monomorphic implementation of matcher IsOkAndHolds(m). StatusOrType is a -// reference to StatusOr<T>. -template <typename StatusOrType> -class IsOkAndHoldsMatcherImpl - : public ::testing::MatcherInterface<StatusOrType> { - public: - typedef - typename std::remove_reference<StatusOrType>::type::value_type value_type; - - template <typename InnerMatcher> - explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher) - : inner_matcher_(::testing::SafeMatcherCast<const value_type&>( - std::forward<InnerMatcher>(inner_matcher))) {} - - void DescribeTo(std::ostream* os) const override { - *os << "is OK and has a value that "; - inner_matcher_.DescribeTo(os); - } - - void DescribeNegationTo(std::ostream* os) const override { - *os << "isn't OK or has a value that "; - inner_matcher_.DescribeNegationTo(os); - } - - bool MatchAndExplain( - StatusOrType actual_value, - ::testing::MatchResultListener* result_listener) const override { - if (!actual_value.ok()) { - *result_listener << "which has status " << actual_value.status(); - return false; - } - - ::testing::StringMatchResultListener inner_listener; - const bool matches = - inner_matcher_.MatchAndExplain(*actual_value, &inner_listener); - const std::string inner_explanation = inner_listener.str(); - if (!inner_explanation.empty()) { - *result_listener << "which contains value " - << ::testing::PrintToString(*actual_value) << ", " - << inner_explanation; - } - return matches; - } - - private: - const ::testing::Matcher<const value_type&> inner_matcher_; -}; - -// Implements IsOkAndHolds(m) as a polymorphic matcher. -template <typename InnerMatcher> -class IsOkAndHoldsMatcher { - public: - explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher) - : inner_matcher_(std::move(inner_matcher)) {} - - // Converts this polymorphic matcher to a monomorphic matcher of the - // given type. StatusOrType can be either StatusOr<T> or a - // reference to StatusOr<T>. - template <typename StatusOrType> - operator ::testing::Matcher<StatusOrType>() const { // NOLINT - return ::testing::Matcher<StatusOrType>( - new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_)); - } - - private: - const InnerMatcher inner_matcher_; -}; - -// Monomorphic implementation of matcher IsOk() for a given type T. -// T can be Status, StatusOr<>, or a reference to either of them. -template <typename T> -class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> { - public: - void DescribeTo(std::ostream* os) const override { *os << "is OK"; } - void DescribeNegationTo(std::ostream* os) const override { - *os << "is not OK"; - } - bool MatchAndExplain(T actual_value, - ::testing::MatchResultListener*) const override { - return GetStatus(actual_value).ok(); - } -}; - -// Implements IsOk() as a polymorphic matcher. -class IsOkMatcher { - public: - template <typename T> - operator ::testing::Matcher<T>() const { // NOLINT - return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<T>()); - } -}; - -// Macros for testing the results of functions that return absl::Status or -// absl::StatusOr<T> (for any type T). -#define EXPECT_OK(expression) EXPECT_THAT(expression, IsOk()) - -// Returns a gMock matcher that matches a StatusOr<> whose status is -// OK and whose value matches the inner matcher. -template <typename InnerMatcher> -IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type> IsOkAndHolds( - InnerMatcher&& inner_matcher) { - return IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>( - std::forward<InnerMatcher>(inner_matcher)); -} - -// Returns a gMock matcher that matches a Status or StatusOr<> which is OK. -inline IsOkMatcher IsOk() { return IsOkMatcher(); } -#endif // GTEST_HAS_STATUS_MATCHERS - -struct CopyDetector { - CopyDetector() = default; - explicit CopyDetector(int xx) : x(xx) {} - CopyDetector(CopyDetector&& d) noexcept - : x(d.x), copied(false), moved(true) {} - CopyDetector(const CopyDetector& d) : x(d.x), copied(true), moved(false) {} - CopyDetector& operator=(const CopyDetector& c) { - x = c.x; - copied = true; - moved = false; - return *this; - } - CopyDetector& operator=(CopyDetector&& c) noexcept { - x = c.x; - copied = false; - moved = true; - return *this; - } - int x = 0; - bool copied = false; - bool moved = false; -}; - -testing::Matcher<const CopyDetector&> CopyDetectorHas(int a, bool b, bool c) { - return AllOf(Field(&CopyDetector::x, a), Field(&CopyDetector::moved, b), - Field(&CopyDetector::copied, c)); -} - -class Base1 { - public: - virtual ~Base1() {} - int pad; -}; - -class Base2 { - public: - virtual ~Base2() {} - int yetotherpad; -}; - -class Derived : public Base1, public Base2 { - public: - virtual ~Derived() {} - int evenmorepad; -}; - -class CopyNoAssign { - public: - explicit CopyNoAssign(int value) : foo(value) {} - CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {} - int foo; - - private: - const CopyNoAssign& operator=(const CopyNoAssign&); -}; - -absl::StatusOr<std::unique_ptr<int>> ReturnUniquePtr() { - // Uses implicit constructor from T&& - return absl::make_unique<int>(0); -} - -TEST(StatusOr, ElementType) { - static_assert(std::is_same<absl::StatusOr<int>::value_type, int>(), ""); - static_assert(std::is_same<absl::StatusOr<char>::value_type, char>(), ""); -} - -TEST(StatusOr, TestMoveOnlyInitialization) { - absl::StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr()); - ASSERT_TRUE(thing.ok()); - EXPECT_EQ(0, **thing); - int* previous = thing->get(); - - thing = ReturnUniquePtr(); - EXPECT_TRUE(thing.ok()); - EXPECT_EQ(0, **thing); - EXPECT_NE(previous, thing->get()); -} - -TEST(StatusOr, TestMoveOnlyValueExtraction) { - absl::StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr()); - ASSERT_TRUE(thing.ok()); - std::unique_ptr<int> ptr = *std::move(thing); - EXPECT_EQ(0, *ptr); - - thing = std::move(ptr); - ptr = std::move(*thing); - EXPECT_EQ(0, *ptr); -} - -TEST(StatusOr, TestMoveOnlyInitializationFromTemporaryByValueOrDie) { - std::unique_ptr<int> ptr(*ReturnUniquePtr()); - EXPECT_EQ(0, *ptr); -} - -TEST(StatusOr, TestValueOrDieOverloadForConstTemporary) { - static_assert( - std::is_same< - const int&&, - decltype(std::declval<const absl::StatusOr<int>&&>().value())>(), - "value() for const temporaries should return const T&&"); -} - -TEST(StatusOr, TestMoveOnlyConversion) { - absl::StatusOr<std::unique_ptr<const int>> const_thing(ReturnUniquePtr()); - EXPECT_TRUE(const_thing.ok()); - EXPECT_EQ(0, **const_thing); - - // Test rvalue converting assignment - const int* const_previous = const_thing->get(); - const_thing = ReturnUniquePtr(); - EXPECT_TRUE(const_thing.ok()); - EXPECT_EQ(0, **const_thing); - EXPECT_NE(const_previous, const_thing->get()); -} - -TEST(StatusOr, TestMoveOnlyVector) { - // Sanity check that absl::StatusOr<MoveOnly> works in vector. - std::vector<absl::StatusOr<std::unique_ptr<int>>> vec; - vec.push_back(ReturnUniquePtr()); - vec.resize(2); - auto another_vec = std::move(vec); - EXPECT_EQ(0, **another_vec[0]); - EXPECT_EQ(absl::UnknownError(""), another_vec[1].status()); -} - -TEST(StatusOr, TestDefaultCtor) { - absl::StatusOr<int> thing; - EXPECT_FALSE(thing.ok()); - 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"); -} - -TEST(BadStatusOrAccessTest, CopyConstructionWhatOk) { - absl::Status error = - absl::InternalError("some arbitrary message too big for the sso buffer"); - absl::BadStatusOrAccess e1{error}; - absl::BadStatusOrAccess e2{e1}; - EXPECT_THAT(e1.what(), HasSubstr(error.ToString())); - EXPECT_THAT(e2.what(), HasSubstr(error.ToString())); -} - -TEST(BadStatusOrAccessTest, CopyAssignmentWhatOk) { - absl::Status error = - absl::InternalError("some arbitrary message too big for the sso buffer"); - absl::BadStatusOrAccess e1{error}; - absl::BadStatusOrAccess e2{absl::InternalError("other")}; - e2 = e1; - EXPECT_THAT(e1.what(), HasSubstr(error.ToString())); - EXPECT_THAT(e2.what(), HasSubstr(error.ToString())); -} - -TEST(BadStatusOrAccessTest, MoveConstructionWhatOk) { - absl::Status error = - absl::InternalError("some arbitrary message too big for the sso buffer"); - absl::BadStatusOrAccess e1{error}; - absl::BadStatusOrAccess e2{std::move(e1)}; - EXPECT_THAT(e2.what(), HasSubstr(error.ToString())); -} - -TEST(BadStatusOrAccessTest, MoveAssignmentWhatOk) { - absl::Status error = - absl::InternalError("some arbitrary message too big for the sso buffer"); - absl::BadStatusOrAccess e1{error}; - absl::BadStatusOrAccess e2{absl::InternalError("other")}; - e2 = std::move(e1); - EXPECT_THAT(e2.what(), HasSubstr(error.ToString())); -} - -// 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. -#ifdef ABSL_HAVE_EXCEPTIONS -#define EXPECT_DEATH_OR_THROW(statement, status_) \ - EXPECT_THROW( \ - { \ - try { \ - statement; \ - } catch (const absl::BadStatusOrAccess& e) { \ - EXPECT_EQ(e.status(), status_); \ - EXPECT_THAT(e.what(), HasSubstr(e.status().ToString())); \ - throw; \ - } \ - }, \ - absl::BadStatusOrAccess); -#else // ABSL_HAVE_EXCEPTIONS -#define EXPECT_DEATH_OR_THROW(statement, status) \ - EXPECT_DEATH_IF_SUPPORTED(statement, status.ToString()); -#endif // ABSL_HAVE_EXCEPTIONS - -TEST(StatusOrDeathTest, TestDefaultCtorValue) { - absl::StatusOr<int> thing; - EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError("")); - const absl::StatusOr<int> thing2; - EXPECT_DEATH_OR_THROW(thing2.value(), absl::UnknownError("")); -} - -TEST(StatusOrDeathTest, TestValueNotOk) { - absl::StatusOr<int> thing(absl::CancelledError()); - EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError()); -} - -TEST(StatusOrDeathTest, TestValueNotOkConst) { - const absl::StatusOr<int> thing(absl::UnknownError("")); - EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError("")); -} - -TEST(StatusOrDeathTest, TestPointerDefaultCtorValue) { - absl::StatusOr<int*> thing; - EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError("")); -} - -TEST(StatusOrDeathTest, TestPointerValueNotOk) { - absl::StatusOr<int*> thing(absl::CancelledError()); - EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError()); -} - -TEST(StatusOrDeathTest, TestPointerValueNotOkConst) { - const absl::StatusOr<int*> thing(absl::CancelledError()); - EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError()); -} - -#if GTEST_HAS_DEATH_TEST -TEST(StatusOrDeathTest, TestStatusCtorStatusOk) { - EXPECT_DEBUG_DEATH( - { - // This will DCHECK - absl::StatusOr<int> thing(absl::OkStatus()); - // In optimized mode, we are actually going to get error::INTERNAL for - // status here, rather than crashing, so check that. - EXPECT_FALSE(thing.ok()); - EXPECT_EQ(thing.status().code(), absl::StatusCode::kInternal); - }, - "An OK status is not a valid constructor argument"); -} - -TEST(StatusOrDeathTest, TestPointerStatusCtorStatusOk) { - EXPECT_DEBUG_DEATH( - { - absl::StatusOr<int*> thing(absl::OkStatus()); - // In optimized mode, we are actually going to get error::INTERNAL for - // status here, rather than crashing, so check that. - EXPECT_FALSE(thing.ok()); - EXPECT_EQ(thing.status().code(), absl::StatusCode::kInternal); - }, - "An OK status is not a valid constructor argument"); -} -#endif - -TEST(StatusOr, ValueAccessor) { - const int kIntValue = 110; - { - absl::StatusOr<int> status_or(kIntValue); - EXPECT_EQ(kIntValue, status_or.value()); - EXPECT_EQ(kIntValue, std::move(status_or).value()); - } - { - absl::StatusOr<CopyDetector> status_or(kIntValue); - EXPECT_THAT(status_or, - IsOkAndHolds(CopyDetectorHas(kIntValue, false, false))); - CopyDetector copy_detector = status_or.value(); - EXPECT_THAT(copy_detector, CopyDetectorHas(kIntValue, false, true)); - copy_detector = std::move(status_or).value(); - EXPECT_THAT(copy_detector, CopyDetectorHas(kIntValue, true, false)); - } -} - -TEST(StatusOr, BadValueAccess) { - const absl::Status kError = absl::CancelledError("message"); - absl::StatusOr<int> status_or(kError); - EXPECT_DEATH_OR_THROW(status_or.value(), kError); -} - -TEST(StatusOr, TestStatusCtor) { - absl::StatusOr<int> thing(absl::CancelledError()); - EXPECT_FALSE(thing.ok()); - EXPECT_EQ(thing.status().code(), absl::StatusCode::kCancelled); -} - -TEST(StatusOr, TestValueCtor) { - const int kI = 4; - const absl::StatusOr<int> thing(kI); - EXPECT_TRUE(thing.ok()); - EXPECT_EQ(kI, *thing); -} - -struct Foo { - const int x; - explicit Foo(int y) : x(y) {} -}; - -TEST(StatusOr, InPlaceConstruction) { - EXPECT_THAT(absl::StatusOr<Foo>(absl::in_place, 10), - IsOkAndHolds(Field(&Foo::x, 10))); -} - -struct InPlaceHelper { - InPlaceHelper(std::initializer_list<int> xs, std::unique_ptr<int> yy) - : x(xs), y(std::move(yy)) {} - const std::vector<int> x; - std::unique_ptr<int> y; -}; - -TEST(StatusOr, InPlaceInitListConstruction) { - absl::StatusOr<InPlaceHelper> status_or(absl::in_place, {10, 11, 12}, - absl::make_unique<int>(13)); - EXPECT_THAT(status_or, IsOkAndHolds(AllOf( - Field(&InPlaceHelper::x, ElementsAre(10, 11, 12)), - Field(&InPlaceHelper::y, Pointee(13))))); -} - -TEST(StatusOr, Emplace) { - absl::StatusOr<Foo> status_or_foo(10); - status_or_foo.emplace(20); - EXPECT_THAT(status_or_foo, IsOkAndHolds(Field(&Foo::x, 20))); - status_or_foo = absl::InvalidArgumentError("msg"); - EXPECT_FALSE(status_or_foo.ok()); - EXPECT_EQ(status_or_foo.status().code(), absl::StatusCode::kInvalidArgument); - EXPECT_EQ(status_or_foo.status().message(), "msg"); - status_or_foo.emplace(20); - EXPECT_THAT(status_or_foo, IsOkAndHolds(Field(&Foo::x, 20))); -} - -TEST(StatusOr, EmplaceInitializerList) { - absl::StatusOr<InPlaceHelper> status_or(absl::in_place, {10, 11, 12}, - absl::make_unique<int>(13)); - status_or.emplace({1, 2, 3}, absl::make_unique<int>(4)); - EXPECT_THAT(status_or, - IsOkAndHolds(AllOf(Field(&InPlaceHelper::x, ElementsAre(1, 2, 3)), - Field(&InPlaceHelper::y, Pointee(4))))); - status_or = absl::InvalidArgumentError("msg"); - EXPECT_FALSE(status_or.ok()); - EXPECT_EQ(status_or.status().code(), absl::StatusCode::kInvalidArgument); - EXPECT_EQ(status_or.status().message(), "msg"); - status_or.emplace({1, 2, 3}, absl::make_unique<int>(4)); - EXPECT_THAT(status_or, - IsOkAndHolds(AllOf(Field(&InPlaceHelper::x, ElementsAre(1, 2, 3)), - Field(&InPlaceHelper::y, Pointee(4))))); -} - -TEST(StatusOr, TestCopyCtorStatusOk) { - const int kI = 4; - const absl::StatusOr<int> original(kI); - const absl::StatusOr<int> copy(original); - EXPECT_OK(copy.status()); - EXPECT_EQ(*original, *copy); -} - -TEST(StatusOr, TestCopyCtorStatusNotOk) { - absl::StatusOr<int> original(absl::CancelledError()); - absl::StatusOr<int> copy(original); - EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled); -} - -TEST(StatusOr, TestCopyCtorNonAssignable) { - const int kI = 4; - CopyNoAssign value(kI); - absl::StatusOr<CopyNoAssign> original(value); - absl::StatusOr<CopyNoAssign> copy(original); - EXPECT_OK(copy.status()); - EXPECT_EQ(original->foo, copy->foo); -} - -TEST(StatusOr, TestCopyCtorStatusOKConverting) { - const int kI = 4; - absl::StatusOr<int> original(kI); - absl::StatusOr<double> copy(original); - EXPECT_OK(copy.status()); - EXPECT_DOUBLE_EQ(*original, *copy); -} - -TEST(StatusOr, TestCopyCtorStatusNotOkConverting) { - absl::StatusOr<int> original(absl::CancelledError()); - absl::StatusOr<double> copy(original); - EXPECT_EQ(copy.status(), original.status()); -} - -TEST(StatusOr, TestAssignmentStatusOk) { - // Copy assignmment - { - const auto p = std::make_shared<int>(17); - absl::StatusOr<std::shared_ptr<int>> source(p); - - absl::StatusOr<std::shared_ptr<int>> target; - target = source; - - ASSERT_TRUE(target.ok()); - EXPECT_OK(target.status()); - EXPECT_EQ(p, *target); - - ASSERT_TRUE(source.ok()); - EXPECT_OK(source.status()); - EXPECT_EQ(p, *source); - } - - // Move asssignment - { - const auto p = std::make_shared<int>(17); - absl::StatusOr<std::shared_ptr<int>> source(p); - - absl::StatusOr<std::shared_ptr<int>> target; - target = std::move(source); - - ASSERT_TRUE(target.ok()); - EXPECT_OK(target.status()); - EXPECT_EQ(p, *target); - - ASSERT_TRUE(source.ok()); - EXPECT_OK(source.status()); - EXPECT_EQ(nullptr, *source); - } -} - -TEST(StatusOr, TestAssignmentStatusNotOk) { - // Copy assignment - { - const absl::Status expected = absl::CancelledError(); - absl::StatusOr<int> source(expected); - - absl::StatusOr<int> target; - target = source; - - EXPECT_FALSE(target.ok()); - EXPECT_EQ(expected, target.status()); - - EXPECT_FALSE(source.ok()); - EXPECT_EQ(expected, source.status()); - } - - // Move assignment - { - const absl::Status expected = absl::CancelledError(); - absl::StatusOr<int> source(expected); - - absl::StatusOr<int> target; - target = std::move(source); - - EXPECT_FALSE(target.ok()); - EXPECT_EQ(expected, target.status()); - - EXPECT_FALSE(source.ok()); - EXPECT_EQ(source.status().code(), absl::StatusCode::kInternal); - } -} - -TEST(StatusOr, TestAssignmentStatusOKConverting) { - // Copy assignment - { - const int kI = 4; - absl::StatusOr<int> source(kI); - - absl::StatusOr<double> target; - target = source; - - ASSERT_TRUE(target.ok()); - EXPECT_OK(target.status()); - EXPECT_DOUBLE_EQ(kI, *target); - - ASSERT_TRUE(source.ok()); - EXPECT_OK(source.status()); - EXPECT_DOUBLE_EQ(kI, *source); - } - - // Move assignment - { - const auto p = new int(17); - absl::StatusOr<std::unique_ptr<int>> source(absl::WrapUnique(p)); - - absl::StatusOr<std::shared_ptr<int>> target; - target = std::move(source); - - ASSERT_TRUE(target.ok()); - EXPECT_OK(target.status()); - EXPECT_EQ(p, target->get()); - - ASSERT_TRUE(source.ok()); - EXPECT_OK(source.status()); - EXPECT_EQ(nullptr, source->get()); - } -} - -struct A { - int x; -}; - -struct ImplicitConstructibleFromA { - int x; - bool moved; - ImplicitConstructibleFromA(const A& a) // NOLINT - : x(a.x), moved(false) {} - ImplicitConstructibleFromA(A&& a) // NOLINT - : x(a.x), moved(true) {} -}; - -TEST(StatusOr, ImplicitConvertingConstructor) { - EXPECT_THAT( - absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromA>>( - absl::StatusOr<A>(A{11})), - IsOkAndHolds(AllOf(Field(&ImplicitConstructibleFromA::x, 11), - Field(&ImplicitConstructibleFromA::moved, true)))); - absl::StatusOr<A> a(A{12}); - EXPECT_THAT( - absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromA>>(a), - IsOkAndHolds(AllOf(Field(&ImplicitConstructibleFromA::x, 12), - Field(&ImplicitConstructibleFromA::moved, false)))); -} - -struct ExplicitConstructibleFromA { - int x; - bool moved; - explicit ExplicitConstructibleFromA(const A& a) : x(a.x), moved(false) {} - explicit ExplicitConstructibleFromA(A&& a) : x(a.x), moved(true) {} -}; - -TEST(StatusOr, ExplicitConvertingConstructor) { - EXPECT_FALSE( - (std::is_convertible<const absl::StatusOr<A>&, - absl::StatusOr<ExplicitConstructibleFromA>>::value)); - EXPECT_FALSE( - (std::is_convertible<absl::StatusOr<A>&&, - absl::StatusOr<ExplicitConstructibleFromA>>::value)); - EXPECT_THAT( - absl::StatusOr<ExplicitConstructibleFromA>(absl::StatusOr<A>(A{11})), - IsOkAndHolds(AllOf(Field(&ExplicitConstructibleFromA::x, 11), - Field(&ExplicitConstructibleFromA::moved, true)))); - absl::StatusOr<A> a(A{12}); - EXPECT_THAT( - absl::StatusOr<ExplicitConstructibleFromA>(a), - IsOkAndHolds(AllOf(Field(&ExplicitConstructibleFromA::x, 12), - Field(&ExplicitConstructibleFromA::moved, false)))); -} - -struct ImplicitConstructibleFromBool { - ImplicitConstructibleFromBool(bool y) : x(y) {} // NOLINT - bool x = false; -}; - -struct ConvertibleToBool { - explicit ConvertibleToBool(bool y) : x(y) {} - operator bool() const { return x; } // NOLINT - bool x = false; -}; - -TEST(StatusOr, ImplicitBooleanConstructionWithImplicitCasts) { - EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(true)), - IsOkAndHolds(true)); - EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(false)), - IsOkAndHolds(false)); - EXPECT_THAT( - absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromBool>>( - absl::StatusOr<bool>(false)), - IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false))); - EXPECT_FALSE((std::is_convertible< - absl::StatusOr<ConvertibleToBool>, - absl::StatusOr<ImplicitConstructibleFromBool>>::value)); -} - -TEST(StatusOr, BooleanConstructionWithImplicitCasts) { - EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(true)), - IsOkAndHolds(true)); - EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(false)), - IsOkAndHolds(false)); - EXPECT_THAT( - absl::StatusOr<ImplicitConstructibleFromBool>{ - absl::StatusOr<bool>(false)}, - IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false))); - EXPECT_THAT( - absl::StatusOr<ImplicitConstructibleFromBool>{ - absl::StatusOr<bool>(absl::InvalidArgumentError(""))}, - Not(IsOk())); - - EXPECT_THAT( - absl::StatusOr<ImplicitConstructibleFromBool>{ - absl::StatusOr<ConvertibleToBool>(ConvertibleToBool{false})}, - IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false))); - EXPECT_THAT( - absl::StatusOr<ImplicitConstructibleFromBool>{ - absl::StatusOr<ConvertibleToBool>(absl::InvalidArgumentError(""))}, - Not(IsOk())); -} - -TEST(StatusOr, ConstImplicitCast) { - EXPECT_THAT(absl::implicit_cast<absl::StatusOr<bool>>( - absl::StatusOr<const bool>(true)), - IsOkAndHolds(true)); - EXPECT_THAT(absl::implicit_cast<absl::StatusOr<bool>>( - absl::StatusOr<const bool>(false)), - IsOkAndHolds(false)); - EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const bool>>( - absl::StatusOr<bool>(true)), - IsOkAndHolds(true)); - EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const bool>>( - absl::StatusOr<bool>(false)), - IsOkAndHolds(false)); - EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const std::string>>( - absl::StatusOr<std::string>("foo")), - IsOkAndHolds("foo")); - EXPECT_THAT(absl::implicit_cast<absl::StatusOr<std::string>>( - absl::StatusOr<const std::string>("foo")), - IsOkAndHolds("foo")); - EXPECT_THAT( - absl::implicit_cast<absl::StatusOr<std::shared_ptr<const std::string>>>( - absl::StatusOr<std::shared_ptr<std::string>>( - std::make_shared<std::string>("foo"))), - IsOkAndHolds(Pointee(std::string("foo")))); -} - -TEST(StatusOr, ConstExplicitConstruction) { - EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<const bool>(true)), - IsOkAndHolds(true)); - EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<const bool>(false)), - IsOkAndHolds(false)); - EXPECT_THAT(absl::StatusOr<const bool>(absl::StatusOr<bool>(true)), - IsOkAndHolds(true)); - EXPECT_THAT(absl::StatusOr<const bool>(absl::StatusOr<bool>(false)), - IsOkAndHolds(false)); -} - -struct ExplicitConstructibleFromInt { - int x; - explicit ExplicitConstructibleFromInt(int y) : x(y) {} -}; - -TEST(StatusOr, ExplicitConstruction) { - EXPECT_THAT(absl::StatusOr<ExplicitConstructibleFromInt>(10), - IsOkAndHolds(Field(&ExplicitConstructibleFromInt::x, 10))); -} - -TEST(StatusOr, ImplicitConstruction) { - // Check implicit casting works. - auto status_or = - absl::implicit_cast<absl::StatusOr<absl::variant<int, std::string>>>(10); - EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10))); -} - -TEST(StatusOr, ImplicitConstructionFromInitliazerList) { - // Note: dropping the explicit std::initializer_list<int> is not supported - // by absl::StatusOr or absl::optional. - auto status_or = - absl::implicit_cast<absl::StatusOr<std::vector<int>>>({{10, 20, 30}}); - EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30))); -} - -TEST(StatusOr, UniquePtrImplicitConstruction) { - auto status_or = absl::implicit_cast<absl::StatusOr<std::unique_ptr<Base1>>>( - absl::make_unique<Derived>()); - EXPECT_THAT(status_or, IsOkAndHolds(Ne(nullptr))); -} - -TEST(StatusOr, NestedStatusOrCopyAndMoveConstructorTests) { - absl::StatusOr<absl::StatusOr<CopyDetector>> status_or = CopyDetector(10); - absl::StatusOr<absl::StatusOr<CopyDetector>> status_error = - absl::InvalidArgumentError("foo"); - EXPECT_THAT(status_or, - IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false)))); - absl::StatusOr<absl::StatusOr<CopyDetector>> a = status_or; - EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true)))); - absl::StatusOr<absl::StatusOr<CopyDetector>> a_err = status_error; - EXPECT_THAT(a_err, Not(IsOk())); - - const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref = status_or; - absl::StatusOr<absl::StatusOr<CopyDetector>> b = cref; // NOLINT - EXPECT_THAT(b, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true)))); - const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref_err = status_error; - absl::StatusOr<absl::StatusOr<CopyDetector>> b_err = cref_err; // NOLINT - EXPECT_THAT(b_err, Not(IsOk())); - - absl::StatusOr<absl::StatusOr<CopyDetector>> c = std::move(status_or); - EXPECT_THAT(c, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false)))); - absl::StatusOr<absl::StatusOr<CopyDetector>> c_err = std::move(status_error); - EXPECT_THAT(c_err, Not(IsOk())); -} - -TEST(StatusOr, NestedStatusOrCopyAndMoveAssignment) { - absl::StatusOr<absl::StatusOr<CopyDetector>> status_or = CopyDetector(10); - absl::StatusOr<absl::StatusOr<CopyDetector>> status_error = - absl::InvalidArgumentError("foo"); - absl::StatusOr<absl::StatusOr<CopyDetector>> a; - a = status_or; - EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true)))); - a = status_error; - EXPECT_THAT(a, Not(IsOk())); - - const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref = status_or; - a = cref; - EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true)))); - const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref_err = status_error; - a = cref_err; - EXPECT_THAT(a, Not(IsOk())); - a = std::move(status_or); - EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false)))); - a = std::move(status_error); - EXPECT_THAT(a, Not(IsOk())); -} - -struct Copyable { - Copyable() {} - Copyable(const Copyable&) {} - Copyable& operator=(const Copyable&) { return *this; } -}; - -struct MoveOnly { - MoveOnly() {} - MoveOnly(MoveOnly&&) {} - MoveOnly& operator=(MoveOnly&&) { return *this; } -}; - -struct NonMovable { - NonMovable() {} - NonMovable(const NonMovable&) = delete; - NonMovable(NonMovable&&) = delete; - NonMovable& operator=(const NonMovable&) = delete; - NonMovable& operator=(NonMovable&&) = delete; -}; - -TEST(StatusOr, CopyAndMoveAbility) { - EXPECT_TRUE(std::is_copy_constructible<Copyable>::value); - EXPECT_TRUE(std::is_copy_assignable<Copyable>::value); - EXPECT_TRUE(std::is_move_constructible<Copyable>::value); - EXPECT_TRUE(std::is_move_assignable<Copyable>::value); - EXPECT_FALSE(std::is_copy_constructible<MoveOnly>::value); - EXPECT_FALSE(std::is_copy_assignable<MoveOnly>::value); - EXPECT_TRUE(std::is_move_constructible<MoveOnly>::value); - EXPECT_TRUE(std::is_move_assignable<MoveOnly>::value); - EXPECT_FALSE(std::is_copy_constructible<NonMovable>::value); - EXPECT_FALSE(std::is_copy_assignable<NonMovable>::value); - EXPECT_FALSE(std::is_move_constructible<NonMovable>::value); - EXPECT_FALSE(std::is_move_assignable<NonMovable>::value); -} - -TEST(StatusOr, StatusOrAnyCopyAndMoveConstructorTests) { - absl::StatusOr<absl::any> status_or = CopyDetector(10); - absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo"); - EXPECT_THAT( - status_or, - IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false)))); - absl::StatusOr<absl::any> a = status_or; - EXPECT_THAT( - a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true)))); - absl::StatusOr<absl::any> a_err = status_error; - EXPECT_THAT(a_err, Not(IsOk())); - - const absl::StatusOr<absl::any>& cref = status_or; - // No lint for no-change copy. - absl::StatusOr<absl::any> b = cref; // NOLINT - EXPECT_THAT( - b, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true)))); - const absl::StatusOr<absl::any>& cref_err = status_error; - // No lint for no-change copy. - absl::StatusOr<absl::any> b_err = cref_err; // NOLINT - EXPECT_THAT(b_err, Not(IsOk())); - - absl::StatusOr<absl::any> c = std::move(status_or); - EXPECT_THAT( - c, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false)))); - absl::StatusOr<absl::any> c_err = std::move(status_error); - EXPECT_THAT(c_err, Not(IsOk())); -} - -TEST(StatusOr, StatusOrAnyCopyAndMoveAssignment) { - absl::StatusOr<absl::any> status_or = CopyDetector(10); - absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo"); - absl::StatusOr<absl::any> a; - a = status_or; - EXPECT_THAT( - a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true)))); - a = status_error; - EXPECT_THAT(a, Not(IsOk())); - - const absl::StatusOr<absl::any>& cref = status_or; - a = cref; - EXPECT_THAT( - a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true)))); - const absl::StatusOr<absl::any>& cref_err = status_error; - a = cref_err; - EXPECT_THAT(a, Not(IsOk())); - a = std::move(status_or); - EXPECT_THAT( - a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false)))); - a = std::move(status_error); - EXPECT_THAT(a, Not(IsOk())); -} - -TEST(StatusOr, StatusOrCopyAndMoveTestsConstructor) { - absl::StatusOr<CopyDetector> status_or(10); - ASSERT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(10, false, false))); - absl::StatusOr<CopyDetector> a(status_or); - EXPECT_THAT(a, IsOkAndHolds(CopyDetectorHas(10, false, true))); - const absl::StatusOr<CopyDetector>& cref = status_or; - absl::StatusOr<CopyDetector> b(cref); // NOLINT - EXPECT_THAT(b, IsOkAndHolds(CopyDetectorHas(10, false, true))); - absl::StatusOr<CopyDetector> c(std::move(status_or)); - EXPECT_THAT(c, IsOkAndHolds(CopyDetectorHas(10, true, false))); -} - -TEST(StatusOr, StatusOrCopyAndMoveTestsAssignment) { - absl::StatusOr<CopyDetector> status_or(10); - ASSERT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(10, false, false))); - absl::StatusOr<CopyDetector> a; - a = status_or; - EXPECT_THAT(a, IsOkAndHolds(CopyDetectorHas(10, false, true))); - const absl::StatusOr<CopyDetector>& cref = status_or; - absl::StatusOr<CopyDetector> b; - b = cref; - EXPECT_THAT(b, IsOkAndHolds(CopyDetectorHas(10, false, true))); - absl::StatusOr<CopyDetector> c; - c = std::move(status_or); - EXPECT_THAT(c, IsOkAndHolds(CopyDetectorHas(10, true, false))); -} - -TEST(StatusOr, AbslAnyAssignment) { - EXPECT_FALSE((std::is_assignable<absl::StatusOr<absl::any>, - absl::StatusOr<int>>::value)); - absl::StatusOr<absl::any> status_or; - status_or = absl::InvalidArgumentError("foo"); - EXPECT_THAT(status_or, Not(IsOk())); -} - -TEST(StatusOr, ImplicitAssignment) { - absl::StatusOr<absl::variant<int, std::string>> status_or; - status_or = 10; - EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10))); -} - -TEST(StatusOr, SelfDirectInitAssignment) { - absl::StatusOr<std::vector<int>> status_or = {{10, 20, 30}}; - status_or = *status_or; - EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30))); -} - -TEST(StatusOr, ImplicitCastFromInitializerList) { - absl::StatusOr<std::vector<int>> status_or = {{10, 20, 30}}; - EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30))); -} - -TEST(StatusOr, UniquePtrImplicitAssignment) { - absl::StatusOr<std::unique_ptr<Base1>> status_or; - status_or = absl::make_unique<Derived>(); - EXPECT_THAT(status_or, IsOkAndHolds(Ne(nullptr))); -} - -TEST(StatusOr, Pointer) { - struct A {}; - struct B : public A {}; - struct C : private A {}; - - EXPECT_TRUE((std::is_constructible<absl::StatusOr<A*>, B*>::value)); - EXPECT_TRUE((std::is_convertible<B*, absl::StatusOr<A*>>::value)); - EXPECT_FALSE((std::is_constructible<absl::StatusOr<A*>, C*>::value)); - EXPECT_FALSE((std::is_convertible<C*, absl::StatusOr<A*>>::value)); -} - -TEST(StatusOr, TestAssignmentStatusNotOkConverting) { - // Copy assignment - { - const absl::Status expected = absl::CancelledError(); - absl::StatusOr<int> source(expected); - - absl::StatusOr<double> target; - target = source; - - EXPECT_FALSE(target.ok()); - EXPECT_EQ(expected, target.status()); - - EXPECT_FALSE(source.ok()); - EXPECT_EQ(expected, source.status()); - } - - // Move assignment - { - const absl::Status expected = absl::CancelledError(); - absl::StatusOr<int> source(expected); - - absl::StatusOr<double> target; - target = std::move(source); - - EXPECT_FALSE(target.ok()); - EXPECT_EQ(expected, target.status()); - - EXPECT_FALSE(source.ok()); - EXPECT_EQ(source.status().code(), absl::StatusCode::kInternal); - } -} - -TEST(StatusOr, SelfAssignment) { - // Copy-assignment, status OK - { - // A string long enough that it's likely to defeat any inline representation - // optimization. - const std::string long_str(128, 'a'); - - absl::StatusOr<std::string> so = long_str; - so = *&so; - - ASSERT_TRUE(so.ok()); - EXPECT_OK(so.status()); - EXPECT_EQ(long_str, *so); - } - - // Copy-assignment, error status - { - absl::StatusOr<int> so = absl::NotFoundError("taco"); - so = *&so; - - EXPECT_FALSE(so.ok()); - EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound); - EXPECT_EQ(so.status().message(), "taco"); - } - - // Move-assignment with copyable type, status OK - { - absl::StatusOr<int> so = 17; - - // Fool the compiler, which otherwise complains. - auto& same = so; - so = std::move(same); - - ASSERT_TRUE(so.ok()); - EXPECT_OK(so.status()); - EXPECT_EQ(17, *so); - } - - // Move-assignment with copyable type, error status - { - absl::StatusOr<int> so = absl::NotFoundError("taco"); - - // Fool the compiler, which otherwise complains. - auto& same = so; - so = std::move(same); - - EXPECT_FALSE(so.ok()); - EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound); - EXPECT_EQ(so.status().message(), "taco"); - } - - // Move-assignment with non-copyable type, status OK - { - const auto raw = new int(17); - absl::StatusOr<std::unique_ptr<int>> so = absl::WrapUnique(raw); - - // Fool the compiler, which otherwise complains. - auto& same = so; - so = std::move(same); - - ASSERT_TRUE(so.ok()); - EXPECT_OK(so.status()); - EXPECT_EQ(raw, so->get()); - } - - // Move-assignment with non-copyable type, error status - { - absl::StatusOr<std::unique_ptr<int>> so = absl::NotFoundError("taco"); - - // Fool the compiler, which otherwise complains. - auto& same = so; - so = std::move(same); - - EXPECT_FALSE(so.ok()); - EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound); - EXPECT_EQ(so.status().message(), "taco"); - } -} - -// These types form the overload sets of the constructors and the assignment -// operators of `MockValue`. They distinguish construction from assignment, -// lvalue from rvalue. -struct FromConstructibleAssignableLvalue {}; -struct FromConstructibleAssignableRvalue {}; -struct FromImplicitConstructibleOnly {}; -struct FromAssignableOnly {}; - -// This class is for testing the forwarding value assignments of `StatusOr`. -// `from_rvalue` indicates whether the constructor or the assignment taking -// rvalue reference is called. `from_assignment` indicates whether any -// assignment is called. -struct MockValue { - // Constructs `MockValue` from `FromConstructibleAssignableLvalue`. - MockValue(const FromConstructibleAssignableLvalue&) // NOLINT - : from_rvalue(false), assigned(false) {} - // Constructs `MockValue` from `FromConstructibleAssignableRvalue`. - MockValue(FromConstructibleAssignableRvalue&&) // NOLINT - : from_rvalue(true), assigned(false) {} - // Constructs `MockValue` from `FromImplicitConstructibleOnly`. - // `MockValue` is not assignable from `FromImplicitConstructibleOnly`. - MockValue(const FromImplicitConstructibleOnly&) // NOLINT - : from_rvalue(false), assigned(false) {} - // Assigns `FromConstructibleAssignableLvalue`. - MockValue& operator=(const FromConstructibleAssignableLvalue&) { - from_rvalue = false; - assigned = true; - return *this; - } - // Assigns `FromConstructibleAssignableRvalue` (rvalue only). - MockValue& operator=(FromConstructibleAssignableRvalue&&) { - from_rvalue = true; - assigned = true; - return *this; - } - // Assigns `FromAssignableOnly`, but not constructible from - // `FromAssignableOnly`. - MockValue& operator=(const FromAssignableOnly&) { - from_rvalue = false; - assigned = true; - return *this; - } - bool from_rvalue; - bool assigned; -}; - -// operator=(U&&) -TEST(StatusOr, PerfectForwardingAssignment) { - // U == T - constexpr int kValue1 = 10, kValue2 = 20; - absl::StatusOr<CopyDetector> status_or; - CopyDetector lvalue(kValue1); - status_or = lvalue; - EXPECT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(kValue1, false, true))); - status_or = CopyDetector(kValue2); - EXPECT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(kValue2, true, false))); - - // U != T - EXPECT_TRUE( - (std::is_assignable<absl::StatusOr<MockValue>&, - const FromConstructibleAssignableLvalue&>::value)); - EXPECT_TRUE((std::is_assignable<absl::StatusOr<MockValue>&, - FromConstructibleAssignableLvalue&&>::value)); - EXPECT_FALSE( - (std::is_assignable<absl::StatusOr<MockValue>&, - const FromConstructibleAssignableRvalue&>::value)); - EXPECT_TRUE((std::is_assignable<absl::StatusOr<MockValue>&, - FromConstructibleAssignableRvalue&&>::value)); - EXPECT_TRUE( - (std::is_assignable<absl::StatusOr<MockValue>&, - const FromImplicitConstructibleOnly&>::value)); - EXPECT_FALSE((std::is_assignable<absl::StatusOr<MockValue>&, - const FromAssignableOnly&>::value)); - - absl::StatusOr<MockValue> from_lvalue(FromConstructibleAssignableLvalue{}); - EXPECT_FALSE(from_lvalue->from_rvalue); - EXPECT_FALSE(from_lvalue->assigned); - from_lvalue = FromConstructibleAssignableLvalue{}; - EXPECT_FALSE(from_lvalue->from_rvalue); - EXPECT_TRUE(from_lvalue->assigned); - - absl::StatusOr<MockValue> from_rvalue(FromConstructibleAssignableRvalue{}); - EXPECT_TRUE(from_rvalue->from_rvalue); - EXPECT_FALSE(from_rvalue->assigned); - from_rvalue = FromConstructibleAssignableRvalue{}; - EXPECT_TRUE(from_rvalue->from_rvalue); - EXPECT_TRUE(from_rvalue->assigned); - - absl::StatusOr<MockValue> from_implicit_constructible( - FromImplicitConstructibleOnly{}); - EXPECT_FALSE(from_implicit_constructible->from_rvalue); - EXPECT_FALSE(from_implicit_constructible->assigned); - // construct a temporary `StatusOr` object and invoke the `StatusOr` move - // assignment operator. - from_implicit_constructible = FromImplicitConstructibleOnly{}; - EXPECT_FALSE(from_implicit_constructible->from_rvalue); - EXPECT_FALSE(from_implicit_constructible->assigned); -} - -TEST(StatusOr, TestStatus) { - absl::StatusOr<int> good(4); - EXPECT_TRUE(good.ok()); - absl::StatusOr<int> bad(absl::CancelledError()); - EXPECT_FALSE(bad.ok()); - EXPECT_EQ(bad.status().code(), absl::StatusCode::kCancelled); -} - -TEST(StatusOr, OperatorStarRefQualifiers) { - static_assert( - std::is_same<const int&, - decltype(*std::declval<const absl::StatusOr<int>&>())>(), - "Unexpected ref-qualifiers"); - static_assert( - std::is_same<int&, decltype(*std::declval<absl::StatusOr<int>&>())>(), - "Unexpected ref-qualifiers"); - static_assert( - std::is_same<const int&&, - decltype(*std::declval<const absl::StatusOr<int>&&>())>(), - "Unexpected ref-qualifiers"); - static_assert( - std::is_same<int&&, decltype(*std::declval<absl::StatusOr<int>&&>())>(), - "Unexpected ref-qualifiers"); -} - -TEST(StatusOr, OperatorStar) { - const absl::StatusOr<std::string> const_lvalue("hello"); - EXPECT_EQ("hello", *const_lvalue); - - absl::StatusOr<std::string> lvalue("hello"); - EXPECT_EQ("hello", *lvalue); - - // Note: Recall that std::move() is equivalent to a static_cast to an rvalue - // reference type. - const absl::StatusOr<std::string> const_rvalue("hello"); - EXPECT_EQ("hello", *std::move(const_rvalue)); // NOLINT - - absl::StatusOr<std::string> rvalue("hello"); - EXPECT_EQ("hello", *std::move(rvalue)); -} - -TEST(StatusOr, OperatorArrowQualifiers) { - static_assert( - std::is_same< - const int*, - decltype(std::declval<const absl::StatusOr<int>&>().operator->())>(), - "Unexpected qualifiers"); - static_assert( - std::is_same< - int*, decltype(std::declval<absl::StatusOr<int>&>().operator->())>(), - "Unexpected qualifiers"); - static_assert( - std::is_same< - const int*, - decltype(std::declval<const absl::StatusOr<int>&&>().operator->())>(), - "Unexpected qualifiers"); - static_assert( - std::is_same< - int*, decltype(std::declval<absl::StatusOr<int>&&>().operator->())>(), - "Unexpected qualifiers"); -} - -TEST(StatusOr, OperatorArrow) { - const absl::StatusOr<std::string> const_lvalue("hello"); - EXPECT_EQ(std::string("hello"), const_lvalue->c_str()); - - absl::StatusOr<std::string> lvalue("hello"); - EXPECT_EQ(std::string("hello"), lvalue->c_str()); -} - -TEST(StatusOr, RValueStatus) { - absl::StatusOr<int> so(absl::NotFoundError("taco")); - const absl::Status s = std::move(so).status(); - - EXPECT_EQ(s.code(), absl::StatusCode::kNotFound); - EXPECT_EQ(s.message(), "taco"); - - // Check that !ok() still implies !status().ok(), even after moving out of the - // object. See the note on the rvalue ref-qualified status method. - EXPECT_FALSE(so.ok()); // NOLINT - EXPECT_FALSE(so.status().ok()); - EXPECT_EQ(so.status().code(), absl::StatusCode::kInternal); - EXPECT_EQ(so.status().message(), "Status accessed after move."); -} - -TEST(StatusOr, TestValue) { - const int kI = 4; - absl::StatusOr<int> thing(kI); - EXPECT_EQ(kI, *thing); -} - -TEST(StatusOr, TestValueConst) { - const int kI = 4; - const absl::StatusOr<int> thing(kI); - EXPECT_EQ(kI, *thing); -} - -TEST(StatusOr, TestPointerDefaultCtor) { - absl::StatusOr<int*> thing; - EXPECT_FALSE(thing.ok()); - EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown); -} - -TEST(StatusOr, TestPointerStatusCtor) { - absl::StatusOr<int*> thing(absl::CancelledError()); - EXPECT_FALSE(thing.ok()); - EXPECT_EQ(thing.status().code(), absl::StatusCode::kCancelled); -} - -TEST(StatusOr, TestPointerValueCtor) { - const int kI = 4; - - // Construction from a non-null pointer - { - absl::StatusOr<const int*> so(&kI); - EXPECT_TRUE(so.ok()); - EXPECT_OK(so.status()); - EXPECT_EQ(&kI, *so); - } - - // Construction from a null pointer constant - { - absl::StatusOr<const int*> so(nullptr); - EXPECT_TRUE(so.ok()); - EXPECT_OK(so.status()); - EXPECT_EQ(nullptr, *so); - } - - // Construction from a non-literal null pointer - { - const int* const p = nullptr; - - absl::StatusOr<const int*> so(p); - EXPECT_TRUE(so.ok()); - EXPECT_OK(so.status()); - EXPECT_EQ(nullptr, *so); - } -} - -TEST(StatusOr, TestPointerCopyCtorStatusOk) { - const int kI = 0; - absl::StatusOr<const int*> original(&kI); - absl::StatusOr<const int*> copy(original); - EXPECT_OK(copy.status()); - EXPECT_EQ(*original, *copy); -} - -TEST(StatusOr, TestPointerCopyCtorStatusNotOk) { - absl::StatusOr<int*> original(absl::CancelledError()); - absl::StatusOr<int*> copy(original); - EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled); -} - -TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) { - Derived derived; - absl::StatusOr<Derived*> original(&derived); - absl::StatusOr<Base2*> copy(original); - EXPECT_OK(copy.status()); - EXPECT_EQ(static_cast<const Base2*>(*original), *copy); -} - -TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) { - absl::StatusOr<Derived*> original(absl::CancelledError()); - absl::StatusOr<Base2*> copy(original); - EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled); -} - -TEST(StatusOr, TestPointerAssignmentStatusOk) { - const int kI = 0; - absl::StatusOr<const int*> source(&kI); - absl::StatusOr<const int*> target; - target = source; - EXPECT_OK(target.status()); - EXPECT_EQ(*source, *target); -} - -TEST(StatusOr, TestPointerAssignmentStatusNotOk) { - absl::StatusOr<int*> source(absl::CancelledError()); - absl::StatusOr<int*> target; - target = source; - EXPECT_EQ(target.status().code(), absl::StatusCode::kCancelled); -} - -TEST(StatusOr, TestPointerAssignmentStatusOKConverting) { - Derived derived; - absl::StatusOr<Derived*> source(&derived); - absl::StatusOr<Base2*> target; - target = source; - EXPECT_OK(target.status()); - EXPECT_EQ(static_cast<const Base2*>(*source), *target); -} - -TEST(StatusOr, TestPointerAssignmentStatusNotOkConverting) { - absl::StatusOr<Derived*> source(absl::CancelledError()); - absl::StatusOr<Base2*> target; - target = source; - EXPECT_EQ(target.status(), source.status()); -} - -TEST(StatusOr, TestPointerStatus) { - const int kI = 0; - absl::StatusOr<const int*> good(&kI); - EXPECT_TRUE(good.ok()); - absl::StatusOr<const int*> bad(absl::CancelledError()); - EXPECT_EQ(bad.status().code(), absl::StatusCode::kCancelled); -} - -TEST(StatusOr, TestPointerValue) { - const int kI = 0; - absl::StatusOr<const int*> thing(&kI); - EXPECT_EQ(&kI, *thing); -} - -TEST(StatusOr, TestPointerValueConst) { - const int kI = 0; - const absl::StatusOr<const int*> thing(&kI); - EXPECT_EQ(&kI, *thing); -} - -TEST(StatusOr, StatusOrVectorOfUniquePointerCanReserveAndResize) { - using EvilType = std::vector<std::unique_ptr<int>>; - static_assert(std::is_copy_constructible<EvilType>::value, ""); - std::vector<::absl::StatusOr<EvilType>> v(5); - v.reserve(v.capacity() + 10); - v.resize(v.capacity() + 10); -} - -TEST(StatusOr, ConstPayload) { - // A reduced version of a problematic type found in the wild. All of the - // operations below should compile. - absl::StatusOr<const int> a; - - // Copy-construction - absl::StatusOr<const int> b(a); - - // Copy-assignment - EXPECT_FALSE(std::is_copy_assignable<absl::StatusOr<const int>>::value); - - // Move-construction - absl::StatusOr<const int> c(std::move(a)); - - // Move-assignment - EXPECT_FALSE(std::is_move_assignable<absl::StatusOr<const int>>::value); -} - -TEST(StatusOr, MapToStatusOrUniquePtr) { - // A reduced version of a problematic type found in the wild. All of the - // operations below should compile. - using MapType = std::map<std::string, absl::StatusOr<std::unique_ptr<int>>>; - - MapType a; - - // Move-construction - MapType b(std::move(a)); - - // Move-assignment - a = std::move(b); -} - -TEST(StatusOr, ValueOrOk) { - const absl::StatusOr<int> status_or = 0; - EXPECT_EQ(status_or.value_or(-1), 0); -} - -TEST(StatusOr, ValueOrDefault) { - const absl::StatusOr<int> status_or = absl::CancelledError(); - EXPECT_EQ(status_or.value_or(-1), -1); -} - -TEST(StatusOr, MoveOnlyValueOrOk) { - EXPECT_THAT(absl::StatusOr<std::unique_ptr<int>>(absl::make_unique<int>(0)) - .value_or(absl::make_unique<int>(-1)), - Pointee(0)); -} - -TEST(StatusOr, MoveOnlyValueOrDefault) { - EXPECT_THAT(absl::StatusOr<std::unique_ptr<int>>(absl::CancelledError()) - .value_or(absl::make_unique<int>(-1)), - Pointee(-1)); -} - -static absl::StatusOr<int> MakeStatus() { return 100; } - -TEST(StatusOr, TestIgnoreError) { MakeStatus().IgnoreError(); } - -TEST(StatusOr, EqualityOperator) { - constexpr int kNumCases = 4; - std::array<absl::StatusOr<int>, kNumCases> group1 = { - absl::StatusOr<int>(1), absl::StatusOr<int>(2), - absl::StatusOr<int>(absl::InvalidArgumentError("msg")), - absl::StatusOr<int>(absl::InternalError("msg"))}; - std::array<absl::StatusOr<int>, kNumCases> group2 = { - absl::StatusOr<int>(1), absl::StatusOr<int>(2), - absl::StatusOr<int>(absl::InvalidArgumentError("msg")), - absl::StatusOr<int>(absl::InternalError("msg"))}; - for (int i = 0; i < kNumCases; ++i) { - for (int j = 0; j < kNumCases; ++j) { - if (i == j) { - EXPECT_TRUE(group1[i] == group2[j]); - EXPECT_FALSE(group1[i] != group2[j]); - } else { - EXPECT_FALSE(group1[i] == group2[j]); - EXPECT_TRUE(group1[i] != group2[j]); - } - } - } -} - -struct MyType { - bool operator==(const MyType&) const { return true; } -}; - -enum class ConvTraits { kNone = 0, kImplicit = 1, kExplicit = 2 }; - -// This class has conversion operator to `StatusOr<T>` based on value of -// `conv_traits`. -template <typename T, ConvTraits conv_traits = ConvTraits::kNone> -struct StatusOrConversionBase {}; - -template <typename T> -struct StatusOrConversionBase<T, ConvTraits::kImplicit> { - operator absl::StatusOr<T>() const& { // NOLINT - return absl::InvalidArgumentError("conversion to absl::StatusOr"); - } - operator absl::StatusOr<T>() && { // NOLINT - return absl::InvalidArgumentError("conversion to absl::StatusOr"); - } -}; - -template <typename T> -struct StatusOrConversionBase<T, ConvTraits::kExplicit> { - explicit operator absl::StatusOr<T>() const& { - return absl::InvalidArgumentError("conversion to absl::StatusOr"); - } - explicit operator absl::StatusOr<T>() && { - return absl::InvalidArgumentError("conversion to absl::StatusOr"); - } -}; - -// This class has conversion operator to `T` based on the value of -// `conv_traits`. -template <typename T, ConvTraits conv_traits = ConvTraits::kNone> -struct ConversionBase {}; - -template <typename T> -struct ConversionBase<T, ConvTraits::kImplicit> { - operator T() const& { return t; } // NOLINT - operator T() && { return std::move(t); } // NOLINT - T t; -}; - -template <typename T> -struct ConversionBase<T, ConvTraits::kExplicit> { - explicit operator T() const& { return t; } - explicit operator T() && { return std::move(t); } - T t; -}; - -// This class has conversion operator to `absl::Status` based on the value of -// `conv_traits`. -template <ConvTraits conv_traits = ConvTraits::kNone> -struct StatusConversionBase {}; - -template <> -struct StatusConversionBase<ConvTraits::kImplicit> { - operator absl::Status() const& { // NOLINT - return absl::InternalError("conversion to Status"); - } - operator absl::Status() && { // NOLINT - return absl::InternalError("conversion to Status"); - } -}; - -template <> -struct StatusConversionBase<ConvTraits::kExplicit> { - explicit operator absl::Status() const& { // NOLINT - return absl::InternalError("conversion to Status"); - } - explicit operator absl::Status() && { // NOLINT - return absl::InternalError("conversion to Status"); - } -}; - -static constexpr int kConvToStatus = 1; -static constexpr int kConvToStatusOr = 2; -static constexpr int kConvToT = 4; -static constexpr int kConvExplicit = 8; - -constexpr ConvTraits GetConvTraits(int bit, int config) { - return (config & bit) == 0 - ? ConvTraits::kNone - : ((config & kConvExplicit) == 0 ? ConvTraits::kImplicit - : ConvTraits::kExplicit); -} - -// This class conditionally has conversion operator to `absl::Status`, `T`, -// `StatusOr<T>`, based on values of the template parameters. -template <typename T, int config> -struct CustomType - : StatusOrConversionBase<T, GetConvTraits(kConvToStatusOr, config)>, - ConversionBase<T, GetConvTraits(kConvToT, config)>, - StatusConversionBase<GetConvTraits(kConvToStatus, config)> {}; - -struct ConvertibleToAnyStatusOr { - template <typename T> - operator absl::StatusOr<T>() const { // NOLINT - return absl::InvalidArgumentError("Conversion to absl::StatusOr"); - } -}; - -// Test the rank of overload resolution for `StatusOr<T>` constructor and -// assignment, from highest to lowest: -// 1. T/Status -// 2. U that has conversion operator to absl::StatusOr<T> -// 3. U that is convertible to Status -// 4. U that is convertible to T -TEST(StatusOr, ConstructionFromT) { - // Construct absl::StatusOr<T> from T when T is convertible to - // absl::StatusOr<T> - { - ConvertibleToAnyStatusOr v; - absl::StatusOr<ConvertibleToAnyStatusOr> statusor(v); - EXPECT_TRUE(statusor.ok()); - } - { - ConvertibleToAnyStatusOr v; - absl::StatusOr<ConvertibleToAnyStatusOr> statusor = v; - EXPECT_TRUE(statusor.ok()); - } - // Construct absl::StatusOr<T> from T when T is explicitly convertible to - // Status - { - CustomType<MyType, kConvToStatus | kConvExplicit> v; - absl::StatusOr<CustomType<MyType, kConvToStatus | kConvExplicit>> statusor( - v); - EXPECT_TRUE(statusor.ok()); - } - { - CustomType<MyType, kConvToStatus | kConvExplicit> v; - absl::StatusOr<CustomType<MyType, kConvToStatus | kConvExplicit>> statusor = - v; - EXPECT_TRUE(statusor.ok()); - } -} - -// Construct absl::StatusOr<T> from U when U is explicitly convertible to T -TEST(StatusOr, ConstructionFromTypeConvertibleToT) { - { - CustomType<MyType, kConvToT | kConvExplicit> v; - absl::StatusOr<MyType> statusor(v); - EXPECT_TRUE(statusor.ok()); - } - { - CustomType<MyType, kConvToT> v; - absl::StatusOr<MyType> statusor = v; - EXPECT_TRUE(statusor.ok()); - } -} - -// Construct absl::StatusOr<T> from U when U has explicit conversion operator to -// absl::StatusOr<T> -TEST(StatusOr, ConstructionFromTypeWithConversionOperatorToStatusOrT) { - { - CustomType<MyType, kConvToStatusOr | kConvExplicit> v; - absl::StatusOr<MyType> statusor(v); - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToT | kConvToStatusOr | kConvExplicit> v; - absl::StatusOr<MyType> statusor(v); - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToStatusOr | kConvToStatus | kConvExplicit> v; - absl::StatusOr<MyType> statusor(v); - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, - kConvToT | kConvToStatusOr | kConvToStatus | kConvExplicit> - v; - absl::StatusOr<MyType> statusor(v); - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToStatusOr> v; - absl::StatusOr<MyType> statusor = v; - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToT | kConvToStatusOr> v; - absl::StatusOr<MyType> statusor = v; - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToStatusOr | kConvToStatus> v; - absl::StatusOr<MyType> statusor = v; - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToT | kConvToStatusOr | kConvToStatus> v; - absl::StatusOr<MyType> statusor = v; - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } -} - -TEST(StatusOr, ConstructionFromTypeConvertibleToStatus) { - // Construction fails because conversion to `Status` is explicit. - { - CustomType<MyType, kConvToStatus | kConvExplicit> v; - absl::StatusOr<MyType> statusor(v); - EXPECT_FALSE(statusor.ok()); - EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v)); - } - { - CustomType<MyType, kConvToT | kConvToStatus | kConvExplicit> v; - absl::StatusOr<MyType> statusor(v); - EXPECT_FALSE(statusor.ok()); - EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v)); - } - { - CustomType<MyType, kConvToStatus> v; - absl::StatusOr<MyType> statusor = v; - EXPECT_FALSE(statusor.ok()); - EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v)); - } - { - CustomType<MyType, kConvToT | kConvToStatus> v; - absl::StatusOr<MyType> statusor = v; - EXPECT_FALSE(statusor.ok()); - EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v)); - } -} - -TEST(StatusOr, AssignmentFromT) { - // Assign to absl::StatusOr<T> from T when T is convertible to - // absl::StatusOr<T> - { - ConvertibleToAnyStatusOr v; - absl::StatusOr<ConvertibleToAnyStatusOr> statusor; - statusor = v; - EXPECT_TRUE(statusor.ok()); - } - // Assign to absl::StatusOr<T> from T when T is convertible to Status - { - CustomType<MyType, kConvToStatus> v; - absl::StatusOr<CustomType<MyType, kConvToStatus>> statusor; - statusor = v; - EXPECT_TRUE(statusor.ok()); - } -} - -TEST(StatusOr, AssignmentFromTypeConvertibleToT) { - // Assign to absl::StatusOr<T> from U when U is convertible to T - { - CustomType<MyType, kConvToT> v; - absl::StatusOr<MyType> statusor; - statusor = v; - EXPECT_TRUE(statusor.ok()); - } -} - -TEST(StatusOr, AssignmentFromTypeWithConversionOperatortoStatusOrT) { - // Assign to absl::StatusOr<T> from U when U has conversion operator to - // absl::StatusOr<T> - { - CustomType<MyType, kConvToStatusOr> v; - absl::StatusOr<MyType> statusor; - statusor = v; - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToT | kConvToStatusOr> v; - absl::StatusOr<MyType> statusor; - statusor = v; - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToStatusOr | kConvToStatus> v; - absl::StatusOr<MyType> statusor; - statusor = v; - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } - { - CustomType<MyType, kConvToT | kConvToStatusOr | kConvToStatus> v; - absl::StatusOr<MyType> statusor; - statusor = v; - EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>()); - } -} - -TEST(StatusOr, AssignmentFromTypeConvertibleToStatus) { - // Assign to absl::StatusOr<T> from U when U is convertible to Status - { - CustomType<MyType, kConvToStatus> v; - absl::StatusOr<MyType> statusor; - statusor = v; - EXPECT_FALSE(statusor.ok()); - EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v)); - } - { - CustomType<MyType, kConvToT | kConvToStatus> v; - absl::StatusOr<MyType> statusor; - statusor = v; - EXPECT_FALSE(statusor.ok()); - EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v)); - } -} - -} // namespace |