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<T>::value> 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} // namespace optional_detail
112
113template <typename T> class Optional {
114 optional_detail::OptionalStorage<T> Storage;
115
116public:
117 using value_type = T;
118
119 constexpr Optional() {}
120 constexpr Optional(NoneType) {}
121
122 Optional(const T &y) : Storage(y) {}
123 Optional(const Optional &O) = default;
124
125 Optional(T &&y) : Storage(std::forward<T>(y)) {}
126 Optional(Optional &&O) = default;
127
128 Optional &operator=(T &&y) {
129 Storage = std::move(y);
130 return *this;
131 }
132 Optional &operator=(Optional &&O) = default;
133
134 /// Create a new object by constructing it in place with the given arguments.
135 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
136 reset();
137 Storage.hasVal = true;
138 new (getPointer()) T(std::forward<ArgTypes>(Args)...);
139 }
140
141 static inline Optional create(const T *y) {
142 return y ? Optional(*y) : Optional();
143 }
144
145 Optional &operator=(const T &y) {
146 Storage = y;
147 return *this;
148 }
149 Optional &operator=(const Optional &O) = default;
150
151 void reset() { Storage.reset(); }
152
153 const T *getPointer() const {
154 assert(Storage.hasVal);
155 return reinterpret_cast<const T *>(Storage.storage.buffer);
156 }
157 T *getPointer() {
158 assert(Storage.hasVal);
159 return reinterpret_cast<T *>(Storage.storage.buffer);
160 }
161 const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
162 T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }
163
164 explicit operator bool() const { return Storage.hasVal; }
165 bool hasValue() const { return Storage.hasVal; }
166 const T *operator->() const { return getPointer(); }
167 T *operator->() { return getPointer(); }
168 const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
169 T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); }
170
171 template <typename U>
172 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
173 return hasValue() ? getValue() : std::forward<U>(value);
174 }
175
176#if LLVM_HAS_RVALUE_REFERENCE_THIS
177 T &&getValue() && { return std::move(*getPointer()); }
178 T &&operator*() && { return std::move(*getPointer()); }
179
180 template <typename U>
181 T getValueOr(U &&value) && {
182 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
183 }
184#endif
185};
186
187template <typename T> struct isPodLike<Optional<T>> {
188 // An Optional<T> is pod-like if T is.
189 static const bool value = isPodLike<T>::value;
190};
191
192template <typename T, typename U>
193bool operator==(const Optional<T> &X, const Optional<U> &Y) {
194 if (X && Y)
195 return *X == *Y;
196 return X.hasValue() == Y.hasValue();
197}
198
199template <typename T, typename U>
200bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
201 return !(X == Y);
202}
203
204template <typename T, typename U>
205bool operator<(const Optional<T> &X, const Optional<U> &Y) {
206 if (X && Y)
207 return *X < *Y;
208 return X.hasValue() < Y.hasValue();
209}
210
211template <typename T, typename U>
212bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
213 return !(Y < X);
214}
215
216template <typename T, typename U>
217bool operator>(const Optional<T> &X, const Optional<U> &Y) {
218 return Y < X;
219}
220
221template <typename T, typename U>
222bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
223 return !(X < Y);
224}
225
226template<typename T>
227bool operator==(const Optional<T> &X, NoneType) {
228 return !X;
229}
230
231template<typename T>
232bool operator==(NoneType, const Optional<T> &X) {
233 return X == None;
234}
235
236template<typename T>
237bool operator!=(const Optional<T> &X, NoneType) {
238 return !(X == None);
239}
240
241template<typename T>
242bool operator!=(NoneType, const Optional<T> &X) {
243 return X != None;
244}
245
246template <typename T> bool operator<(const Optional<T> &X, NoneType) {
247 return false;
248}
249
250template <typename T> bool operator<(NoneType, const Optional<T> &X) {
251 return X.hasValue();
252}
253
254template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
255 return !(None < X);
256}
257
258template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
259 return !(X < None);
260}
261
262template <typename T> bool operator>(const Optional<T> &X, NoneType) {
263 return None < X;
264}
265
266template <typename T> bool operator>(NoneType, const Optional<T> &X) {
267 return X < None;
268}
269
270template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
271 return None <= X;
272}
273
274template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
275 return X <= None;
276}
277
278template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
279 return X && *X == Y;
280}
281
282template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
283 return Y && X == *Y;
284}
285
286template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
287 return !(X == Y);
288}
289
290template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
291 return !(X == Y);
292}
293
294template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
295 return !X || *X < Y;
296}
297
298template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
299 return Y && X < *Y;
300}
301
302template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
303 return !(Y < X);
304}
305
306template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
307 return !(Y < X);
308}
309
310template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
311 return Y < X;
312}
313
314template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
315 return Y < X;
316}
317
318template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
319 return !(X < Y);
320}
321
322template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
323 return !(X < Y);
324}
325
326} // end namespace llvm
327
328#endif // LLVM_ADT_OPTIONAL_H
329