Optional.h revision 360784
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 26namespace llvm { 27 28class raw_ostream; 29 30namespace optional_detail { 31 32struct in_place_t {}; 33 34/// Storage for any type. 35template <typename T, bool = is_trivially_copyable<T>::value> 36class OptionalStorage { 37 union { 38 char empty; 39 T value; 40 }; 41 bool hasVal; 42 43public: 44 ~OptionalStorage() { reset(); } 45 46 OptionalStorage() noexcept : empty(), hasVal(false) {} 47 48 OptionalStorage(OptionalStorage const &other) : OptionalStorage() { 49 if (other.hasValue()) { 50 emplace(other.value); 51 } 52 } 53 OptionalStorage(OptionalStorage &&other) : OptionalStorage() { 54 if (other.hasValue()) { 55 emplace(std::move(other.value)); 56 } 57 } 58 59 template <class... Args> 60 explicit OptionalStorage(in_place_t, Args &&... args) 61 : value(std::forward<Args>(args)...), hasVal(true) {} 62 63 void reset() noexcept { 64 if (hasVal) { 65 value.~T(); 66 hasVal = false; 67 } 68 } 69 70 bool hasValue() const noexcept { return hasVal; } 71 72 T &getValue() LLVM_LVALUE_FUNCTION noexcept { 73 assert(hasVal); 74 return value; 75 } 76 T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { 77 assert(hasVal); 78 return value; 79 } 80#if LLVM_HAS_RVALUE_REFERENCE_THIS 81 T &&getValue() && noexcept { 82 assert(hasVal); 83 return std::move(value); 84 } 85#endif 86 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 141template <typename T> class OptionalStorage<T, true> { 142 union { 143 char empty; 144 T value; 145 }; 146 bool hasVal = false; 147 148public: 149 ~OptionalStorage() = default; 150 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> 160 explicit OptionalStorage(in_place_t, Args &&... args) 161 : value(std::forward<Args>(args)...), hasVal(true) {} 162 163 void reset() noexcept { 164 if (hasVal) { 165 value.~T(); 166 hasVal = false; 167 } 168 } 169 170 bool hasValue() const noexcept { return hasVal; } 171 172 T &getValue() LLVM_LVALUE_FUNCTION noexcept { 173 assert(hasVal); 174 return value; 175 } 176 T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { 177 assert(hasVal); 178 return value; 179 } 180#if LLVM_HAS_RVALUE_REFERENCE_THIS 181 T &&getValue() && noexcept { 182 assert(hasVal); 183 return std::move(value); 184 } 185#endif 186 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 215template <typename T> class Optional { 216 optional_detail::OptionalStorage<T> Storage; 217 218public: 219 using value_type = T; 220 221 constexpr Optional() {} 222 constexpr Optional(NoneType) {} 223 224 Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {} 225 Optional(const Optional &O) = default; 226 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. 237 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { 238 Storage.emplace(std::forward<ArgTypes>(Args)...); 239 } 240 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 251 void reset() { Storage.reset(); } 252 253 const T *getPointer() const { return &Storage.getValue(); } 254 T *getPointer() { return &Storage.getValue(); } 255 const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); } 256 T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); } 257 258 explicit operator bool() const { return 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> 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 279 T &&getValue() && { return std::move(Storage.getValue()); } 280 T &&operator*() && { return std::move(Storage.getValue()); } 281 282 template <typename U> 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 297template <typename T, typename U> 298bool 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 304template <typename T, typename U> 305bool operator!=(const Optional<T> &X, const Optional<U> &Y) { 306 return !(X == Y); 307} 308 309template <typename T, typename U> 310bool 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 316template <typename T, typename U> 317bool operator<=(const Optional<T> &X, const Optional<U> &Y) { 318 return !(Y < X); 319} 320 321template <typename T, typename U> 322bool operator>(const Optional<T> &X, const Optional<U> &Y) { 323 return Y < X; 324} 325 326template <typename T, typename U> 327bool operator>=(const Optional<T> &X, const Optional<U> &Y) { 328 return !(X < Y); 329} 330 331template<typename T> 332bool operator==(const Optional<T> &X, NoneType) { 333 return !X; 334} 335 336template<typename T> 337bool operator==(NoneType, const Optional<T> &X) { 338 return X == None; 339} 340 341template<typename T> 342bool operator!=(const Optional<T> &X, NoneType) { 343 return !(X == None); 344} 345 346template<typename T> 347bool operator!=(NoneType, const Optional<T> &X) { 348 return X != None; 349} 350 351template <typename T> bool operator<(const Optional<T> &X, NoneType) { 352 return false; 353} 354 355template <typename T> bool operator<(NoneType, const Optional<T> &X) { 356 return X.hasValue(); 357} 358 359template <typename T> bool operator<=(const Optional<T> &X, NoneType) { 360 return !(None < X); 361} 362 363template <typename T> bool operator<=(NoneType, const Optional<T> &X) { 364 return !(X < None); 365} 366 367template <typename T> bool operator>(const Optional<T> &X, NoneType) { 368 return None < X; 369} 370 371template <typename T> bool operator>(NoneType, const Optional<T> &X) { 372 return X < None; 373} 374 375template <typename T> bool operator>=(const Optional<T> &X, NoneType) { 376 return None <= X; 377} 378 379template <typename T> bool operator>=(NoneType, const Optional<T> &X) { 380 return X <= None; 381} 382 383template <typename T> bool operator==(const Optional<T> &X, const T &Y) { 384 return X && *X == Y; 385} 386 387template <typename T> bool operator==(const T &X, const Optional<T> &Y) { 388 return Y && X == *Y; 389} 390 391template <typename T> bool operator!=(const Optional<T> &X, const T &Y) { 392 return !(X == Y); 393} 394 395template <typename T> bool operator!=(const T &X, const Optional<T> &Y) { 396 return !(X == Y); 397} 398 399template <typename T> bool operator<(const Optional<T> &X, const T &Y) { 400 return !X || *X < Y; 401} 402 403template <typename T> bool operator<(const T &X, const Optional<T> &Y) { 404 return Y && X < *Y; 405} 406 407template <typename T> bool operator<=(const Optional<T> &X, const T &Y) { 408 return !(Y < X); 409} 410 411template <typename T> bool operator<=(const T &X, const Optional<T> &Y) { 412 return !(Y < X); 413} 414 415template <typename T> bool operator>(const Optional<T> &X, const T &Y) { 416 return Y < X; 417} 418 419template <typename T> bool operator>(const T &X, const Optional<T> &Y) { 420 return Y < X; 421} 422 423template <typename T> bool operator>=(const Optional<T> &X, const T &Y) { 424 return !(X < Y); 425} 426 427template <typename T> bool operator>=(const T &X, const Optional<T> &Y) { 428 return !(X < Y); 429} 430 431raw_ostream &operator<<(raw_ostream &OS, NoneType); 432 433template <typename T, typename = decltype(std::declval<raw_ostream &>() 434 << std::declval<const T &>())> 435raw_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