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