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 <cassert> 23#include <utility> 24 25namespace llvm { 26 27template<typename T> 28class Optional { 29 AlignedCharArrayUnion<T> storage; 30 bool hasVal; 31public: 32 Optional(NoneType) : hasVal(false) {} 33 explicit Optional() : hasVal(false) {} 34 Optional(const T &y) : hasVal(true) { 35 new (storage.buffer) T(y); 36 } 37 Optional(const Optional &O) : hasVal(O.hasVal) { 38 if (hasVal) 39 new (storage.buffer) T(*O); 40 } 41 42 Optional(T &&y) : hasVal(true) { 43 new (storage.buffer) T(std::forward<T>(y)); 44 } 45 Optional(Optional<T> &&O) : hasVal(O) { 46 if (O) { 47 new (storage.buffer) T(std::move(*O)); 48 O.reset(); 49 } 50 } 51 Optional &operator=(T &&y) { 52 if (hasVal) 53 **this = std::move(y); 54 else { 55 new (storage.buffer) T(std::move(y)); 56 hasVal = true; 57 } 58 return *this; 59 } 60 Optional &operator=(Optional &&O) { 61 if (!O) 62 reset(); 63 else { 64 *this = std::move(*O); 65 O.reset(); 66 } 67 return *this; 68 } 69 70 static inline Optional create(const T* y) { 71 return y ? Optional(*y) : Optional(); 72 } 73 74 // FIXME: these assignments (& the equivalent const T&/const Optional& ctors) 75 // could be made more efficient by passing by value, possibly unifying them 76 // with the rvalue versions above - but this could place a different set of 77 // requirements (notably: the existence of a default ctor) when implemented 78 // in that way. Careful SFINAE to avoid such pitfalls would be required. 79 Optional &operator=(const T &y) { 80 if (hasVal) 81 **this = y; 82 else { 83 new (storage.buffer) T(y); 84 hasVal = true; 85 } 86 return *this; 87 } 88 89 Optional &operator=(const Optional &O) { 90 if (!O) 91 reset(); 92 else 93 *this = *O; 94 return *this; 95 } 96 97 void reset() { 98 if (hasVal) { 99 (**this).~T(); 100 hasVal = false; 101 } 102 } 103 104 ~Optional() { 105 reset(); 106 } 107 108 const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); } 109 T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); } 110 const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 111 T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 112 113 LLVM_EXPLICIT operator bool() const { return hasVal; } 114 bool hasValue() const { return hasVal; } 115 const T* operator->() const { return getPointer(); } 116 T* operator->() { return getPointer(); } 117 const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 118 T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 119 120#if LLVM_HAS_RVALUE_REFERENCE_THIS 121 T&& getValue() && { assert(hasVal); return std::move(*getPointer()); } 122 T&& operator*() && { assert(hasVal); return std::move(*getPointer()); } 123#endif 124}; 125 126template <typename T> struct isPodLike; 127template <typename T> struct isPodLike<Optional<T> > { 128 // An Optional<T> is pod-like if T is. 129 static const bool value = isPodLike<T>::value; 130}; 131 132/// \brief Poison comparison between two \c Optional objects. Clients needs to 133/// explicitly compare the underlying values and account for empty \c Optional 134/// objects. 135/// 136/// This routine will never be defined. It returns \c void to help diagnose 137/// errors at compile time. 138template<typename T, typename U> 139void operator==(const Optional<T> &X, const Optional<U> &Y); 140 141/// \brief Poison comparison between two \c Optional objects. Clients needs to 142/// explicitly compare the underlying values and account for empty \c Optional 143/// objects. 144/// 145/// This routine will never be defined. It returns \c void to help diagnose 146/// errors at compile time. 147template<typename T, typename U> 148void operator!=(const Optional<T> &X, const Optional<U> &Y); 149 150/// \brief Poison comparison between two \c Optional objects. Clients needs to 151/// explicitly compare the underlying values and account for empty \c Optional 152/// objects. 153/// 154/// This routine will never be defined. It returns \c void to help diagnose 155/// errors at compile time. 156template<typename T, typename U> 157void operator<(const Optional<T> &X, const Optional<U> &Y); 158 159/// \brief Poison comparison between two \c Optional objects. Clients needs to 160/// explicitly compare the underlying values and account for empty \c Optional 161/// objects. 162/// 163/// This routine will never be defined. It returns \c void to help diagnose 164/// errors at compile time. 165template<typename T, typename U> 166void operator<=(const Optional<T> &X, const Optional<U> &Y); 167 168/// \brief Poison comparison between two \c Optional objects. Clients needs to 169/// explicitly compare the underlying values and account for empty \c Optional 170/// objects. 171/// 172/// This routine will never be defined. It returns \c void to help diagnose 173/// errors at compile time. 174template<typename T, typename U> 175void operator>=(const Optional<T> &X, const Optional<U> &Y); 176 177/// \brief Poison comparison between two \c Optional objects. Clients needs to 178/// explicitly compare the underlying values and account for empty \c Optional 179/// objects. 180/// 181/// This routine will never be defined. It returns \c void to help diagnose 182/// errors at compile time. 183template<typename T, typename U> 184void operator>(const Optional<T> &X, const Optional<U> &Y); 185 186} // end llvm namespace 187 188#endif 189