#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
enum class StatusCode : int {
kOk = 0,
kCancelled = 1,
kUnknown = 2,
kInvalidArgument = 3,
kDeadlineExceeded = 4,
kNotFound = 5,
kAlreadyExists = 6,
kPermissionDenied = 7,
kResourceExhausted = 8,
kFailedPrecondition = 9,
kAborted = 10,
kOutOfRange = 11,
kUnimplemented = 12,
kInternal = 13,
kUnavailable = 14,
kDataLoss = 15,
kUnauthenticated = 16,
kDoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_ = 20
};
std::string StatusCodeToString(StatusCode code);
std::ostream& operator<<(std::ostream& os, StatusCode code);
enum class StatusToStringMode : int {
kWithNoExtraData = 0,
kWithPayload = 1 << 0,
kWithEverything = ~kWithNoExtraData,
kDefault = kWithPayload,
};
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;
}
class ABSL_ATTRIBUTE_TRIVIAL_ABI Status final {
public:
Status();
Status(absl::StatusCode code, absl::string_view msg);
Status(const Status&);
Status& operator=(const Status& x);
Status(Status&&) noexcept;
Status& operator=(Status&&) noexcept;
~Status();
void Update(const Status& new_status);
void Update(Status&& new_status);
ABSL_MUST_USE_RESULT bool ok() const;
absl::StatusCode code() const;
int raw_code() const;
absl::string_view message() const;
friend bool operator==(const Status&, const Status&);
friend bool operator!=(const Status&, const Status&);
std::string ToString(
StatusToStringMode mode = StatusToStringMode::kDefault) const;
template <typename Sink>
friend void AbslStringify(Sink& sink, const Status& status) {
sink.Append(status.ToString(StatusToStringMode::kWithEverything));
}
void IgnoreError() const;
friend void swap(Status& a, Status& b) noexcept;
absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
void SetPayload(absl::string_view type_url, absl::Cord payload);
bool ErasePayload(absl::string_view type_url);
void ForEachPayload(
absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor)
const;
private:
friend Status CancelledError();
explicit Status(absl::StatusCode code);
explicit Status(uintptr_t rep) : rep_(rep) {}
static void Ref(uintptr_t rep);
static void Unref(uintptr_t rep);
static absl::Nonnull<status_internal::StatusRep*> PrepareToModify(
uintptr_t rep);
static constexpr const char kMovedFromString[] =
"Status accessed after move.";
static absl::Nonnull<const std::string*> EmptyString();
static absl::Nonnull<const std::string*> MovedFromString();
static constexpr bool IsInlined(uintptr_t rep);
static constexpr bool IsMovedFrom(uintptr_t rep);
static constexpr uintptr_t MovedFromRep();
static constexpr uintptr_t CodeToInlinedRep(absl::StatusCode code);
static constexpr absl::StatusCode InlinedRepToCode(uintptr_t rep);
static uintptr_t PointerToRep(status_internal::StatusRep* r);
static absl::Nonnull<const status_internal::StatusRep*> RepToPointer(
uintptr_t r);
static std::string ToStringSlow(uintptr_t rep, StatusToStringMode mode);
uintptr_t rep_;
friend class status_internal::StatusRep;
};
Status OkStatus();
std::ostream& operator<<(std::ostream& os, const Status& x);
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);
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);
absl::StatusCode ErrnoToStatusCode(int error_number);
Status ErrnoToStatus(int error_number, absl::string_view message);
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 {
}
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(); }
inline Status CancelledError() { return Status(absl::StatusCode::kCancelled); }
absl::Nonnull<const char*> StatusMessageAsCStr(
const Status& status ABSL_ATTRIBUTE_LIFETIME_BOUND);
ABSL_NAMESPACE_END
}
#endif