1 #ifndef ANDROID_PDX_STATUS_H_ 2 #define ANDROID_PDX_STATUS_H_ 3 4 #include <algorithm> 5 #include <memory> 6 #include <string> 7 8 namespace android { 9 namespace pdx { 10 11 // This is a helper class for constructing Status<T> with an error code. 12 struct ErrorStatus { 13 public: 14 ErrorStatus(int error) : error_{error} {} 15 int error() const { return error_; } 16 17 static std::string ErrorToString(int error_code); 18 19 private: 20 int error_; 21 }; 22 23 // Status<T> is a container class that can be used to return a value of type T 24 // or error code to the caller. 25 template <typename T> 26 class Status { 27 public: 28 // Default constructor so an empty Status object can be created. 29 Status() : error_{-1} {} 30 31 // Value copy/move constructors. These are intentionally not marked as 32 // explicit to allow direct value returns from functions without having 33 // to explicitly wrap them into Status<T>(). 34 Status(const T& value) : value_{value} {} // NOLINT(runtime/explicit) 35 Status(T&& value) : value_{std::move(value)} {} // NOLINT(runtime/explicit) 36 37 // Constructor for storing an error code inside the Status object. 38 Status(const ErrorStatus& error_status) // NOLINT(runtime/explicit) 39 : error_{error_status.error()} {} 40 41 // Copy/move constructors. Move constructor leaves |other| object in empty 42 // state. 43 Status(const Status& other) = default; 44 Status(Status&& other) 45 : value_{std::move(other.value_)}, error_{other.error_} { 46 other.error_ = -1; 47 } 48 49 // Assignment operators. 50 Status& operator=(const Status& other) = default; 51 Status& operator=(Status&& other) { 52 error_ = other.error_; 53 value_ = std::move(other.value_); 54 other.error_ = -1; 55 T empty; 56 std::swap(other.value_, empty); 57 return *this; 58 } 59 60 // Change the value/error code of the status object directly. 61 void SetValue(T value) { 62 error_ = 0; 63 value_ = std::move(value); 64 } 65 void SetError(int error) { 66 error_ = error; 67 T empty; 68 std::swap(value_, empty); 69 } 70 71 // If |other| is in error state, copy the error code to this object. 72 // Returns true if error was propagated 73 template<typename U> 74 bool PropagateError(const Status<U>& other) { 75 if (!other.ok() && !other.empty()) { 76 SetError(other.error()); 77 return true; 78 } 79 return false; 80 } 81 82 // Returns true if the status object contains valid value for type T. 83 // This means, the object is not empty and does not contain an error code. 84 bool ok() const { return error_ == 0; } 85 86 // Checks if the object is empty (doesn't contain a valid value nor an error). 87 bool empty() const { return error_ < 0; } 88 89 // Explicit bool conversion, equivalent to invoking ok(). 90 explicit operator bool() const { return ok(); } 91 92 // Accessors for the value stored in Status. Calling when ok() is false leads 93 // to undefined behavior. 94 const T& get() const { return value_; } 95 T&& take() { 96 error_ = -1; 97 return std::move(value_); 98 } 99 100 // Returns the error code stored in the object. These codes are positive 101 // non-zero values. 102 // Can be called only when an error is actually stored (that is, the object 103 // is not empty nor containing a valid value). 104 int error() const { return std::max(error_, 0); } 105 106 // Returns the error code as ErrorStatus object. This is a helper method 107 // to aid in propagation of error codes between Status<T> of different types 108 // as in the following example: 109 // Status<int> foo() { 110 // Status<void> status = bar(); 111 // if(!status) 112 // return status.error_status(); 113 // return 12; 114 // } 115 inline ErrorStatus error_status() const { return ErrorStatus{error()}; } 116 117 // Returns the error message associated with error code stored in the object. 118 // The message is the same as the string returned by strerror(status.error()). 119 // Can be called only when an error is actually stored (that is, the object 120 // is not empty nor containing a valid value). 121 std::string GetErrorMessage() const { 122 std::string message; 123 if (error_ > 0) 124 message = ErrorStatus::ErrorToString(error_); 125 return message; 126 } 127 128 private: 129 T value_{}; 130 int error_{0}; 131 }; 132 133 // Specialization for status containing no other value but the error code. 134 template <> 135 class Status<void> { 136 public: 137 Status() = default; 138 Status(const ErrorStatus& error_status) // NOLINT(runtime/explicit) 139 : error_{error_status.error()} {} 140 void SetValue() { error_ = 0; } 141 void SetError(int error) { error_ = error; } 142 143 template<typename U> 144 bool PropagateError(const Status<U>& other) { 145 if (!other.ok() && !other.empty()) { 146 SetError(other.error()); 147 return true; 148 } 149 return false; 150 } 151 152 bool ok() const { return error_ == 0; } 153 bool empty() const { return false; } 154 explicit operator bool() const { return ok(); } 155 int error() const { return std::max(error_, 0); } 156 inline ErrorStatus error_status() const { return ErrorStatus{error()}; } 157 std::string GetErrorMessage() const { 158 std::string message; 159 if (error_ > 0) 160 message = ErrorStatus::ErrorToString(error_); 161 return message; 162 } 163 164 private: 165 int error_{0}; 166 }; 167 168 // TODO(avakulenko): Remove these function once all callers of it are gone. 169 inline int ReturnStatusOrError(const Status<void>& status) { 170 return status ? 0 : -status.error(); 171 } 172 173 inline int ReturnStatusOrError(const Status<int>& status) { 174 return status ? status.get() : -status.error(); 175 } 176 177 } // namespace pdx 178 } // namespace android 179 180 #endif // ANDROID_PDX_STATUS_H_ 181