1 //===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
30 namespace optional_detail
{
34 /// Storage for any type.
35 template <typename T
, bool = is_trivially_copyable
<T
>::value
>
36 class OptionalStorage
{
44 ~OptionalStorage() { reset(); }
46 OptionalStorage() noexcept
: empty(), hasVal(false) {}
48 OptionalStorage(OptionalStorage
const &other
) : OptionalStorage() {
49 if (other
.hasValue()) {
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
{
70 bool hasValue() const noexcept
{ return hasVal
; }
72 T
&getValue() LLVM_LVALUE_FUNCTION noexcept
{
76 T
const &getValue() const LLVM_LVALUE_FUNCTION noexcept
{
80 #if LLVM_HAS_RVALUE_REFERENCE_THIS
81 T
&&getValue() && noexcept
{
83 return std::move(value
);
87 template <class... Args
> void emplace(Args
&&... args
) {
89 ::new ((void *)std::addressof(value
)) T(std::forward
<Args
>(args
)...);
93 OptionalStorage
&operator=(T
const &y
) {
97 ::new ((void *)std::addressof(value
)) T(y
);
102 OptionalStorage
&operator=(T
&&y
) {
104 value
= std::move(y
);
106 ::new ((void *)std::addressof(value
)) T(std::move(y
));
112 OptionalStorage
&operator=(OptionalStorage
const &other
) {
113 if (other
.hasValue()) {
117 ::new ((void *)std::addressof(value
)) T(other
.value
);
126 OptionalStorage
&operator=(OptionalStorage
&&other
) {
127 if (other
.hasValue()) {
129 value
= std::move(other
.value
);
131 ::new ((void *)std::addressof(value
)) T(std::move(other
.value
));
141 template <typename T
> class OptionalStorage
<T
, true> {
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
{
170 bool hasValue() const noexcept
{ return hasVal
; }
172 T
&getValue() LLVM_LVALUE_FUNCTION noexcept
{
176 T
const &getValue() const LLVM_LVALUE_FUNCTION noexcept
{
180 #if LLVM_HAS_RVALUE_REFERENCE_THIS
181 T
&&getValue() && noexcept
{
183 return std::move(value
);
187 template <class... Args
> void emplace(Args
&&... args
) {
189 ::new ((void *)std::addressof(value
)) T(std::forward
<Args
>(args
)...);
193 OptionalStorage
&operator=(T
const &y
) {
197 ::new ((void *)std::addressof(value
)) T(y
);
202 OptionalStorage
&operator=(T
&&y
) {
204 value
= std::move(y
);
206 ::new ((void *)std::addressof(value
)) T(std::move(y
));
213 } // namespace optional_detail
215 template <typename T
> class Optional
{
216 optional_detail::OptionalStorage
<T
> Storage
;
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
);
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
) {
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
);
281 template <typename T
, typename U
>
282 bool operator==(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
285 return X
.hasValue() == Y
.hasValue();
288 template <typename T
, typename U
>
289 bool operator!=(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
293 template <typename T
, typename U
>
294 bool operator<(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
297 return X
.hasValue() < Y
.hasValue();
300 template <typename T
, typename U
>
301 bool operator<=(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
305 template <typename T
, typename U
>
306 bool operator>(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
310 template <typename T
, typename U
>
311 bool operator>=(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
316 bool operator==(const Optional
<T
> &X
, NoneType
) {
321 bool operator==(NoneType
, const Optional
<T
> &X
) {
326 bool operator!=(const Optional
<T
> &X
, NoneType
) {
331 bool operator!=(NoneType
, const Optional
<T
> &X
) {
335 template <typename T
> bool operator<(const Optional
<T
> &X
, NoneType
) {
339 template <typename T
> bool operator<(NoneType
, const Optional
<T
> &X
) {
343 template <typename T
> bool operator<=(const Optional
<T
> &X
, NoneType
) {
347 template <typename T
> bool operator<=(NoneType
, const Optional
<T
> &X
) {
351 template <typename T
> bool operator>(const Optional
<T
> &X
, NoneType
) {
355 template <typename T
> bool operator>(NoneType
, const Optional
<T
> &X
) {
359 template <typename T
> bool operator>=(const Optional
<T
> &X
, NoneType
) {
363 template <typename T
> bool operator>=(NoneType
, const Optional
<T
> &X
) {
367 template <typename T
> bool operator==(const Optional
<T
> &X
, const T
&Y
) {
371 template <typename T
> bool operator==(const T
&X
, const Optional
<T
> &Y
) {
375 template <typename T
> bool operator!=(const Optional
<T
> &X
, const T
&Y
) {
379 template <typename T
> bool operator!=(const T
&X
, const Optional
<T
> &Y
) {
383 template <typename T
> bool operator<(const Optional
<T
> &X
, const T
&Y
) {
387 template <typename T
> bool operator<(const T
&X
, const Optional
<T
> &Y
) {
391 template <typename T
> bool operator<=(const Optional
<T
> &X
, const T
&Y
) {
395 template <typename T
> bool operator<=(const T
&X
, const Optional
<T
> &Y
) {
399 template <typename T
> bool operator>(const Optional
<T
> &X
, const T
&Y
) {
403 template <typename T
> bool operator>(const T
&X
, const Optional
<T
> &Y
) {
407 template <typename T
> bool operator>=(const Optional
<T
> &X
, const T
&Y
) {
411 template <typename T
> bool operator>=(const T
&X
, const Optional
<T
> &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
) {
427 } // end namespace llvm
429 #endif // LLVM_ADT_OPTIONAL_H