[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / include / llvm / ADT / Optional.h
blobb45a74002e10c9d6b6bd7aac8456b2e3dca029bb
1 //===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
2 //
3 // 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
6 //
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.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_ADT_OPTIONAL_H
16 #define LLVM_ADT_OPTIONAL_H
18 #include "llvm/ADT/None.h"
19 #include "llvm/Support/Compiler.h"
20 #include "llvm/Support/type_traits.h"
21 #include <cassert>
22 #include <memory>
23 #include <new>
24 #include <utility>
26 namespace llvm {
28 class raw_ostream;
30 namespace optional_detail {
32 struct in_place_t {};
34 /// Storage for any type.
35 template <typename T, bool = is_trivially_copyable<T>::value>
36 class OptionalStorage {
37 union {
38 char empty;
39 T value;
41 bool hasVal;
43 public:
44 ~OptionalStorage() { reset(); }
46 OptionalStorage() noexcept : empty(), hasVal(false) {}
48 OptionalStorage(OptionalStorage const &other) : OptionalStorage() {
49 if (other.hasValue()) {
50 emplace(other.value);
53 OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
54 if (other.hasValue()) {
55 emplace(std::move(other.value));
59 template <class... Args>
60 explicit OptionalStorage(in_place_t, Args &&... args)
61 : value(std::forward<Args>(args)...), hasVal(true) {}
63 void reset() noexcept {
64 if (hasVal) {
65 value.~T();
66 hasVal = false;
70 bool hasValue() const noexcept { return hasVal; }
72 T &getValue() LLVM_LVALUE_FUNCTION noexcept {
73 assert(hasVal);
74 return value;
76 T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
77 assert(hasVal);
78 return value;
80 #if LLVM_HAS_RVALUE_REFERENCE_THIS
81 T &&getValue() && noexcept {
82 assert(hasVal);
83 return std::move(value);
85 #endif
87 template <class... Args> void emplace(Args &&... args) {
88 reset();
89 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
90 hasVal = true;
93 OptionalStorage &operator=(T const &y) {
94 if (hasValue()) {
95 value = y;
96 } else {
97 ::new ((void *)std::addressof(value)) T(y);
98 hasVal = true;
100 return *this;
102 OptionalStorage &operator=(T &&y) {
103 if (hasValue()) {
104 value = std::move(y);
105 } else {
106 ::new ((void *)std::addressof(value)) T(std::move(y));
107 hasVal = true;
109 return *this;
112 OptionalStorage &operator=(OptionalStorage const &other) {
113 if (other.hasValue()) {
114 if (hasValue()) {
115 value = other.value;
116 } else {
117 ::new ((void *)std::addressof(value)) T(other.value);
118 hasVal = true;
120 } else {
121 reset();
123 return *this;
126 OptionalStorage &operator=(OptionalStorage &&other) {
127 if (other.hasValue()) {
128 if (hasValue()) {
129 value = std::move(other.value);
130 } else {
131 ::new ((void *)std::addressof(value)) T(std::move(other.value));
132 hasVal = true;
134 } else {
135 reset();
137 return *this;
141 template <typename T> class OptionalStorage<T, true> {
142 union {
143 char empty;
144 T value;
146 bool hasVal = false;
148 public:
149 ~OptionalStorage() = default;
151 OptionalStorage() noexcept : empty{} {}
153 OptionalStorage(OptionalStorage const &other) = default;
154 OptionalStorage(OptionalStorage &&other) = default;
156 OptionalStorage &operator=(OptionalStorage const &other) = default;
157 OptionalStorage &operator=(OptionalStorage &&other) = default;
159 template <class... Args>
160 explicit OptionalStorage(in_place_t, Args &&... args)
161 : value(std::forward<Args>(args)...), hasVal(true) {}
163 void reset() noexcept {
164 if (hasVal) {
165 value.~T();
166 hasVal = false;
170 bool hasValue() const noexcept { return hasVal; }
172 T &getValue() LLVM_LVALUE_FUNCTION noexcept {
173 assert(hasVal);
174 return value;
176 T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
177 assert(hasVal);
178 return value;
180 #if LLVM_HAS_RVALUE_REFERENCE_THIS
181 T &&getValue() && noexcept {
182 assert(hasVal);
183 return std::move(value);
185 #endif
187 template <class... Args> void emplace(Args &&... args) {
188 reset();
189 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
190 hasVal = true;
193 OptionalStorage &operator=(T const &y) {
194 if (hasValue()) {
195 value = y;
196 } else {
197 ::new ((void *)std::addressof(value)) T(y);
198 hasVal = true;
200 return *this;
202 OptionalStorage &operator=(T &&y) {
203 if (hasValue()) {
204 value = std::move(y);
205 } else {
206 ::new ((void *)std::addressof(value)) T(std::move(y));
207 hasVal = true;
209 return *this;
213 } // namespace optional_detail
215 template <typename T> class Optional {
216 optional_detail::OptionalStorage<T> Storage;
218 public:
219 using value_type = T;
221 constexpr Optional() {}
222 constexpr Optional(NoneType) {}
224 Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {}
225 Optional(const Optional &O) = default;
227 Optional(T &&y) : Storage(optional_detail::in_place_t{}, std::move(y)) {}
228 Optional(Optional &&O) = default;
230 Optional &operator=(T &&y) {
231 Storage = std::move(y);
232 return *this;
234 Optional &operator=(Optional &&O) = default;
236 /// Create a new object by constructing it in place with the given arguments.
237 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
238 Storage.emplace(std::forward<ArgTypes>(Args)...);
241 static inline Optional create(const T *y) {
242 return y ? Optional(*y) : Optional();
245 Optional &operator=(const T &y) {
246 Storage = y;
247 return *this;
249 Optional &operator=(const Optional &O) = default;
251 void reset() { Storage.reset(); }
253 const T *getPointer() const { return &Storage.getValue(); }
254 T *getPointer() { return &Storage.getValue(); }
255 const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); }
256 T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); }
258 explicit operator bool() const { return hasValue(); }
259 bool hasValue() const { return Storage.hasValue(); }
260 const T *operator->() const { return getPointer(); }
261 T *operator->() { return getPointer(); }
262 const T &operator*() const LLVM_LVALUE_FUNCTION { return getValue(); }
263 T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); }
265 template <typename U>
266 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
267 return hasValue() ? getValue() : std::forward<U>(value);
270 #if LLVM_HAS_RVALUE_REFERENCE_THIS
271 T &&getValue() && { return std::move(Storage.getValue()); }
272 T &&operator*() && { return std::move(Storage.getValue()); }
274 template <typename U>
275 T getValueOr(U &&value) && {
276 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
278 #endif
281 template <typename T, typename U>
282 bool operator==(const Optional<T> &X, const Optional<U> &Y) {
283 if (X && Y)
284 return *X == *Y;
285 return X.hasValue() == Y.hasValue();
288 template <typename T, typename U>
289 bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
290 return !(X == Y);
293 template <typename T, typename U>
294 bool operator<(const Optional<T> &X, const Optional<U> &Y) {
295 if (X && Y)
296 return *X < *Y;
297 return X.hasValue() < Y.hasValue();
300 template <typename T, typename U>
301 bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
302 return !(Y < X);
305 template <typename T, typename U>
306 bool operator>(const Optional<T> &X, const Optional<U> &Y) {
307 return Y < X;
310 template <typename T, typename U>
311 bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
312 return !(X < Y);
315 template<typename T>
316 bool operator==(const Optional<T> &X, NoneType) {
317 return !X;
320 template<typename T>
321 bool operator==(NoneType, const Optional<T> &X) {
322 return X == None;
325 template<typename T>
326 bool operator!=(const Optional<T> &X, NoneType) {
327 return !(X == None);
330 template<typename T>
331 bool operator!=(NoneType, const Optional<T> &X) {
332 return X != None;
335 template <typename T> bool operator<(const Optional<T> &X, NoneType) {
336 return false;
339 template <typename T> bool operator<(NoneType, const Optional<T> &X) {
340 return X.hasValue();
343 template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
344 return !(None < X);
347 template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
348 return !(X < None);
351 template <typename T> bool operator>(const Optional<T> &X, NoneType) {
352 return None < X;
355 template <typename T> bool operator>(NoneType, const Optional<T> &X) {
356 return X < None;
359 template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
360 return None <= X;
363 template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
364 return X <= None;
367 template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
368 return X && *X == Y;
371 template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
372 return Y && X == *Y;
375 template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
376 return !(X == Y);
379 template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
380 return !(X == Y);
383 template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
384 return !X || *X < Y;
387 template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
388 return Y && X < *Y;
391 template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
392 return !(Y < X);
395 template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
396 return !(Y < X);
399 template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
400 return Y < X;
403 template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
404 return Y < X;
407 template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
408 return !(X < Y);
411 template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
412 return !(X < Y);
415 raw_ostream &operator<<(raw_ostream &OS, NoneType);
417 template <typename T, typename = decltype(std::declval<raw_ostream &>()
418 << std::declval<const T &>())>
419 raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) {
420 if (O)
421 OS << *O;
422 else
423 OS << None;
424 return OS;
427 } // end namespace llvm
429 #endif // LLVM_ADT_OPTIONAL_H