Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
|
|
@ -0,0 +1,252 @@
|
|||
// Copyright 2023 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/internal/status_internal.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/debugging/leak_check.h"
|
||||
#include "absl/debugging/stacktrace.h"
|
||||
#include "absl/debugging/symbolize.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/status_payload_printer.h"
|
||||
#include "absl/strings/cord.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace status_internal {
|
||||
|
||||
void StatusRep::Unref() const {
|
||||
// Fast path: if ref==1, there is no need for a RefCountDec (since
|
||||
// this is the only reference and therefore no other thread is
|
||||
// allowed to be mucking with r).
|
||||
if (ref_.load(std::memory_order_acquire) == 1 ||
|
||||
ref_.fetch_sub(1, std::memory_order_acq_rel) - 1 == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
static absl::optional<size_t> FindPayloadIndexByUrl(
|
||||
const Payloads* payloads, absl::string_view type_url) {
|
||||
if (payloads == nullptr) return absl::nullopt;
|
||||
|
||||
for (size_t i = 0; i < payloads->size(); ++i) {
|
||||
if ((*payloads)[i].type_url == type_url) return i;
|
||||
}
|
||||
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<absl::Cord> StatusRep::GetPayload(
|
||||
absl::string_view type_url) const {
|
||||
absl::optional<size_t> index =
|
||||
status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
|
||||
if (index.has_value()) return (*payloads_)[index.value()].payload;
|
||||
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
void StatusRep::SetPayload(absl::string_view type_url, absl::Cord payload) {
|
||||
if (payloads_ == nullptr) {
|
||||
payloads_ = absl::make_unique<status_internal::Payloads>();
|
||||
}
|
||||
|
||||
absl::optional<size_t> index =
|
||||
status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
|
||||
if (index.has_value()) {
|
||||
(*payloads_)[index.value()].payload = std::move(payload);
|
||||
return;
|
||||
}
|
||||
|
||||
payloads_->push_back({std::string(type_url), std::move(payload)});
|
||||
}
|
||||
|
||||
StatusRep::EraseResult StatusRep::ErasePayload(absl::string_view type_url) {
|
||||
absl::optional<size_t> index =
|
||||
status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
|
||||
if (!index.has_value()) return {false, Status::PointerToRep(this)};
|
||||
payloads_->erase(payloads_->begin() + index.value());
|
||||
if (payloads_->empty() && message_.empty()) {
|
||||
// Special case: If this can be represented inlined, it MUST be inlined
|
||||
// (== depends on this behavior).
|
||||
EraseResult result = {true, Status::CodeToInlinedRep(code_)};
|
||||
Unref();
|
||||
return result;
|
||||
}
|
||||
return {true, Status::PointerToRep(this)};
|
||||
}
|
||||
|
||||
void StatusRep::ForEachPayload(
|
||||
absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor)
|
||||
const {
|
||||
if (auto* payloads = payloads_.get()) {
|
||||
bool in_reverse =
|
||||
payloads->size() > 1 && reinterpret_cast<uintptr_t>(payloads) % 13 > 6;
|
||||
|
||||
for (size_t 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.
|
||||
|
||||
// NOLINTNEXTLINE intentional extra conversion to force temporary.
|
||||
visitor(std::string(elem.type_url), elem.payload);
|
||||
#endif // NDEBUG
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string StatusRep::ToString(StatusToStringMode mode) 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)),
|
||||
"']");
|
||||
});
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
bool StatusRep::operator==(const StatusRep& other) const {
|
||||
assert(this != &other);
|
||||
if (code_ != other.code_) return false;
|
||||
if (message_ != other.message_) return false;
|
||||
const status_internal::Payloads* this_payloads = payloads_.get();
|
||||
const status_internal::Payloads* other_payloads = other.payloads_.get();
|
||||
|
||||
const status_internal::Payloads no_payloads;
|
||||
const status_internal::Payloads* larger_payloads =
|
||||
this_payloads ? this_payloads : &no_payloads;
|
||||
const status_internal::Payloads* smaller_payloads =
|
||||
other_payloads ? other_payloads : &no_payloads;
|
||||
if (larger_payloads->size() < smaller_payloads->size()) {
|
||||
std::swap(larger_payloads, smaller_payloads);
|
||||
}
|
||||
if ((larger_payloads->size() - smaller_payloads->size()) > 1) return false;
|
||||
// Payloads can be ordered differently, so we can't just compare payload
|
||||
// vectors.
|
||||
for (const auto& payload : *larger_payloads) {
|
||||
|
||||
bool found = false;
|
||||
for (const auto& other_payload : *smaller_payloads) {
|
||||
if (payload.type_url == other_payload.type_url) {
|
||||
if (payload.payload != other_payload.payload) {
|
||||
return false;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
absl::Nonnull<StatusRep*> StatusRep::CloneAndUnref() const {
|
||||
// Optimization: no need to create a clone if we already have a refcount of 1.
|
||||
if (ref_.load(std::memory_order_acquire) == 1) {
|
||||
// All StatusRep instances are heap allocated and mutable, therefore this
|
||||
// const_cast will never cast away const from a stack instance.
|
||||
//
|
||||
// CloneAndUnref is the only method that doesn't involve an external cast to
|
||||
// get a mutable StatusRep* from the uintptr_t rep stored in Status.
|
||||
return const_cast<StatusRep*>(this);
|
||||
}
|
||||
std::unique_ptr<status_internal::Payloads> payloads;
|
||||
if (payloads_) {
|
||||
payloads = absl::make_unique<status_internal::Payloads>(*payloads_);
|
||||
}
|
||||
auto* new_rep = new StatusRep(code_, message_, std::move(payloads));
|
||||
Unref();
|
||||
return new_rep;
|
||||
}
|
||||
|
||||
// Convert canonical code to a value known to this binary.
|
||||
absl::StatusCode MapToLocalCode(int value) {
|
||||
absl::StatusCode code = static_cast<absl::StatusCode>(value);
|
||||
switch (code) {
|
||||
case absl::StatusCode::kOk:
|
||||
case absl::StatusCode::kCancelled:
|
||||
case absl::StatusCode::kUnknown:
|
||||
case absl::StatusCode::kInvalidArgument:
|
||||
case absl::StatusCode::kDeadlineExceeded:
|
||||
case absl::StatusCode::kNotFound:
|
||||
case absl::StatusCode::kAlreadyExists:
|
||||
case absl::StatusCode::kPermissionDenied:
|
||||
case absl::StatusCode::kResourceExhausted:
|
||||
case absl::StatusCode::kFailedPrecondition:
|
||||
case absl::StatusCode::kAborted:
|
||||
case absl::StatusCode::kOutOfRange:
|
||||
case absl::StatusCode::kUnimplemented:
|
||||
case absl::StatusCode::kInternal:
|
||||
case absl::StatusCode::kUnavailable:
|
||||
case absl::StatusCode::kDataLoss:
|
||||
case absl::StatusCode::kUnauthenticated:
|
||||
return code;
|
||||
default:
|
||||
return absl::StatusCode::kUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
absl::Nonnull<const char*> MakeCheckFailString(
|
||||
absl::Nonnull<const absl::Status*> status,
|
||||
absl::Nonnull<const char*> prefix) {
|
||||
// There's no need to free this string since the process is crashing.
|
||||
return absl::IgnoreLeak(
|
||||
new std::string(absl::StrCat(
|
||||
prefix, " (",
|
||||
status->ToString(StatusToStringMode::kWithEverything), ")")))
|
||||
->c_str();
|
||||
}
|
||||
|
||||
} // namespace status_internal
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
// 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 <atomic>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/container/inlined_vector.h"
|
||||
#include "absl/strings/cord.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.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.
|
||||
//
|
||||
// TODO(b/176172494): ABSL_MUST_USE_RESULT should expand to the more strict
|
||||
// [[nodiscard]]. For now, just use [[nodiscard]] directly when it is available.
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(nodiscard)
|
||||
class [[nodiscard]] ABSL_ATTRIBUTE_TRIVIAL_ABI Status;
|
||||
#else
|
||||
class ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_TRIVIAL_ABI Status;
|
||||
#endif
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
#endif // !SWIG
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
enum class StatusCode : int;
|
||||
enum class StatusToStringMode : 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.
|
||||
class StatusRep {
|
||||
public:
|
||||
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)) {}
|
||||
|
||||
absl::StatusCode code() const { return code_; }
|
||||
const std::string& message() const { return message_; }
|
||||
|
||||
// Ref and unref are const to allow access through a const pointer, and are
|
||||
// used during copying operations.
|
||||
void Ref() const { ref_.fetch_add(1, std::memory_order_relaxed); }
|
||||
void Unref() const;
|
||||
|
||||
// Payload methods correspond to the same methods in absl::Status.
|
||||
absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
|
||||
void SetPayload(absl::string_view type_url, absl::Cord payload);
|
||||
struct EraseResult {
|
||||
bool erased;
|
||||
uintptr_t new_rep;
|
||||
};
|
||||
EraseResult ErasePayload(absl::string_view type_url);
|
||||
void ForEachPayload(
|
||||
absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor)
|
||||
const;
|
||||
|
||||
std::string ToString(StatusToStringMode mode) const;
|
||||
|
||||
bool operator==(const StatusRep& other) const;
|
||||
bool operator!=(const StatusRep& other) const { return !(*this == other); }
|
||||
|
||||
// Returns an equivalent heap allocated StatusRep with refcount 1.
|
||||
//
|
||||
// `this` is not safe to be used after calling as it may have been deleted.
|
||||
absl::Nonnull<StatusRep*> CloneAndUnref() const;
|
||||
|
||||
private:
|
||||
mutable std::atomic<int32_t> ref_;
|
||||
absl::StatusCode code_;
|
||||
|
||||
// As an internal implementation detail, we guarantee that if status.message()
|
||||
// is non-empty, then the resulting string_view is null terminated.
|
||||
// This is required to implement 'StatusMessageAsCStr(...)'
|
||||
std::string message_;
|
||||
std::unique_ptr<status_internal::Payloads> payloads_;
|
||||
};
|
||||
|
||||
absl::StatusCode MapToLocalCode(int value);
|
||||
|
||||
// Returns a pointer to a newly-allocated string with the given `prefix`,
|
||||
// suitable for output as an error message in assertion/`CHECK()` failures.
|
||||
//
|
||||
// This is an internal implementation detail for Abseil logging.
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION
|
||||
absl::Nonnull<const char*> MakeCheckFailString(
|
||||
absl::Nonnull<const absl::Status*> status,
|
||||
absl::Nonnull<const char*> prefix);
|
||||
|
||||
} // namespace status_internal
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2024 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: status_matchers.cc
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "absl/status/internal/status_matchers.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h" // gmock_for_status_matchers.h
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/status/status.h"
|
||||
|
||||
namespace absl_testing {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace status_internal {
|
||||
|
||||
void StatusIsMatcherCommonImpl::DescribeTo(std::ostream* os) const {
|
||||
*os << ", has a status code that ";
|
||||
code_matcher_.DescribeTo(os);
|
||||
*os << ", and has an error message that ";
|
||||
message_matcher_.DescribeTo(os);
|
||||
}
|
||||
|
||||
void StatusIsMatcherCommonImpl::DescribeNegationTo(std::ostream* os) const {
|
||||
*os << ", or has a status code that ";
|
||||
code_matcher_.DescribeNegationTo(os);
|
||||
*os << ", or has an error message that ";
|
||||
message_matcher_.DescribeNegationTo(os);
|
||||
}
|
||||
|
||||
bool StatusIsMatcherCommonImpl::MatchAndExplain(
|
||||
const ::absl::Status& status,
|
||||
::testing::MatchResultListener* result_listener) const {
|
||||
::testing::StringMatchResultListener inner_listener;
|
||||
if (!code_matcher_.MatchAndExplain(status.code(), &inner_listener)) {
|
||||
*result_listener << (inner_listener.str().empty()
|
||||
? "whose status code is wrong"
|
||||
: "which has a status code " +
|
||||
inner_listener.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!message_matcher_.Matches(std::string(status.message()))) {
|
||||
*result_listener << "whose error message is wrong";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace status_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl_testing
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
// Copyright 2024 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_MATCHERS_H_
|
||||
#define ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
|
||||
|
||||
#include <ostream> // NOLINT
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "gmock/gmock.h" // gmock_for_status_matchers.h
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace absl_testing {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace status_internal {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Implementation of IsOkAndHolds().
|
||||
|
||||
// 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 (!GetStatus(actual_value).ok()) {
|
||||
*result_listener << "which has status " << GetStatus(actual_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call through to the inner matcher.
|
||||
return inner_matcher_.MatchAndExplain(*actual_value, result_listener);
|
||||
}
|
||||
|
||||
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::forward<InnerMatcher>(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_;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Implementation of StatusIs().
|
||||
|
||||
// `StatusCode` is implicitly convertible from `int`, `absl::StatusCode`, and
|
||||
// is explicitly convertible to these types as well.
|
||||
//
|
||||
// We need this class because `absl::StatusCode` (as a scoped enum) is not
|
||||
// implicitly convertible to `int`. In order to handle use cases like
|
||||
// ```
|
||||
// StatusIs(Anyof(absl::StatusCode::kUnknown, absl::StatusCode::kCancelled))
|
||||
// ```
|
||||
// which uses polymorphic matchers, we need to unify the interfaces into
|
||||
// `Matcher<StatusCode>`.
|
||||
class StatusCode {
|
||||
public:
|
||||
/*implicit*/ StatusCode(int code) // NOLINT
|
||||
: code_(static_cast<::absl::StatusCode>(code)) {}
|
||||
/*implicit*/ StatusCode(::absl::StatusCode code) : code_(code) {} // NOLINT
|
||||
|
||||
explicit operator int() const { return static_cast<int>(code_); }
|
||||
|
||||
friend inline void PrintTo(const StatusCode& code, std::ostream* os) {
|
||||
// TODO(b/321095377): Change this to print the status code as a string.
|
||||
*os << static_cast<int>(code);
|
||||
}
|
||||
|
||||
private:
|
||||
::absl::StatusCode code_;
|
||||
};
|
||||
|
||||
// Relational operators to handle matchers like Eq, Lt, etc..
|
||||
inline bool operator==(const StatusCode& lhs, const StatusCode& rhs) {
|
||||
return static_cast<int>(lhs) == static_cast<int>(rhs);
|
||||
}
|
||||
inline bool operator!=(const StatusCode& lhs, const StatusCode& rhs) {
|
||||
return static_cast<int>(lhs) != static_cast<int>(rhs);
|
||||
}
|
||||
|
||||
// StatusIs() is a polymorphic matcher. This class is the common
|
||||
// implementation of it shared by all types T where StatusIs() can be
|
||||
// used as a Matcher<T>.
|
||||
class StatusIsMatcherCommonImpl {
|
||||
public:
|
||||
StatusIsMatcherCommonImpl(
|
||||
::testing::Matcher<StatusCode> code_matcher,
|
||||
::testing::Matcher<absl::string_view> message_matcher)
|
||||
: code_matcher_(std::move(code_matcher)),
|
||||
message_matcher_(std::move(message_matcher)) {}
|
||||
|
||||
void DescribeTo(std::ostream* os) const;
|
||||
|
||||
void DescribeNegationTo(std::ostream* os) const;
|
||||
|
||||
bool MatchAndExplain(const absl::Status& status,
|
||||
::testing::MatchResultListener* result_listener) const;
|
||||
|
||||
private:
|
||||
const ::testing::Matcher<StatusCode> code_matcher_;
|
||||
const ::testing::Matcher<absl::string_view> message_matcher_;
|
||||
};
|
||||
|
||||
// Monomorphic implementation of matcher StatusIs() for a given type
|
||||
// T. T can be Status, StatusOr<>, or a reference to either of them.
|
||||
template <typename T>
|
||||
class MonoStatusIsMatcherImpl : public ::testing::MatcherInterface<T> {
|
||||
public:
|
||||
explicit MonoStatusIsMatcherImpl(StatusIsMatcherCommonImpl common_impl)
|
||||
: common_impl_(std::move(common_impl)) {}
|
||||
|
||||
void DescribeTo(std::ostream* os) const override {
|
||||
common_impl_.DescribeTo(os);
|
||||
}
|
||||
|
||||
void DescribeNegationTo(std::ostream* os) const override {
|
||||
common_impl_.DescribeNegationTo(os);
|
||||
}
|
||||
|
||||
bool MatchAndExplain(
|
||||
T actual_value,
|
||||
::testing::MatchResultListener* result_listener) const override {
|
||||
return common_impl_.MatchAndExplain(GetStatus(actual_value),
|
||||
result_listener);
|
||||
}
|
||||
|
||||
private:
|
||||
StatusIsMatcherCommonImpl common_impl_;
|
||||
};
|
||||
|
||||
// Implements StatusIs() as a polymorphic matcher.
|
||||
class StatusIsMatcher {
|
||||
public:
|
||||
template <typename StatusCodeMatcher, typename StatusMessageMatcher>
|
||||
StatusIsMatcher(StatusCodeMatcher&& code_matcher,
|
||||
StatusMessageMatcher&& message_matcher)
|
||||
: common_impl_(::testing::MatcherCast<StatusCode>(
|
||||
std::forward<StatusCodeMatcher>(code_matcher)),
|
||||
::testing::MatcherCast<absl::string_view>(
|
||||
std::forward<StatusMessageMatcher>(message_matcher))) {
|
||||
}
|
||||
|
||||
// Converts this polymorphic matcher to a monomorphic matcher of the
|
||||
// given type. T can be StatusOr<>, Status, or a reference to
|
||||
// either of them.
|
||||
template <typename T>
|
||||
/*implicit*/ operator ::testing::Matcher<T>() const { // NOLINT
|
||||
return ::testing::Matcher<T>(
|
||||
new MonoStatusIsMatcherImpl<const T&>(common_impl_));
|
||||
}
|
||||
|
||||
private:
|
||||
const StatusIsMatcherCommonImpl common_impl_;
|
||||
};
|
||||
|
||||
// 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>
|
||||
/*implicit*/ operator ::testing::Matcher<T>() const { // NOLINT
|
||||
return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<const T&>());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace status_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl_testing
|
||||
|
||||
#endif // ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
|
||||
|
|
@ -0,0 +1,494 @@
|
|||
// 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 <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/string_view.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_cvref_t<U>, U>::value, std::false_type,
|
||||
IsDirectInitializationAmbiguous<T, absl::remove_cvref_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_cvref_t<U>>,
|
||||
absl::negation<absl::disjunction<
|
||||
std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
|
||||
std::is_same<absl::Status, absl::remove_cvref_t<U>>,
|
||||
std::is_same<absl::in_place_t, absl::remove_cvref_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_cvref_t<U>, U>::value, std::false_type,
|
||||
IsForwardingAssignmentAmbiguous<T, absl::remove_cvref_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_cvref_t<U>>,
|
||||
absl::negation<absl::disjunction<
|
||||
std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
|
||||
std::is_same<absl::Status, absl::remove_cvref_t<U>>,
|
||||
std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
|
||||
IsForwardingAssignmentAmbiguous<T, U>>>>;
|
||||
|
||||
template <bool Value, typename T>
|
||||
using Equality = std::conditional_t<Value, T, absl::negation<T>>;
|
||||
|
||||
template <bool Explicit, typename T, typename U, bool Lifetimebound>
|
||||
using IsConstructionValid = absl::conjunction<
|
||||
Equality<Lifetimebound,
|
||||
type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
|
||||
IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>,
|
||||
Equality<!Explicit, std::is_convertible<U&&, T>>,
|
||||
absl::disjunction<
|
||||
std::is_same<T, absl::remove_cvref_t<U>>,
|
||||
absl::conjunction<
|
||||
std::conditional_t<
|
||||
Explicit,
|
||||
absl::negation<std::is_constructible<absl::Status, U&&>>,
|
||||
absl::negation<std::is_convertible<U&&, absl::Status>>>,
|
||||
absl::negation<
|
||||
internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>;
|
||||
|
||||
template <typename T, typename U, bool Lifetimebound>
|
||||
using IsAssignmentValid = absl::conjunction<
|
||||
Equality<Lifetimebound,
|
||||
type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
|
||||
std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
|
||||
absl::disjunction<
|
||||
std::is_same<T, absl::remove_cvref_t<U>>,
|
||||
absl::conjunction<
|
||||
absl::negation<std::is_convertible<U&&, absl::Status>>,
|
||||
absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>,
|
||||
IsForwardingAssignmentValid<T, U&&>>;
|
||||
|
||||
template <bool Explicit, typename T, typename U>
|
||||
using IsConstructionFromStatusValid = absl::conjunction<
|
||||
absl::negation<std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>>,
|
||||
absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
|
||||
absl::negation<std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>>,
|
||||
Equality<!Explicit, std::is_convertible<U, absl::Status>>,
|
||||
std::is_constructible<absl::Status, U>,
|
||||
absl::negation<HasConversionOperatorToStatusOr<T, U>>>;
|
||||
|
||||
template <bool Explicit, typename T, typename U, bool Lifetimebound,
|
||||
typename UQ>
|
||||
using IsConstructionFromStatusOrValid = absl::conjunction<
|
||||
absl::negation<std::is_same<T, U>>,
|
||||
Equality<Lifetimebound,
|
||||
type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
|
||||
std::is_constructible<T, UQ>,
|
||||
Equality<!Explicit, std::is_convertible<UQ, T>>,
|
||||
absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>;
|
||||
|
||||
template <typename T, typename U, bool Lifetimebound>
|
||||
using IsStatusOrAssignmentValid = absl::conjunction<
|
||||
absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
|
||||
Equality<Lifetimebound,
|
||||
type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
|
||||
std::is_constructible<T, U>, std::is_assignable<T, U>,
|
||||
absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
|
||||
T, absl::remove_cvref_t<U>>>>;
|
||||
|
||||
class Helper {
|
||||
public:
|
||||
// Move type-agnostic error handling to the .cc.
|
||||
static void HandleInvalidStatusCtorArg(absl::Nonnull<Status*>);
|
||||
[[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(absl::Nonnull<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;
|
||||
};
|
||||
|
||||
[[noreturn]] void ThrowBadStatusOrAccess(absl::Status status);
|
||||
|
||||
// Used to introduce jitter into the output of printing functions for
|
||||
// `StatusOr` (i.e. `AbslStringify` and `operator<<`).
|
||||
class StringifyRandom {
|
||||
enum BracesType {
|
||||
kBareParens = 0,
|
||||
kSpaceParens,
|
||||
kBareBrackets,
|
||||
kSpaceBrackets,
|
||||
};
|
||||
|
||||
// Returns a random `BracesType` determined once per binary load.
|
||||
static BracesType RandomBraces() {
|
||||
static const BracesType kRandomBraces = static_cast<BracesType>(
|
||||
(reinterpret_cast<uintptr_t>(&kRandomBraces) >> 4) % 4);
|
||||
return kRandomBraces;
|
||||
}
|
||||
|
||||
public:
|
||||
static inline absl::string_view OpenBrackets() {
|
||||
switch (RandomBraces()) {
|
||||
case kBareParens:
|
||||
return "(";
|
||||
case kSpaceParens:
|
||||
return "( ";
|
||||
case kBareBrackets:
|
||||
return "[";
|
||||
case kSpaceBrackets:
|
||||
return "[ ";
|
||||
}
|
||||
return "(";
|
||||
}
|
||||
|
||||
static inline absl::string_view CloseBrackets() {
|
||||
switch (RandomBraces()) {
|
||||
case kBareParens:
|
||||
return ")";
|
||||
case kSpaceParens:
|
||||
return " )";
|
||||
case kBareBrackets:
|
||||
return "]";
|
||||
case kSpaceBrackets:
|
||||
return " ]";
|
||||
}
|
||||
return ")";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal_statusor
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
|
||||
421
TMessagesProj/jni/voip/webrtc/absl/status/status.cc
Normal file
421
TMessagesProj/jni/voip/webrtc/absl/status/status.cc
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
// 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.
|
||||
#include "absl/status/status.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/internal/strerror.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/no_destructor.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/debugging/stacktrace.h"
|
||||
#include "absl/debugging/symbolize.h"
|
||||
#include "absl/status/internal/status_internal.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
static_assert(
|
||||
alignof(status_internal::StatusRep) >= 4,
|
||||
"absl::Status assumes it can use the bottom 2 bits of a StatusRep*.");
|
||||
|
||||
std::string StatusCodeToString(StatusCode code) {
|
||||
switch (code) {
|
||||
case StatusCode::kOk:
|
||||
return "OK";
|
||||
case StatusCode::kCancelled:
|
||||
return "CANCELLED";
|
||||
case StatusCode::kUnknown:
|
||||
return "UNKNOWN";
|
||||
case StatusCode::kInvalidArgument:
|
||||
return "INVALID_ARGUMENT";
|
||||
case StatusCode::kDeadlineExceeded:
|
||||
return "DEADLINE_EXCEEDED";
|
||||
case StatusCode::kNotFound:
|
||||
return "NOT_FOUND";
|
||||
case StatusCode::kAlreadyExists:
|
||||
return "ALREADY_EXISTS";
|
||||
case StatusCode::kPermissionDenied:
|
||||
return "PERMISSION_DENIED";
|
||||
case StatusCode::kUnauthenticated:
|
||||
return "UNAUTHENTICATED";
|
||||
case StatusCode::kResourceExhausted:
|
||||
return "RESOURCE_EXHAUSTED";
|
||||
case StatusCode::kFailedPrecondition:
|
||||
return "FAILED_PRECONDITION";
|
||||
case StatusCode::kAborted:
|
||||
return "ABORTED";
|
||||
case StatusCode::kOutOfRange:
|
||||
return "OUT_OF_RANGE";
|
||||
case StatusCode::kUnimplemented:
|
||||
return "UNIMPLEMENTED";
|
||||
case StatusCode::kInternal:
|
||||
return "INTERNAL";
|
||||
case StatusCode::kUnavailable:
|
||||
return "UNAVAILABLE";
|
||||
case StatusCode::kDataLoss:
|
||||
return "DATA_LOSS";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, StatusCode code) {
|
||||
return os << StatusCodeToString(code);
|
||||
}
|
||||
|
||||
absl::Nonnull<const std::string*> Status::EmptyString() {
|
||||
static const absl::NoDestructor<std::string> kEmpty;
|
||||
return kEmpty.get();
|
||||
}
|
||||
|
||||
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr const char Status::kMovedFromString[];
|
||||
#endif
|
||||
|
||||
absl::Nonnull<const std::string*> Status::MovedFromString() {
|
||||
static const absl::NoDestructor<std::string> kMovedFrom(kMovedFromString);
|
||||
return kMovedFrom.get();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Nonnull<status_internal::StatusRep*> Status::PrepareToModify(
|
||||
uintptr_t rep) {
|
||||
if (IsInlined(rep)) {
|
||||
return new status_internal::StatusRep(InlinedRepToCode(rep),
|
||||
absl::string_view(), nullptr);
|
||||
}
|
||||
return RepToPointer(rep)->CloneAndUnref();
|
||||
}
|
||||
|
||||
std::string Status::ToStringSlow(uintptr_t rep, StatusToStringMode mode) {
|
||||
if (IsInlined(rep)) {
|
||||
return absl::StrCat(absl::StatusCodeToString(InlinedRepToCode(rep)), ": ");
|
||||
}
|
||||
return RepToPointer(rep)->ToString(mode);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Status& x) {
|
||||
os << x.ToString(StatusToStringMode::kWithEverything);
|
||||
return os;
|
||||
}
|
||||
|
||||
Status AbortedError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kAborted, message);
|
||||
}
|
||||
|
||||
Status AlreadyExistsError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kAlreadyExists, message);
|
||||
}
|
||||
|
||||
Status CancelledError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kCancelled, message);
|
||||
}
|
||||
|
||||
Status DataLossError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kDataLoss, message);
|
||||
}
|
||||
|
||||
Status DeadlineExceededError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kDeadlineExceeded, message);
|
||||
}
|
||||
|
||||
Status FailedPreconditionError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kFailedPrecondition, message);
|
||||
}
|
||||
|
||||
Status InternalError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kInternal, message);
|
||||
}
|
||||
|
||||
Status InvalidArgumentError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kInvalidArgument, message);
|
||||
}
|
||||
|
||||
Status NotFoundError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kNotFound, message);
|
||||
}
|
||||
|
||||
Status OutOfRangeError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kOutOfRange, message);
|
||||
}
|
||||
|
||||
Status PermissionDeniedError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kPermissionDenied, message);
|
||||
}
|
||||
|
||||
Status ResourceExhaustedError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kResourceExhausted, message);
|
||||
}
|
||||
|
||||
Status UnauthenticatedError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kUnauthenticated, message);
|
||||
}
|
||||
|
||||
Status UnavailableError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kUnavailable, message);
|
||||
}
|
||||
|
||||
Status UnimplementedError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kUnimplemented, message);
|
||||
}
|
||||
|
||||
Status UnknownError(absl::string_view message) {
|
||||
return Status(absl::StatusCode::kUnknown, message);
|
||||
}
|
||||
|
||||
bool IsAborted(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kAborted;
|
||||
}
|
||||
|
||||
bool IsAlreadyExists(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kAlreadyExists;
|
||||
}
|
||||
|
||||
bool IsCancelled(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kCancelled;
|
||||
}
|
||||
|
||||
bool IsDataLoss(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kDataLoss;
|
||||
}
|
||||
|
||||
bool IsDeadlineExceeded(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kDeadlineExceeded;
|
||||
}
|
||||
|
||||
bool IsFailedPrecondition(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kFailedPrecondition;
|
||||
}
|
||||
|
||||
bool IsInternal(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kInternal;
|
||||
}
|
||||
|
||||
bool IsInvalidArgument(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kInvalidArgument;
|
||||
}
|
||||
|
||||
bool IsNotFound(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kNotFound;
|
||||
}
|
||||
|
||||
bool IsOutOfRange(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kOutOfRange;
|
||||
}
|
||||
|
||||
bool IsPermissionDenied(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kPermissionDenied;
|
||||
}
|
||||
|
||||
bool IsResourceExhausted(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kResourceExhausted;
|
||||
}
|
||||
|
||||
bool IsUnauthenticated(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kUnauthenticated;
|
||||
}
|
||||
|
||||
bool IsUnavailable(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kUnavailable;
|
||||
}
|
||||
|
||||
bool IsUnimplemented(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kUnimplemented;
|
||||
}
|
||||
|
||||
bool IsUnknown(const Status& status) {
|
||||
return status.code() == absl::StatusCode::kUnknown;
|
||||
}
|
||||
|
||||
StatusCode ErrnoToStatusCode(int error_number) {
|
||||
switch (error_number) {
|
||||
case 0:
|
||||
return StatusCode::kOk;
|
||||
case EINVAL: // Invalid argument
|
||||
case ENAMETOOLONG: // Filename too long
|
||||
case E2BIG: // Argument list too long
|
||||
case EDESTADDRREQ: // Destination address required
|
||||
case EDOM: // Mathematics argument out of domain of function
|
||||
case EFAULT: // Bad address
|
||||
case EILSEQ: // Illegal byte sequence
|
||||
case ENOPROTOOPT: // Protocol not available
|
||||
case ENOTSOCK: // Not a socket
|
||||
case ENOTTY: // Inappropriate I/O control operation
|
||||
case EPROTOTYPE: // Protocol wrong type for socket
|
||||
case ESPIPE: // Invalid seek
|
||||
return StatusCode::kInvalidArgument;
|
||||
case ETIMEDOUT: // Connection timed out
|
||||
return StatusCode::kDeadlineExceeded;
|
||||
case ENODEV: // No such device
|
||||
case ENOENT: // No such file or directory
|
||||
#ifdef ENOMEDIUM
|
||||
case ENOMEDIUM: // No medium found
|
||||
#endif
|
||||
case ENXIO: // No such device or address
|
||||
case ESRCH: // No such process
|
||||
return StatusCode::kNotFound;
|
||||
case EEXIST: // File exists
|
||||
case EADDRNOTAVAIL: // Address not available
|
||||
case EALREADY: // Connection already in progress
|
||||
#ifdef ENOTUNIQ
|
||||
case ENOTUNIQ: // Name not unique on network
|
||||
#endif
|
||||
return StatusCode::kAlreadyExists;
|
||||
case EPERM: // Operation not permitted
|
||||
case EACCES: // Permission denied
|
||||
#ifdef ENOKEY
|
||||
case ENOKEY: // Required key not available
|
||||
#endif
|
||||
case EROFS: // Read only file system
|
||||
return StatusCode::kPermissionDenied;
|
||||
case ENOTEMPTY: // Directory not empty
|
||||
case EISDIR: // Is a directory
|
||||
case ENOTDIR: // Not a directory
|
||||
case EADDRINUSE: // Address already in use
|
||||
case EBADF: // Invalid file descriptor
|
||||
#ifdef EBADFD
|
||||
case EBADFD: // File descriptor in bad state
|
||||
#endif
|
||||
case EBUSY: // Device or resource busy
|
||||
case ECHILD: // No child processes
|
||||
case EISCONN: // Socket is connected
|
||||
#ifdef EISNAM
|
||||
case EISNAM: // Is a named type file
|
||||
#endif
|
||||
#ifdef ENOTBLK
|
||||
case ENOTBLK: // Block device required
|
||||
#endif
|
||||
case ENOTCONN: // The socket is not connected
|
||||
case EPIPE: // Broken pipe
|
||||
#ifdef ESHUTDOWN
|
||||
case ESHUTDOWN: // Cannot send after transport endpoint shutdown
|
||||
#endif
|
||||
case ETXTBSY: // Text file busy
|
||||
#ifdef EUNATCH
|
||||
case EUNATCH: // Protocol driver not attached
|
||||
#endif
|
||||
return StatusCode::kFailedPrecondition;
|
||||
case ENOSPC: // No space left on device
|
||||
#ifdef EDQUOT
|
||||
case EDQUOT: // Disk quota exceeded
|
||||
#endif
|
||||
case EMFILE: // Too many open files
|
||||
case EMLINK: // Too many links
|
||||
case ENFILE: // Too many open files in system
|
||||
case ENOBUFS: // No buffer space available
|
||||
case ENOMEM: // Not enough space
|
||||
#ifdef EUSERS
|
||||
case EUSERS: // Too many users
|
||||
#endif
|
||||
return StatusCode::kResourceExhausted;
|
||||
#ifdef ECHRNG
|
||||
case ECHRNG: // Channel number out of range
|
||||
#endif
|
||||
case EFBIG: // File too large
|
||||
case EOVERFLOW: // Value too large to be stored in data type
|
||||
case ERANGE: // Result too large
|
||||
return StatusCode::kOutOfRange;
|
||||
#ifdef ENOPKG
|
||||
case ENOPKG: // Package not installed
|
||||
#endif
|
||||
case ENOSYS: // Function not implemented
|
||||
case ENOTSUP: // Operation not supported
|
||||
case EAFNOSUPPORT: // Address family not supported
|
||||
#ifdef EPFNOSUPPORT
|
||||
case EPFNOSUPPORT: // Protocol family not supported
|
||||
#endif
|
||||
case EPROTONOSUPPORT: // Protocol not supported
|
||||
#ifdef ESOCKTNOSUPPORT
|
||||
case ESOCKTNOSUPPORT: // Socket type not supported
|
||||
#endif
|
||||
case EXDEV: // Improper link
|
||||
return StatusCode::kUnimplemented;
|
||||
case EAGAIN: // Resource temporarily unavailable
|
||||
#ifdef ECOMM
|
||||
case ECOMM: // Communication error on send
|
||||
#endif
|
||||
case ECONNREFUSED: // Connection refused
|
||||
case ECONNABORTED: // Connection aborted
|
||||
case ECONNRESET: // Connection reset
|
||||
case EINTR: // Interrupted function call
|
||||
#ifdef EHOSTDOWN
|
||||
case EHOSTDOWN: // Host is down
|
||||
#endif
|
||||
case EHOSTUNREACH: // Host is unreachable
|
||||
case ENETDOWN: // Network is down
|
||||
case ENETRESET: // Connection aborted by network
|
||||
case ENETUNREACH: // Network unreachable
|
||||
case ENOLCK: // No locks available
|
||||
case ENOLINK: // Link has been severed
|
||||
#ifdef ENONET
|
||||
case ENONET: // Machine is not on the network
|
||||
#endif
|
||||
return StatusCode::kUnavailable;
|
||||
case EDEADLK: // Resource deadlock avoided
|
||||
#ifdef ESTALE
|
||||
case ESTALE: // Stale file handle
|
||||
#endif
|
||||
return StatusCode::kAborted;
|
||||
case ECANCELED: // Operation cancelled
|
||||
return StatusCode::kCancelled;
|
||||
default:
|
||||
return StatusCode::kUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string MessageForErrnoToStatus(int error_number,
|
||||
absl::string_view message) {
|
||||
return absl::StrCat(message, ": ",
|
||||
absl::base_internal::StrError(error_number));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Status ErrnoToStatus(int error_number, absl::string_view message) {
|
||||
return Status(ErrnoToStatusCode(error_number),
|
||||
MessageForErrnoToStatus(error_number, message));
|
||||
}
|
||||
|
||||
absl::Nonnull<const char*> StatusMessageAsCStr(const Status& status) {
|
||||
// As an internal implementation detail, we guarantee that if status.message()
|
||||
// is non-empty, then the resulting string_view is null terminated.
|
||||
auto sv_message = status.message();
|
||||
return sv_message.empty() ? "" : sv_message.data();
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
943
TMessagesProj/jni/voip/webrtc/absl/status/status.h
Normal file
943
TMessagesProj/jni/voip/webrtc/absl/status/status.h
Normal file
|
|
@ -0,0 +1,943 @@
|
|||
// 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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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 communicating
|
||||
// errors in C++, and is used to represent error state in both in-process
|
||||
// library calls as well as RPC calls. 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_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/base/optimization.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,
|
||||
};
|
||||
|
||||
// absl::StatusToStringMode is specified as a bitmask type, which means the
|
||||
// following operations must be provided:
|
||||
inline constexpr StatusToStringMode operator&(StatusToStringMode lhs,
|
||||
StatusToStringMode rhs) {
|
||||
return static_cast<StatusToStringMode>(static_cast<int>(lhs) &
|
||||
static_cast<int>(rhs));
|
||||
}
|
||||
inline constexpr StatusToStringMode operator|(StatusToStringMode lhs,
|
||||
StatusToStringMode rhs) {
|
||||
return static_cast<StatusToStringMode>(static_cast<int>(lhs) |
|
||||
static_cast<int>(rhs));
|
||||
}
|
||||
inline constexpr StatusToStringMode operator^(StatusToStringMode lhs,
|
||||
StatusToStringMode rhs) {
|
||||
return static_cast<StatusToStringMode>(static_cast<int>(lhs) ^
|
||||
static_cast<int>(rhs));
|
||||
}
|
||||
inline constexpr StatusToStringMode operator~(StatusToStringMode arg) {
|
||||
return static_cast<StatusToStringMode>(~static_cast<int>(arg));
|
||||
}
|
||||
inline StatusToStringMode& operator&=(StatusToStringMode& lhs,
|
||||
StatusToStringMode rhs) {
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
inline StatusToStringMode& operator|=(StatusToStringMode& lhs,
|
||||
StatusToStringMode rhs) {
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
inline StatusToStringMode& operator^=(StatusToStringMode& lhs,
|
||||
StatusToStringMode rhs) {
|
||||
lhs = lhs ^ rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// absl::Status
|
||||
//
|
||||
// The `absl::Status` class is generally used to gracefully handle errors
|
||||
// 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 contextual 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 ABSL_ATTRIBUTE_TRIVIAL_ABI Status final {
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
// 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()`.
|
||||
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.
|
||||
//
|
||||
// The `msg` string must be in UTF-8. The implementation may complain (e.g., // NOLINT
|
||||
// by printing a warning) if it is not.
|
||||
Status(absl::StatusCode code, absl::string_view msg);
|
||||
|
||||
Status(const Status&);
|
||||
Status& operator=(const Status& x);
|
||||
|
||||
// Move operators
|
||||
|
||||
// The moved-from state is valid but unspecified.
|
||||
Status(Status&&) noexcept;
|
||||
Status& operator=(Status&&) noexcept;
|
||||
|
||||
~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`.
|
||||
//
|
||||
// `Update()` provides a convenient way of keeping track of the first error
|
||||
// encountered.
|
||||
//
|
||||
// Example:
|
||||
// // Instead of "if (overall_status.ok()) overall_status = new_status"
|
||||
// overall_status.Update(new_status);
|
||||
//
|
||||
void Update(const Status& new_status);
|
||||
void Update(Status&& new_status);
|
||||
|
||||
// Status::ok()
|
||||
//
|
||||
// Returns `true` if `this->code()` == `absl::StatusCode::kOk`,
|
||||
// indicating the absence of an error.
|
||||
// Prefer checking for an OK status using this member function.
|
||||
ABSL_MUST_USE_RESULT bool ok() const;
|
||||
|
||||
// Status::code()
|
||||
//
|
||||
// Returns the canonical error code of type `absl::StatusCode` of this status.
|
||||
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.
|
||||
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.
|
||||
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;
|
||||
|
||||
// Support `absl::StrCat`, `absl::StrFormat`, etc.
|
||||
template <typename Sink>
|
||||
friend void AbslStringify(Sink& sink, const Status& status) {
|
||||
sink.Append(status.ToString(StatusToStringMode::kWithEverything));
|
||||
}
|
||||
|
||||
// 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.
|
||||
friend void swap(Status& a, Status& b) noexcept;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Payload Management APIs
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// A payload may be attached to a status to provide additional context to an
|
||||
// error that may not be satisfied 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 contextual information that is more
|
||||
// appropriate to display to an end user.
|
||||
//
|
||||
// A payload consists of a [key,value] pair, where the key is a string
|
||||
// referring to a unique "type URL" and the value is an object of type
|
||||
// `absl::Cord` to hold the contextual data.
|
||||
//
|
||||
// The "type URL" should be unique and follow the format of a URL
|
||||
// (https://en.wikipedia.org/wiki/URL) and, ideally, provide some
|
||||
// documentation or schema on how to interpret its associated data. For
|
||||
// example, the default type URL for a protobuf message type is
|
||||
// "type.googleapis.com/packagename.messagename". Other custom wire formats
|
||||
// should define the format of type URL in a similar practice so as to
|
||||
// minimize the chance of conflict between type URLs.
|
||||
// Users should ensure that the type URL can be mapped to a concrete
|
||||
// C++ type if they want to deserialize the payload and read it effectively.
|
||||
//
|
||||
// To attach a payload to a status object, call `Status::SetPayload()`,
|
||||
// passing it the type URL and an `absl::Cord` of associated data. Similarly,
|
||||
// to extract the payload from a status, call `Status::GetPayload()`. You
|
||||
// may attach multiple payloads (with differing type URLs) to any given
|
||||
// status object, provided that the status is currently exhibiting an error
|
||||
// code (i.e. is not OK).
|
||||
|
||||
// Status::GetPayload()
|
||||
//
|
||||
// Gets the payload of a status given its unique `type_url` key, if present.
|
||||
absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
|
||||
|
||||
// Status::SetPayload()
|
||||
//
|
||||
// Sets the payload for 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.
|
||||
void SetPayload(absl::string_view type_url, absl::Cord payload);
|
||||
|
||||
// Status::ErasePayload()
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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
|
||||
// forbidden and could result in undefined behavior.
|
||||
void ForEachPayload(
|
||||
absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor)
|
||||
const;
|
||||
|
||||
private:
|
||||
friend Status CancelledError();
|
||||
|
||||
// Creates a status in the canonical error space with the specified
|
||||
// code, and an empty error message.
|
||||
explicit Status(absl::StatusCode code);
|
||||
|
||||
// Underlying constructor for status from a rep_.
|
||||
explicit Status(uintptr_t rep) : rep_(rep) {}
|
||||
|
||||
static void Ref(uintptr_t rep);
|
||||
static void Unref(uintptr_t rep);
|
||||
|
||||
// REQUIRES: !ok()
|
||||
// Ensures rep is not inlined or shared with any other Status.
|
||||
static absl::Nonnull<status_internal::StatusRep*> PrepareToModify(
|
||||
uintptr_t rep);
|
||||
|
||||
// MSVC 14.0 limitation requires the const.
|
||||
static constexpr const char kMovedFromString[] =
|
||||
"Status accessed after move.";
|
||||
|
||||
static absl::Nonnull<const std::string*> EmptyString();
|
||||
static absl::Nonnull<const std::string*> MovedFromString();
|
||||
|
||||
// Returns whether rep contains an inlined representation.
|
||||
// See rep_ for details.
|
||||
static constexpr bool IsInlined(uintptr_t rep);
|
||||
|
||||
// Indicates whether this Status was the rhs of a move operation. See rep_
|
||||
// for details.
|
||||
static constexpr bool IsMovedFrom(uintptr_t rep);
|
||||
static constexpr uintptr_t MovedFromRep();
|
||||
|
||||
// Convert between error::Code and the inlined uintptr_t representation used
|
||||
// by rep_. See rep_ for details.
|
||||
static constexpr uintptr_t CodeToInlinedRep(absl::StatusCode code);
|
||||
static constexpr absl::StatusCode InlinedRepToCode(uintptr_t rep);
|
||||
|
||||
// Converts between StatusRep* and the external uintptr_t representation used
|
||||
// by rep_. See rep_ for details.
|
||||
static uintptr_t PointerToRep(absl::Nonnull<status_internal::StatusRep*> r);
|
||||
static absl::Nonnull<const status_internal::StatusRep*> RepToPointer(
|
||||
uintptr_t r);
|
||||
|
||||
static std::string ToStringSlow(uintptr_t rep, StatusToStringMode mode);
|
||||
|
||||
// Status supports two different representations.
|
||||
// - When the low bit is set it is an inlined representation.
|
||||
// It uses the canonical error space, no message or payload.
|
||||
// The error code is (rep_ >> 2).
|
||||
// The (rep_ & 2) bit is the "moved from" indicator, used in IsMovedFrom().
|
||||
// - When the low bit is off it is an external representation.
|
||||
// In this case all the data comes from a heap allocated Rep object.
|
||||
// rep_ is a status_internal::StatusRep* pointer to that structure.
|
||||
uintptr_t rep_;
|
||||
|
||||
friend class status_internal::StatusRep;
|
||||
};
|
||||
|
||||
// OkStatus()
|
||||
//
|
||||
// Returns an OK status, equivalent to a default constructed instance. Prefer
|
||||
// usage of `absl::OkStatus()` when constructing such an OK status.
|
||||
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);
|
||||
|
||||
// ErrnoToStatusCode()
|
||||
//
|
||||
// Returns the StatusCode for `error_number`, which should be an `errno` value.
|
||||
// See https://en.cppreference.com/w/cpp/error/errno_macros and similar
|
||||
// references.
|
||||
absl::StatusCode ErrnoToStatusCode(int error_number);
|
||||
|
||||
// ErrnoToStatus()
|
||||
//
|
||||
// Convenience function that creates a `absl::Status` using an `error_number`,
|
||||
// which should be an `errno` value.
|
||||
Status ErrnoToStatus(int error_number, absl::string_view message);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementation details follow
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline Status::Status() : Status(absl::StatusCode::kOk) {}
|
||||
|
||||
inline Status::Status(absl::StatusCode code) : Status(CodeToInlinedRep(code)) {}
|
||||
|
||||
inline Status::Status(const Status& x) : Status(x.rep_) { Ref(rep_); }
|
||||
|
||||
inline Status& Status::operator=(const Status& x) {
|
||||
uintptr_t old_rep = rep_;
|
||||
if (x.rep_ != old_rep) {
|
||||
Ref(x.rep_);
|
||||
rep_ = x.rep_;
|
||||
Unref(old_rep);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Status::Status(Status&& x) noexcept : Status(x.rep_) {
|
||||
x.rep_ = MovedFromRep();
|
||||
}
|
||||
|
||||
inline Status& Status::operator=(Status&& x) noexcept {
|
||||
uintptr_t old_rep = rep_;
|
||||
if (x.rep_ != old_rep) {
|
||||
rep_ = x.rep_;
|
||||
x.rep_ = MovedFromRep();
|
||||
Unref(old_rep);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void Status::Update(const Status& new_status) {
|
||||
if (ok()) {
|
||||
*this = new_status;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Status::Update(Status&& new_status) {
|
||||
if (ok()) {
|
||||
*this = std::move(new_status);
|
||||
}
|
||||
}
|
||||
|
||||
inline Status::~Status() { Unref(rep_); }
|
||||
|
||||
inline bool Status::ok() const {
|
||||
return rep_ == CodeToInlinedRep(absl::StatusCode::kOk);
|
||||
}
|
||||
|
||||
inline absl::StatusCode Status::code() const {
|
||||
return status_internal::MapToLocalCode(raw_code());
|
||||
}
|
||||
|
||||
inline int Status::raw_code() const {
|
||||
if (IsInlined(rep_)) return static_cast<int>(InlinedRepToCode(rep_));
|
||||
return static_cast<int>(RepToPointer(rep_)->code());
|
||||
}
|
||||
|
||||
inline absl::string_view Status::message() const {
|
||||
return !IsInlined(rep_)
|
||||
? RepToPointer(rep_)->message()
|
||||
: (IsMovedFrom(rep_) ? absl::string_view(kMovedFromString)
|
||||
: absl::string_view());
|
||||
}
|
||||
|
||||
inline bool operator==(const Status& lhs, const Status& rhs) {
|
||||
if (lhs.rep_ == rhs.rep_) return true;
|
||||
if (Status::IsInlined(lhs.rep_)) return false;
|
||||
if (Status::IsInlined(rhs.rep_)) return false;
|
||||
return *Status::RepToPointer(lhs.rep_) == *Status::RepToPointer(rhs.rep_);
|
||||
}
|
||||
|
||||
inline bool operator!=(const Status& lhs, const Status& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline std::string Status::ToString(StatusToStringMode mode) const {
|
||||
return ok() ? "OK" : ToStringSlow(rep_, mode);
|
||||
}
|
||||
|
||||
inline void Status::IgnoreError() const {
|
||||
// no-op
|
||||
}
|
||||
|
||||
inline void swap(absl::Status& a, absl::Status& b) noexcept {
|
||||
using std::swap;
|
||||
swap(a.rep_, b.rep_);
|
||||
}
|
||||
|
||||
inline absl::optional<absl::Cord> Status::GetPayload(
|
||||
absl::string_view type_url) const {
|
||||
if (IsInlined(rep_)) return absl::nullopt;
|
||||
return RepToPointer(rep_)->GetPayload(type_url);
|
||||
}
|
||||
|
||||
inline void Status::SetPayload(absl::string_view type_url, absl::Cord payload) {
|
||||
if (ok()) return;
|
||||
status_internal::StatusRep* rep = PrepareToModify(rep_);
|
||||
rep->SetPayload(type_url, std::move(payload));
|
||||
rep_ = PointerToRep(rep);
|
||||
}
|
||||
|
||||
inline bool Status::ErasePayload(absl::string_view type_url) {
|
||||
if (IsInlined(rep_)) return false;
|
||||
status_internal::StatusRep* rep = PrepareToModify(rep_);
|
||||
auto res = rep->ErasePayload(type_url);
|
||||
rep_ = res.new_rep;
|
||||
return res.erased;
|
||||
}
|
||||
|
||||
inline void Status::ForEachPayload(
|
||||
absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor)
|
||||
const {
|
||||
if (IsInlined(rep_)) return;
|
||||
RepToPointer(rep_)->ForEachPayload(visitor);
|
||||
}
|
||||
|
||||
constexpr bool Status::IsInlined(uintptr_t rep) { return (rep & 1) != 0; }
|
||||
|
||||
constexpr bool Status::IsMovedFrom(uintptr_t rep) { return (rep & 2) != 0; }
|
||||
|
||||
constexpr uintptr_t Status::CodeToInlinedRep(absl::StatusCode code) {
|
||||
return (static_cast<uintptr_t>(code) << 2) + 1;
|
||||
}
|
||||
|
||||
constexpr absl::StatusCode Status::InlinedRepToCode(uintptr_t rep) {
|
||||
ABSL_ASSERT(IsInlined(rep));
|
||||
return static_cast<absl::StatusCode>(rep >> 2);
|
||||
}
|
||||
|
||||
constexpr uintptr_t Status::MovedFromRep() {
|
||||
return CodeToInlinedRep(absl::StatusCode::kInternal) | 2;
|
||||
}
|
||||
|
||||
inline absl::Nonnull<const status_internal::StatusRep*> Status::RepToPointer(
|
||||
uintptr_t rep) {
|
||||
assert(!IsInlined(rep));
|
||||
return reinterpret_cast<const status_internal::StatusRep*>(rep);
|
||||
}
|
||||
|
||||
inline uintptr_t Status::PointerToRep(
|
||||
absl::Nonnull<status_internal::StatusRep*> rep) {
|
||||
return reinterpret_cast<uintptr_t>(rep);
|
||||
}
|
||||
|
||||
inline void Status::Ref(uintptr_t rep) {
|
||||
if (!IsInlined(rep)) RepToPointer(rep)->Ref();
|
||||
}
|
||||
|
||||
inline void Status::Unref(uintptr_t rep) {
|
||||
if (!IsInlined(rep)) RepToPointer(rep)->Unref();
|
||||
}
|
||||
|
||||
inline Status OkStatus() { return Status(); }
|
||||
|
||||
// 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); }
|
||||
|
||||
// Retrieves a message's status as a null terminated C string. The lifetime of
|
||||
// this string is tied to the lifetime of the status object itself.
|
||||
//
|
||||
// If the status's message is empty, the empty string is returned.
|
||||
//
|
||||
// StatusMessageAsCStr exists for C support. Use `status.message()` in C++.
|
||||
absl::Nonnull<const char*> StatusMessageAsCStr(
|
||||
const Status& status ABSL_ATTRIBUTE_LIFETIME_BOUND);
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_STATUS_STATUS_H_
|
||||
118
TMessagesProj/jni/voip/webrtc/absl/status/status_matchers.h
Normal file
118
TMessagesProj/jni/voip/webrtc/absl/status/status_matchers.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2024 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: status_matchers.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Testing utilities for working with `absl::Status` and `absl::StatusOr`.
|
||||
//
|
||||
// Defines the following utilities:
|
||||
//
|
||||
// ===============
|
||||
// `IsOkAndHolds(m)`
|
||||
// ===============
|
||||
//
|
||||
// This gMock matcher matches a StatusOr<T> value whose status is OK
|
||||
// and whose inner value matches matcher m. Example:
|
||||
//
|
||||
// ```
|
||||
// using ::testing::MatchesRegex;
|
||||
// using ::absl_testing::IsOkAndHolds;
|
||||
// ...
|
||||
// absl::StatusOr<string> maybe_name = ...;
|
||||
// EXPECT_THAT(maybe_name, IsOkAndHolds(MatchesRegex("John .*")));
|
||||
// ```
|
||||
//
|
||||
// ===============================
|
||||
// `StatusIs(status_code_matcher)`
|
||||
// ===============================
|
||||
//
|
||||
// This is a shorthand for
|
||||
// `StatusIs(status_code_matcher, ::testing::_)`
|
||||
// In other words, it's like the two-argument `StatusIs()`, except that it
|
||||
// ignores error message.
|
||||
//
|
||||
// ===============
|
||||
// `IsOk()`
|
||||
// ===============
|
||||
//
|
||||
// Matches an `absl::Status` or `absl::StatusOr<T>` value whose status value
|
||||
// is `absl::StatusCode::kOk.`
|
||||
//
|
||||
// Equivalent to 'StatusIs(absl::StatusCode::kOk)'.
|
||||
// Example:
|
||||
// ```
|
||||
// using ::absl_testing::IsOk;
|
||||
// ...
|
||||
// absl::StatusOr<string> maybe_name = ...;
|
||||
// EXPECT_THAT(maybe_name, IsOk());
|
||||
// Status s = ...;
|
||||
// EXPECT_THAT(s, IsOk());
|
||||
// ```
|
||||
|
||||
#ifndef ABSL_STATUS_STATUS_MATCHERS_H_
|
||||
#define ABSL_STATUS_STATUS_MATCHERS_H_
|
||||
|
||||
#include <ostream> // NOLINT
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "gmock/gmock.h" // gmock_for_status_matchers.h
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/status/internal/status_matchers.h"
|
||||
|
||||
namespace absl_testing {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// Returns a gMock matcher that matches a StatusOr<> whose status is
|
||||
// OK and whose value matches the inner matcher.
|
||||
template <typename InnerMatcherT>
|
||||
status_internal::IsOkAndHoldsMatcher<typename std::decay<InnerMatcherT>::type>
|
||||
IsOkAndHolds(InnerMatcherT&& inner_matcher) {
|
||||
return status_internal::IsOkAndHoldsMatcher<
|
||||
typename std::decay<InnerMatcherT>::type>(
|
||||
std::forward<InnerMatcherT>(inner_matcher));
|
||||
}
|
||||
|
||||
// Returns a gMock matcher that matches a Status or StatusOr<> whose status code
|
||||
// matches code_matcher and whose error message matches message_matcher.
|
||||
// Typically, code_matcher will be an absl::StatusCode, e.g.
|
||||
//
|
||||
// StatusIs(absl::StatusCode::kInvalidArgument, "...")
|
||||
template <typename StatusCodeMatcherT, typename StatusMessageMatcherT>
|
||||
status_internal::StatusIsMatcher StatusIs(
|
||||
StatusCodeMatcherT&& code_matcher,
|
||||
StatusMessageMatcherT&& message_matcher) {
|
||||
return status_internal::StatusIsMatcher(
|
||||
std::forward<StatusCodeMatcherT>(code_matcher),
|
||||
std::forward<StatusMessageMatcherT>(message_matcher));
|
||||
}
|
||||
|
||||
// Returns a gMock matcher that matches a Status or StatusOr<> and whose status
|
||||
// code matches code_matcher. See above for details.
|
||||
template <typename StatusCodeMatcherT>
|
||||
status_internal::StatusIsMatcher StatusIs(StatusCodeMatcherT&& code_matcher) {
|
||||
return StatusIs(std::forward<StatusCodeMatcherT>(code_matcher), ::testing::_);
|
||||
}
|
||||
|
||||
// Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
|
||||
inline status_internal::IsOkMatcher IsOk() {
|
||||
return status_internal::IsOkMatcher();
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl_testing
|
||||
|
||||
#endif // ABSL_STATUS_STATUS_MATCHERS_H_
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright 2024 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: status_matchers_test.cc
|
||||
// -----------------------------------------------------------------------------
|
||||
#include "absl/status/status_matchers.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::absl_testing::IsOk;
|
||||
using ::absl_testing::IsOkAndHolds;
|
||||
using ::absl_testing::StatusIs;
|
||||
using ::testing::Gt;
|
||||
|
||||
TEST(StatusMatcherTest, StatusIsOk) { EXPECT_THAT(absl::OkStatus(), IsOk()); }
|
||||
|
||||
TEST(StatusMatcherTest, StatusOrIsOk) {
|
||||
absl::StatusOr<int> ok_int = {0};
|
||||
EXPECT_THAT(ok_int, IsOk());
|
||||
}
|
||||
|
||||
TEST(StatusMatcherTest, StatusIsNotOk) {
|
||||
absl::Status error = absl::UnknownError("Smigla");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THAT(error, IsOk()), "Smigla");
|
||||
}
|
||||
|
||||
TEST(StatusMatcherTest, StatusOrIsNotOk) {
|
||||
absl::StatusOr<int> error = absl::UnknownError("Smigla");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THAT(error, IsOk()), "Smigla");
|
||||
}
|
||||
|
||||
TEST(StatusMatcherTest, IsOkAndHolds) {
|
||||
absl::StatusOr<int> ok_int = {4};
|
||||
absl::StatusOr<absl::string_view> ok_str = {"text"};
|
||||
EXPECT_THAT(ok_int, IsOkAndHolds(4));
|
||||
EXPECT_THAT(ok_int, IsOkAndHolds(Gt(0)));
|
||||
EXPECT_THAT(ok_str, IsOkAndHolds("text"));
|
||||
}
|
||||
|
||||
TEST(StatusMatcherTest, IsOkAndHoldsFailure) {
|
||||
absl::StatusOr<int> ok_int = {502};
|
||||
absl::StatusOr<int> error = absl::UnknownError("Smigla");
|
||||
absl::StatusOr<absl::string_view> ok_str = {"actual"};
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THAT(ok_int, IsOkAndHolds(0)), "502");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THAT(error, IsOkAndHolds(0)), "Smigla");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THAT(ok_str, IsOkAndHolds("expected")),
|
||||
"actual");
|
||||
}
|
||||
|
||||
TEST(StatusMatcherTest, StatusIs) {
|
||||
absl::Status unknown = absl::UnknownError("unbekannt");
|
||||
absl::Status invalid = absl::InvalidArgumentError("ungueltig");
|
||||
EXPECT_THAT(absl::OkStatus(), StatusIs(absl::StatusCode::kOk));
|
||||
EXPECT_THAT(absl::OkStatus(), StatusIs(0));
|
||||
EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown));
|
||||
EXPECT_THAT(unknown, StatusIs(2));
|
||||
EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown, "unbekannt"));
|
||||
EXPECT_THAT(invalid, StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
EXPECT_THAT(invalid, StatusIs(3));
|
||||
EXPECT_THAT(invalid,
|
||||
StatusIs(absl::StatusCode::kInvalidArgument, "ungueltig"));
|
||||
}
|
||||
|
||||
TEST(StatusMatcherTest, StatusOrIs) {
|
||||
absl::StatusOr<int> ok = {42};
|
||||
absl::StatusOr<int> unknown = absl::UnknownError("unbekannt");
|
||||
absl::StatusOr<absl::string_view> invalid =
|
||||
absl::InvalidArgumentError("ungueltig");
|
||||
EXPECT_THAT(ok, StatusIs(absl::StatusCode::kOk));
|
||||
EXPECT_THAT(ok, StatusIs(0));
|
||||
EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown));
|
||||
EXPECT_THAT(unknown, StatusIs(2));
|
||||
EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown, "unbekannt"));
|
||||
EXPECT_THAT(invalid, StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
EXPECT_THAT(invalid, StatusIs(3));
|
||||
EXPECT_THAT(invalid,
|
||||
StatusIs(absl::StatusCode::kInvalidArgument, "ungueltig"));
|
||||
}
|
||||
|
||||
TEST(StatusMatcherTest, StatusIsFailure) {
|
||||
absl::Status unknown = absl::UnknownError("unbekannt");
|
||||
absl::Status invalid = absl::InvalidArgumentError("ungueltig");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THAT(absl::OkStatus(),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument)),
|
||||
"OK");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kCancelled)), "UNKNOWN");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown, "inconnu")),
|
||||
"unbekannt");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THAT(invalid, StatusIs(absl::StatusCode::kOutOfRange)), "INVALID");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THAT(invalid,
|
||||
StatusIs(absl::StatusCode::kInvalidArgument, "invalide")),
|
||||
"ungueltig");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// 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.
|
||||
#include "absl/status/status_payload_printer.h"
|
||||
|
||||
#include "absl/base/config.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;
|
||||
|
||||
void SetStatusPayloadPrinter(StatusPayloadPrinter printer) {
|
||||
storage.Store(printer);
|
||||
}
|
||||
|
||||
StatusPayloadPrinter GetStatusPayloadPrinter() {
|
||||
return storage.Load();
|
||||
}
|
||||
|
||||
} // namespace status_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// 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_STATUS_PAYLOAD_PRINTER_H_
|
||||
#define ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/strings/cord.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace status_internal {
|
||||
|
||||
// By default, `Status::ToString` and `operator<<(Status)` print a payload by
|
||||
// dumping the type URL and the raw bytes. To help debugging, we provide an
|
||||
// extension point, which is a global printer function that can be set by users
|
||||
// to specify how to print payloads. The function takes the type URL and the
|
||||
// payload as input, and should return a valid human-readable string on success
|
||||
// or `absl::nullopt` on failure (in which case it falls back to the default
|
||||
// approach of printing the raw bytes).
|
||||
// NOTE: This is an internal API and the design is subject to change in the
|
||||
// future in a non-backward-compatible way. Since it's only meant for debugging
|
||||
// purpose, you should not rely on it in any critical logic.
|
||||
using StatusPayloadPrinter = absl::Nullable<absl::optional<std::string> (*)(
|
||||
absl::string_view, const absl::Cord&)>;
|
||||
|
||||
// Sets the global payload printer. Only one printer should be set per process.
|
||||
// If multiple printers are set, it's undefined which one will be used.
|
||||
void SetStatusPayloadPrinter(StatusPayloadPrinter);
|
||||
|
||||
// Returns the global payload printer if previously set, otherwise `nullptr`.
|
||||
StatusPayloadPrinter GetStatusPayloadPrinter();
|
||||
|
||||
} // namespace status_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_
|
||||
579
TMessagesProj/jni/voip/webrtc/absl/status/status_test.cc
Normal file
579
TMessagesProj/jni/voip/webrtc/absl/status/status_test.cc
Normal file
|
|
@ -0,0 +1,579 @@
|
|||
// 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.
|
||||
|
||||
#include "absl/status/status.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/cord.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Optional;
|
||||
using ::testing::UnorderedElementsAreArray;
|
||||
|
||||
TEST(StatusCode, InsertionOperator) {
|
||||
const absl::StatusCode code = absl::StatusCode::kUnknown;
|
||||
std::ostringstream oss;
|
||||
oss << code;
|
||||
EXPECT_EQ(oss.str(), absl::StatusCodeToString(code));
|
||||
}
|
||||
|
||||
// This structure holds the details for testing a single error code,
|
||||
// its creator, and its classifier.
|
||||
struct ErrorTest {
|
||||
absl::StatusCode code;
|
||||
using Creator = absl::Status (*)(
|
||||
absl::string_view
|
||||
);
|
||||
using Classifier = bool (*)(const absl::Status&);
|
||||
Creator creator;
|
||||
Classifier classifier;
|
||||
};
|
||||
|
||||
constexpr ErrorTest kErrorTests[]{
|
||||
{absl::StatusCode::kCancelled, absl::CancelledError, absl::IsCancelled},
|
||||
{absl::StatusCode::kUnknown, absl::UnknownError, absl::IsUnknown},
|
||||
{absl::StatusCode::kInvalidArgument, absl::InvalidArgumentError,
|
||||
absl::IsInvalidArgument},
|
||||
{absl::StatusCode::kDeadlineExceeded, absl::DeadlineExceededError,
|
||||
absl::IsDeadlineExceeded},
|
||||
{absl::StatusCode::kNotFound, absl::NotFoundError, absl::IsNotFound},
|
||||
{absl::StatusCode::kAlreadyExists, absl::AlreadyExistsError,
|
||||
absl::IsAlreadyExists},
|
||||
{absl::StatusCode::kPermissionDenied, absl::PermissionDeniedError,
|
||||
absl::IsPermissionDenied},
|
||||
{absl::StatusCode::kResourceExhausted, absl::ResourceExhaustedError,
|
||||
absl::IsResourceExhausted},
|
||||
{absl::StatusCode::kFailedPrecondition, absl::FailedPreconditionError,
|
||||
absl::IsFailedPrecondition},
|
||||
{absl::StatusCode::kAborted, absl::AbortedError, absl::IsAborted},
|
||||
{absl::StatusCode::kOutOfRange, absl::OutOfRangeError, absl::IsOutOfRange},
|
||||
{absl::StatusCode::kUnimplemented, absl::UnimplementedError,
|
||||
absl::IsUnimplemented},
|
||||
{absl::StatusCode::kInternal, absl::InternalError, absl::IsInternal},
|
||||
{absl::StatusCode::kUnavailable, absl::UnavailableError,
|
||||
absl::IsUnavailable},
|
||||
{absl::StatusCode::kDataLoss, absl::DataLossError, absl::IsDataLoss},
|
||||
{absl::StatusCode::kUnauthenticated, absl::UnauthenticatedError,
|
||||
absl::IsUnauthenticated},
|
||||
};
|
||||
|
||||
TEST(Status, CreateAndClassify) {
|
||||
for (const auto& test : kErrorTests) {
|
||||
SCOPED_TRACE(absl::StatusCodeToString(test.code));
|
||||
|
||||
// Ensure that the creator does, in fact, create status objects with the
|
||||
// expected error code and message.
|
||||
std::string message =
|
||||
absl::StrCat("error code ", test.code, " test message");
|
||||
absl::Status status = test.creator(
|
||||
message
|
||||
);
|
||||
EXPECT_EQ(test.code, status.code());
|
||||
EXPECT_EQ(message, status.message());
|
||||
|
||||
// Ensure that the classifier returns true for a status produced by the
|
||||
// creator.
|
||||
EXPECT_TRUE(test.classifier(status));
|
||||
|
||||
// Ensure that the classifier returns false for status with a different
|
||||
// code.
|
||||
for (const auto& other : kErrorTests) {
|
||||
if (other.code != test.code) {
|
||||
EXPECT_FALSE(test.classifier(absl::Status(other.code, "")))
|
||||
<< " other.code = " << other.code;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, DefaultConstructor) {
|
||||
absl::Status status;
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_EQ(absl::StatusCode::kOk, status.code());
|
||||
EXPECT_EQ("", status.message());
|
||||
}
|
||||
|
||||
TEST(Status, OkStatus) {
|
||||
absl::Status status = absl::OkStatus();
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_EQ(absl::StatusCode::kOk, status.code());
|
||||
EXPECT_EQ("", status.message());
|
||||
}
|
||||
|
||||
TEST(Status, ConstructorWithCodeMessage) {
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kCancelled, "");
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_EQ(absl::StatusCode::kCancelled, status.code());
|
||||
EXPECT_EQ("", status.message());
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInternal, "message");
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_EQ(absl::StatusCode::kInternal, status.code());
|
||||
EXPECT_EQ("message", status.message());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, StatusMessageCStringTest) {
|
||||
{
|
||||
absl::Status status = absl::OkStatus();
|
||||
EXPECT_EQ(status.message(), "");
|
||||
EXPECT_STREQ(absl::StatusMessageAsCStr(status), "");
|
||||
EXPECT_EQ(status.message(), absl::StatusMessageAsCStr(status));
|
||||
EXPECT_NE(absl::StatusMessageAsCStr(status), nullptr);
|
||||
}
|
||||
{
|
||||
absl::Status status;
|
||||
EXPECT_EQ(status.message(), "");
|
||||
EXPECT_NE(absl::StatusMessageAsCStr(status), nullptr);
|
||||
EXPECT_STREQ(absl::StatusMessageAsCStr(status), "");
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInternal, "message");
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_EQ(absl::StatusCode::kInternal, status.code());
|
||||
EXPECT_EQ("message", status.message());
|
||||
EXPECT_STREQ("message", absl::StatusMessageAsCStr(status));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, ConstructOutOfRangeCode) {
|
||||
const int kRawCode = 9999;
|
||||
absl::Status status(static_cast<absl::StatusCode>(kRawCode), "");
|
||||
EXPECT_EQ(absl::StatusCode::kUnknown, status.code());
|
||||
EXPECT_EQ(kRawCode, status.raw_code());
|
||||
}
|
||||
|
||||
constexpr char kUrl1[] = "url.payload.1";
|
||||
constexpr char kUrl2[] = "url.payload.2";
|
||||
constexpr char kUrl3[] = "url.payload.3";
|
||||
constexpr char kUrl4[] = "url.payload.xx";
|
||||
|
||||
constexpr char kPayload1[] = "aaaaa";
|
||||
constexpr char kPayload2[] = "bbbbb";
|
||||
constexpr char kPayload3[] = "ccccc";
|
||||
|
||||
using PayloadsVec = std::vector<std::pair<std::string, absl::Cord>>;
|
||||
|
||||
TEST(Status, TestGetSetPayload) {
|
||||
absl::Status ok_status = absl::OkStatus();
|
||||
ok_status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
ok_status.SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
|
||||
EXPECT_FALSE(ok_status.GetPayload(kUrl1));
|
||||
EXPECT_FALSE(ok_status.GetPayload(kUrl2));
|
||||
|
||||
absl::Status bad_status(absl::StatusCode::kInternal, "fail");
|
||||
bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
|
||||
EXPECT_THAT(bad_status.GetPayload(kUrl1), Optional(Eq(kPayload1)));
|
||||
EXPECT_THAT(bad_status.GetPayload(kUrl2), Optional(Eq(kPayload2)));
|
||||
|
||||
EXPECT_FALSE(bad_status.GetPayload(kUrl3));
|
||||
|
||||
bad_status.SetPayload(kUrl1, absl::Cord(kPayload3));
|
||||
EXPECT_THAT(bad_status.GetPayload(kUrl1), Optional(Eq(kPayload3)));
|
||||
|
||||
// Testing dynamically generated type_url
|
||||
bad_status.SetPayload(absl::StrCat(kUrl1, ".1"), absl::Cord(kPayload1));
|
||||
EXPECT_THAT(bad_status.GetPayload(absl::StrCat(kUrl1, ".1")),
|
||||
Optional(Eq(kPayload1)));
|
||||
}
|
||||
|
||||
TEST(Status, TestErasePayload) {
|
||||
absl::Status bad_status(absl::StatusCode::kInternal, "fail");
|
||||
bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
bad_status.SetPayload(kUrl3, absl::Cord(kPayload3));
|
||||
|
||||
EXPECT_FALSE(bad_status.ErasePayload(kUrl4));
|
||||
|
||||
EXPECT_TRUE(bad_status.GetPayload(kUrl2));
|
||||
EXPECT_TRUE(bad_status.ErasePayload(kUrl2));
|
||||
EXPECT_FALSE(bad_status.GetPayload(kUrl2));
|
||||
EXPECT_FALSE(bad_status.ErasePayload(kUrl2));
|
||||
|
||||
EXPECT_TRUE(bad_status.ErasePayload(kUrl1));
|
||||
EXPECT_TRUE(bad_status.ErasePayload(kUrl3));
|
||||
|
||||
bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
EXPECT_TRUE(bad_status.ErasePayload(kUrl1));
|
||||
}
|
||||
|
||||
TEST(Status, TestComparePayloads) {
|
||||
absl::Status bad_status1(absl::StatusCode::kInternal, "fail");
|
||||
bad_status1.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
bad_status1.SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
bad_status1.SetPayload(kUrl3, absl::Cord(kPayload3));
|
||||
|
||||
absl::Status bad_status2(absl::StatusCode::kInternal, "fail");
|
||||
bad_status2.SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
bad_status2.SetPayload(kUrl3, absl::Cord(kPayload3));
|
||||
bad_status2.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
|
||||
EXPECT_EQ(bad_status1, bad_status2);
|
||||
}
|
||||
|
||||
TEST(Status, TestComparePayloadsAfterErase) {
|
||||
absl::Status payload_status(absl::StatusCode::kInternal, "");
|
||||
payload_status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
payload_status.SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
|
||||
absl::Status empty_status(absl::StatusCode::kInternal, "");
|
||||
|
||||
// Different payloads, not equal
|
||||
EXPECT_NE(payload_status, empty_status);
|
||||
EXPECT_TRUE(payload_status.ErasePayload(kUrl1));
|
||||
|
||||
// Still Different payloads, still not equal.
|
||||
EXPECT_NE(payload_status, empty_status);
|
||||
EXPECT_TRUE(payload_status.ErasePayload(kUrl2));
|
||||
|
||||
// Both empty payloads, should be equal
|
||||
EXPECT_EQ(payload_status, empty_status);
|
||||
}
|
||||
|
||||
PayloadsVec AllVisitedPayloads(const absl::Status& s) {
|
||||
PayloadsVec result;
|
||||
|
||||
s.ForEachPayload([&](absl::string_view type_url, const absl::Cord& payload) {
|
||||
result.push_back(std::make_pair(std::string(type_url), payload));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(Status, TestForEachPayload) {
|
||||
absl::Status bad_status(absl::StatusCode::kInternal, "fail");
|
||||
bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
bad_status.SetPayload(kUrl3, absl::Cord(kPayload3));
|
||||
|
||||
int count = 0;
|
||||
|
||||
bad_status.ForEachPayload(
|
||||
[&count](absl::string_view, const absl::Cord&) { ++count; });
|
||||
|
||||
EXPECT_EQ(count, 3);
|
||||
|
||||
PayloadsVec expected_payloads = {{kUrl1, absl::Cord(kPayload1)},
|
||||
{kUrl2, absl::Cord(kPayload2)},
|
||||
{kUrl3, absl::Cord(kPayload3)}};
|
||||
|
||||
// Test that we visit all the payloads in the status.
|
||||
PayloadsVec visited_payloads = AllVisitedPayloads(bad_status);
|
||||
EXPECT_THAT(visited_payloads, UnorderedElementsAreArray(expected_payloads));
|
||||
|
||||
// Test that visitation order is not consistent between run.
|
||||
std::vector<absl::Status> scratch;
|
||||
while (true) {
|
||||
scratch.emplace_back(absl::StatusCode::kInternal, "fail");
|
||||
|
||||
scratch.back().SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
scratch.back().SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
scratch.back().SetPayload(kUrl3, absl::Cord(kPayload3));
|
||||
|
||||
if (AllVisitedPayloads(scratch.back()) != visited_payloads) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, ToString) {
|
||||
absl::Status status(absl::StatusCode::kInternal, "fail");
|
||||
EXPECT_EQ("INTERNAL: fail", status.ToString());
|
||||
status.SetPayload("foo", absl::Cord("bar"));
|
||||
EXPECT_EQ("INTERNAL: fail [foo='bar']", status.ToString());
|
||||
status.SetPayload("bar", absl::Cord("\377"));
|
||||
EXPECT_THAT(status.ToString(),
|
||||
AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
|
||||
HasSubstr("[bar='\\xff']")));
|
||||
}
|
||||
|
||||
TEST(Status, ToStringMode) {
|
||||
absl::Status status(absl::StatusCode::kInternal, "fail");
|
||||
status.SetPayload("foo", absl::Cord("bar"));
|
||||
status.SetPayload("bar", absl::Cord("\377"));
|
||||
|
||||
EXPECT_EQ("INTERNAL: fail",
|
||||
status.ToString(absl::StatusToStringMode::kWithNoExtraData));
|
||||
|
||||
EXPECT_THAT(status.ToString(absl::StatusToStringMode::kWithPayload),
|
||||
AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
|
||||
HasSubstr("[bar='\\xff']")));
|
||||
|
||||
EXPECT_THAT(status.ToString(absl::StatusToStringMode::kWithEverything),
|
||||
AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
|
||||
HasSubstr("[bar='\\xff']")));
|
||||
|
||||
EXPECT_THAT(status.ToString(~absl::StatusToStringMode::kWithPayload),
|
||||
AllOf(HasSubstr("INTERNAL: fail"), Not(HasSubstr("[foo='bar']")),
|
||||
Not(HasSubstr("[bar='\\xff']"))));
|
||||
}
|
||||
|
||||
TEST(Status, OstreamOperator) {
|
||||
absl::Status status(absl::StatusCode::kInternal, "fail");
|
||||
{ std::stringstream stream;
|
||||
stream << status;
|
||||
EXPECT_EQ("INTERNAL: fail", stream.str());
|
||||
}
|
||||
status.SetPayload("foo", absl::Cord("bar"));
|
||||
{ std::stringstream stream;
|
||||
stream << status;
|
||||
EXPECT_EQ("INTERNAL: fail [foo='bar']", stream.str());
|
||||
}
|
||||
status.SetPayload("bar", absl::Cord("\377"));
|
||||
{ std::stringstream stream;
|
||||
stream << status;
|
||||
EXPECT_THAT(stream.str(),
|
||||
AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
|
||||
HasSubstr("[bar='\\xff']")));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, AbslStringify) {
|
||||
absl::Status status(absl::StatusCode::kInternal, "fail");
|
||||
EXPECT_EQ("INTERNAL: fail", absl::StrCat(status));
|
||||
EXPECT_EQ("INTERNAL: fail", absl::StrFormat("%v", status));
|
||||
status.SetPayload("foo", absl::Cord("bar"));
|
||||
EXPECT_EQ("INTERNAL: fail [foo='bar']", absl::StrCat(status));
|
||||
status.SetPayload("bar", absl::Cord("\377"));
|
||||
EXPECT_THAT(absl::StrCat(status),
|
||||
AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
|
||||
HasSubstr("[bar='\\xff']")));
|
||||
}
|
||||
|
||||
TEST(Status, OstreamEqStringify) {
|
||||
absl::Status status(absl::StatusCode::kUnknown, "fail");
|
||||
status.SetPayload("foo", absl::Cord("bar"));
|
||||
std::stringstream stream;
|
||||
stream << status;
|
||||
EXPECT_EQ(stream.str(), absl::StrCat(status));
|
||||
}
|
||||
|
||||
absl::Status EraseAndReturn(const absl::Status& base) {
|
||||
absl::Status copy = base;
|
||||
EXPECT_TRUE(copy.ErasePayload(kUrl1));
|
||||
return copy;
|
||||
}
|
||||
|
||||
TEST(Status, CopyOnWriteForErasePayload) {
|
||||
{
|
||||
absl::Status base(absl::StatusCode::kInvalidArgument, "fail");
|
||||
base.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
|
||||
absl::Status copy = EraseAndReturn(base);
|
||||
EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
|
||||
EXPECT_FALSE(copy.GetPayload(kUrl1).has_value());
|
||||
}
|
||||
{
|
||||
absl::Status base(absl::StatusCode::kInvalidArgument, "fail");
|
||||
base.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
absl::Status copy = base;
|
||||
|
||||
EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
|
||||
EXPECT_TRUE(copy.GetPayload(kUrl1).has_value());
|
||||
|
||||
EXPECT_TRUE(base.ErasePayload(kUrl1));
|
||||
|
||||
EXPECT_FALSE(base.GetPayload(kUrl1).has_value());
|
||||
EXPECT_TRUE(copy.GetPayload(kUrl1).has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, CopyConstructor) {
|
||||
{
|
||||
absl::Status status;
|
||||
absl::Status copy(status);
|
||||
EXPECT_EQ(copy, status);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
absl::Status copy(status);
|
||||
EXPECT_EQ(copy, status);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
absl::Status copy(status);
|
||||
EXPECT_EQ(copy, status);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, CopyAssignment) {
|
||||
absl::Status assignee;
|
||||
{
|
||||
absl::Status status;
|
||||
assignee = status;
|
||||
EXPECT_EQ(assignee, status);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
assignee = status;
|
||||
EXPECT_EQ(assignee, status);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
assignee = status;
|
||||
EXPECT_EQ(assignee, status);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, CopyAssignmentIsNotRef) {
|
||||
const absl::Status status_orig(absl::StatusCode::kInvalidArgument, "message");
|
||||
absl::Status status_copy = status_orig;
|
||||
EXPECT_EQ(status_orig, status_copy);
|
||||
status_copy.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
EXPECT_NE(status_orig, status_copy);
|
||||
}
|
||||
|
||||
TEST(Status, MoveConstructor) {
|
||||
{
|
||||
absl::Status status;
|
||||
absl::Status copy(absl::Status{});
|
||||
EXPECT_EQ(copy, status);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
absl::Status copy(
|
||||
absl::Status(absl::StatusCode::kInvalidArgument, "message"));
|
||||
EXPECT_EQ(copy, status);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
absl::Status copy1(status);
|
||||
absl::Status copy2(std::move(status));
|
||||
EXPECT_EQ(copy1, copy2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, MoveAssignment) {
|
||||
absl::Status assignee;
|
||||
{
|
||||
absl::Status status;
|
||||
assignee = absl::Status();
|
||||
EXPECT_EQ(assignee, status);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
assignee = absl::Status(absl::StatusCode::kInvalidArgument, "message");
|
||||
EXPECT_EQ(assignee, status);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
status.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
absl::Status copy(status);
|
||||
assignee = std::move(status);
|
||||
EXPECT_EQ(assignee, copy);
|
||||
}
|
||||
{
|
||||
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
|
||||
absl::Status copy(status);
|
||||
assignee = static_cast<absl::Status&&>(status);
|
||||
EXPECT_EQ(assignee, copy);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, Update) {
|
||||
absl::Status s;
|
||||
s.Update(absl::OkStatus());
|
||||
EXPECT_TRUE(s.ok());
|
||||
const absl::Status a(absl::StatusCode::kCancelled, "message");
|
||||
s.Update(a);
|
||||
EXPECT_EQ(s, a);
|
||||
const absl::Status b(absl::StatusCode::kInternal, "other message");
|
||||
s.Update(b);
|
||||
EXPECT_EQ(s, a);
|
||||
s.Update(absl::OkStatus());
|
||||
EXPECT_EQ(s, a);
|
||||
EXPECT_FALSE(s.ok());
|
||||
}
|
||||
|
||||
TEST(Status, Equality) {
|
||||
absl::Status ok;
|
||||
absl::Status no_payload = absl::CancelledError("no payload");
|
||||
absl::Status one_payload = absl::InvalidArgumentError("one payload");
|
||||
one_payload.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
absl::Status two_payloads = one_payload;
|
||||
two_payloads.SetPayload(kUrl2, absl::Cord(kPayload2));
|
||||
const std::array<absl::Status, 4> status_arr = {ok, no_payload, one_payload,
|
||||
two_payloads};
|
||||
for (int i = 0; i < status_arr.size(); i++) {
|
||||
for (int j = 0; j < status_arr.size(); j++) {
|
||||
if (i == j) {
|
||||
EXPECT_TRUE(status_arr[i] == status_arr[j]);
|
||||
EXPECT_FALSE(status_arr[i] != status_arr[j]);
|
||||
} else {
|
||||
EXPECT_TRUE(status_arr[i] != status_arr[j]);
|
||||
EXPECT_FALSE(status_arr[i] == status_arr[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Status, Swap) {
|
||||
auto test_swap = [](const absl::Status& s1, const absl::Status& s2) {
|
||||
absl::Status copy1 = s1, copy2 = s2;
|
||||
swap(copy1, copy2);
|
||||
EXPECT_EQ(copy1, s2);
|
||||
EXPECT_EQ(copy2, s1);
|
||||
};
|
||||
const absl::Status ok;
|
||||
const absl::Status no_payload(absl::StatusCode::kAlreadyExists, "no payload");
|
||||
absl::Status with_payload(absl::StatusCode::kInternal, "with payload");
|
||||
with_payload.SetPayload(kUrl1, absl::Cord(kPayload1));
|
||||
test_swap(ok, no_payload);
|
||||
test_swap(no_payload, ok);
|
||||
test_swap(ok, with_payload);
|
||||
test_swap(with_payload, ok);
|
||||
test_swap(no_payload, with_payload);
|
||||
test_swap(with_payload, no_payload);
|
||||
}
|
||||
|
||||
TEST(StatusErrno, ErrnoToStatusCode) {
|
||||
EXPECT_EQ(absl::ErrnoToStatusCode(0), absl::StatusCode::kOk);
|
||||
|
||||
// Spot-check a few errno values.
|
||||
EXPECT_EQ(absl::ErrnoToStatusCode(EINVAL),
|
||||
absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(absl::ErrnoToStatusCode(ENOENT), absl::StatusCode::kNotFound);
|
||||
|
||||
// We'll pick a very large number so it hopefully doesn't collide to errno.
|
||||
EXPECT_EQ(absl::ErrnoToStatusCode(19980927), absl::StatusCode::kUnknown);
|
||||
}
|
||||
|
||||
TEST(StatusErrno, ErrnoToStatus) {
|
||||
absl::Status status = absl::ErrnoToStatus(ENOENT, "Cannot open 'path'");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kNotFound);
|
||||
EXPECT_EQ(status.message(), "Cannot open 'path': No such file or directory");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
106
TMessagesProj/jni/voip/webrtc/absl/status/statusor.cc
Normal file
106
TMessagesProj/jni/voip/webrtc/absl/status/statusor.cc
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// 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/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/status/internal/statusor_internal.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_)) {}
|
||||
|
||||
absl::Nonnull<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::Nonnull<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
|
||||
796
TMessagesProj/jni/voip/webrtc/absl/status/statusor.h
Normal file
796
TMessagesProj/jni/voip/webrtc/absl/status/statusor.h
Normal file
|
|
@ -0,0 +1,796 @@
|
|||
// 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 <ostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/nullability.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/strings/has_absl_stringify.h"
|
||||
#include "absl/strings/has_ostream_operator.h"
|
||||
#include "absl/strings/str_format.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.
|
||||
absl::Nonnull<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>
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(nodiscard)
|
||||
// TODO(b/176172494): ABSL_MUST_USE_RESULT should expand to the more strict
|
||||
// [[nodiscard]]. For now, just use [[nodiscard]] directly when it is available.
|
||||
class [[nodiscard]] StatusOr;
|
||||
#else
|
||||
class ABSL_MUST_USE_RESULT StatusOr;
|
||||
#endif // ABSL_HAVE_CPP_ATTRIBUTE(nodiscard)
|
||||
|
||||
// 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<
|
||||
internal_statusor::IsConstructionFromStatusOrValid<
|
||||
false, T, U, false, const 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<
|
||||
internal_statusor::IsConstructionFromStatusOrValid<
|
||||
false, T, U, true, const U&>::value,
|
||||
int> = 0>
|
||||
StatusOr(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
|
||||
: Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
|
||||
template <typename U, absl::enable_if_t<
|
||||
internal_statusor::IsConstructionFromStatusOrValid<
|
||||
true, T, U, false, const 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<
|
||||
internal_statusor::IsConstructionFromStatusOrValid<
|
||||
true, T, U, true, const U&>::value,
|
||||
int> = 0>
|
||||
explicit StatusOr(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND)
|
||||
: Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
|
||||
|
||||
template <typename U, absl::enable_if_t<
|
||||
internal_statusor::IsConstructionFromStatusOrValid<
|
||||
false, T, U, false, U&&>::value,
|
||||
int> = 0>
|
||||
StatusOr(StatusOr<U>&& other) // NOLINT
|
||||
: Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
|
||||
template <typename U, absl::enable_if_t<
|
||||
internal_statusor::IsConstructionFromStatusOrValid<
|
||||
false, T, U, true, U&&>::value,
|
||||
int> = 0>
|
||||
StatusOr(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
|
||||
: Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
|
||||
template <typename U, absl::enable_if_t<
|
||||
internal_statusor::IsConstructionFromStatusOrValid<
|
||||
true, T, U, false, U&&>::value,
|
||||
int> = 0>
|
||||
explicit StatusOr(StatusOr<U>&& other)
|
||||
: Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
|
||||
template <typename U, absl::enable_if_t<
|
||||
internal_statusor::IsConstructionFromStatusOrValid<
|
||||
true, T, U, true, U&&>::value,
|
||||
int> = 0>
|
||||
explicit StatusOr(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND)
|
||||
: 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<internal_statusor::IsStatusOrAssignmentValid<
|
||||
T, const U&, false>::value,
|
||||
int> = 0>
|
||||
StatusOr& operator=(const StatusOr<U>& other) {
|
||||
this->Assign(other);
|
||||
return *this;
|
||||
}
|
||||
template <typename U,
|
||||
absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
|
||||
T, const U&, true>::value,
|
||||
int> = 0>
|
||||
StatusOr& operator=(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) {
|
||||
this->Assign(other);
|
||||
return *this;
|
||||
}
|
||||
template <typename U,
|
||||
absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
|
||||
T, U&&, false>::value,
|
||||
int> = 0>
|
||||
StatusOr& operator=(StatusOr<U>&& other) {
|
||||
this->Assign(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
template <typename U,
|
||||
absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
|
||||
T, U&&, true>::value,
|
||||
int> = 0>
|
||||
StatusOr& operator=(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) {
|
||||
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<internal_statusor::IsConstructionFromStatusValid<
|
||||
false, T, U>::value,
|
||||
int> = 0>
|
||||
StatusOr(U&& v) : Base(std::forward<U>(v)) {}
|
||||
|
||||
template <typename U = absl::Status,
|
||||
absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
|
||||
true, T, U>::value,
|
||||
int> = 0>
|
||||
explicit StatusOr(U&& v) : Base(std::forward<U>(v)) {}
|
||||
template <typename U = absl::Status,
|
||||
absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
|
||||
false, 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 std::enable_if<
|
||||
internal_statusor::IsAssignmentValid<T, U, false>::value,
|
||||
int>::type = 0>
|
||||
StatusOr& operator=(U&& v) {
|
||||
this->Assign(std::forward<U>(v));
|
||||
return *this;
|
||||
}
|
||||
template <typename U = T,
|
||||
typename std::enable_if<
|
||||
internal_statusor::IsAssignmentValid<T, U, true>::value,
|
||||
int>::type = 0>
|
||||
StatusOr& operator=(U&& v ABSL_ATTRIBUTE_LIFETIME_BOUND) {
|
||||
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<internal_statusor::IsConstructionValid<
|
||||
false, T, U, false>::value,
|
||||
int> = 0>
|
||||
StatusOr(U&& u) // NOLINT
|
||||
: StatusOr(absl::in_place, std::forward<U>(u)) {}
|
||||
template <typename U = T,
|
||||
absl::enable_if_t<internal_statusor::IsConstructionValid<
|
||||
false, T, U, true>::value,
|
||||
int> = 0>
|
||||
StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
|
||||
: StatusOr(absl::in_place, std::forward<U>(u)) {}
|
||||
|
||||
template <typename U = T,
|
||||
absl::enable_if_t<internal_statusor::IsConstructionValid<
|
||||
true, T, U, false>::value,
|
||||
int> = 0>
|
||||
explicit StatusOr(U&& u) // NOLINT
|
||||
: StatusOr(absl::in_place, std::forward<U>(u)) {}
|
||||
template <typename U = T,
|
||||
absl::enable_if_t<
|
||||
internal_statusor::IsConstructionValid<true, T, U, true>::value,
|
||||
int> = 0>
|
||||
explicit StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // 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 analogous 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) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
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) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
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_;
|
||||
}
|
||||
|
||||
// StatusOr<T>::AssignStatus()
|
||||
//
|
||||
// Sets the status of `absl::StatusOr<T>` to the given non-ok status value.
|
||||
//
|
||||
// NOTE: We recommend using the constructor and `operator=` where possible.
|
||||
// This method is intended for use in generic programming, to enable setting
|
||||
// the status of a `StatusOr<T>` when `T` may be `Status`. In that case, the
|
||||
// constructor and `operator=` would assign into the inner value of type
|
||||
// `Status`, rather than status of the `StatusOr` (b/280392796).
|
||||
//
|
||||
// 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.
|
||||
using internal_statusor::StatusOrData<T>::AssignStatus;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Prints the `value` or the status in brackets to `os`.
|
||||
//
|
||||
// Requires `T` supports `operator<<`. Do not rely on the output format which
|
||||
// may change without notice.
|
||||
template <typename T, typename std::enable_if<
|
||||
absl::HasOstreamOperator<T>::value, int>::type = 0>
|
||||
std::ostream& operator<<(std::ostream& os, const StatusOr<T>& status_or) {
|
||||
if (status_or.ok()) {
|
||||
os << status_or.value();
|
||||
} else {
|
||||
os << internal_statusor::StringifyRandom::OpenBrackets()
|
||||
<< status_or.status()
|
||||
<< internal_statusor::StringifyRandom::CloseBrackets();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
// As above, but supports `StrCat`, `StrFormat`, etc.
|
||||
//
|
||||
// Requires `T` has `AbslStringify`. Do not rely on the output format which
|
||||
// may change without notice.
|
||||
template <
|
||||
typename Sink, typename T,
|
||||
typename std::enable_if<absl::HasAbslStringify<T>::value, int>::type = 0>
|
||||
void AbslStringify(Sink& sink, const StatusOr<T>& status_or) {
|
||||
if (status_or.ok()) {
|
||||
absl::Format(&sink, "%v", status_or.value());
|
||||
} else {
|
||||
absl::Format(&sink, "%s%v%s",
|
||||
internal_statusor::StringifyRandom::OpenBrackets(),
|
||||
status_or.status(),
|
||||
internal_statusor::StringifyRandom::CloseBrackets());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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>
|
||||
absl::Nonnull<const T*> StatusOr<T>::operator->() const {
|
||||
this->EnsureOk();
|
||||
return &this->data_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
absl::Nonnull<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_
|
||||
1802
TMessagesProj/jni/voip/webrtc/absl/status/statusor_test.cc
Normal file
1802
TMessagesProj/jni/voip/webrtc/absl/status/statusor_test.cc
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue