/ src / result.hpp
result.hpp
  1  #ifndef RESULT_HPP
  2  #define RESULT_HPP
  3  
  4  #include <assert.h>
  5  
  6  // enum to tag the Result as Ok or Err
  7  enum ResultTag {
  8      OK,
  9      ERR
 10  };
 11  
 12  template <typename T, typename E>
 13  struct Result {
 14  private:
 15      ResultTag tag;
 16  
 17      T ok_value;
 18      E err_value;
 19  
 20      // private constructor to enforce Ok/Err creation
 21      Result() {}
 22  
 23      void destroy()
 24      {
 25          switch (tag) {
 26          case OK: {
 27              ok_value.~T();
 28          } break;
 29          case ERR: {
 30              err_value.~E();
 31          } break;
 32          }
 33      }
 34  
 35  public:
 36      // constructor for ok(t)
 37      static Result Ok(const T& value)
 38      {
 39          Result result;
 40          result.tag = OK;
 41          new (&result.ok_value) T(value);
 42          return result;
 43      }
 44  
 45      // constructor for Err(E)
 46      static Result Err(const E& error)
 47      {
 48          Result result;
 49          result.tag = ERR;
 50          new (&result.err_value) E(error);
 51          return result;
 52      }
 53  
 54      // copy constructor
 55      Result(const Result& other) :
 56          tag(other.tag)
 57      {
 58          switch (tag) {
 59          case OK: {
 60              new (&ok_value) T(other.ok_value);
 61          } break;
 62          case ERR: {
 63              new (&err_value) E(other.err_value);
 64          } break;
 65          default: assert(0 && "UNREACHABLE");
 66          }
 67      }
 68  
 69      // assignment operator
 70      Result& operator=(const Result& other)
 71      {
 72          if (this != &other) {
 73              destroy();
 74              tag = other.tag;
 75  
 76              switch (tag) {
 77              case OK: {
 78                  new (&ok_value) T(other.ok_value);
 79              } break;
 80              case ERR: {
 81                  new (&err_value) E(other.err_value);
 82              } break;
 83              default: assert(0 && "UNREACHABLE");
 84              }
 85          }
 86          return *this;
 87      }
 88  
 89      // destructor
 90      ~Result()
 91      {
 92          destroy();
 93      }
 94  
 95      // check if the Result is Ok
 96      bool is_ok() const
 97      {
 98          return tag == OK;
 99      }
100  
101      // check if the Result is Err
102      bool is_err() const
103      {
104          return tag == ERR;
105      }
106  
107      // unwrap the Ok value, or throw an exception if Err
108      T unwrap() const
109      {
110          switch (tag) {
111          case OK: {
112              return ok_value;
113          } break;
114          case ERR: {
115              throw err_value;
116          } break;
117          default: assert(0 && "UNREACHABLE");
118          }
119      }
120  
121      // unwrap the Ok value, or throw an exception with a message if Err
122      T expect(const char* message) const
123      {
124          switch (tag) {
125          case OK: {
126              return ok_value;
127          } break;
128          case ERR: {
129              throw message;
130          } break;
131          default: assert(0 && "UNREACHABLE");
132          }
133      }
134  
135      // get Ok value if present, else default value
136      T unwrap_or(const T& default_value) const
137      {
138          switch (tag) {
139          case OK: {
140              return ok_value;
141          } break;
142          case ERR: {
143              return default_value;
144          } break;
145          default: assert(0 && "UNREACHABLE");
146          }
147      }
148  };
149  
150  template <typename T>
151  struct Ok {
152      T value;
153      Ok(const T& val) : value(val) {}
154  };
155  
156  template <typename E>
157  struct Err {
158      E value;
159      Err(const E& val) : value(val) {}
160  };
161  
162  #endif // RESULT_HPP
163