Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 14:04:28 +01:00
parent 81b91f4139
commit f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions

View file

@ -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

View file

@ -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_

View file

@ -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

View file

@ -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_

View file

@ -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_