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/Hashing.h" 19 #include "llvm/ADT/None.h" 20 #include "llvm/ADT/STLForwardCompat.h" 21 #include "llvm/Support/Compiler.h" 22 #include "llvm/Support/type_traits.h" 23 #include <cassert> 24 #include <memory> 25 #include <new> 26 #include <utility> 27 28 namespace llvm { 29 30 class raw_ostream; 31 32 namespace optional_detail { 33 34 /// Storage for any type. 35 // 36 // The specialization condition intentionally uses 37 // llvm::is_trivially_copy_constructible instead of 38 // std::is_trivially_copy_constructible. GCC versions prior to 7.4 may 39 // instantiate the copy constructor of `T` when 40 // std::is_trivially_copy_constructible is instantiated. This causes 41 // compilation to fail if we query the trivially copy constructible property of 42 // a class which is not copy constructible. 43 // 44 // The current implementation of OptionalStorage insists that in order to use 45 // the trivial specialization, the value_type must be trivially copy 46 // constructible and trivially copy assignable due to =default implementations 47 // of the copy/move constructor/assignment. It does not follow that this is 48 // necessarily the case std::is_trivially_copyable is true (hence the expanded 49 // specialization condition). 50 // 51 // The move constructible / assignable conditions emulate the remaining behavior 52 // of std::is_trivially_copyable. 53 template <typename T, bool = (llvm::is_trivially_copy_constructible<T>::value && 54 std::is_trivially_copy_assignable<T>::value && 55 (std::is_trivially_move_constructible<T>::value || 56 !std::is_move_constructible<T>::value) && 57 (std::is_trivially_move_assignable<T>::value || 58 !std::is_move_assignable<T>::value))> 59 class OptionalStorage { 60 union { 61 char empty; 62 T value; 63 }; 64 bool hasVal; 65 66 public: 67 ~OptionalStorage() { reset(); } 68 69 constexpr OptionalStorage() noexcept : empty(), hasVal(false) {} 70 71 constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() { 72 if (other.hasValue()) { 73 emplace(other.value); 74 } 75 } 76 constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() { 77 if (other.hasValue()) { 78 emplace(std::move(other.value)); 79 } 80 } 81 82 template <class... Args> 83 constexpr explicit OptionalStorage(in_place_t, Args &&... args) 84 : value(std::forward<Args>(args)...), hasVal(true) {} 85 86 void reset() noexcept { 87 if (hasVal) { 88 value.~T(); 89 hasVal = false; 90 } 91 } 92 93 constexpr bool hasValue() const noexcept { return hasVal; } 94 95 T &getValue() LLVM_LVALUE_FUNCTION noexcept { 96 assert(hasVal); 97 return value; 98 } 99 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { 100 assert(hasVal); 101 return value; 102 } 103 #if LLVM_HAS_RVALUE_REFERENCE_THIS 104 T &&getValue() && noexcept { 105 assert(hasVal); 106 return std::move(value); 107 } 108 #endif 109 110 template <class... Args> void emplace(Args &&... args) { 111 reset(); 112 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); 113 hasVal = true; 114 } 115 116 OptionalStorage &operator=(T const &y) { 117 if (hasValue()) { 118 value = y; 119 } else { 120 ::new ((void *)std::addressof(value)) T(y); 121 hasVal = true; 122 } 123 return *this; 124 } 125 OptionalStorage &operator=(T &&y) { 126 if (hasValue()) { 127 value = std::move(y); 128 } else { 129 ::new ((void *)std::addressof(value)) T(std::move(y)); 130 hasVal = true; 131 } 132 return *this; 133 } 134 135 OptionalStorage &operator=(OptionalStorage const &other) { 136 if (other.hasValue()) { 137 if (hasValue()) { 138 value = other.value; 139 } else { 140 ::new ((void *)std::addressof(value)) T(other.value); 141 hasVal = true; 142 } 143 } else { 144 reset(); 145 } 146 return *this; 147 } 148 149 OptionalStorage &operator=(OptionalStorage &&other) { 150 if (other.hasValue()) { 151 if (hasValue()) { 152 value = std::move(other.value); 153 } else { 154 ::new ((void *)std::addressof(value)) T(std::move(other.value)); 155 hasVal = true; 156 } 157 } else { 158 reset(); 159 } 160 return *this; 161 } 162 }; 163 164 template <typename T> class OptionalStorage<T, true> { 165 union { 166 char empty; 167 T value; 168 }; 169 bool hasVal = false; 170 171 public: 172 ~OptionalStorage() = default; 173 174 constexpr OptionalStorage() noexcept : empty{} {} 175 176 constexpr OptionalStorage(OptionalStorage const &other) = default; 177 constexpr OptionalStorage(OptionalStorage &&other) = default; 178 179 OptionalStorage &operator=(OptionalStorage const &other) = default; 180 OptionalStorage &operator=(OptionalStorage &&other) = default; 181 182 template <class... Args> 183 constexpr explicit OptionalStorage(in_place_t, Args &&... args) 184 : value(std::forward<Args>(args)...), hasVal(true) {} 185 186 void reset() noexcept { 187 if (hasVal) { 188 value.~T(); 189 hasVal = false; 190 } 191 } 192 193 constexpr bool hasValue() const noexcept { return hasVal; } 194 195 T &getValue() LLVM_LVALUE_FUNCTION noexcept { 196 assert(hasVal); 197 return value; 198 } 199 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { 200 assert(hasVal); 201 return value; 202 } 203 #if LLVM_HAS_RVALUE_REFERENCE_THIS 204 T &&getValue() && noexcept { 205 assert(hasVal); 206 return std::move(value); 207 } 208 #endif 209 210 template <class... Args> void emplace(Args &&... args) { 211 reset(); 212 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); 213 hasVal = true; 214 } 215 216 OptionalStorage &operator=(T const &y) { 217 if (hasValue()) { 218 value = y; 219 } else { 220 ::new ((void *)std::addressof(value)) T(y); 221 hasVal = true; 222 } 223 return *this; 224 } 225 OptionalStorage &operator=(T &&y) { 226 if (hasValue()) { 227 value = std::move(y); 228 } else { 229 ::new ((void *)std::addressof(value)) T(std::move(y)); 230 hasVal = true; 231 } 232 return *this; 233 } 234 }; 235 236 } // namespace optional_detail 237 238 template <typename T> class Optional { 239 optional_detail::OptionalStorage<T> Storage; 240 241 public: 242 using value_type = T; 243 244 constexpr Optional() {} 245 constexpr Optional(NoneType) {} 246 247 constexpr Optional(const T &y) : Storage(in_place, y) {} 248 constexpr Optional(const Optional &O) = default; 249 250 constexpr Optional(T &&y) : Storage(in_place, std::move(y)) {} 251 constexpr Optional(Optional &&O) = default; 252 253 template <typename... ArgTypes> 254 constexpr Optional(in_place_t, ArgTypes &&...Args) 255 : Storage(in_place, std::forward<ArgTypes>(Args)...) {} 256 257 Optional &operator=(T &&y) { 258 Storage = std::move(y); 259 return *this; 260 } 261 Optional &operator=(Optional &&O) = default; 262 263 /// Create a new object by constructing it in place with the given arguments. 264 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { 265 Storage.emplace(std::forward<ArgTypes>(Args)...); 266 } 267 268 static constexpr Optional create(const T *y) { 269 return y ? Optional(*y) : Optional(); 270 } 271 272 Optional &operator=(const T &y) { 273 Storage = y; 274 return *this; 275 } 276 Optional &operator=(const Optional &O) = default; 277 278 void reset() { Storage.reset(); } 279 280 constexpr const T *getPointer() const { return &Storage.getValue(); } 281 T *getPointer() { return &Storage.getValue(); } 282 constexpr const T &getValue() const LLVM_LVALUE_FUNCTION { 283 return Storage.getValue(); 284 } 285 T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); } 286 287 constexpr explicit operator bool() const { return hasValue(); } 288 constexpr bool hasValue() const { return Storage.hasValue(); } 289 constexpr const T *operator->() const { return getPointer(); } 290 T *operator->() { return getPointer(); } 291 constexpr const T &operator*() const LLVM_LVALUE_FUNCTION { 292 return getValue(); 293 } 294 T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); } 295 296 template <typename U> 297 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION { 298 return hasValue() ? getValue() : std::forward<U>(value); 299 } 300 301 /// Apply a function to the value if present; otherwise return None. 302 template <class Function> 303 auto map(const Function &F) const LLVM_LVALUE_FUNCTION 304 -> Optional<decltype(F(getValue()))> { 305 if (*this) return F(getValue()); 306 return None; 307 } 308 309 #if LLVM_HAS_RVALUE_REFERENCE_THIS 310 T &&getValue() && { return std::move(Storage.getValue()); } 311 T &&operator*() && { return std::move(Storage.getValue()); } 312 313 template <typename U> 314 T getValueOr(U &&value) && { 315 return hasValue() ? std::move(getValue()) : std::forward<U>(value); 316 } 317 318 /// Apply a function to the value if present; otherwise return None. 319 template <class Function> 320 auto map(const Function &F) && 321 -> Optional<decltype(F(std::move(*this).getValue()))> { 322 if (*this) return F(std::move(*this).getValue()); 323 return None; 324 } 325 #endif 326 }; 327 328 template <class T> llvm::hash_code hash_value(const Optional<T> &O) { 329 return O ? hash_combine(true, *O) : hash_value(false); 330 } 331 332 template <typename T, typename U> 333 constexpr bool operator==(const Optional<T> &X, const Optional<U> &Y) { 334 if (X && Y) 335 return *X == *Y; 336 return X.hasValue() == Y.hasValue(); 337 } 338 339 template <typename T, typename U> 340 constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) { 341 return !(X == Y); 342 } 343 344 template <typename T, typename U> 345 constexpr bool operator<(const Optional<T> &X, const Optional<U> &Y) { 346 if (X && Y) 347 return *X < *Y; 348 return X.hasValue() < Y.hasValue(); 349 } 350 351 template <typename T, typename U> 352 constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) { 353 return !(Y < X); 354 } 355 356 template <typename T, typename U> 357 constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) { 358 return Y < X; 359 } 360 361 template <typename T, typename U> 362 constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) { 363 return !(X < Y); 364 } 365 366 template <typename T> 367 constexpr bool operator==(const Optional<T> &X, NoneType) { 368 return !X; 369 } 370 371 template <typename T> 372 constexpr bool operator==(NoneType, const Optional<T> &X) { 373 return X == None; 374 } 375 376 template <typename T> 377 constexpr bool operator!=(const Optional<T> &X, NoneType) { 378 return !(X == None); 379 } 380 381 template <typename T> 382 constexpr bool operator!=(NoneType, const Optional<T> &X) { 383 return X != None; 384 } 385 386 template <typename T> constexpr bool operator<(const Optional<T> &, NoneType) { 387 return false; 388 } 389 390 template <typename T> constexpr bool operator<(NoneType, const Optional<T> &X) { 391 return X.hasValue(); 392 } 393 394 template <typename T> 395 constexpr bool operator<=(const Optional<T> &X, NoneType) { 396 return !(None < X); 397 } 398 399 template <typename T> 400 constexpr bool operator<=(NoneType, const Optional<T> &X) { 401 return !(X < None); 402 } 403 404 template <typename T> constexpr bool operator>(const Optional<T> &X, NoneType) { 405 return None < X; 406 } 407 408 template <typename T> constexpr bool operator>(NoneType, const Optional<T> &X) { 409 return X < None; 410 } 411 412 template <typename T> 413 constexpr bool operator>=(const Optional<T> &X, NoneType) { 414 return None <= X; 415 } 416 417 template <typename T> 418 constexpr bool operator>=(NoneType, const Optional<T> &X) { 419 return X <= None; 420 } 421 422 template <typename T> 423 constexpr bool operator==(const Optional<T> &X, const T &Y) { 424 return X && *X == Y; 425 } 426 427 template <typename T> 428 constexpr bool operator==(const T &X, const Optional<T> &Y) { 429 return Y && X == *Y; 430 } 431 432 template <typename T> 433 constexpr bool operator!=(const Optional<T> &X, const T &Y) { 434 return !(X == Y); 435 } 436 437 template <typename T> 438 constexpr bool operator!=(const T &X, const Optional<T> &Y) { 439 return !(X == Y); 440 } 441 442 template <typename T> 443 constexpr bool operator<(const Optional<T> &X, const T &Y) { 444 return !X || *X < Y; 445 } 446 447 template <typename T> 448 constexpr bool operator<(const T &X, const Optional<T> &Y) { 449 return Y && X < *Y; 450 } 451 452 template <typename T> 453 constexpr bool operator<=(const Optional<T> &X, const T &Y) { 454 return !(Y < X); 455 } 456 457 template <typename T> 458 constexpr bool operator<=(const T &X, const Optional<T> &Y) { 459 return !(Y < X); 460 } 461 462 template <typename T> 463 constexpr bool operator>(const Optional<T> &X, const T &Y) { 464 return Y < X; 465 } 466 467 template <typename T> 468 constexpr bool operator>(const T &X, const Optional<T> &Y) { 469 return Y < X; 470 } 471 472 template <typename T> 473 constexpr bool operator>=(const Optional<T> &X, const T &Y) { 474 return !(X < Y); 475 } 476 477 template <typename T> 478 constexpr bool operator>=(const T &X, const Optional<T> &Y) { 479 return !(X < Y); 480 } 481 482 raw_ostream &operator<<(raw_ostream &OS, NoneType); 483 484 template <typename T, typename = decltype(std::declval<raw_ostream &>() 485 << std::declval<const T &>())> 486 raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) { 487 if (O) 488 OS << *O; 489 else 490 OS << None; 491 return OS; 492 } 493 494 } // end namespace llvm 495 496 #endif // LLVM_ADT_OPTIONAL_H 497