C/C++ API Reference
Loading...
Searching...
No Matches
optional.h
1// Copyright 2026 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <new>
17#include <type_traits>
18#include <utility>
19
20#ifdef __cpp_concepts
21#include <concepts>
22#endif // __cpp_concepts
23
24#include "pw_assert/assert.h"
25#include "pw_containers/internal/optional_data.h"
26
27namespace pw::containers::internal {
28
30
31#ifdef __cpp_concepts
32template <typename T>
33concept OptionalState = std::regular<T>;
34#define PW_OPTIONAL_STATE OptionalState
35#else
36#define PW_OPTIONAL_STATE
37#endif // __cpp_concepts
38
55template <typename T,
56 PW_OPTIONAL_STATE auto kHasValueState,
57 bool IsTriviallyDestructible = std::is_trivially_destructible_v<T>>
58class Optional final : private OptionalData<T,
59 decltype(kHasValueState),
60 kHasValueState,
61 IsTriviallyDestructible>,
62 private CopyCtorBase<T>,
63 private MoveCtorBase<T>,
64 private CopyAssignBase<T>,
65 private MoveAssignBase<T> {
66 private:
67 template <typename, PW_OPTIONAL_STATE auto, bool>
68 friend class Optional;
69
70 using Base = OptionalData<T,
71 decltype(kHasValueState),
72 kHasValueState,
73 IsTriviallyDestructible>;
74
75 public:
76 using state_type = decltype(kHasValueState);
77 using value_type = T;
78
79 Optional() = delete;
80
82 explicit constexpr Optional(state_type state) : Base(state) {}
83
85 constexpr Optional(const value_type& value) : Base(value) {}
86 constexpr Optional(value_type&& value) : Base(std::move(value)) {}
87
89 template <typename... Args>
90 explicit constexpr Optional(std::in_place_t, Args&&... args)
91 : Base(std::in_place, std::forward<Args>(args)...) {}
92
93 constexpr Optional(const Optional&) = default;
94 constexpr Optional& operator=(const Optional&) = default;
95 constexpr Optional(Optional&&) = default;
96 constexpr Optional& operator=(Optional&&) = default;
97
99 template <
100 typename U,
101 std::enable_if_t<std::conjunction_v<std::negation<std::is_same<T, U>>,
102 std::is_constructible<T, const U&>,
103 std::is_convertible<const U&, T>>,
104 int> = 0>
105 constexpr Optional(const Optional<U, kHasValueState>& other) : Base(other) {}
106
107 template <
108 typename U,
109 std::enable_if_t<
110 std::conjunction_v<std::negation<std::is_same<T, U>>,
111 std::is_constructible<T, const U&>,
112 std::negation<std::is_convertible<const U&, T>>>,
113 int> = 0>
114 explicit constexpr Optional(const Optional<U, kHasValueState>& other)
115 : Base(other) {}
116
117 template <
118 typename U,
119 std::enable_if_t<std::conjunction_v<std::negation<std::is_same<T, U>>,
120 std::is_constructible<T, U&&>,
121 std::is_convertible<U&&, T>>,
122 int> = 0>
123 constexpr Optional(Optional<U, kHasValueState>&& other)
124 : Base(std::move(other)) {}
125
126 template <typename U,
127 std::enable_if_t<
128 std::conjunction_v<std::negation<std::is_same<T, U>>,
129 std::is_constructible<T, U&&>,
130 std::negation<std::is_convertible<U&&, T>>>,
131 int> = 0>
132 explicit constexpr Optional(Optional<U, kHasValueState>&& other)
133 : Base(std::move(other)) {}
134
136 constexpr Optional& operator=(const value_type& value) {
137 this->Assign(value);
138 return *this;
139 }
140
142 constexpr Optional& operator=(value_type&& value) {
143 this->Assign(std::move(value));
144 return *this;
145 }
146
148 template <typename... Args>
149 constexpr void emplace(Args&&... args) {
150 this->Clear();
151 this->MakeValue(std::forward<Args>(args)...);
152 this->state_ = kHasValueState;
153 }
154
158 constexpr void reset(state_type state) { this->AssignState(state); }
159
161 template <state_type kState>
162 constexpr void reset() {
163 this->template AssignState<kState>();
164 }
165
167 [[nodiscard]] constexpr bool has_value() const {
168 return this->state_ == kHasValueState;
169 }
170
174 constexpr T& operator*() & { return this->data_; }
176 constexpr const T& operator*() const& { return this->data_; }
177
179 constexpr T&& operator*() && { return std::move(this->data_); }
181 constexpr const T&& operator*() const&& { return std::move(this->data_); }
182
184 constexpr T* operator->() { return &this->data_; }
186 constexpr const T* operator->() const { return &this->data_; }
187
189 constexpr T& value() & {
190 PW_ASSERT(has_value());
191 return this->data_;
192 }
194 constexpr const T& value() const& {
195 PW_ASSERT(has_value());
196 return this->data_;
197 }
198
200 constexpr T&& value() && {
201 PW_ASSERT(has_value());
202 return std::move(this->data_);
203 }
205 constexpr const T&& value() const&& {
206 PW_ASSERT(has_value());
207 return std::move(this->data_);
208 }
209
211 constexpr state_type state() const { return this->state_; }
212
213 friend constexpr bool operator==(const Optional& lhs, const Optional& rhs) {
214 if (lhs.has_value() && rhs.has_value()) {
215 return *lhs == *rhs;
216 }
217 return lhs.state() == rhs.state();
218 }
219 friend constexpr bool operator!=(const Optional& lhs, const Optional& rhs) {
220 return !(lhs == rhs);
221 }
222
223 friend constexpr bool operator==(const Optional& lhs, const T& rhs) {
224 return lhs.has_value() && *lhs == rhs;
225 }
226 friend constexpr bool operator==(const T& lhs, const Optional& rhs) {
227 return rhs == lhs;
228 }
229 friend constexpr bool operator!=(const Optional& lhs, const T& rhs) {
230 return !(lhs == rhs);
231 }
232 friend constexpr bool operator!=(const T& lhs, const Optional& rhs) {
233 return !(rhs == lhs);
234 }
235
236 static_assert(!std::is_convertible_v<T, state_type>,
237 "To avoid ambiguity, T cannot be convertible to the state "
238 "type. Consider using `enum class` to restrict conversions.");
239 static_assert(!std::is_convertible_v<state_type, T>,
240 "To avoid ambiguity, the state cannot be convertible to T "
241 "type. Consider using `enum class` to restrict conversions.");
242};
243
246template <PW_OPTIONAL_STATE auto kHasValueState, bool IsTriviallyDestructible>
248 public:
249 using state_type = decltype(kHasValueState);
250 using value_type = void;
251
252 constexpr Optional() = delete;
253
254 constexpr Optional(const Optional&) = default;
255 constexpr Optional(Optional&&) = default;
256
257 constexpr Optional& operator=(const Optional&) = default;
258 constexpr Optional& operator=(Optional&&) = default;
259
261 explicit constexpr Optional(state_type state) : state_(state) {
262 PW_ASSERT(state != kHasValueState);
263 }
264
266 explicit constexpr Optional(std::in_place_t) : state_(kHasValueState) {}
267
269 constexpr void emplace() { state_ = kHasValueState; }
270
274 constexpr void reset(state_type state) {
275 PW_ASSERT(state != kHasValueState);
276 state_ = state;
277 }
278
280 template <state_type kState>
281 constexpr void reset() {
282 static_assert(
283 kState != kHasValueState,
284 "Cannot set state to the has-value state; set the value instead");
285 state_ = kState;
286 }
287
289 [[nodiscard]] constexpr bool has_value() const {
290 return state_ == kHasValueState;
291 }
292
294 constexpr void value() const { PW_ASSERT(has_value()); }
295
297 constexpr state_type state() const { return state_; }
298
299 friend constexpr bool operator==(const Optional& lhs, const Optional& rhs) {
300 return lhs.state() == rhs.state();
301 }
302 friend constexpr bool operator!=(const Optional& lhs, const Optional& rhs) {
303 return lhs.state() != rhs.state();
304 }
305
306 private:
307 state_type state_;
308};
309
311
312#undef PW_OPTIONAL_STATE
313
314} // namespace pw::containers::internal
constexpr Optional(std::in_place_t)
Constructs an optional containing a value.
Definition: optional.h:266
constexpr state_type state() const
Returns the underlying state value.
Definition: optional.h:297
constexpr void reset(state_type state)
Definition: optional.h:274
constexpr bool has_value() const
True if the optional contains a value.
Definition: optional.h:289
constexpr void emplace()
Sets the state to indicate a value is present.
Definition: optional.h:269
constexpr void value() const
Asserts that has_value() is true.
Definition: optional.h:294
constexpr Optional(state_type state)
Constructs an optional without a value using the provided state.
Definition: optional.h:261
Definition: optional.h:65
constexpr T && operator*() &&
Definition: optional.h:179
constexpr bool has_value() const
Returns true if the optional contains a value.
Definition: optional.h:167
constexpr T & operator*() &
Definition: optional.h:174
constexpr Optional & operator=(value_type &&value)
Move assigns a new value to the optional.
Definition: optional.h:142
constexpr T && value() &&
Returns the contained value. Asserts if the value is not present.
Definition: optional.h:200
constexpr const T * operator->() const
Definition: optional.h:186
constexpr void emplace(Args &&... args)
Constructs a new value in-place.
Definition: optional.h:149
constexpr Optional(state_type state)
Constructs an optional without a value using the provided state.
Definition: optional.h:82
constexpr state_type state() const
Returns the state. Always valid, whether has_value is true or false.
Definition: optional.h:211
constexpr Optional(std::in_place_t, Args &&... args)
Constructs an optional in-place containing a value.
Definition: optional.h:90
constexpr void reset(state_type state)
Definition: optional.h:158
constexpr void reset()
Definition: optional.h:162
constexpr const T && value() const &&
Returns the contained value. Asserts if the value is not present.
Definition: optional.h:205
constexpr Optional(const value_type &value)
Constructs an optional containing a value.
Definition: optional.h:85
constexpr T & value() &
Returns the contained value. Asserts if the value is not present.
Definition: optional.h:189
constexpr Optional(const Optional< U, kHasValueState > &other)
Constructs an optional from another optional with a compatible value type.
Definition: optional.h:105
constexpr Optional & operator=(const value_type &value)
Assigns a new value to the optional.
Definition: optional.h:136
constexpr const T && operator*() const &&
Definition: optional.h:181
constexpr const T & operator*() const &
Definition: optional.h:176
constexpr T * operator->()
Definition: optional.h:184
constexpr const T & value() const &
Returns the contained value. Asserts if the value is not present.
Definition: optional.h:194