|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma once |
|
|
|
#include <cstring> |
|
#include <iosfwd> |
|
#include <memory> |
|
#include <string> |
|
#include <utility> |
|
|
|
#include "arrow/util/compare.h" |
|
#include "arrow/util/macros.h" |
|
#include "arrow/util/string_builder.h" |
|
#include "arrow/util/visibility.h" |
|
|
|
#ifdef ARROW_EXTRA_ERROR_CONTEXT |
|
|
|
|
|
# define ARROW_RETURN_IF_(condition, status, expr) \ |
|
do { \ |
|
if (ARROW_PREDICT_FALSE(condition)) { \ |
|
::arrow::Status _st = (status); \ |
|
_st.AddContextLine(__FILE__, __LINE__, expr); \ |
|
return _st; \ |
|
} \ |
|
} while (0) |
|
|
|
#else |
|
|
|
# define ARROW_RETURN_IF_(condition, status, _) \ |
|
do { \ |
|
if (ARROW_PREDICT_FALSE(condition)) { \ |
|
return (status); \ |
|
} \ |
|
} while (0) |
|
|
|
#endif |
|
|
|
#define ARROW_RETURN_IF(condition, status) \ |
|
ARROW_RETURN_IF_(condition, status, ARROW_STRINGIFY(status)) |
|
|
|
|
|
#define ARROW_RETURN_NOT_OK(status) \ |
|
do { \ |
|
::arrow::Status __s = ::arrow::internal::GenericToStatus(status); \ |
|
ARROW_RETURN_IF_(!__s.ok(), __s, ARROW_STRINGIFY(status)); \ |
|
} while (false) |
|
|
|
|
|
#define ARROW_WARN_NOT_OK(expr, warn_msg) \ |
|
do { \ |
|
::arrow::Status _s = (expr); \ |
|
if (ARROW_PREDICT_FALSE(!_s.ok())) { \ |
|
_s.Warn(warn_msg); \ |
|
} \ |
|
} while (false) |
|
|
|
#define RETURN_NOT_OK_ELSE(s, else_) \ |
|
do { \ |
|
::arrow::Status _s = ::arrow::internal::GenericToStatus(s); \ |
|
if (!_s.ok()) { \ |
|
else_; \ |
|
return _s; \ |
|
} \ |
|
} while (false) |
|
|
|
|
|
#ifndef RETURN_NOT_OK |
|
# define RETURN_NOT_OK(s) ARROW_RETURN_NOT_OK(s) |
|
#endif |
|
|
|
namespace arrow { |
|
namespace internal { |
|
class StatusConstant; |
|
} |
|
|
|
enum class StatusCode : char { |
|
OK = 0, |
|
OutOfMemory = 1, |
|
KeyError = 2, |
|
TypeError = 3, |
|
Invalid = 4, |
|
IOError = 5, |
|
CapacityError = 6, |
|
IndexError = 7, |
|
Cancelled = 8, |
|
UnknownError = 9, |
|
NotImplemented = 10, |
|
SerializationError = 11, |
|
RError = 13, |
|
|
|
CodeGenError = 40, |
|
ExpressionValidationError = 41, |
|
ExecutionError = 42, |
|
|
|
AlreadyExists = 45 |
|
}; |
|
|
|
|
|
|
|
class ARROW_EXPORT StatusDetail { |
|
public: |
|
virtual ~StatusDetail() = default; |
|
|
|
|
|
virtual const char* type_id() const = 0; |
|
|
|
virtual std::string ToString() const = 0; |
|
|
|
bool operator==(const StatusDetail& other) const noexcept { |
|
return std::string(type_id()) == other.type_id() && ToString() == other.ToString(); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ARROW_EXPORT [[nodiscard]] Status : public util::EqualityComparable<Status>, |
|
public util::ToStringOstreamable<Status> { |
|
public: |
|
|
|
constexpr Status() noexcept : state_(NULLPTR) {} |
|
~Status() noexcept { |
|
if (ARROW_PREDICT_FALSE(state_ != NULL)) { |
|
if (!state_->is_constant) { |
|
DeleteState(); |
|
} |
|
} |
|
} |
|
|
|
Status(StatusCode code, const std::string& msg); |
|
|
|
Status(StatusCode code, std::string msg, std::shared_ptr<StatusDetail> detail); |
|
|
|
|
|
inline Status(const Status& s); |
|
inline Status& operator=(const Status& s); |
|
|
|
|
|
inline Status(Status&& s) noexcept; |
|
inline Status& operator=(Status&& s) noexcept; |
|
|
|
inline bool Equals(const Status& s) const; |
|
|
|
|
|
inline Status operator&(const Status& s) const noexcept; |
|
inline Status operator&(Status&& s) const noexcept; |
|
inline Status& operator&=(const Status& s) noexcept; |
|
inline Status& operator&=(Status&& s) noexcept; |
|
|
|
|
|
static Status OK() { return Status(); } |
|
|
|
template <typename... Args> |
|
static Status FromArgs(StatusCode code, Args&&... args) { |
|
return Status(code, util::StringBuilder(std::forward<Args>(args)...)); |
|
} |
|
|
|
template <typename... Args> |
|
static Status FromDetailAndArgs(StatusCode code, std::shared_ptr<StatusDetail> detail, |
|
Args&&... args) { |
|
return Status(code, util::StringBuilder(std::forward<Args>(args)...), |
|
std::move(detail)); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status OutOfMemory(Args&&... args) { |
|
return Status::FromArgs(StatusCode::OutOfMemory, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status KeyError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::KeyError, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status TypeError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::TypeError, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status UnknownError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::UnknownError, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
|
|
template <typename... Args> |
|
static Status NotImplemented(Args&&... args) { |
|
return Status::FromArgs(StatusCode::NotImplemented, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status Invalid(Args&&... args) { |
|
return Status::FromArgs(StatusCode::Invalid, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status Cancelled(Args&&... args) { |
|
return Status::FromArgs(StatusCode::Cancelled, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status IndexError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::IndexError, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status CapacityError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::CapacityError, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status IOError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::IOError, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
template <typename... Args> |
|
static Status SerializationError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::SerializationError, std::forward<Args>(args)...); |
|
} |
|
|
|
template <typename... Args> |
|
static Status RError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::RError, std::forward<Args>(args)...); |
|
} |
|
|
|
template <typename... Args> |
|
static Status CodeGenError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::CodeGenError, std::forward<Args>(args)...); |
|
} |
|
|
|
template <typename... Args> |
|
static Status ExpressionValidationError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::ExpressionValidationError, |
|
std::forward<Args>(args)...); |
|
} |
|
|
|
template <typename... Args> |
|
static Status ExecutionError(Args&&... args) { |
|
return Status::FromArgs(StatusCode::ExecutionError, std::forward<Args>(args)...); |
|
} |
|
|
|
template <typename... Args> |
|
static Status AlreadyExists(Args&&... args) { |
|
return Status::FromArgs(StatusCode::AlreadyExists, std::forward<Args>(args)...); |
|
} |
|
|
|
|
|
constexpr bool ok() const { return (state_ == NULLPTR); } |
|
|
|
|
|
constexpr bool IsOutOfMemory() const { return code() == StatusCode::OutOfMemory; } |
|
|
|
constexpr bool IsKeyError() const { return code() == StatusCode::KeyError; } |
|
|
|
constexpr bool IsInvalid() const { return code() == StatusCode::Invalid; } |
|
|
|
constexpr bool IsCancelled() const { return code() == StatusCode::Cancelled; } |
|
|
|
constexpr bool IsIOError() const { return code() == StatusCode::IOError; } |
|
|
|
constexpr bool IsCapacityError() const { return code() == StatusCode::CapacityError; } |
|
|
|
constexpr bool IsIndexError() const { return code() == StatusCode::IndexError; } |
|
|
|
constexpr bool IsTypeError() const { return code() == StatusCode::TypeError; } |
|
|
|
constexpr bool IsUnknownError() const { return code() == StatusCode::UnknownError; } |
|
|
|
constexpr bool IsNotImplemented() const { return code() == StatusCode::NotImplemented; } |
|
|
|
constexpr bool IsSerializationError() const { |
|
return code() == StatusCode::SerializationError; |
|
} |
|
|
|
constexpr bool IsRError() const { return code() == StatusCode::RError; } |
|
|
|
constexpr bool IsCodeGenError() const { return code() == StatusCode::CodeGenError; } |
|
|
|
constexpr bool IsExpressionValidationError() const { |
|
return code() == StatusCode::ExpressionValidationError; |
|
} |
|
|
|
constexpr bool IsExecutionError() const { return code() == StatusCode::ExecutionError; } |
|
constexpr bool IsAlreadyExists() const { return code() == StatusCode::AlreadyExists; } |
|
|
|
|
|
|
|
|
|
std::string ToString() const; |
|
|
|
|
|
|
|
|
|
|
|
std::string ToStringWithoutContextLines() const; |
|
|
|
|
|
|
|
std::string CodeAsString() const; |
|
static std::string CodeAsString(StatusCode); |
|
|
|
|
|
constexpr StatusCode code() const { return ok() ? StatusCode::OK : state_->code; } |
|
|
|
|
|
const std::string& message() const; |
|
|
|
|
|
const std::shared_ptr<StatusDetail>& detail() const; |
|
|
|
|
|
|
|
Status WithDetail(std::shared_ptr<StatusDetail> new_detail) const { |
|
return Status(code(), message(), std::move(new_detail)); |
|
} |
|
|
|
|
|
|
|
template <typename... Args> |
|
Status WithMessage(Args&&... args) const { |
|
return FromArgs(code(), std::forward<Args>(args)...).WithDetail(detail()); |
|
} |
|
|
|
void Warn() const; |
|
void Warn(const std::string& message) const; |
|
|
|
[[noreturn]] void Abort() const; |
|
[[noreturn]] void Abort(const std::string& message) const; |
|
|
|
#ifdef ARROW_EXTRA_ERROR_CONTEXT |
|
void AddContextLine(const char* filename, int line, const char* expr); |
|
#endif |
|
|
|
private: |
|
struct State { |
|
StatusCode code; |
|
bool is_constant; |
|
std::string msg; |
|
std::shared_ptr<StatusDetail> detail; |
|
}; |
|
|
|
|
|
State* state_; |
|
|
|
void DeleteState() noexcept { |
|
|
|
|
|
delete state_; |
|
} |
|
void CopyFrom(const Status& s); |
|
inline void MoveFrom(Status& s); |
|
|
|
friend class internal::StatusConstant; |
|
}; |
|
|
|
void Status::MoveFrom(Status& s) { |
|
if (ARROW_PREDICT_FALSE(state_ != NULL)) { |
|
if (!state_->is_constant) { |
|
DeleteState(); |
|
} |
|
} |
|
state_ = s.state_; |
|
s.state_ = NULLPTR; |
|
} |
|
|
|
Status::Status(const Status& s) : state_{NULLPTR} { CopyFrom(s); } |
|
|
|
Status& Status::operator=(const Status& s) { |
|
|
|
|
|
if (state_ != s.state_) { |
|
CopyFrom(s); |
|
} |
|
return *this; |
|
} |
|
|
|
Status::Status(Status&& s) noexcept : state_(s.state_) { s.state_ = NULLPTR; } |
|
|
|
Status& Status::operator=(Status&& s) noexcept { |
|
MoveFrom(s); |
|
return *this; |
|
} |
|
|
|
bool Status::Equals(const Status& s) const { |
|
if (state_ == s.state_) { |
|
return true; |
|
} |
|
|
|
if (ok() || s.ok()) { |
|
return false; |
|
} |
|
|
|
if (detail() != s.detail()) { |
|
if ((detail() && !s.detail()) || (!detail() && s.detail())) { |
|
return false; |
|
} |
|
return *detail() == *s.detail(); |
|
} |
|
|
|
return code() == s.code() && message() == s.message(); |
|
} |
|
|
|
|
|
|
|
|
|
Status Status::operator&(const Status& s) const noexcept { |
|
if (ok()) { |
|
return s; |
|
} else { |
|
return *this; |
|
} |
|
} |
|
|
|
Status Status::operator&(Status&& s) const noexcept { |
|
if (ok()) { |
|
return std::move(s); |
|
} else { |
|
return *this; |
|
} |
|
} |
|
|
|
Status& Status::operator&=(const Status& s) noexcept { |
|
if (ok() && !s.ok()) { |
|
CopyFrom(s); |
|
} |
|
return *this; |
|
} |
|
|
|
Status& Status::operator&=(Status&& s) noexcept { |
|
if (ok() && !s.ok()) { |
|
MoveFrom(s); |
|
} |
|
return *this; |
|
} |
|
|
|
|
|
namespace internal { |
|
|
|
|
|
|
|
inline const Status& GenericToStatus(const Status& st) { return st; } |
|
inline Status GenericToStatus(Status&& st) { return std::move(st); } |
|
|
|
} |
|
|
|
} |
|
|