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