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