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