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 16249423Sdim#ifndef LLVM_ADT_OPTIONAL_H 17249423Sdim#define LLVM_ADT_OPTIONAL_H 18207618Srdivacky 19249423Sdim#include "llvm/ADT/None.h" 20243830Sdim#include "llvm/Support/Compiler.h" 21249423Sdim#include "llvm/Support/AlignOf.h" 22207618Srdivacky#include <cassert> 23207618Srdivacky 24249423Sdim#if LLVM_HAS_RVALUE_REFERENCES 25243830Sdim#include <utility> 26243830Sdim#endif 27243830Sdim 28207618Srdivackynamespace llvm { 29207618Srdivacky 30207618Srdivackytemplate<typename T> 31207618Srdivackyclass Optional { 32249423Sdim AlignedCharArrayUnion<T> storage; 33249423Sdim bool hasVal; 34207618Srdivackypublic: 35249423Sdim Optional(NoneType) : hasVal(false) {} 36249423Sdim explicit Optional() : hasVal(false) {} 37249423Sdim Optional(const T &y) : hasVal(true) { 38249423Sdim new (storage.buffer) T(y); 39249423Sdim } 40249423Sdim Optional(const Optional &O) : hasVal(O.hasVal) { 41249423Sdim if (hasVal) 42249423Sdim new (storage.buffer) T(*O); 43249423Sdim } 44207618Srdivacky 45249423Sdim#if LLVM_HAS_RVALUE_REFERENCES 46249423Sdim Optional(T &&y) : hasVal(true) { 47249423Sdim new (storage.buffer) T(std::forward<T>(y)); 48249423Sdim } 49249423Sdim Optional(Optional<T> &&O) : hasVal(O) { 50249423Sdim if (O) { 51249423Sdim new (storage.buffer) T(std::move(*O)); 52249423Sdim O.reset(); 53249423Sdim } 54249423Sdim } 55249423Sdim Optional &operator=(T &&y) { 56249423Sdim if (hasVal) 57249423Sdim **this = std::move(y); 58249423Sdim else { 59249423Sdim new (storage.buffer) T(std::move(y)); 60249423Sdim hasVal = true; 61249423Sdim } 62249423Sdim return *this; 63249423Sdim } 64249423Sdim Optional &operator=(Optional &&O) { 65249423Sdim if (!O) 66249423Sdim reset(); 67249423Sdim else { 68249423Sdim *this = std::move(*O); 69249423Sdim O.reset(); 70249423Sdim } 71249423Sdim return *this; 72249423Sdim } 73243830Sdim#endif 74243830Sdim 75207618Srdivacky static inline Optional create(const T* y) { 76207618Srdivacky return y ? Optional(*y) : Optional(); 77207618Srdivacky } 78207618Srdivacky 79249423Sdim // FIXME: these assignments (& the equivalent const T&/const Optional& ctors) 80249423Sdim // could be made more efficient by passing by value, possibly unifying them 81249423Sdim // with the rvalue versions above - but this could place a different set of 82249423Sdim // requirements (notably: the existence of a default ctor) when implemented 83249423Sdim // in that way. Careful SFINAE to avoid such pitfalls would be required. 84207618Srdivacky Optional &operator=(const T &y) { 85249423Sdim if (hasVal) 86249423Sdim **this = y; 87249423Sdim else { 88249423Sdim new (storage.buffer) T(y); 89249423Sdim hasVal = true; 90249423Sdim } 91207618Srdivacky return *this; 92207618Srdivacky } 93207618Srdivacky 94249423Sdim Optional &operator=(const Optional &O) { 95249423Sdim if (!O) 96249423Sdim reset(); 97249423Sdim else 98249423Sdim *this = *O; 99249423Sdim return *this; 100249423Sdim } 101249423Sdim 102249423Sdim void reset() { 103249423Sdim if (hasVal) { 104249423Sdim (**this).~T(); 105249423Sdim hasVal = false; 106249423Sdim } 107249423Sdim } 108249423Sdim 109249423Sdim ~Optional() { 110249423Sdim reset(); 111249423Sdim } 112249423Sdim 113249423Sdim const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); } 114249423Sdim T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); } 115249423Sdim const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 116249423Sdim T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 117249423Sdim 118249423Sdim LLVM_EXPLICIT operator bool() const { return hasVal; } 119207618Srdivacky bool hasValue() const { return hasVal; } 120207618Srdivacky const T* operator->() const { return getPointer(); } 121249423Sdim T* operator->() { return getPointer(); } 122249423Sdim const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 123249423Sdim T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } 124249423Sdim 125249423Sdim#if LLVM_HAS_RVALUE_REFERENCE_THIS 126249423Sdim T&& getValue() && { assert(hasVal); return std::move(*getPointer()); } 127249423Sdim T&& operator*() && { assert(hasVal); return std::move(*getPointer()); } 128249423Sdim#endif 129207618Srdivacky}; 130207618Srdivacky 131249423Sdimtemplate <typename T> struct isPodLike; 132249423Sdimtemplate <typename T> struct isPodLike<Optional<T> > { 133249423Sdim // An Optional<T> is pod-like if T is. 134249423Sdim 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/// 141249423Sdim/// 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/// 150249423Sdim/// 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/// 159249423Sdim/// 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/// 168249423Sdim/// 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/// 177249423Sdim/// 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/// 186249423Sdim/// 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