1 //===- Optional.h - Simple variant for passing optional values --*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file provides Optional, a template class modeled in the spirit of 11 // OCaml's 'opt' variant. The idea is to strongly type whether or not 12 // a value can be optional. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_ADT_OPTIONAL_H 17 #define LLVM_ADT_OPTIONAL_H 18 19 #include "llvm/ADT/None.h" 20 #include "llvm/Support/AlignOf.h" 21 #include "llvm/Support/Compiler.h" 22 #include "llvm/Support/type_traits.h" 23 #include <algorithm> 24 #include <cassert> 25 #include <new> 26 #include <utility> 27 28 namespace llvm { 29 30 template<typename T> 31 class Optional { 32 AlignedCharArrayUnion<T> storage; 33 bool hasVal = false; 34 35 public: 36 using value_type = T; 37 38 Optional(NoneType) {} 39 explicit Optional() {} 40 41 Optional(const T &y) : hasVal(true) { 42 new (storage.buffer) T(y); 43 } 44 45 Optional(const Optional &O) : hasVal(O.hasVal) { 46 if (hasVal) 47 new (storage.buffer) T(*O); 48 } 49 50 Optional(T &&y) : hasVal(true) { 51 new (storage.buffer) T(std::forward<T>(y)); 52 } 53 54 Optional(Optional<T> &&O) : hasVal(O) { 55 if (O) { 56 new (storage.buffer) T(std::move(*O)); 57 O.reset(); 58 } 59 } 60 61 ~Optional() { 62 reset(); 63 } 64 65 Optional &operator=(T &&y) { 66 if (hasVal) 67 **this = std::move(y); 68 else { 69 new (storage.buffer) T(std::move(y)); 70 hasVal = true; 71 } 72 return *this; 73 } 74 75 Optional &operator=(Optional &&O) { 76 if (!O) 77 reset(); 78 else { 79 *this = std::move(*O); 80 O.reset(); 81 } 82 return *this; 83 } 84 85 /// Create a new object by constructing it in place with the given arguments. 86 template<typename ...ArgTypes> 87 void emplace(ArgTypes &&...Args) { 88 reset(); 89 hasVal = true; 90 new (storage.buffer) T(std::forward<ArgTypes>(Args)...); 91 } 92 93 static inline Optional create(const T* y) { 94 return y ? Optional(*y) : Optional(); 95 } 96 97 // FIXME: these assignments (& the equivalent const T&/const Optional& ctors) 98 // could be made more efficient by passing by value, possibly unifying them 99 // with the rvalue versions above - but this could place a different set of 100 // requirements (notably: the existence of a default ctor) when implemented 101 // in that way. Careful SFINAE to avoid such pitfalls would be required. 102 Optional &operator=(const T &y) { 103 if (hasVal) 104 **this = y; 105 else { 106 new (storage.buffer) T(y); 107 hasVal = true; 108 } 109 return *this; 110 } 111 112 Optional &operator=(const Optional &O) { 113 if (!O) 114 reset(); 115 else 116 *this = *O; 117 return *this; 118 } 119 120 void reset() { 121 if (hasVal) { 122 (**this).~T(); 123 hasVal = false; 124 } 125 } 126 127 const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); } 128 T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); } 129 const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 130 T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 131 132 explicit operator bool() const { return hasVal; } 133 bool hasValue() const { return hasVal; } 134 const T* operator->() const { return getPointer(); } 135 T* operator->() { return getPointer(); } 136 const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 137 T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 138 139 template <typename U> 140 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION { 141 return hasValue() ? getValue() : std::forward<U>(value); 142 } 143 144 #if LLVM_HAS_RVALUE_REFERENCE_THIS 145 T&& getValue() && { assert(hasVal); return std::move(*getPointer()); } 146 T&& operator*() && { assert(hasVal); return std::move(*getPointer()); } 147 148 template <typename U> 149 T getValueOr(U &&value) && { 150 return hasValue() ? std::move(getValue()) : std::forward<U>(value); 151 } 152 #endif 153 }; 154 155 template <typename T> struct isPodLike<Optional<T>> { 156 // An Optional<T> is pod-like if T is. 157 static const bool value = isPodLike<T>::value; 158 }; 159 160 template <typename T, typename U> 161 bool operator==(const Optional<T> &X, const Optional<U> &Y) { 162 if (X && Y) 163 return *X == *Y; 164 return X.hasValue() == Y.hasValue(); 165 } 166 167 template <typename T, typename U> 168 bool operator!=(const Optional<T> &X, const Optional<U> &Y) { 169 return !(X == Y); 170 } 171 172 template <typename T, typename U> 173 bool operator<(const Optional<T> &X, const Optional<U> &Y) { 174 if (X && Y) 175 return *X < *Y; 176 return X.hasValue() < Y.hasValue(); 177 } 178 179 template <typename T, typename U> 180 bool operator<=(const Optional<T> &X, const Optional<U> &Y) { 181 return !(Y < X); 182 } 183 184 template <typename T, typename U> 185 bool operator>(const Optional<T> &X, const Optional<U> &Y) { 186 return Y < X; 187 } 188 189 template <typename T, typename U> 190 bool operator>=(const Optional<T> &X, const Optional<U> &Y) { 191 return !(X < Y); 192 } 193 194 template<typename T> 195 bool operator==(const Optional<T> &X, NoneType) { 196 return !X; 197 } 198 199 template<typename T> 200 bool operator==(NoneType, const Optional<T> &X) { 201 return X == None; 202 } 203 204 template<typename T> 205 bool operator!=(const Optional<T> &X, NoneType) { 206 return !(X == None); 207 } 208 209 template<typename T> 210 bool operator!=(NoneType, const Optional<T> &X) { 211 return X != None; 212 } 213 214 template <typename T> bool operator<(const Optional<T> &X, NoneType) { 215 return false; 216 } 217 218 template <typename T> bool operator<(NoneType, const Optional<T> &X) { 219 return X.hasValue(); 220 } 221 222 template <typename T> bool operator<=(const Optional<T> &X, NoneType) { 223 return !(None < X); 224 } 225 226 template <typename T> bool operator<=(NoneType, const Optional<T> &X) { 227 return !(X < None); 228 } 229 230 template <typename T> bool operator>(const Optional<T> &X, NoneType) { 231 return None < X; 232 } 233 234 template <typename T> bool operator>(NoneType, const Optional<T> &X) { 235 return X < None; 236 } 237 238 template <typename T> bool operator>=(const Optional<T> &X, NoneType) { 239 return None <= X; 240 } 241 242 template <typename T> bool operator>=(NoneType, const Optional<T> &X) { 243 return X <= None; 244 } 245 246 template <typename T> bool operator==(const Optional<T> &X, const T &Y) { 247 return X && *X == Y; 248 } 249 250 template <typename T> bool operator==(const T &X, const Optional<T> &Y) { 251 return Y && X == *Y; 252 } 253 254 template <typename T> bool operator!=(const Optional<T> &X, const T &Y) { 255 return !(X == Y); 256 } 257 258 template <typename T> bool operator!=(const T &X, const Optional<T> &Y) { 259 return !(X == Y); 260 } 261 262 template <typename T> bool operator<(const Optional<T> &X, const T &Y) { 263 return !X || *X < Y; 264 } 265 266 template <typename T> bool operator<(const T &X, const Optional<T> &Y) { 267 return Y && X < *Y; 268 } 269 270 template <typename T> bool operator<=(const Optional<T> &X, const T &Y) { 271 return !(Y < X); 272 } 273 274 template <typename T> bool operator<=(const T &X, const Optional<T> &Y) { 275 return !(Y < X); 276 } 277 278 template <typename T> bool operator>(const Optional<T> &X, const T &Y) { 279 return Y < X; 280 } 281 282 template <typename T> bool operator>(const T &X, const Optional<T> &Y) { 283 return Y < X; 284 } 285 286 template <typename T> bool operator>=(const Optional<T> &X, const T &Y) { 287 return !(X < Y); 288 } 289 290 template <typename T> bool operator>=(const T &X, const Optional<T> &Y) { 291 return !(X < Y); 292 } 293 294 } // end namespace llvm 295 296 #endif // LLVM_ADT_OPTIONAL_H 297