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<T>::value> 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 } // namespace optional_detail
113 template <typename T> class Optional {
114 optional_detail::OptionalStorage<T> Storage;
117 using value_type = T;
119 constexpr Optional() {}
120 constexpr Optional(NoneType) {}
122 Optional(const T &y) : Storage(y) {}
123 Optional(const Optional &O) = default;
125 Optional(T &&y) : Storage(std::forward<T>(y)) {}
126 Optional(Optional &&O) = default;
128 Optional &operator=(T &&y) {
129 Storage = std::move(y);
132 Optional &operator=(Optional &&O) = default;
134 /// Create a new object by constructing it in place with the given arguments.
135 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
137 Storage.hasVal = true;
138 new (getPointer()) T(std::forward<ArgTypes>(Args)...);
141 static inline Optional create(const T *y) {
142 return y ? Optional(*y) : Optional();
145 Optional &operator=(const T &y) {
149 Optional &operator=(const Optional &O) = default;
151 void reset() { Storage.reset(); }
153 const T *getPointer() const {
154 assert(Storage.hasVal);
155 return reinterpret_cast<const T *>(Storage.storage.buffer);
158 assert(Storage.hasVal);
159 return reinterpret_cast<T *>(Storage.storage.buffer);
161 const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
162 T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }
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(); }
171 template <typename U>
172 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
173 return hasValue() ? getValue() : std::forward<U>(value);
176 #if LLVM_HAS_RVALUE_REFERENCE_THIS
177 T &&getValue() && { return std::move(*getPointer()); }
178 T &&operator*() && { return std::move(*getPointer()); }
180 template <typename U>
181 T getValueOr(U &&value) && {
182 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
187 template <typename T> struct isPodLike<Optional<T>> {
188 // An Optional<T> is pod-like if T is.
189 static const bool value = isPodLike<T>::value;
192 template <typename T, typename U>
193 bool operator==(const Optional<T> &X, const Optional<U> &Y) {
196 return X.hasValue() == Y.hasValue();
199 template <typename T, typename U>
200 bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
204 template <typename T, typename U>
205 bool operator<(const Optional<T> &X, const Optional<U> &Y) {
208 return X.hasValue() < Y.hasValue();
211 template <typename T, typename U>
212 bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
216 template <typename T, typename U>
217 bool operator>(const Optional<T> &X, const Optional<U> &Y) {
221 template <typename T, typename U>
222 bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
227 bool operator==(const Optional<T> &X, NoneType) {
232 bool operator==(NoneType, const Optional<T> &X) {
237 bool operator!=(const Optional<T> &X, NoneType) {
242 bool operator!=(NoneType, const Optional<T> &X) {
246 template <typename T> bool operator<(const Optional<T> &X, NoneType) {
250 template <typename T> bool operator<(NoneType, const Optional<T> &X) {
254 template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
258 template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
262 template <typename T> bool operator>(const Optional<T> &X, NoneType) {
266 template <typename T> bool operator>(NoneType, const Optional<T> &X) {
270 template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
274 template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
278 template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
282 template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
286 template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
290 template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
294 template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
298 template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
302 template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
306 template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
310 template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
314 template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
318 template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
322 template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
326 } // end namespace llvm
328 #endif // LLVM_ADT_OPTIONAL_H