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