You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
5.5 KiB
184 lines
5.5 KiB
#ifndef ANDROID_PDX_STATUS_H_
|
|
#define ANDROID_PDX_STATUS_H_
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
namespace android {
|
|
namespace pdx {
|
|
|
|
// This is a helper class for constructing Status<T> with an error code.
|
|
struct ErrorStatus {
|
|
public:
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
ErrorStatus(int error) : error_{error} {}
|
|
int error() const { return error_; }
|
|
|
|
static std::string ErrorToString(int error_code);
|
|
|
|
private:
|
|
int error_;
|
|
};
|
|
|
|
// Status<T> is a container class that can be used to return a value of type T
|
|
// or error code to the caller.
|
|
template <typename T>
|
|
class Status {
|
|
public:
|
|
// Default constructor so an empty Status object can be created.
|
|
Status() : error_{-1} {}
|
|
|
|
// Value copy/move constructors. These are intentionally not marked as
|
|
// explicit to allow direct value returns from functions without having
|
|
// to explicitly wrap them into Status<T>().
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
Status(const T& value) : value_{value} {}
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
Status(T&& value) : value_{std::move(value)} {}
|
|
|
|
// Constructor for storing an error code inside the Status object.
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
Status(const ErrorStatus& error_status) : error_{error_status.error()} {}
|
|
|
|
// Copy/move constructors. Move constructor leaves |other| object in empty
|
|
// state.
|
|
Status(const Status& other) = default;
|
|
Status(Status&& other) noexcept
|
|
: value_{std::move(other.value_)}, error_{other.error_} {
|
|
other.error_ = -1;
|
|
}
|
|
|
|
// Assignment operators.
|
|
Status& operator=(const Status& other) = default;
|
|
Status& operator=(Status&& other) noexcept {
|
|
error_ = other.error_;
|
|
value_ = std::move(other.value_);
|
|
other.error_ = -1;
|
|
T empty;
|
|
std::swap(other.value_, empty);
|
|
return *this;
|
|
}
|
|
|
|
// Change the value/error code of the status object directly.
|
|
void SetValue(T value) {
|
|
error_ = 0;
|
|
value_ = std::move(value);
|
|
}
|
|
void SetError(int error) {
|
|
error_ = error;
|
|
T empty;
|
|
std::swap(value_, empty);
|
|
}
|
|
|
|
// If |other| is in error state, copy the error code to this object.
|
|
// Returns true if error was propagated
|
|
template<typename U>
|
|
bool PropagateError(const Status<U>& other) {
|
|
if (!other.ok() && !other.empty()) {
|
|
SetError(other.error());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Returns true if the status object contains valid value for type T.
|
|
// This means, the object is not empty and does not contain an error code.
|
|
bool ok() const { return error_ == 0; }
|
|
|
|
// Checks if the object is empty (doesn't contain a valid value nor an error).
|
|
bool empty() const { return error_ < 0; }
|
|
|
|
// Explicit bool conversion, equivalent to invoking ok().
|
|
explicit operator bool() const { return ok(); }
|
|
|
|
// Accessors for the value stored in Status. Calling when ok() is false leads
|
|
// to undefined behavior.
|
|
const T& get() const { return value_; }
|
|
T&& take() {
|
|
error_ = -1;
|
|
return std::move(value_);
|
|
}
|
|
|
|
// Returns the error code stored in the object. These codes are positive
|
|
// non-zero values.
|
|
// Can be called only when an error is actually stored (that is, the object
|
|
// is not empty nor containing a valid value).
|
|
int error() const { return std::max(error_, 0); }
|
|
|
|
// Returns the error code as ErrorStatus object. This is a helper method
|
|
// to aid in propagation of error codes between Status<T> of different types
|
|
// as in the following example:
|
|
// Status<int> foo() {
|
|
// Status<void> status = bar();
|
|
// if(!status)
|
|
// return status.error_status();
|
|
// return 12;
|
|
// }
|
|
inline ErrorStatus error_status() const { return ErrorStatus{error()}; }
|
|
|
|
// Returns the error message associated with error code stored in the object.
|
|
// The message is the same as the string returned by strerror(status.error()).
|
|
// Can be called only when an error is actually stored (that is, the object
|
|
// is not empty nor containing a valid value).
|
|
std::string GetErrorMessage() const {
|
|
std::string message;
|
|
if (error_ > 0)
|
|
message = ErrorStatus::ErrorToString(error_);
|
|
return message;
|
|
}
|
|
|
|
private:
|
|
T value_{};
|
|
int error_{0};
|
|
};
|
|
|
|
// Specialization for status containing no other value but the error code.
|
|
template <>
|
|
class Status<void> {
|
|
public:
|
|
Status() = default;
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
Status(const ErrorStatus& error_status) : error_{error_status.error()} {}
|
|
void SetValue() { error_ = 0; }
|
|
void SetError(int error) { error_ = error; }
|
|
|
|
template<typename U>
|
|
bool PropagateError(const Status<U>& other) {
|
|
if (!other.ok() && !other.empty()) {
|
|
SetError(other.error());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ok() const { return error_ == 0; }
|
|
bool empty() const { return false; }
|
|
explicit operator bool() const { return ok(); }
|
|
int error() const { return std::max(error_, 0); }
|
|
inline ErrorStatus error_status() const { return ErrorStatus{error()}; }
|
|
std::string GetErrorMessage() const {
|
|
std::string message;
|
|
if (error_ > 0)
|
|
message = ErrorStatus::ErrorToString(error_);
|
|
return message;
|
|
}
|
|
|
|
private:
|
|
int error_{0};
|
|
};
|
|
|
|
// TODO(avakulenko): Remove these function once all callers of it are gone.
|
|
inline int ReturnStatusOrError(const Status<void>& status) {
|
|
return status ? 0 : -status.error();
|
|
}
|
|
|
|
inline int ReturnStatusOrError(const Status<int>& status) {
|
|
return status ? status.get() : -status.error();
|
|
}
|
|
|
|
} // namespace pdx
|
|
} // namespace android
|
|
|
|
#endif // ANDROID_PDX_STATUS_H_
|