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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue