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/AlignOf.h"
21#include "llvm/Support/Compiler.h"
22#include <cassert>
23#include <new>
24#include <utility>
25
26namespace llvm {
27
28template<typename T>
29class Optional {
30  AlignedCharArrayUnion<T> storage;
31  bool hasVal;
32public:
33  typedef T value_type;
34
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  Optional(T &&y) : hasVal(true) {
46    new (storage.buffer) T(std::forward<T>(y));
47  }
48  Optional(Optional<T> &&O) : hasVal(O) {
49    if (O) {
50      new (storage.buffer) T(std::move(*O));
51      O.reset();
52    }
53  }
54  Optional &operator=(T &&y) {
55    if (hasVal)
56      **this = std::move(y);
57    else {
58      new (storage.buffer) T(std::move(y));
59      hasVal = true;
60    }
61    return *this;
62  }
63  Optional &operator=(Optional &&O) {
64    if (!O)
65      reset();
66    else {
67      *this = std::move(*O);
68      O.reset();
69    }
70    return *this;
71  }
72
73  /// Create a new object by constructing it in place with the given arguments.
74  template<typename ...ArgTypes>
75  void emplace(ArgTypes &&...Args) {
76    reset();
77    hasVal = true;
78    new (storage.buffer) T(std::forward<ArgTypes>(Args)...);
79  }
80
81  static inline Optional create(const T* y) {
82    return y ? Optional(*y) : Optional();
83  }
84
85  // FIXME: these assignments (& the equivalent const T&/const Optional& ctors)
86  // could be made more efficient by passing by value, possibly unifying them
87  // with the rvalue versions above - but this could place a different set of
88  // requirements (notably: the existence of a default ctor) when implemented
89  // in that way. Careful SFINAE to avoid such pitfalls would be required.
90  Optional &operator=(const T &y) {
91    if (hasVal)
92      **this = y;
93    else {
94      new (storage.buffer) T(y);
95      hasVal = true;
96    }
97    return *this;
98  }
99
100  Optional &operator=(const Optional &O) {
101    if (!O)
102      reset();
103    else
104      *this = *O;
105    return *this;
106  }
107
108  void reset() {
109    if (hasVal) {
110      (**this).~T();
111      hasVal = false;
112    }
113  }
114
115  ~Optional() {
116    reset();
117  }
118
119  const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); }
120  T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); }
121  const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
122  T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
123
124  explicit operator bool() const { return hasVal; }
125  bool hasValue() const { return hasVal; }
126  const T* operator->() const { return getPointer(); }
127  T* operator->() { return getPointer(); }
128  const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
129  T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
130
131  template <typename U>
132  constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
133    return hasValue() ? getValue() : std::forward<U>(value);
134  }
135
136#if LLVM_HAS_RVALUE_REFERENCE_THIS
137  T&& getValue() && { assert(hasVal); return std::move(*getPointer()); }
138  T&& operator*() && { assert(hasVal); return std::move(*getPointer()); }
139
140  template <typename U>
141  T getValueOr(U &&value) && {
142    return hasValue() ? std::move(getValue()) : std::forward<U>(value);
143  }
144#endif
145};
146
147template <typename T> struct isPodLike;
148template <typename T> struct isPodLike<Optional<T> > {
149  // An Optional<T> is pod-like if T is.
150  static const bool value = isPodLike<T>::value;
151};
152
153template <typename T, typename U>
154bool operator==(const Optional<T> &X, const Optional<U> &Y) {
155  if (X && Y)
156    return *X == *Y;
157  return X.hasValue() == Y.hasValue();
158}
159
160template <typename T, typename U>
161bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
162  return !(X == Y);
163}
164
165template <typename T, typename U>
166bool operator<(const Optional<T> &X, const Optional<U> &Y) {
167  if (X && Y)
168    return *X < *Y;
169  return X.hasValue() < Y.hasValue();
170}
171
172template <typename T, typename U>
173bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
174  return !(Y < X);
175}
176
177template <typename T, typename U>
178bool operator>(const Optional<T> &X, const Optional<U> &Y) {
179  return Y < X;
180}
181
182template <typename T, typename U>
183bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
184  return !(X < Y);
185}
186
187template<typename T>
188bool operator==(const Optional<T> &X, NoneType) {
189  return !X;
190}
191
192template<typename T>
193bool operator==(NoneType, const Optional<T> &X) {
194  return X == None;
195}
196
197template<typename T>
198bool operator!=(const Optional<T> &X, NoneType) {
199  return !(X == None);
200}
201
202template<typename T>
203bool operator!=(NoneType, const Optional<T> &X) {
204  return X != None;
205}
206
207template <typename T> bool operator<(const Optional<T> &X, NoneType) {
208  return false;
209}
210
211template <typename T> bool operator<(NoneType, const Optional<T> &X) {
212  return X.hasValue();
213}
214
215template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
216  return !(None < X);
217}
218
219template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
220  return !(X < None);
221}
222
223template <typename T> bool operator>(const Optional<T> &X, NoneType) {
224  return None < X;
225}
226
227template <typename T> bool operator>(NoneType, const Optional<T> &X) {
228  return X < None;
229}
230
231template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
232  return None <= X;
233}
234
235template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
236  return X <= None;
237}
238
239template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
240  return X && *X == Y;
241}
242
243template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
244  return Y && X == *Y;
245}
246
247template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
248  return !(X == Y);
249}
250
251template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
252  return !(X == Y);
253}
254
255template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
256  return !X || *X < Y;
257}
258
259template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
260  return Y && X < *Y;
261}
262
263template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
264  return !(Y < X);
265}
266
267template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
268  return !(Y < X);
269}
270
271template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
272  return Y < X;
273}
274
275template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
276  return Y < X;
277}
278
279template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
280  return !(X < Y);
281}
282
283template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
284  return !(X < Y);
285}
286
287} // end llvm namespace
288
289#endif
290