blob: daa9ee627fa902bd5579eeed9b19802e71ab4dcb [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9// This file provides Optional, a template class modeled in the spirit of
10// OCaml's 'opt' variant. The idea is to strongly type whether or not
11// a value can be optional.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_ADT_OPTIONAL_H
16#define LLVM_ADT_OPTIONAL_H
17
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020018#include "llvm/ADT/Hashing.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010019#include "llvm/ADT/None.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010020#include "llvm/Support/Compiler.h"
21#include "llvm/Support/type_traits.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010022#include <cassert>
Andrew Walbran3d2c1972020-04-07 12:24:26 +010023#include <memory>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010024#include <new>
25#include <utility>
26
27namespace llvm {
28
Andrew Walbran16937d02019-10-22 13:54:20 +010029class raw_ostream;
30
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010031namespace optional_detail {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010032
33struct in_place_t {};
34
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010035/// Storage for any type.
Andrew Walbran3d2c1972020-04-07 12:24:26 +010036template <typename T, bool = is_trivially_copyable<T>::value>
37class OptionalStorage {
38 union {
39 char empty;
40 T value;
41 };
42 bool hasVal;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010043
Andrew Walbran3d2c1972020-04-07 12:24:26 +010044public:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010045 ~OptionalStorage() { reset(); }
46
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020047 constexpr OptionalStorage() noexcept : empty(), hasVal(false) {}
Andrew Walbran3d2c1972020-04-07 12:24:26 +010048
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020049 constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010050 if (other.hasValue()) {
51 emplace(other.value);
52 }
53 }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020054 constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010055 if (other.hasValue()) {
56 emplace(std::move(other.value));
57 }
58 }
59
60 template <class... Args>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020061 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
Andrew Walbran3d2c1972020-04-07 12:24:26 +010062 : value(std::forward<Args>(args)...), hasVal(true) {}
63
64 void reset() noexcept {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010065 if (hasVal) {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010066 value.~T();
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010067 hasVal = false;
68 }
69 }
70
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020071 constexpr bool hasValue() const noexcept { return hasVal; }
Andrew Walbran3d2c1972020-04-07 12:24:26 +010072
73 T &getValue() LLVM_LVALUE_FUNCTION noexcept {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010074 assert(hasVal);
Andrew Walbran3d2c1972020-04-07 12:24:26 +010075 return value;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010076 }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020077 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010078 assert(hasVal);
Andrew Walbran3d2c1972020-04-07 12:24:26 +010079 return value;
80 }
81#if LLVM_HAS_RVALUE_REFERENCE_THIS
82 T &&getValue() && noexcept {
83 assert(hasVal);
84 return std::move(value);
85 }
86#endif
87
88 template <class... Args> void emplace(Args &&... args) {
89 reset();
90 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
91 hasVal = true;
92 }
93
94 OptionalStorage &operator=(T const &y) {
95 if (hasValue()) {
96 value = y;
97 } else {
98 ::new ((void *)std::addressof(value)) T(y);
99 hasVal = true;
100 }
101 return *this;
102 }
103 OptionalStorage &operator=(T &&y) {
104 if (hasValue()) {
105 value = std::move(y);
106 } else {
107 ::new ((void *)std::addressof(value)) T(std::move(y));
108 hasVal = true;
109 }
110 return *this;
111 }
112
113 OptionalStorage &operator=(OptionalStorage const &other) {
114 if (other.hasValue()) {
115 if (hasValue()) {
116 value = other.value;
117 } else {
118 ::new ((void *)std::addressof(value)) T(other.value);
119 hasVal = true;
120 }
121 } else {
122 reset();
123 }
124 return *this;
125 }
126
127 OptionalStorage &operator=(OptionalStorage &&other) {
128 if (other.hasValue()) {
129 if (hasValue()) {
130 value = std::move(other.value);
131 } else {
132 ::new ((void *)std::addressof(value)) T(std::move(other.value));
133 hasVal = true;
134 }
135 } else {
136 reset();
137 }
138 return *this;
139 }
140};
141
142template <typename T> class OptionalStorage<T, true> {
143 union {
144 char empty;
145 T value;
146 };
147 bool hasVal = false;
148
149public:
150 ~OptionalStorage() = default;
151
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200152 constexpr OptionalStorage() noexcept : empty{} {}
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100153
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200154 constexpr OptionalStorage(OptionalStorage const &other) = default;
155 constexpr OptionalStorage(OptionalStorage &&other) = default;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100156
157 OptionalStorage &operator=(OptionalStorage const &other) = default;
158 OptionalStorage &operator=(OptionalStorage &&other) = default;
159
160 template <class... Args>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200161 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100162 : value(std::forward<Args>(args)...), hasVal(true) {}
163
164 void reset() noexcept {
165 if (hasVal) {
166 value.~T();
167 hasVal = false;
168 }
169 }
170
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200171 constexpr bool hasValue() const noexcept { return hasVal; }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100172
173 T &getValue() LLVM_LVALUE_FUNCTION noexcept {
174 assert(hasVal);
175 return value;
176 }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200177 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100178 assert(hasVal);
179 return value;
180 }
181#if LLVM_HAS_RVALUE_REFERENCE_THIS
182 T &&getValue() && noexcept {
183 assert(hasVal);
184 return std::move(value);
185 }
186#endif
187
188 template <class... Args> void emplace(Args &&... args) {
189 reset();
190 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
191 hasVal = true;
192 }
193
194 OptionalStorage &operator=(T const &y) {
195 if (hasValue()) {
196 value = y;
197 } else {
198 ::new ((void *)std::addressof(value)) T(y);
199 hasVal = true;
200 }
201 return *this;
202 }
203 OptionalStorage &operator=(T &&y) {
204 if (hasValue()) {
205 value = std::move(y);
206 } else {
207 ::new ((void *)std::addressof(value)) T(std::move(y));
208 hasVal = true;
209 }
210 return *this;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100211 }
212};
213
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100214} // namespace optional_detail
215
216template <typename T> class Optional {
Andrew Walbran16937d02019-10-22 13:54:20 +0100217 optional_detail::OptionalStorage<T> Storage;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100218
219public:
220 using value_type = T;
221
222 constexpr Optional() {}
223 constexpr Optional(NoneType) {}
224
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200225 constexpr Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {}
226 constexpr Optional(const Optional &O) = default;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100227
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200228 constexpr Optional(T &&y)
229 : Storage(optional_detail::in_place_t{}, std::move(y)) {}
230 constexpr Optional(Optional &&O) = default;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100231
232 Optional &operator=(T &&y) {
233 Storage = std::move(y);
234 return *this;
235 }
236 Optional &operator=(Optional &&O) = default;
237
238 /// Create a new object by constructing it in place with the given arguments.
239 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100240 Storage.emplace(std::forward<ArgTypes>(Args)...);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100241 }
242
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200243 static constexpr Optional create(const T *y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100244 return y ? Optional(*y) : Optional();
245 }
246
247 Optional &operator=(const T &y) {
248 Storage = y;
249 return *this;
250 }
251 Optional &operator=(const Optional &O) = default;
252
253 void reset() { Storage.reset(); }
254
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200255 constexpr const T *getPointer() const { return &Storage.getValue(); }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100256 T *getPointer() { return &Storage.getValue(); }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200257 constexpr const T &getValue() const LLVM_LVALUE_FUNCTION {
258 return Storage.getValue();
259 }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100260 T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100261
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200262 constexpr explicit operator bool() const { return hasValue(); }
263 constexpr bool hasValue() const { return Storage.hasValue(); }
264 constexpr const T *operator->() const { return getPointer(); }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100265 T *operator->() { return getPointer(); }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200266 constexpr const T &operator*() const LLVM_LVALUE_FUNCTION {
267 return getValue();
268 }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100269 T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100270
271 template <typename U>
272 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
273 return hasValue() ? getValue() : std::forward<U>(value);
274 }
275
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200276 /// Apply a function to the value if present; otherwise return None.
277 template <class Function>
278 auto map(const Function &F) const LLVM_LVALUE_FUNCTION
279 -> Optional<decltype(F(getValue()))> {
280 if (*this) return F(getValue());
281 return None;
282 }
283
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100284#if LLVM_HAS_RVALUE_REFERENCE_THIS
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100285 T &&getValue() && { return std::move(Storage.getValue()); }
286 T &&operator*() && { return std::move(Storage.getValue()); }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100287
288 template <typename U>
289 T getValueOr(U &&value) && {
290 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
291 }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200292
293 /// Apply a function to the value if present; otherwise return None.
294 template <class Function>
295 auto map(const Function &F) &&
296 -> Optional<decltype(F(std::move(*this).getValue()))> {
297 if (*this) return F(std::move(*this).getValue());
298 return None;
299 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100300#endif
301};
302
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200303template <class T> llvm::hash_code hash_value(const Optional<T> &O) {
304 return O ? hash_combine(true, *O) : hash_value(false);
305}
306
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100307template <typename T, typename U>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200308constexpr bool operator==(const Optional<T> &X, const Optional<U> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100309 if (X && Y)
310 return *X == *Y;
311 return X.hasValue() == Y.hasValue();
312}
313
314template <typename T, typename U>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200315constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100316 return !(X == Y);
317}
318
319template <typename T, typename U>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200320constexpr bool operator<(const Optional<T> &X, const Optional<U> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100321 if (X && Y)
322 return *X < *Y;
323 return X.hasValue() < Y.hasValue();
324}
325
326template <typename T, typename U>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200327constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100328 return !(Y < X);
329}
330
331template <typename T, typename U>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200332constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100333 return Y < X;
334}
335
336template <typename T, typename U>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200337constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100338 return !(X < Y);
339}
340
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200341template <typename T>
342constexpr bool operator==(const Optional<T> &X, NoneType) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100343 return !X;
344}
345
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200346template <typename T>
347constexpr bool operator==(NoneType, const Optional<T> &X) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100348 return X == None;
349}
350
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200351template <typename T>
352constexpr bool operator!=(const Optional<T> &X, NoneType) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100353 return !(X == None);
354}
355
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200356template <typename T>
357constexpr bool operator!=(NoneType, const Optional<T> &X) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100358 return X != None;
359}
360
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200361template <typename T> constexpr bool operator<(const Optional<T> &X, NoneType) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100362 return false;
363}
364
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200365template <typename T> constexpr bool operator<(NoneType, const Optional<T> &X) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100366 return X.hasValue();
367}
368
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200369template <typename T>
370constexpr bool operator<=(const Optional<T> &X, NoneType) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100371 return !(None < X);
372}
373
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200374template <typename T>
375constexpr bool operator<=(NoneType, const Optional<T> &X) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100376 return !(X < None);
377}
378
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200379template <typename T> constexpr bool operator>(const Optional<T> &X, NoneType) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100380 return None < X;
381}
382
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200383template <typename T> constexpr bool operator>(NoneType, const Optional<T> &X) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100384 return X < None;
385}
386
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200387template <typename T>
388constexpr bool operator>=(const Optional<T> &X, NoneType) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100389 return None <= X;
390}
391
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200392template <typename T>
393constexpr bool operator>=(NoneType, const Optional<T> &X) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100394 return X <= None;
395}
396
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200397template <typename T>
398constexpr bool operator==(const Optional<T> &X, const T &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100399 return X && *X == Y;
400}
401
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200402template <typename T>
403constexpr bool operator==(const T &X, const Optional<T> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100404 return Y && X == *Y;
405}
406
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200407template <typename T>
408constexpr bool operator!=(const Optional<T> &X, const T &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100409 return !(X == Y);
410}
411
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200412template <typename T>
413constexpr bool operator!=(const T &X, const Optional<T> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100414 return !(X == Y);
415}
416
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200417template <typename T>
418constexpr bool operator<(const Optional<T> &X, const T &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100419 return !X || *X < Y;
420}
421
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200422template <typename T>
423constexpr bool operator<(const T &X, const Optional<T> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100424 return Y && X < *Y;
425}
426
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200427template <typename T>
428constexpr bool operator<=(const Optional<T> &X, const T &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100429 return !(Y < X);
430}
431
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200432template <typename T>
433constexpr bool operator<=(const T &X, const Optional<T> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100434 return !(Y < X);
435}
436
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200437template <typename T>
438constexpr bool operator>(const Optional<T> &X, const T &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100439 return Y < X;
440}
441
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200442template <typename T>
443constexpr bool operator>(const T &X, const Optional<T> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100444 return Y < X;
445}
446
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200447template <typename T>
448constexpr bool operator>=(const Optional<T> &X, const T &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100449 return !(X < Y);
450}
451
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200452template <typename T>
453constexpr bool operator>=(const T &X, const Optional<T> &Y) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100454 return !(X < Y);
455}
456
Andrew Walbran16937d02019-10-22 13:54:20 +0100457raw_ostream &operator<<(raw_ostream &OS, NoneType);
458
459template <typename T, typename = decltype(std::declval<raw_ostream &>()
460 << std::declval<const T &>())>
461raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) {
462 if (O)
463 OS << *O;
464 else
465 OS << None;
466 return OS;
467}
468
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100469} // end namespace llvm
470
471#endif // LLVM_ADT_OPTIONAL_H