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 25 namespace llvm { 26 27 template<typename T> 28 class Optional { 29 AlignedCharArrayUnion<T> storage; 30 bool hasVal; 31 public: Optional(NoneType)32 Optional(NoneType) : hasVal(false) {} Optional()33 explicit Optional() : hasVal(false) {} Optional(const T & y)34 Optional(const T &y) : hasVal(true) { 35 new (storage.buffer) T(y); 36 } Optional(const Optional & O)37 Optional(const Optional &O) : hasVal(O.hasVal) { 38 if (hasVal) 39 new (storage.buffer) T(*O); 40 } 41 Optional(T && y)42 Optional(T &&y) : hasVal(true) { 43 new (storage.buffer) T(std::forward<T>(y)); 44 } Optional(Optional<T> && O)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 create(const T * y)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 reset()97 void reset() { 98 if (hasVal) { 99 (**this).~T(); 100 hasVal = false; 101 } 102 } 103 ~Optional()104 ~Optional() { 105 reset(); 106 } 107 getPointer()108 const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); } getPointer()109 T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); } getValue()110 const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } getValue()111 T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 112 113 LLVM_EXPLICIT operator bool() const { return hasVal; } hasValue()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 getValue()121 T&& getValue() && { assert(hasVal); return std::move(*getPointer()); } 122 T&& operator*() && { assert(hasVal); return std::move(*getPointer()); } 123 #endif 124 }; 125 126 template <typename T> struct isPodLike; 127 template <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. 138 template<typename T, typename U> 139 void 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. 147 template<typename T, typename U> 148 void 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. 156 template<typename T, typename U> 157 void 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. 165 template<typename T, typename U> 166 void 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. 174 template<typename T, typename U> 175 void 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. 183 template<typename T, typename U> 184 void operator>(const Optional<T> &X, const Optional<U> &Y); 185 186 } // end llvm namespace 187 188 #endif 189