/** * @file : status_or * @created : Thursday Feb 01, 2024 18:04:44 CST * @license : MIT **/ #pragma once #ifndef SLED_STATUS_OR_H #define SLED_STATUS_OR_H #include "sled/optional.h" #include "sled/status.h" #include #include namespace sled { template class StatusOr final { public: static_assert(!std::is_reference::value, "StatusOr requires T to **not** be a reference type"); using value_type = T; StatusOr() : StatusOr(MakeDefaultStatus()) {} StatusOr(StatusOr const &) = default; StatusOr &operator=(StatusOr const &) = default; StatusOr(StatusOr &&other) : status_(std::move(other.status_)), value_(std::move(other.value_)) { other.status_ = MakeDefaultStatus(); } StatusOr &operator=(StatusOr &&other) { status_ = std::move(other.status_); value_ = std::move(other.value_); other.status_ = MakeDefaultStatus(); return *this; } StatusOr(Status rhs) : status_(std::move(rhs)) { if (status_.ok()) { throw std::invalid_argument("Status::OK is not a valid argument to StatusOr"); } } StatusOr &operator=(Status status) { *this = StatusOr(std::move(status)); return *this; } template::type>::value, int>::type = 0 /// @code end > StatusOr &operator=(U &&rhs) { status_ = Status(); value_ = std::forward(rhs); return *this; } StatusOr(T &&rhs) : value_(std::move(rhs)) {} StatusOr(T const &rhs) : value_(rhs) {} bool ok() const { return status_.ok(); } explicit operator bool() const { return status_.ok(); } T &operator*() & { return *value_; } T const &operator*() const & { return *value_; } T &&operator*() && { return *std::move(value_); } T const &&operator*() const && { return *std::move(value_); } T *operator->() & { return &*value_; } T const *operator->() const & { return &*value_; } T &value() & { CheckHasValue(); return **this; } T const &value() const & { CheckHasValue(); return **this; } T &&value() && { CheckHasValue(); return std::move(**this); } T const &&value() const && { CheckHasValue(); return std::move(**this); } T &value_or(T &&val) & { if (!ok()) return val; return **this; } T const &value_or(T &&val) const & { if (!ok()) return val; return **this; } T &&value_or(T &&val) && { if (!ok()) return std::forward(val); return std::move(**this); } T const &&value_or(T &&val) const && { if (!ok()) return std::forward(val); return std::move(**this); } Status const &status() const & { return status_; } Status &&status() && { return std::move(status_); } private: static Status MakeDefaultStatus() { return Status{StatusCode::kUnknown, "default"}; } void CheckHasValue() const & { if (!ok()) { throw std::invalid_argument("no value"); } } Status status_; sled::optional value_; }; template bool operator==(StatusOr const &a, StatusOr const &b) { if (!a || !b) return a.status() == b.status(); } template bool operator!=(StatusOr const &a, StatusOr const &b) { return !(a == b); } template StatusOr make_status_or(T rhs) { return StatusOr(std::move(rhs)); } template StatusOr make_status_or(StatusCode code, std::string message = "", ErrorInfo info = {}) { return StatusOr(Status(code, std::move(message))); } }// namespace sled #endif// SLED_STATUS_OR_H