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/AlignOf.h"
20 #include "llvm/Support/Compiler.h"
21 #include "llvm/Support/type_traits.h"
31 namespace optional_detail
{
35 /// Storage for any type.
36 template <typename T
, bool = is_trivially_copyable
<T
>::value
>
37 class OptionalStorage
{
45 ~OptionalStorage() { reset(); }
47 OptionalStorage() noexcept
: empty(), hasVal(false) {}
49 OptionalStorage(OptionalStorage
const &other
) : OptionalStorage() {
50 if (other
.hasValue()) {
54 OptionalStorage(OptionalStorage
&&other
) : OptionalStorage() {
55 if (other
.hasValue()) {
56 emplace(std::move(other
.value
));
60 template <class... Args
>
61 explicit OptionalStorage(in_place_t
, Args
&&... args
)
62 : value(std::forward
<Args
>(args
)...), hasVal(true) {}
64 void reset() noexcept
{
71 bool hasValue() const noexcept
{ return hasVal
; }
73 T
&getValue() LLVM_LVALUE_FUNCTION noexcept
{
77 T
const &getValue() const LLVM_LVALUE_FUNCTION noexcept
{
81 #if LLVM_HAS_RVALUE_REFERENCE_THIS
82 T
&&getValue() && noexcept
{
84 return std::move(value
);
88 template <class... Args
> void emplace(Args
&&... args
) {
90 ::new ((void *)std::addressof(value
)) T(std::forward
<Args
>(args
)...);
94 OptionalStorage
&operator=(T
const &y
) {
98 ::new ((void *)std::addressof(value
)) T(y
);
103 OptionalStorage
&operator=(T
&&y
) {
105 value
= std::move(y
);
107 ::new ((void *)std::addressof(value
)) T(std::move(y
));
113 OptionalStorage
&operator=(OptionalStorage
const &other
) {
114 if (other
.hasValue()) {
118 ::new ((void *)std::addressof(value
)) T(other
.value
);
127 OptionalStorage
&operator=(OptionalStorage
&&other
) {
128 if (other
.hasValue()) {
130 value
= std::move(other
.value
);
132 ::new ((void *)std::addressof(value
)) T(std::move(other
.value
));
142 } // namespace optional_detail
144 template <typename T
> class Optional
{
145 optional_detail::OptionalStorage
<T
> Storage
;
148 using value_type
= T
;
150 constexpr Optional() {}
151 constexpr Optional(NoneType
) {}
153 Optional(const T
&y
) : Storage(optional_detail::in_place_t
{}, y
) {}
154 Optional(const Optional
&O
) = default;
156 Optional(T
&&y
) : Storage(optional_detail::in_place_t
{}, std::move(y
)) {}
157 Optional(Optional
&&O
) = default;
159 Optional
&operator=(T
&&y
) {
160 Storage
= std::move(y
);
163 Optional
&operator=(Optional
&&O
) = default;
165 /// Create a new object by constructing it in place with the given arguments.
166 template <typename
... ArgTypes
> void emplace(ArgTypes
&&... Args
) {
167 Storage
.emplace(std::forward
<ArgTypes
>(Args
)...);
170 static inline Optional
create(const T
*y
) {
171 return y
? Optional(*y
) : Optional();
174 Optional
&operator=(const T
&y
) {
178 Optional
&operator=(const Optional
&O
) = default;
180 void reset() { Storage
.reset(); }
182 const T
*getPointer() const { return &Storage
.getValue(); }
183 T
*getPointer() { return &Storage
.getValue(); }
184 const T
&getValue() const LLVM_LVALUE_FUNCTION
{ return Storage
.getValue(); }
185 T
&getValue() LLVM_LVALUE_FUNCTION
{ return Storage
.getValue(); }
187 explicit operator bool() const { return hasValue(); }
188 bool hasValue() const { return Storage
.hasValue(); }
189 const T
*operator->() const { return getPointer(); }
190 T
*operator->() { return getPointer(); }
191 const T
&operator*() const LLVM_LVALUE_FUNCTION
{ return getValue(); }
192 T
&operator*() LLVM_LVALUE_FUNCTION
{ return getValue(); }
194 template <typename U
>
195 constexpr T
getValueOr(U
&&value
) const LLVM_LVALUE_FUNCTION
{
196 return hasValue() ? getValue() : std::forward
<U
>(value
);
199 #if LLVM_HAS_RVALUE_REFERENCE_THIS
200 T
&&getValue() && { return std::move(Storage
.getValue()); }
201 T
&&operator*() && { return std::move(Storage
.getValue()); }
203 template <typename U
>
204 T
getValueOr(U
&&value
) && {
205 return hasValue() ? std::move(getValue()) : std::forward
<U
>(value
);
210 template <typename T
, typename U
>
211 bool operator==(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
214 return X
.hasValue() == Y
.hasValue();
217 template <typename T
, typename U
>
218 bool operator!=(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
222 template <typename T
, typename U
>
223 bool operator<(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
226 return X
.hasValue() < Y
.hasValue();
229 template <typename T
, typename U
>
230 bool operator<=(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
234 template <typename T
, typename U
>
235 bool operator>(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
239 template <typename T
, typename U
>
240 bool operator>=(const Optional
<T
> &X
, const Optional
<U
> &Y
) {
245 bool operator==(const Optional
<T
> &X
, NoneType
) {
250 bool operator==(NoneType
, const Optional
<T
> &X
) {
255 bool operator!=(const Optional
<T
> &X
, NoneType
) {
260 bool operator!=(NoneType
, const Optional
<T
> &X
) {
264 template <typename T
> bool operator<(const Optional
<T
> &X
, NoneType
) {
268 template <typename T
> bool operator<(NoneType
, const Optional
<T
> &X
) {
272 template <typename T
> bool operator<=(const Optional
<T
> &X
, NoneType
) {
276 template <typename T
> bool operator<=(NoneType
, const Optional
<T
> &X
) {
280 template <typename T
> bool operator>(const Optional
<T
> &X
, NoneType
) {
284 template <typename T
> bool operator>(NoneType
, const Optional
<T
> &X
) {
288 template <typename T
> bool operator>=(const Optional
<T
> &X
, NoneType
) {
292 template <typename T
> bool operator>=(NoneType
, const Optional
<T
> &X
) {
296 template <typename T
> bool operator==(const Optional
<T
> &X
, const T
&Y
) {
300 template <typename T
> bool operator==(const T
&X
, const Optional
<T
> &Y
) {
304 template <typename T
> bool operator!=(const Optional
<T
> &X
, const T
&Y
) {
308 template <typename T
> bool operator!=(const T
&X
, const Optional
<T
> &Y
) {
312 template <typename T
> bool operator<(const Optional
<T
> &X
, const T
&Y
) {
316 template <typename T
> bool operator<(const T
&X
, const Optional
<T
> &Y
) {
320 template <typename T
> bool operator<=(const Optional
<T
> &X
, const T
&Y
) {
324 template <typename T
> bool operator<=(const T
&X
, const Optional
<T
> &Y
) {
328 template <typename T
> bool operator>(const Optional
<T
> &X
, const T
&Y
) {
332 template <typename T
> bool operator>(const T
&X
, const Optional
<T
> &Y
) {
336 template <typename T
> bool operator>=(const Optional
<T
> &X
, const T
&Y
) {
340 template <typename T
> bool operator>=(const T
&X
, const Optional
<T
> &Y
) {
344 raw_ostream
&operator<<(raw_ostream
&OS
, NoneType
);
346 template <typename T
, typename
= decltype(std::declval
<raw_ostream
&>()
347 << std::declval
<const T
&>())>
348 raw_ostream
&operator<<(raw_ostream
&OS
, const Optional
<T
> &O
) {
356 } // end namespace llvm
358 #endif // LLVM_ADT_OPTIONAL_H