1207618Srdivacky//===-- Optional.h - Simple variant for passing optional values ---*- C++ -*-=// 2207618Srdivacky// 3207618Srdivacky// The LLVM Compiler Infrastructure 4207618Srdivacky// 5207618Srdivacky// This file is distributed under the University of Illinois Open Source 6207618Srdivacky// License. See LICENSE.TXT for details. 7207618Srdivacky// 8207618Srdivacky//===----------------------------------------------------------------------===// 9207618Srdivacky// 10207618Srdivacky// This file provides Optional, a template class modeled in the spirit of 11207618Srdivacky// OCaml's 'opt' variant. The idea is to strongly type whether or not 12207618Srdivacky// a value can be optional. 13207618Srdivacky// 14207618Srdivacky//===----------------------------------------------------------------------===// 15207618Srdivacky 16252723Sdim#ifndef LLVM_ADT_OPTIONAL_H 17252723Sdim#define LLVM_ADT_OPTIONAL_H 18207618Srdivacky 19252723Sdim#include "llvm/ADT/None.h" 20245431Sdim#include "llvm/Support/Compiler.h" 21252723Sdim#include "llvm/Support/AlignOf.h" 22207618Srdivacky#include <cassert> 23207618Srdivacky 24252723Sdim#if LLVM_HAS_RVALUE_REFERENCES 25245431Sdim#include <utility> 26245431Sdim#endif 27245431Sdim 28207618Srdivackynamespace llvm { 29207618Srdivacky 30207618Srdivackytemplate<typename T> 31207618Srdivackyclass Optional { 32252723Sdim AlignedCharArrayUnion<T> storage; 33252723Sdim bool hasVal; 34207618Srdivackypublic: 35252723Sdim Optional(NoneType) : hasVal(false) {} 36252723Sdim explicit Optional() : hasVal(false) {} 37252723Sdim Optional(const T &y) : hasVal(true) { 38252723Sdim new (storage.buffer) T(y); 39252723Sdim } 40252723Sdim Optional(const Optional &O) : hasVal(O.hasVal) { 41252723Sdim if (hasVal) 42252723Sdim new (storage.buffer) T(*O); 43252723Sdim } 44207618Srdivacky 45252723Sdim#if LLVM_HAS_RVALUE_REFERENCES 46252723Sdim Optional(T &&y) : hasVal(true) { 47252723Sdim new (storage.buffer) T(std::forward<T>(y)); 48252723Sdim } 49252723Sdim Optional(Optional<T> &&O) : hasVal(O) { 50252723Sdim if (O) { 51252723Sdim new (storage.buffer) T(std::move(*O)); 52252723Sdim O.reset(); 53252723Sdim } 54252723Sdim } 55252723Sdim Optional &operator=(T &&y) { 56252723Sdim if (hasVal) 57252723Sdim **this = std::move(y); 58252723Sdim else { 59252723Sdim new (storage.buffer) T(std::move(y)); 60252723Sdim hasVal = true; 61252723Sdim } 62252723Sdim return *this; 63252723Sdim } 64252723Sdim Optional &operator=(Optional &&O) { 65252723Sdim if (!O) 66252723Sdim reset(); 67252723Sdim else { 68252723Sdim *this = std::move(*O); 69252723Sdim O.reset(); 70252723Sdim } 71252723Sdim return *this; 72252723Sdim } 73245431Sdim#endif 74245431Sdim 75207618Srdivacky static inline Optional create(const T* y) { 76207618Srdivacky return y ? Optional(*y) : Optional(); 77207618Srdivacky } 78207618Srdivacky 79252723Sdim // FIXME: these assignments (& the equivalent const T&/const Optional& ctors) 80252723Sdim // could be made more efficient by passing by value, possibly unifying them 81252723Sdim // with the rvalue versions above - but this could place a different set of 82252723Sdim // requirements (notably: the existence of a default ctor) when implemented 83252723Sdim // in that way. Careful SFINAE to avoid such pitfalls would be required. 84207618Srdivacky Optional &operator=(const T &y) { 85252723Sdim if (hasVal) 86252723Sdim **this = y; 87252723Sdim else { 88252723Sdim new (storage.buffer) T(y); 89252723Sdim hasVal = true; 90252723Sdim } 91207618Srdivacky return *this; 92207618Srdivacky } 93207618Srdivacky 94252723Sdim Optional &operator=(const Optional &O) { 95252723Sdim if (!O) 96252723Sdim reset(); 97252723Sdim else 98252723Sdim *this = *O; 99252723Sdim return *this; 100252723Sdim } 101252723Sdim 102252723Sdim void reset() { 103252723Sdim if (hasVal) { 104252723Sdim (**this).~T(); 105252723Sdim hasVal = false; 106252723Sdim } 107252723Sdim } 108252723Sdim 109252723Sdim ~Optional() { 110252723Sdim reset(); 111252723Sdim } 112252723Sdim 113252723Sdim const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); } 114252723Sdim T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); } 115252723Sdim const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 116252723Sdim T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 117252723Sdim 118252723Sdim LLVM_EXPLICIT operator bool() const { return hasVal; } 119207618Srdivacky bool hasValue() const { return hasVal; } 120207618Srdivacky const T* operator->() const { return getPointer(); } 121252723Sdim T* operator->() { return getPointer(); } 122252723Sdim const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 123252723Sdim T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 124252723Sdim 125252723Sdim#if LLVM_HAS_RVALUE_REFERENCE_THIS 126252723Sdim T&& getValue() && { assert(hasVal); return std::move(*getPointer()); } 127252723Sdim T&& operator*() && { assert(hasVal); return std::move(*getPointer()); } 128252723Sdim#endif 129207618Srdivacky}; 130207618Srdivacky 131252723Sdimtemplate <typename T> struct isPodLike; 132252723Sdimtemplate <typename T> struct isPodLike<Optional<T> > { 133252723Sdim // An Optional<T> is pod-like if T is. 134252723Sdim static const bool value = isPodLike<T>::value; 135207618Srdivacky}; 136207618Srdivacky 137218893Sdim/// \brief Poison comparison between two \c Optional objects. Clients needs to 138218893Sdim/// explicitly compare the underlying values and account for empty \c Optional 139218893Sdim/// objects. 140218893Sdim/// 141252723Sdim/// This routine will never be defined. It returns \c void to help diagnose 142218893Sdim/// errors at compile time. 143218893Sdimtemplate<typename T, typename U> 144218893Sdimvoid operator==(const Optional<T> &X, const Optional<U> &Y); 145218893Sdim 146218893Sdim/// \brief Poison comparison between two \c Optional objects. Clients needs to 147218893Sdim/// explicitly compare the underlying values and account for empty \c Optional 148218893Sdim/// objects. 149218893Sdim/// 150252723Sdim/// This routine will never be defined. It returns \c void to help diagnose 151218893Sdim/// errors at compile time. 152218893Sdimtemplate<typename T, typename U> 153218893Sdimvoid operator!=(const Optional<T> &X, const Optional<U> &Y); 154218893Sdim 155218893Sdim/// \brief Poison comparison between two \c Optional objects. Clients needs to 156218893Sdim/// explicitly compare the underlying values and account for empty \c Optional 157218893Sdim/// objects. 158218893Sdim/// 159252723Sdim/// This routine will never be defined. It returns \c void to help diagnose 160218893Sdim/// errors at compile time. 161218893Sdimtemplate<typename T, typename U> 162218893Sdimvoid operator<(const Optional<T> &X, const Optional<U> &Y); 163218893Sdim 164218893Sdim/// \brief Poison comparison between two \c Optional objects. Clients needs to 165218893Sdim/// explicitly compare the underlying values and account for empty \c Optional 166218893Sdim/// objects. 167218893Sdim/// 168252723Sdim/// This routine will never be defined. It returns \c void to help diagnose 169218893Sdim/// errors at compile time. 170218893Sdimtemplate<typename T, typename U> 171218893Sdimvoid operator<=(const Optional<T> &X, const Optional<U> &Y); 172218893Sdim 173218893Sdim/// \brief Poison comparison between two \c Optional objects. Clients needs to 174218893Sdim/// explicitly compare the underlying values and account for empty \c Optional 175218893Sdim/// objects. 176218893Sdim/// 177252723Sdim/// This routine will never be defined. It returns \c void to help diagnose 178218893Sdim/// errors at compile time. 179218893Sdimtemplate<typename T, typename U> 180218893Sdimvoid operator>=(const Optional<T> &X, const Optional<U> &Y); 181218893Sdim 182218893Sdim/// \brief Poison comparison between two \c Optional objects. Clients needs to 183218893Sdim/// explicitly compare the underlying values and account for empty \c Optional 184218893Sdim/// objects. 185218893Sdim/// 186252723Sdim/// This routine will never be defined. It returns \c void to help diagnose 187218893Sdim/// errors at compile time. 188218893Sdimtemplate<typename T, typename U> 189218893Sdimvoid operator>(const Optional<T> &X, const Optional<U> &Y); 190218893Sdim 191207618Srdivacky} // end llvm namespace 192207618Srdivacky 193207618Srdivacky#endif 194