1 | //===-- Standalone implementation of std::optional --------------*- 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 | #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H |
10 | #define LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H |
11 | |
12 | #include "src/__support/CPP/type_traits.h" |
13 | #include "src/__support/CPP/utility.h" |
14 | #include "src/__support/macros/attributes.h" |
15 | |
16 | namespace LIBC_NAMESPACE { |
17 | namespace cpp { |
18 | |
19 | // Trivial nullopt_t struct. |
20 | struct nullopt_t { |
21 | LIBC_INLINE constexpr explicit nullopt_t() = default; |
22 | }; |
23 | |
24 | // nullopt that can be used and returned. |
25 | LIBC_INLINE_VAR constexpr nullopt_t nullopt{}; |
26 | |
27 | // This is very simple implementation of the std::optional class. It makes |
28 | // several assumptions that the underlying type is trivially constructible, |
29 | // copyable, or movable. |
30 | template <typename T> class optional { |
31 | template <typename U, bool = !is_trivially_destructible<U>::value> |
32 | struct OptionalStorage { |
33 | union { |
34 | char empty; |
35 | U stored_value; |
36 | }; |
37 | |
38 | bool in_use = false; |
39 | |
40 | LIBC_INLINE ~OptionalStorage() { reset(); } |
41 | |
42 | LIBC_INLINE constexpr OptionalStorage() : empty() {} |
43 | |
44 | template <typename... Args> |
45 | LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) |
46 | : stored_value(forward<Args>(args)...) {} |
47 | |
48 | LIBC_INLINE constexpr void reset() { |
49 | if (in_use) |
50 | stored_value.~U(); |
51 | in_use = false; |
52 | } |
53 | }; |
54 | |
55 | // The only difference is that this type U doesn't have a nontrivial |
56 | // destructor. |
57 | template <typename U> struct OptionalStorage<U, false> { |
58 | union { |
59 | char empty; |
60 | U stored_value; |
61 | }; |
62 | |
63 | bool in_use = false; |
64 | |
65 | LIBC_INLINE constexpr OptionalStorage() : empty() {} |
66 | |
67 | template <typename... Args> |
68 | LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) |
69 | : stored_value(forward<Args>(args)...) {} |
70 | |
71 | LIBC_INLINE constexpr void reset() { in_use = false; } |
72 | }; |
73 | |
74 | OptionalStorage<T> storage; |
75 | |
76 | public: |
77 | LIBC_INLINE constexpr optional() = default; |
78 | LIBC_INLINE constexpr optional(nullopt_t) {} |
79 | |
80 | LIBC_INLINE constexpr optional(const T &t) : storage(in_place, t) { |
81 | storage.in_use = true; |
82 | } |
83 | LIBC_INLINE constexpr optional(const optional &) = default; |
84 | |
85 | LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) { |
86 | storage.in_use = true; |
87 | } |
88 | LIBC_INLINE constexpr optional(optional &&O) = default; |
89 | |
90 | template <typename... ArgTypes> |
91 | LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args) |
92 | : storage(in_place, forward<ArgTypes>(Args)...) { |
93 | storage.in_use = true; |
94 | } |
95 | |
96 | LIBC_INLINE constexpr optional &operator=(T &&t) { |
97 | storage = move(t); |
98 | return *this; |
99 | } |
100 | LIBC_INLINE constexpr optional &operator=(optional &&) = default; |
101 | |
102 | LIBC_INLINE constexpr optional &operator=(const T &t) { |
103 | storage = t; |
104 | return *this; |
105 | } |
106 | LIBC_INLINE constexpr optional &operator=(const optional &) = default; |
107 | |
108 | LIBC_INLINE constexpr void reset() { storage.reset(); } |
109 | |
110 | LIBC_INLINE constexpr const T &value() const & { |
111 | return storage.stored_value; |
112 | } |
113 | |
114 | LIBC_INLINE constexpr T &value() & { return storage.stored_value; } |
115 | |
116 | LIBC_INLINE constexpr explicit operator bool() const { |
117 | return storage.in_use; |
118 | } |
119 | LIBC_INLINE constexpr bool has_value() const { return storage.in_use; } |
120 | LIBC_INLINE constexpr const T *operator->() const { |
121 | return &storage.stored_value; |
122 | } |
123 | LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; } |
124 | LIBC_INLINE constexpr const T &operator*() const & { |
125 | return storage.stored_value; |
126 | } |
127 | LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; } |
128 | |
129 | LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); } |
130 | LIBC_INLINE constexpr T &&operator*() && { |
131 | return move(storage.stored_value); |
132 | } |
133 | }; |
134 | |
135 | } // namespace cpp |
136 | } // namespace LIBC_NAMESPACE |
137 | |
138 | #endif // LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H |
139 | |