• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ErrorStatusErrorStatus14   ErrorStatus(int error) : error_{error} {}
errorErrorStatus15   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.
Status()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>().
Status(const T & value)34   Status(const T& value) : value_{value} {}        // NOLINT(runtime/explicit)
Status(T && value)35   Status(T&& value) : value_{std::move(value)} {}  // NOLINT(runtime/explicit)
36 
37   // Constructor for storing an error code inside the Status object.
Status(const ErrorStatus & error_status)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;
Status(Status && other)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.
SetValue(T value)61   void SetValue(T value) {
62     error_ = 0;
63     value_ = std::move(value);
64   }
SetError(int error)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>
PropagateError(const Status<U> & other)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.
ok()84   bool ok() const { return error_ == 0; }
85 
86   // Checks if the object is empty (doesn't contain a valid value nor an error).
empty()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.
get()94   const T& get() const { return value_; }
take()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).
error()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   //    }
error_status()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).
GetErrorMessage()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;
Status(const ErrorStatus & error_status)138   Status(const ErrorStatus& error_status)  // NOLINT(runtime/explicit)
139       : error_{error_status.error()} {}
SetValue()140   void SetValue() { error_ = 0; }
SetError(int error)141   void SetError(int error) { error_ = error; }
142 
143   template<typename U>
PropagateError(const Status<U> & other)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 
ok()152   bool ok() const { return error_ == 0; }
empty()153   bool empty() const { return false; }
154   explicit operator bool() const { return ok(); }
error()155   int error() const { return std::max(error_, 0); }
error_status()156   inline ErrorStatus error_status() const { return ErrorStatus{error()}; }
GetErrorMessage()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.
ReturnStatusOrError(const Status<void> & status)169 inline int ReturnStatusOrError(const Status<void>& status) {
170   return status ? 0 : -status.error();
171 }
172 
ReturnStatusOrError(const Status<int> & status)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