LLVM  9.0.0svn
Optional.h
Go to the documentation of this file.
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.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_ADT_OPTIONAL_H
16 #define LLVM_ADT_OPTIONAL_H
17 
18 #include "llvm/ADT/None.h"
19 #include "llvm/Support/Compiler.h"
21 #include <cassert>
22 #include <memory>
23 #include <new>
24 #include <utility>
25 
26 namespace llvm {
27 
28 class raw_ostream;
29 
30 namespace optional_detail {
31 
32 struct in_place_t {};
33 
34 /// Storage for any type.
35 template <typename T, bool = is_trivially_copyable<T>::value>
37  union {
38  char empty;
40  };
41  bool hasVal;
42 
43 public:
44  ~OptionalStorage() { reset(); }
45 
46  OptionalStorage() noexcept : empty(), hasVal(false) {}
47 
49  if (other.hasValue()) {
50  emplace(other.value);
51  }
52  }
54  if (other.hasValue()) {
55  emplace(std::move(other.value));
56  }
57  }
58 
59  template <class... Args>
60  explicit OptionalStorage(in_place_t, Args &&... args)
61  : value(std::forward<Args>(args)...), hasVal(true) {}
62 
63  void reset() noexcept {
64  if (hasVal) {
65  value.~T();
66  hasVal = false;
67  }
68  }
69 
70  bool hasValue() const noexcept { return hasVal; }
71 
73  assert(hasVal);
74  return value;
75  }
76  T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
77  assert(hasVal);
78  return value;
79  }
80 #if LLVM_HAS_RVALUE_REFERENCE_THIS
81  T &&getValue() && noexcept {
82  assert(hasVal);
83  return std::move(value);
84  }
85 #endif
86 
87  template <class... Args> void emplace(Args &&... args) {
88  reset();
89  ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
90  hasVal = true;
91  }
92 
94  if (hasValue()) {
95  value = y;
96  } else {
97  ::new ((void *)std::addressof(value)) T(y);
98  hasVal = true;
99  }
100  return *this;
101  }
103  if (hasValue()) {
104  value = std::move(y);
105  } else {
106  ::new ((void *)std::addressof(value)) T(std::move(y));
107  hasVal = true;
108  }
109  return *this;
110  }
111 
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;
119  }
120  } else {
121  reset();
122  }
123  return *this;
124  }
125 
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;
133  }
134  } else {
135  reset();
136  }
137  return *this;
138  }
139 };
140 
141 template <typename T> class OptionalStorage<T, true> {
142  union {
143  char empty;
145  };
146  bool hasVal = false;
147 
148 public:
149  ~OptionalStorage() = default;
150 
151  OptionalStorage() noexcept : empty{} {}
152 
153  OptionalStorage(OptionalStorage const &other) = default;
154  OptionalStorage(OptionalStorage &&other) = default;
155 
156  OptionalStorage &operator=(OptionalStorage const &other) = default;
157  OptionalStorage &operator=(OptionalStorage &&other) = default;
158 
159  template <class... Args>
160  explicit OptionalStorage(in_place_t, Args &&... args)
161  : value(std::forward<Args>(args)...), hasVal(true) {}
162 
163  void reset() noexcept {
164  if (hasVal) {
165  value.~T();
166  hasVal = false;
167  }
168  }
169 
170  bool hasValue() const noexcept { return hasVal; }
171 
173  assert(hasVal);
174  return value;
175  }
176  T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
177  assert(hasVal);
178  return value;
179  }
180 #if LLVM_HAS_RVALUE_REFERENCE_THIS
181  T &&getValue() && noexcept {
182  assert(hasVal);
183  return std::move(value);
184  }
185 #endif
186 
187  template <class... Args> void emplace(Args &&... args) {
188  reset();
189  ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
190  hasVal = true;
191  }
192 
194  if (hasValue()) {
195  value = y;
196  } else {
197  ::new ((void *)std::addressof(value)) T(y);
198  hasVal = true;
199  }
200  return *this;
201  }
203  if (hasValue()) {
204  value = std::move(y);
205  } else {
206  ::new ((void *)std::addressof(value)) T(std::move(y));
207  hasVal = true;
208  }
209  return *this;
210  }
211 };
212 
213 } // namespace optional_detail
214 
215 template <typename T> class Optional {
217 
218 public:
219  using value_type = T;
220 
221  constexpr Optional() {}
222  constexpr Optional(NoneType) {}
223 
224  Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {}
225  Optional(const Optional &O) = default;
226 
227  Optional(T &&y) : Storage(optional_detail::in_place_t{}, std::move(y)) {}
228  Optional(Optional &&O) = default;
229 
231  Storage = std::move(y);
232  return *this;
233  }
234  Optional &operator=(Optional &&O) = default;
235 
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)...);
239  }
240 
241  static inline Optional create(const T *y) {
242  return y ? Optional(*y) : Optional();
243  }
244 
245  Optional &operator=(const T &y) {
246  Storage = y;
247  return *this;
248  }
249  Optional &operator=(const Optional &O) = default;
250 
251  void reset() { Storage.reset(); }
252 
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(); }
257 
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(); }
264 
265  template <typename U>
266  constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
267  return hasValue() ? getValue() : std::forward<U>(value);
268  }
269 
270 #if LLVM_HAS_RVALUE_REFERENCE_THIS
271  T &&getValue() && { return std::move(Storage.getValue()); }
272  T &&operator*() && { return std::move(Storage.getValue()); }
273 
274  template <typename U>
275  T getValueOr(U &&value) && {
276  return hasValue() ? std::move(getValue()) : std::forward<U>(value);
277  }
278 #endif
279 };
280 
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();
286 }
287 
288 template <typename T, typename U>
289 bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
290  return !(X == Y);
291 }
292 
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();
298 }
299 
300 template <typename T, typename U>
301 bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
302  return !(Y < X);
303 }
304 
305 template <typename T, typename U>
306 bool operator>(const Optional<T> &X, const Optional<U> &Y) {
307  return Y < X;
308 }
309 
310 template <typename T, typename U>
311 bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
312  return !(X < Y);
313 }
314 
315 template<typename T>
316 bool operator==(const Optional<T> &X, NoneType) {
317  return !X;
318 }
319 
320 template<typename T>
321 bool operator==(NoneType, const Optional<T> &X) {
322  return X == None;
323 }
324 
325 template<typename T>
326 bool operator!=(const Optional<T> &X, NoneType) {
327  return !(X == None);
328 }
329 
330 template<typename T>
331 bool operator!=(NoneType, const Optional<T> &X) {
332  return X != None;
333 }
334 
335 template <typename T> bool operator<(const Optional<T> &X, NoneType) {
336  return false;
337 }
338 
339 template <typename T> bool operator<(NoneType, const Optional<T> &X) {
340  return X.hasValue();
341 }
342 
343 template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
344  return !(None < X);
345 }
346 
347 template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
348  return !(X < None);
349 }
350 
351 template <typename T> bool operator>(const Optional<T> &X, NoneType) {
352  return None < X;
353 }
354 
355 template <typename T> bool operator>(NoneType, const Optional<T> &X) {
356  return X < None;
357 }
358 
359 template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
360  return None <= X;
361 }
362 
363 template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
364  return X <= None;
365 }
366 
367 template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
368  return X && *X == Y;
369 }
370 
371 template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
372  return Y && X == *Y;
373 }
374 
375 template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
376  return !(X == Y);
377 }
378 
379 template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
380  return !(X == Y);
381 }
382 
383 template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
384  return !X || *X < Y;
385 }
386 
387 template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
388  return Y && X < *Y;
389 }
390 
391 template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
392  return !(Y < X);
393 }
394 
395 template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
396  return !(Y < X);
397 }
398 
399 template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
400  return Y < X;
401 }
402 
403 template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
404  return Y < X;
405 }
406 
407 template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
408  return !(X < Y);
409 }
410 
411 template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
412  return !(X < Y);
413 }
414 
416 
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;
425 }
426 
427 } // end namespace llvm
428 
429 #endif // LLVM_ADT_OPTIONAL_H
const NoneType None
Definition: None.h:23
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
Optional(const T &y)
Definition: Optional.h:224
const T & operator*() const LLVM_LVALUE_FUNCTION
Definition: Optional.h:262
This class represents lattice values for constants.
Definition: AllocatorList.h:23
NoneType
A simple null object to allow implicit construction of Optional<T> and similar types without having t...
Definition: None.h:22
bool operator>(int64_t V1, const APSInt &V2)
Definition: APSInt.h:344
constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION
Definition: Optional.h:266
void emplace(ArgTypes &&... Args)
Create a new object by constructing it in place with the given arguments.
Definition: Optional.h:237
OptionalStorage(OptionalStorage const &other)
Definition: Optional.h:48
OptionalStorage(OptionalStorage &&other)
Definition: Optional.h:53
block Block Frequency true
OptionalStorage(in_place_t, Args &&... args)
Definition: Optional.h:60
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
Definition: BitVector.h:937
T & getValue() LLVM_LVALUE_FUNCTION
Definition: Optional.h:256
bool operator>=(int64_t V1, const APSInt &V2)
Definition: APSInt.h:342
OptionalStorage & operator=(T const &y)
Definition: Optional.h:93
#define LLVM_LVALUE_FUNCTION
Expands to &#39;&&#39; if ref-qualifiers for *this are supported.
Definition: Compiler.h:95
Optional & operator=(const T &y)
Definition: Optional.h:245
APInt operator*(APInt a, uint64_t RHS)
Definition: APInt.h:2090
#define T
const T & getValue() const LLVM_LVALUE_FUNCTION
Definition: Optional.h:255
OptionalStorage & operator=(T const &y)
Definition: Optional.h:193
constexpr Optional()
Definition: Optional.h:221
T * operator->()
Definition: Optional.h:261
const T * operator->() const
Definition: Optional.h:260
static Optional create(const T *y)
Definition: Optional.h:241
OptionalStorage & operator=(T &&y)
Definition: Optional.h:102
T & operator*() LLVM_LVALUE_FUNCTION
Definition: Optional.h:263
const T * getPointer() const
Definition: Optional.h:253
constexpr Optional(NoneType)
Definition: Optional.h:222
constexpr bool empty(const T &RangeOrContainer)
Test whether RangeOrContainer is empty. Similar to C++17 std::empty.
Definition: STLExtras.h:209
Storage for any type.
Definition: Optional.h:36
void emplace(Args &&... args)
Definition: Optional.h:87
T const & getValue() const LLVM_LVALUE_FUNCTION noexcept
Definition: Optional.h:176
OptionalStorage(in_place_t, Args &&... args)
Definition: Optional.h:160
T & getValue() LLVM_LVALUE_FUNCTION noexcept
Definition: Optional.h:172
T const & getValue() const LLVM_LVALUE_FUNCTION noexcept
Definition: Optional.h:76
bool operator!=(uint64_t V1, const APInt &V2)
Definition: APInt.h:1968
OptionalStorage & operator=(OptionalStorage &&other)
Definition: Optional.h:126
bool hasValue() const
Definition: Optional.h:259
bool hasValue() const noexcept
Definition: Optional.h:70
Optional & operator=(T &&y)
Definition: Optional.h:230
OptionalStorage & operator=(OptionalStorage const &other)
Definition: Optional.h:112
raw_ostream & operator<<(raw_ostream &OS, const APInt &I)
Definition: APInt.h:2038
void reset()
Definition: Optional.h:251
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
aarch64 promote const
T & getValue() LLVM_LVALUE_FUNCTION noexcept
Definition: Optional.h:72
Optional(T &&y)
Definition: Optional.h:227
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
T * getPointer()
Definition: Optional.h:254
bool operator==(uint64_t V1, const APInt &V2)
Definition: APInt.h:1966
constexpr char Args[]
Key for Kernel::Metadata::mArgs.