1 //===-- Standalone implementation of std::optional --------------*- 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 #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H
10 #define LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H
12 #include "src/__support/CPP/type_traits.h"
13 #include "src/__support/CPP/utility.h"
14 #include "src/__support/macros/attributes.h"
15 #include "src/__support/macros/config.h"
17 namespace LIBC_NAMESPACE_DECL
{
20 // Trivial nullopt_t struct.
22 LIBC_INLINE
constexpr explicit nullopt_t() = default;
25 // nullopt that can be used and returned.
26 LIBC_INLINE_VAR
constexpr nullopt_t nullopt
{};
28 // This is very simple implementation of the std::optional class. It makes
29 // several assumptions that the underlying type is trivially constructible,
30 // copyable, or movable.
31 template <typename T
> class optional
{
32 template <typename U
, bool = !is_trivially_destructible
<U
>::value
>
33 struct OptionalStorage
{
41 LIBC_INLINE
~OptionalStorage() { reset(); }
43 LIBC_INLINE
constexpr OptionalStorage() : empty() {}
45 template <typename
... Args
>
46 LIBC_INLINE
constexpr explicit OptionalStorage(in_place_t
, Args
&&...args
)
47 : stored_value(forward
<Args
>(args
)...) {}
49 LIBC_INLINE
constexpr void reset() {
56 // The only difference is that this type U doesn't have a nontrivial
58 template <typename U
> struct OptionalStorage
<U
, false> {
66 LIBC_INLINE
constexpr OptionalStorage() : empty() {}
68 template <typename
... Args
>
69 LIBC_INLINE
constexpr explicit OptionalStorage(in_place_t
, Args
&&...args
)
70 : stored_value(forward
<Args
>(args
)...) {}
72 LIBC_INLINE
constexpr void reset() { in_use
= false; }
75 OptionalStorage
<T
> storage
;
78 LIBC_INLINE
constexpr optional() = default;
79 LIBC_INLINE
constexpr optional(nullopt_t
) {}
81 LIBC_INLINE
constexpr optional(const T
&t
) : storage(in_place
, t
) {
82 storage
.in_use
= true;
84 LIBC_INLINE
constexpr optional(const optional
&) = default;
86 LIBC_INLINE
constexpr optional(T
&&t
) : storage(in_place
, move(t
)) {
87 storage
.in_use
= true;
89 LIBC_INLINE
constexpr optional(optional
&&O
) = default;
91 template <typename
... ArgTypes
>
92 LIBC_INLINE
constexpr optional(in_place_t
, ArgTypes
&&...Args
)
93 : storage(in_place
, forward
<ArgTypes
>(Args
)...) {
94 storage
.in_use
= true;
97 LIBC_INLINE
constexpr optional
&operator=(T
&&t
) {
101 LIBC_INLINE
constexpr optional
&operator=(optional
&&) = default;
103 LIBC_INLINE
constexpr optional
&operator=(const T
&t
) {
107 LIBC_INLINE
constexpr optional
&operator=(const optional
&) = default;
109 LIBC_INLINE
constexpr void reset() { storage
.reset(); }
111 LIBC_INLINE
constexpr const T
&value() const & {
112 return storage
.stored_value
;
115 LIBC_INLINE
constexpr T
&value() & { return storage
.stored_value
; }
117 LIBC_INLINE
constexpr explicit operator bool() const {
118 return storage
.in_use
;
120 LIBC_INLINE
constexpr bool has_value() const { return storage
.in_use
; }
121 LIBC_INLINE
constexpr const T
*operator->() const {
122 return &storage
.stored_value
;
124 LIBC_INLINE
constexpr T
*operator->() { return &storage
.stored_value
; }
125 LIBC_INLINE
constexpr const T
&operator*() const & {
126 return storage
.stored_value
;
128 LIBC_INLINE
constexpr T
&operator*() & { return storage
.stored_value
; }
130 LIBC_INLINE
constexpr T
&&value() && { return move(storage
.stored_value
); }
131 LIBC_INLINE
constexpr T
&&operator*() && {
132 return move(storage
.stored_value
);
137 } // namespace LIBC_NAMESPACE_DECL
139 #endif // LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H