1 //===- Optional.h - Simple variant for passing optional values --*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides Optional, a template class modeled in the spirit of 10 // OCaml's 'opt' variant. The idea is to strongly type whether or not 11 // a value can be optional. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_ADT_OPTIONAL_H 16 #define LLVM_ADT_OPTIONAL_H 17 18 #include "llvm/ADT/None.h" 19 #include "llvm/Support/Compiler.h" 20 #include "llvm/Support/type_traits.h" 21 #include <cassert> 22 #include <memory> 23 #include <new> 24 #include <utility> 25 26 namespace llvm { 27 28 class raw_ostream; 29 30 namespace optional_detail { 31 32 struct in_place_t {}; 33 34 /// Storage for any type. 35 template <typename T, bool = is_trivially_copyable<T>::value> 36 class OptionalStorage { 37 union { 38 char empty; 39 T value; 40 }; 41 bool hasVal; 42 43 public: ~OptionalStorage()44 ~OptionalStorage() { reset(); } 45 OptionalStorage()46 OptionalStorage() noexcept : empty(), hasVal(false) {} 47 OptionalStorage(OptionalStorage const & other)48 OptionalStorage(OptionalStorage const &other) : OptionalStorage() { 49 if (other.hasValue()) { 50 emplace(other.value); 51 } 52 } OptionalStorage(OptionalStorage && other)53 OptionalStorage(OptionalStorage &&other) : OptionalStorage() { 54 if (other.hasValue()) { 55 emplace(std::move(other.value)); 56 } 57 } 58 59 template <class... Args> OptionalStorage(in_place_t,Args &&...args)60 explicit OptionalStorage(in_place_t, Args &&... args) 61 : value(std::forward<Args>(args)...), hasVal(true) {} 62 reset()63 void reset() noexcept { 64 if (hasVal) { 65 value.~T(); 66 hasVal = false; 67 } 68 } 69 hasValue()70 bool hasValue() const noexcept { return hasVal; } 71 getValue()72 T &getValue() LLVM_LVALUE_FUNCTION noexcept { 73 assert(hasVal); 74 return value; 75 } getValue()76 T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { 77 assert(hasVal); 78 return value; 79 } 80 #if LLVM_HAS_RVALUE_REFERENCE_THIS getValue()81 T &&getValue() && noexcept { 82 assert(hasVal); 83 return std::move(value); 84 } 85 #endif 86 emplace(Args &&...args)87 template <class... Args> void emplace(Args &&... args) { 88 reset(); 89 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); 90 hasVal = true; 91 } 92 93 OptionalStorage &operator=(T const &y) { 94 if (hasValue()) { 95 value = y; 96 } else { 97 ::new ((void *)std::addressof(value)) T(y); 98 hasVal = true; 99 } 100 return *this; 101 } 102 OptionalStorage &operator=(T &&y) { 103 if (hasValue()) { 104 value = std::move(y); 105 } else { 106 ::new ((void *)std::addressof(value)) T(std::move(y)); 107 hasVal = true; 108 } 109 return *this; 110 } 111 112 OptionalStorage &operator=(OptionalStorage const &other) { 113 if (other.hasValue()) { 114 if (hasValue()) { 115 value = other.value; 116 } else { 117 ::new ((void *)std::addressof(value)) T(other.value); 118 hasVal = true; 119 } 120 } else { 121 reset(); 122 } 123 return *this; 124 } 125 126 OptionalStorage &operator=(OptionalStorage &&other) { 127 if (other.hasValue()) { 128 if (hasValue()) { 129 value = std::move(other.value); 130 } else { 131 ::new ((void *)std::addressof(value)) T(std::move(other.value)); 132 hasVal = true; 133 } 134 } else { 135 reset(); 136 } 137 return *this; 138 } 139 }; 140 141 template <typename T> class OptionalStorage<T, true> { 142 union { 143 char empty; 144 T value; 145 }; 146 bool hasVal = false; 147 148 public: 149 ~OptionalStorage() = default; 150 OptionalStorage()151 OptionalStorage() noexcept : empty{} {} 152 153 OptionalStorage(OptionalStorage const &other) = default; 154 OptionalStorage(OptionalStorage &&other) = default; 155 156 OptionalStorage &operator=(OptionalStorage const &other) = default; 157 OptionalStorage &operator=(OptionalStorage &&other) = default; 158 159 template <class... Args> OptionalStorage(in_place_t,Args &&...args)160 explicit OptionalStorage(in_place_t, Args &&... args) 161 : value(std::forward<Args>(args)...), hasVal(true) {} 162 reset()163 void reset() noexcept { 164 if (hasVal) { 165 value.~T(); 166 hasVal = false; 167 } 168 } 169 hasValue()170 bool hasValue() const noexcept { return hasVal; } 171 getValue()172 T &getValue() LLVM_LVALUE_FUNCTION noexcept { 173 assert(hasVal); 174 return value; 175 } getValue()176 T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { 177 assert(hasVal); 178 return value; 179 } 180 #if LLVM_HAS_RVALUE_REFERENCE_THIS getValue()181 T &&getValue() && noexcept { 182 assert(hasVal); 183 return std::move(value); 184 } 185 #endif 186 emplace(Args &&...args)187 template <class... Args> void emplace(Args &&... args) { 188 reset(); 189 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); 190 hasVal = true; 191 } 192 193 OptionalStorage &operator=(T const &y) { 194 if (hasValue()) { 195 value = y; 196 } else { 197 ::new ((void *)std::addressof(value)) T(y); 198 hasVal = true; 199 } 200 return *this; 201 } 202 OptionalStorage &operator=(T &&y) { 203 if (hasValue()) { 204 value = std::move(y); 205 } else { 206 ::new ((void *)std::addressof(value)) T(std::move(y)); 207 hasVal = true; 208 } 209 return *this; 210 } 211 }; 212 213 } // namespace optional_detail 214 215 template <typename T> class Optional { 216 optional_detail::OptionalStorage<T> Storage; 217 218 public: 219 using value_type = T; 220 Optional()221 constexpr Optional() {} Optional(NoneType)222 constexpr Optional(NoneType) {} 223 Optional(const T & y)224 Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {} 225 Optional(const Optional &O) = default; 226 Optional(T && y)227 Optional(T &&y) : Storage(optional_detail::in_place_t{}, std::move(y)) {} 228 Optional(Optional &&O) = default; 229 230 Optional &operator=(T &&y) { 231 Storage = std::move(y); 232 return *this; 233 } 234 Optional &operator=(Optional &&O) = default; 235 236 /// Create a new object by constructing it in place with the given arguments. emplace(ArgTypes &&...Args)237 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { 238 Storage.emplace(std::forward<ArgTypes>(Args)...); 239 } 240 create(const T * y)241 static inline Optional create(const T *y) { 242 return y ? Optional(*y) : Optional(); 243 } 244 245 Optional &operator=(const T &y) { 246 Storage = y; 247 return *this; 248 } 249 Optional &operator=(const Optional &O) = default; 250 reset()251 void reset() { Storage.reset(); } 252 getPointer()253 const T *getPointer() const { return &Storage.getValue(); } getPointer()254 T *getPointer() { return &Storage.getValue(); } getValue()255 const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); } getValue()256 T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); } 257 258 explicit operator bool() const { return hasValue(); } hasValue()259 bool hasValue() const { return Storage.hasValue(); } 260 const T *operator->() const { return getPointer(); } 261 T *operator->() { return getPointer(); } 262 const T &operator*() const LLVM_LVALUE_FUNCTION { return getValue(); } 263 T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); } 264 265 template <typename U> getValueOr(U && value)266 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION { 267 return hasValue() ? getValue() : std::forward<U>(value); 268 } 269 270 /// Apply a function to the value if present; otherwise return None. 271 template <class Function> 272 auto map(const Function &F) const 273 -> Optional<decltype(F(getValue()))> { 274 if (*this) return F(getValue()); 275 return None; 276 } 277 278 #if LLVM_HAS_RVALUE_REFERENCE_THIS getValue()279 T &&getValue() && { return std::move(Storage.getValue()); } 280 T &&operator*() && { return std::move(Storage.getValue()); } 281 282 template <typename U> getValueOr(U && value)283 T getValueOr(U &&value) && { 284 return hasValue() ? std::move(getValue()) : std::forward<U>(value); 285 } 286 287 /// Apply a function to the value if present; otherwise return None. 288 template <class Function> 289 auto map(const Function &F) && 290 -> Optional<decltype(F(std::move(*this).getValue()))> { 291 if (*this) return F(std::move(*this).getValue()); 292 return None; 293 } 294 #endif 295 }; 296 297 template <typename T, typename U> 298 bool operator==(const Optional<T> &X, const Optional<U> &Y) { 299 if (X && Y) 300 return *X == *Y; 301 return X.hasValue() == Y.hasValue(); 302 } 303 304 template <typename T, typename U> 305 bool operator!=(const Optional<T> &X, const Optional<U> &Y) { 306 return !(X == Y); 307 } 308 309 template <typename T, typename U> 310 bool operator<(const Optional<T> &X, const Optional<U> &Y) { 311 if (X && Y) 312 return *X < *Y; 313 return X.hasValue() < Y.hasValue(); 314 } 315 316 template <typename T, typename U> 317 bool operator<=(const Optional<T> &X, const Optional<U> &Y) { 318 return !(Y < X); 319 } 320 321 template <typename T, typename U> 322 bool operator>(const Optional<T> &X, const Optional<U> &Y) { 323 return Y < X; 324 } 325 326 template <typename T, typename U> 327 bool operator>=(const Optional<T> &X, const Optional<U> &Y) { 328 return !(X < Y); 329 } 330 331 template<typename T> 332 bool operator==(const Optional<T> &X, NoneType) { 333 return !X; 334 } 335 336 template<typename T> 337 bool operator==(NoneType, const Optional<T> &X) { 338 return X == None; 339 } 340 341 template<typename T> 342 bool operator!=(const Optional<T> &X, NoneType) { 343 return !(X == None); 344 } 345 346 template<typename T> 347 bool operator!=(NoneType, const Optional<T> &X) { 348 return X != None; 349 } 350 351 template <typename T> bool operator<(const Optional<T> &X, NoneType) { 352 return false; 353 } 354 355 template <typename T> bool operator<(NoneType, const Optional<T> &X) { 356 return X.hasValue(); 357 } 358 359 template <typename T> bool operator<=(const Optional<T> &X, NoneType) { 360 return !(None < X); 361 } 362 363 template <typename T> bool operator<=(NoneType, const Optional<T> &X) { 364 return !(X < None); 365 } 366 367 template <typename T> bool operator>(const Optional<T> &X, NoneType) { 368 return None < X; 369 } 370 371 template <typename T> bool operator>(NoneType, const Optional<T> &X) { 372 return X < None; 373 } 374 375 template <typename T> bool operator>=(const Optional<T> &X, NoneType) { 376 return None <= X; 377 } 378 379 template <typename T> bool operator>=(NoneType, const Optional<T> &X) { 380 return X <= None; 381 } 382 383 template <typename T> bool operator==(const Optional<T> &X, const T &Y) { 384 return X && *X == Y; 385 } 386 387 template <typename T> bool operator==(const T &X, const Optional<T> &Y) { 388 return Y && X == *Y; 389 } 390 391 template <typename T> bool operator!=(const Optional<T> &X, const T &Y) { 392 return !(X == Y); 393 } 394 395 template <typename T> bool operator!=(const T &X, const Optional<T> &Y) { 396 return !(X == Y); 397 } 398 399 template <typename T> bool operator<(const Optional<T> &X, const T &Y) { 400 return !X || *X < Y; 401 } 402 403 template <typename T> bool operator<(const T &X, const Optional<T> &Y) { 404 return Y && X < *Y; 405 } 406 407 template <typename T> bool operator<=(const Optional<T> &X, const T &Y) { 408 return !(Y < X); 409 } 410 411 template <typename T> bool operator<=(const T &X, const Optional<T> &Y) { 412 return !(Y < X); 413 } 414 415 template <typename T> bool operator>(const Optional<T> &X, const T &Y) { 416 return Y < X; 417 } 418 419 template <typename T> bool operator>(const T &X, const Optional<T> &Y) { 420 return Y < X; 421 } 422 423 template <typename T> bool operator>=(const Optional<T> &X, const T &Y) { 424 return !(X < Y); 425 } 426 427 template <typename T> bool operator>=(const T &X, const Optional<T> &Y) { 428 return !(X < Y); 429 } 430 431 raw_ostream &operator<<(raw_ostream &OS, NoneType); 432 433 template <typename T, typename = decltype(std::declval<raw_ostream &>() 434 << std::declval<const T &>())> 435 raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) { 436 if (O) 437 OS << *O; 438 else 439 OS << None; 440 return OS; 441 } 442 443 } // end namespace llvm 444 445 #endif // LLVM_ADT_OPTIONAL_H 446