Home | History | Annotate | Download | only in pdx
      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