1 //===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
14 //===----------------------------------------------------------------------===//
16 #ifndef LLVM_ADT_OPTIONAL_H
17 #define LLVM_ADT_OPTIONAL_H
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"
30 namespace optional_detail {
31 /// Storage for any type.
32 template <typename T, bool IsPodLike> struct OptionalStorage {
33 AlignedCharArrayUnion<T> storage;
36 OptionalStorage() = default;
38 OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
39 OptionalStorage(const OptionalStorage &O) : hasVal(O.hasVal) {
41 new (storage.buffer) T(*O.getPointer());
43 OptionalStorage(T &&y) : hasVal(true) {
44 new (storage.buffer) T(std::forward<T>(y));
46 OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) {
48 new (storage.buffer) T(std::move(*O.getPointer()));
52 OptionalStorage &operator=(T &&y) {
54 *getPointer() = std::move(y);
56 new (storage.buffer) T(std::move(y));
61 OptionalStorage &operator=(OptionalStorage &&O) {
65 *this = std::move(*O.getPointer());
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) {
79 new (storage.buffer) T(y);
84 OptionalStorage &operator=(const OptionalStorage &O) {
88 *this = *O.getPointer();
92 ~OptionalStorage() { reset(); }
103 return reinterpret_cast<T *>(storage.buffer);
105 const T *getPointer() const {
107 return reinterpret_cast<const T *>(storage.buffer);
111 #if !defined(__GNUC__) || defined(__clang__) // GCC up to GCC7 miscompiles this.
112 /// Storage for trivially copyable types only.
113 template <typename T> struct OptionalStorage<T, true> {
114 AlignedCharArrayUnion<T> storage;
117 OptionalStorage() = default;
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;
126 void reset() { hasVal = false; }
129 } // namespace optional_detail
131 template <typename T> class Optional {
132 optional_detail::OptionalStorage<T, isPodLike<T>::value> Storage;
135 using value_type = T;
137 constexpr Optional() {}
138 constexpr Optional(NoneType) {}
140 Optional(const T &y) : Storage(y) {}
141 Optional(const Optional &O) = default;
143 Optional(T &&y) : Storage(std::forward<T>(y)) {}
144 Optional(Optional &&O) = default;
146 Optional &operator=(T &&y) {
147 Storage = std::move(y);
150 Optional &operator=(Optional &&O) = default;
152 /// Create a new object by constructing it in place with the given arguments.
153 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
155 Storage.hasVal = true;
156 new (getPointer()) T(std::forward<ArgTypes>(Args)...);
159 static inline Optional create(const T *y) {
160 return y ? Optional(*y) : Optional();
163 Optional &operator=(const T &y) {
167 Optional &operator=(const Optional &O) = default;
169 void reset() { Storage.reset(); }
171 const T *getPointer() const {
172 assert(Storage.hasVal);
173 return reinterpret_cast<const T *>(Storage.storage.buffer);
176 assert(Storage.hasVal);
177 return reinterpret_cast<T *>(Storage.storage.buffer);
179 const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
180 T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }
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(); }
189 template <typename U>
190 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
191 return hasValue() ? getValue() : std::forward<U>(value);
194 #if LLVM_HAS_RVALUE_REFERENCE_THIS
195 T &&getValue() && { return std::move(*getPointer()); }
196 T &&operator*() && { return std::move(*getPointer()); }
198 template <typename U>
199 T getValueOr(U &&value) && {
200 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
205 template <typename T> struct isPodLike<Optional<T>> {
206 // An Optional<T> is pod-like if T is.
207 static const bool value = isPodLike<T>::value;
210 template <typename T, typename U>
211 bool operator==(const Optional<T> &X, const Optional<U> &Y) {
214 return X.hasValue() == Y.hasValue();
217 template <typename T, typename U>
218 bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
222 template <typename T, typename U>
223 bool operator<(const Optional<T> &X, const Optional<U> &Y) {
226 return X.hasValue() < Y.hasValue();
229 template <typename T, typename U>
230 bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
234 template <typename T, typename U>
235 bool operator>(const Optional<T> &X, const Optional<U> &Y) {
239 template <typename T, typename U>
240 bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
245 bool operator==(const Optional<T> &X, NoneType) {
250 bool operator==(NoneType, const Optional<T> &X) {
255 bool operator!=(const Optional<T> &X, NoneType) {
260 bool operator!=(NoneType, const Optional<T> &X) {
264 template <typename T> bool operator<(const Optional<T> &X, NoneType) {
268 template <typename T> bool operator<(NoneType, const Optional<T> &X) {
272 template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
276 template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
280 template <typename T> bool operator>(const Optional<T> &X, NoneType) {
284 template <typename T> bool operator>(NoneType, const Optional<T> &X) {
288 template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
292 template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
296 template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
300 template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
304 template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
308 template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
312 template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
316 template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
320 template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
324 template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
328 template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
332 template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
336 template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
340 template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
344 } // end namespace llvm
346 #endif // LLVM_ADT_OPTIONAL_H