blob: ca2832c2a5d5c55da2153937e048e6125f87b9e0 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#ifndef ANDROID_PDX_STATUS_H_
2#define ANDROID_PDX_STATUS_H_
3
4#include <algorithm>
5#include <memory>
6#include <string>
7
8namespace android {
9namespace pdx {
10
11// This is a helper class for constructing Status<T> with an error code.
12struct 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.
25template <typename T>
26class 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 message associated with error code stored in the object.
107 // The message is the same as the string returned by strerror(status.error()).
108 // Can be called only when an error is actually stored (that is, the object
109 // is not empty nor containing a valid value).
110 std::string GetErrorMessage() const {
111 std::string message;
112 if (error_ > 0)
113 message = ErrorStatus::ErrorToString(error_);
114 return message;
115 }
116
117 private:
118 T value_{};
119 int error_{0};
120};
121
122// Specialization for status containing no other value but the error code.
123template <>
124class Status<void> {
125 public:
126 Status() = default;
127 Status(const ErrorStatus& error_status) // NOLINT(runtime/explicit)
128 : error_{error_status.error()} {}
129 void SetValue() { error_ = 0; }
130 void SetError(int error) { error_ = error; }
131
132 template<typename U>
133 bool PropagateError(const Status<U>& other) {
134 if (!other.ok() && !other.empty()) {
135 SetError(other.error());
136 return true;
137 }
138 return false;
139 }
140
141 bool ok() const { return error_ == 0; }
142 bool empty() const { return false; }
143 explicit operator bool() const { return ok(); }
144 int error() const { return std::max(error_, 0); }
145 std::string GetErrorMessage() const {
146 std::string message;
147 if (error_ > 0)
148 message = ErrorStatus::ErrorToString(error_);
149 return message;
150 }
151
152 private:
153 int error_{0};
154};
155
156// TODO(avakulenko): Remove these function once all callers of it are gone.
157inline int ReturnStatusOrError(const Status<void>& status) {
158 return status ? 0 : -status.error();
159}
160
161inline int ReturnStatusOrError(const Status<int>& status) {
162 return status ? status.get() : -status.error();
163}
164
165} // namespace pdx
166} // namespace android
167
168#endif // ANDROID_PDX_STATUS_H_