1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_OPTIONAL_H_
6 #define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_OPTIONAL_H_
7
8 #include "utility.h"
9 #include "version.h"
10
11 #if defined(__cpp_lib_optional) && __cpp_lib_optional >= 201606L && \
12 !defined(LIB_STDCOMPAT_USE_POLYFILLS)
13
14 #include <optional>
15
16 namespace cpp17 {
17
18 using std::bad_optional_access;
19 using std::make_optional;
20 using std::nullopt;
21 using std::nullopt_t;
22 using std::optional;
23
24 } // namespace cpp17
25
26 #else // Provide std::optional and std::nullopt_t polyfill.
27
28 #include <cstdlib>
29 #include <exception>
30 #include <new>
31
32 #include "internal/constructors.h"
33 #include "internal/exception.h"
34 #include "internal/storage.h"
35 #include "internal/utility.h"
36 #include "type_traits.h"
37
38 namespace cpp17 {
39
40 // A sentinel value for indicating that it contains no value.
41 struct nullopt_t {
nullopt_tnullopt_t42 explicit constexpr nullopt_t(int) {}
43 };
44 static constexpr nullopt_t nullopt{0};
45
46 // Exception type to report bad accesses to optional.
47 class bad_optional_access : public std::exception {
48 public:
bad_optional_access()49 bad_optional_access() noexcept {}
50
what()51 const char* what() const noexcept override { return reason_; }
52
53 private:
54 template <typename T>
55 friend class optional;
56
bad_optional_access(const char * reason)57 bad_optional_access(const char* reason) noexcept : reason_{reason} {}
58
59 // String describing the reason for the bad access. Must point to a string
60 // with static storage duration.
61 const char* reason_;
62
63 template <typename T,
64 typename std::enable_if<std::is_base_of<std::exception, T>::value, bool>::type>
65 friend constexpr void cpp17::internal::throw_or_abort(const char*);
66 };
67
68 // A reasonably complete implementation of std::optional compatible with C++14.
69 template <typename T>
70 class optional : private ::cpp17::internal::modulate_copy_and_move<T> {
71 private:
72 // Helper types and values for SFINAE and noexcept rules.
73 static constexpr bool nothrow_move_constructible = std::is_nothrow_move_constructible<T>::value;
74
75 static constexpr bool nothrow_swappable = std::is_nothrow_move_constructible<T>::value &&
76 ::cpp17::internal::is_nothrow_swappable<T>::value;
77
78 static constexpr auto trivial_init_v = ::cpp17::internal::trivial_init_v;
79 static constexpr auto maybe_init_v = ::cpp17::internal::maybe_init_v;
80 using type_tag = ::cpp17::internal::type_tag<T>;
81
82 template <typename U, typename V>
83 using converts_from_optional = disjunction<
84 std::is_constructible<U, const optional<V>&>, std::is_constructible<U, optional<V>&>,
85 std::is_constructible<U, const optional<V>&&>, std::is_constructible<U, optional<V>&&>,
86 std::is_convertible<const optional<V>&, U>, std::is_convertible<optional<V>&, U>,
87 std::is_convertible<const optional<V>&&, U>, std::is_convertible<optional<V>&&, U>>;
88
89 template <typename U, typename V>
90 using assigns_from_optional =
91 disjunction<std::is_assignable<U&, const optional<V>&>, std::is_assignable<U&, optional<V>&>,
92 std::is_assignable<U&, const optional<V>&&>,
93 std::is_assignable<U&, optional<V>&&>>;
94
95 template <typename U>
96 using not_self_type = ::cpp17::internal::not_same_type<optional, U>;
97
98 template <typename U>
99 using not_in_place = ::cpp17::internal::not_same_type<in_place_t, U>;
100
101 template <typename... Conditions>
102 using requires_conditions = ::cpp17::internal::requires_conditions<Conditions...>;
103
104 template <typename... Conditions>
105 using assignment_requires_conditions =
106 ::cpp17::internal::assignment_requires_conditions<optional&, Conditions...>;
107
108 template <typename... Args>
109 using emplace_constructible = std::enable_if_t<std::is_constructible<T, Args...>::value, T&>;
110
111 public:
112 using value_type = T;
113
114 // Default constructors.
115
116 constexpr optional() = default;
117
optional(nullopt_t)118 constexpr optional(nullopt_t) noexcept {}
119
120 // Copy/move constructors and assignment operators.
121
122 constexpr optional(const optional&) = default;
123 constexpr optional& operator=(const optional&) = default;
124
125 constexpr optional(optional&&) = default;
126 constexpr optional& operator=(optional&&) = default;
127
128 // Converting constructors.
129
130 template <typename U = T,
131 requires_conditions<not_self_type<U>, not_in_place<U>, std::is_constructible<T, U&&>,
132 std::is_convertible<U&&, T>> = true>
optional(U && value)133 constexpr optional(U&& value) : storage_(type_tag{}, std::forward<U>(value)) {}
134
135 template <typename U = T,
136 requires_conditions<not_self_type<U>, not_in_place<U>, std::is_constructible<T, U&&>,
137 negation<std::is_convertible<U&&, T>>> = false>
optional(U && value)138 explicit constexpr optional(U&& value) : storage_{type_tag{}, std::forward<U>(value)} {}
139
140 template <typename U,
141 requires_conditions<negation<std::is_same<T, U>>, std::is_constructible<T, const U&>,
142 std::is_convertible<const U&, T>,
143 negation<converts_from_optional<T, U>>> = true>
optional(const optional<U> & other)144 constexpr optional(const optional<U>& other) : storage_{maybe_init_v, other.storage_} {}
145
146 template <typename U,
147 requires_conditions<negation<std::is_same<T, U>>, std::is_constructible<T, const U&>,
148 negation<std::is_convertible<const U&, T>>,
149 negation<converts_from_optional<T, U>>> = false>
optional(const optional<U> & other)150 explicit constexpr optional(const optional<U>& other) : storage_{maybe_init_v, other.storage_} {}
151
152 template <typename U,
153 requires_conditions<negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
154 std::is_convertible<U&&, T>,
155 negation<converts_from_optional<T, U>>> = true>
optional(optional<U> && other)156 constexpr optional(optional<U>&& other) : storage_{maybe_init_v, std::move(other.storage_)} {}
157
158 template <typename U,
159 requires_conditions<negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
160 negation<std::is_convertible<U&&, T>>,
161 negation<converts_from_optional<T, U>>> = false>
optional(optional<U> && other)162 explicit constexpr optional(optional<U>&& other)
163 : storage_{maybe_init_v, std::move(other.storage_)} {}
164
165 template <typename... Args, requires_conditions<std::is_constructible<T, Args&&...>> = false>
optional(in_place_t,Args &&...args)166 explicit constexpr optional(in_place_t, Args&&... args)
167 : storage_(type_tag{}, std::forward<Args>(args)...) {}
168
169 template <
170 typename U, typename... Args,
171 requires_conditions<std::is_constructible<T, std::initializer_list<U>&, Args&&...>> = false>
optional(in_place_t,std::initializer_list<U> init_list,Args &&...args)172 explicit constexpr optional(in_place_t, std::initializer_list<U> init_list, Args&&... args)
173 : storage_(type_tag{}, init_list, std::forward<Args>(args)...) {}
174
175 // Destructor.
176
177 ~optional() = default;
178
179 // Checked accessors.
180
value()181 constexpr T& value() & {
182 if (has_value()) {
183 return storage_.get(type_tag{});
184 }
185 internal::throw_or_abort<bad_optional_access>("Accessed value of empty optional!");
186 }
value()187 constexpr const T& value() const& {
188 if (has_value()) {
189 return storage_.get(type_tag{});
190 }
191 internal::throw_or_abort<bad_optional_access>("Accessed value of empty optional!");
192 }
value()193 constexpr T&& value() && {
194 if (has_value()) {
195 return std::move(storage_.get(type_tag{}));
196 }
197 internal::throw_or_abort<bad_optional_access>("Accessed value of empty optional!");
198 }
value()199 constexpr const T&& value() const&& {
200 if (has_value()) {
201 return std::move(storage_.get(type_tag{}));
202 }
203 internal::throw_or_abort<bad_optional_access>("Accessed value of empty optional!");
204 }
205
206 template <typename U>
value_or(U && default_value)207 constexpr T value_or(U&& default_value) const& {
208 static_assert(std::is_copy_constructible<T>::value,
209 "value_or() requires copy-constructible value_type!");
210 static_assert(std::is_convertible<U&&, T>::value,
211 "Default value must be convertible to value_type!");
212
213 return has_value() ? storage_.get(type_tag{}) : static_cast<T>(std::forward<U>(default_value));
214 }
215 template <typename U>
value_or(U && default_value)216 constexpr T value_or(U&& default_value) && {
217 static_assert(std::is_move_constructible<T>::value,
218 "value_or() requires move-constructible value_type!");
219 static_assert(std::is_convertible<U&&, T>::value,
220 "Default value must be convertible to value_type!");
221
222 return has_value() ? std::move(storage_.get(type_tag{}))
223 : static_cast<T>(std::forward<U>(default_value));
224 }
225
226 // Unchecked accessors.
227
228 constexpr T* operator->() { return std::addressof(storage_.get(type_tag{})); }
229 constexpr const T* operator->() const { return std::addressof(storage_.get(type_tag{})); }
230
231 constexpr T& operator*() { return storage_.get(type_tag{}); }
232 constexpr const T& operator*() const { return storage_.get(type_tag{}); }
233
234 // Availability accessors/operators.
235
has_value()236 constexpr bool has_value() const { return !storage_.is_empty(); }
237 constexpr explicit operator bool() const { return has_value(); }
238
239 // Assignment operators.
240
241 template <typename U>
242 constexpr assignment_requires_conditions<
243 not_self_type<U>, negation<conjunction<std::is_scalar<T>, std::is_same<T, std::decay_t<U>>>>,
244 std::is_constructible<T, U>, std::is_assignable<T&, U>>
245 operator=(U&& value) {
246 if (has_value()) {
247 storage_.get(type_tag{}) = std::forward<U>(value);
248 } else {
249 storage_.construct(type_tag{}, std::forward<U>(value));
250 }
251 return *this;
252 }
253
254 template <typename U>
255 constexpr assignment_requires_conditions<
256 negation<std::is_same<T, U>>, std::is_constructible<T, const U&>, std::is_assignable<T&, U>,
257 negation<converts_from_optional<T, U>>, negation<assigns_from_optional<T, U>>>
258 operator=(const optional<U>& other) {
259 storage_.assign(other.storage_);
260 return *this;
261 }
262
263 template <typename U>
264 constexpr assignment_requires_conditions<
265 negation<std::is_same<T, U>>, std::is_constructible<T, U>, std::is_assignable<T&, U>,
266 negation<converts_from_optional<T, U>>, negation<assigns_from_optional<T, U>>>
267 operator=(optional<U>&& other) {
268 storage_.assign(std::move(other.storage_));
269 return *this;
270 }
271
272 constexpr optional& operator=(nullopt_t) {
273 storage_.reset();
274 return *this;
275 }
276
277 // Swap.
278
swap(optional & other)279 constexpr void swap(optional& other) noexcept(nothrow_swappable) {
280 storage_.swap(other.storage_);
281 }
282
283 // Emplacement.
284
285 template <typename... Args>
emplace(Args &&...args)286 constexpr emplace_constructible<Args&&...> emplace(Args&&... args) {
287 storage_.reset();
288 storage_.construct(type_tag{}, std::forward<Args>(args)...);
289 return storage_.get(type_tag{});
290 }
291
292 template <typename U, typename... Args>
emplace(std::initializer_list<U> init_list,Args &&...args)293 constexpr emplace_constructible<std::initializer_list<U>&, Args&&...> emplace(
294 std::initializer_list<U> init_list, Args&&... args) {
295 storage_.reset();
296 storage_.construct(type_tag{}, init_list, std::forward<Args>(args)...);
297 return storage_.get(type_tag{});
298 }
299
300 // Reset.
301
reset()302 void reset() noexcept { storage_.reset(); }
303
304 private:
305 ::cpp17::internal::storage_type<T> storage_;
306 };
307
308 // Swap.
309 template <typename T>
310 inline std::enable_if_t<(std::is_move_constructible<T>::value &&
311 ::cpp17::internal::is_swappable<T>::value)>
swap(optional<T> & a,optional<T> & b)312 swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) {
313 a.swap(b);
314 }
315 template <typename T>
316 inline std::enable_if_t<(!std::is_move_constructible<T>::value &&
317 ::cpp17::internal::is_swappable<T>::value)>
318 swap(optional<T>& a, optional<T>& b) = delete;
319
320 // Make optional.
321 template <typename T>
make_optional(T && value)322 constexpr optional<std::decay_t<T>> make_optional(T&& value) {
323 return optional<std::decay_t<T>>{std::forward<T>(value)};
324 }
325 template <typename T, typename... Args>
make_optional(Args &&...args)326 constexpr optional<T> make_optional(Args&&... args) {
327 return optional<T>{in_place, std::forward<Args>(args)...};
328 }
329 template <typename T, typename U, typename... Args>
make_optional(std::initializer_list<U> init_list,Args &&...args)330 constexpr optional<T> make_optional(std::initializer_list<U> init_list, Args&&... args) {
331 return optional<T>{in_place, init_list, std::forward<Args>(args)...};
332 }
333
334 // Empty.
335 template <typename T>
336 constexpr bool operator==(const optional<T>& lhs, nullopt_t) {
337 return !lhs.has_value();
338 }
339 template <typename T>
340 constexpr bool operator!=(const optional<T>& lhs, nullopt_t) {
341 return lhs.has_value();
342 }
343
344 template <typename T>
345 constexpr bool operator==(nullopt_t, const optional<T>& rhs) {
346 return !rhs.has_value();
347 }
348 template <typename T>
349 constexpr bool operator!=(nullopt_t, const optional<T>& rhs) {
350 return rhs.has_value();
351 }
352
353 // Equal/not equal.
354 template <
355 typename T, typename U,
356 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() == std::declval<U>())> = true>
357 constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
358 return (lhs.has_value() == rhs.has_value()) && (!lhs.has_value() || *lhs == *rhs);
359 }
360 template <
361 typename T, typename U,
362 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() != std::declval<U>())> = true>
363 constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
364 return (lhs.has_value() != rhs.has_value()) || (lhs.has_value() && *lhs != *rhs);
365 }
366
367 template <typename T, typename U,
368 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() == std::declval<U>()),
369 ::cpp17::internal::not_same_type<nullopt_t, U>> = true>
370 constexpr bool operator==(const optional<T>& lhs, const U& rhs) {
371 return lhs.has_value() && *lhs == rhs;
372 }
373 template <typename T, typename U,
374 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() != std::declval<U>()),
375 ::cpp17::internal::not_same_type<nullopt_t, U>> = true>
376 constexpr bool operator!=(const optional<T>& lhs, const U& rhs) {
377 return !lhs.has_value() || *lhs != rhs;
378 }
379
380 template <typename T, typename U,
381 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() == std::declval<U>()),
382 ::cpp17::internal::not_same_type<nullopt_t, T>> = true>
383 constexpr bool operator==(const T& lhs, const optional<U>& rhs) {
384 return rhs.has_value() && lhs == *rhs;
385 }
386 template <typename T, typename U,
387 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() != std::declval<U>()),
388 ::cpp17::internal::not_same_type<nullopt_t, T>> = true>
389 constexpr bool operator!=(const T& lhs, const optional<U>& rhs) {
390 return !rhs.has_value() || lhs != *rhs;
391 }
392
393 // Less than/greater than.
394 template <typename T, typename U,
395 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() < std::declval<U>())> = true>
396 constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) {
397 return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
398 }
399 template <typename T, typename U,
400 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() > std::declval<U>())> = true>
401 constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) {
402 return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
403 }
404
405 template <typename T, typename U,
406 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() < std::declval<U>()),
407 ::cpp17::internal::not_same_type<nullopt_t, U>> = true>
408 constexpr bool operator<(const optional<T>& lhs, const U& rhs) {
409 return !lhs.has_value() || *lhs < rhs;
410 }
411 template <typename T, typename U,
412 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() > std::declval<U>()),
413 ::cpp17::internal::not_same_type<nullopt_t, U>> = true>
414 constexpr bool operator>(const optional<T>& lhs, const U& rhs) {
415 return lhs.has_value() && *lhs > rhs;
416 }
417
418 template <typename T, typename U,
419 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() < std::declval<U>()),
420 ::cpp17::internal::not_same_type<nullopt_t, T>> = true>
421 constexpr bool operator<(const T& lhs, const optional<U>& rhs) {
422 return rhs.has_value() && lhs < *rhs;
423 }
424 template <typename T, typename U,
425 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() > std::declval<U>()),
426 ::cpp17::internal::not_same_type<nullopt_t, T>> = true>
427 constexpr bool operator>(const T& lhs, const optional<U>& rhs) {
428 return !rhs.has_value() || lhs > *rhs;
429 }
430
431 // Less than or equal/greater than or equal.
432 template <
433 typename T, typename U,
434 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() <= std::declval<U>())> = true>
435 constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) {
436 return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
437 }
438 template <
439 typename T, typename U,
440 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() >= std::declval<U>())> = true>
441 constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) {
442 return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
443 }
444
445 template <typename T, typename U,
446 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() <= std::declval<U>()),
447 ::cpp17::internal::not_same_type<nullopt_t, U>> = true>
448 constexpr bool operator<=(const optional<T>& lhs, const U& rhs) {
449 return !lhs.has_value() || *lhs <= rhs;
450 }
451 template <typename T, typename U,
452 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() >= std::declval<U>()),
453 ::cpp17::internal::not_same_type<nullopt_t, U>> = true>
454 constexpr bool operator>=(const optional<T>& lhs, const U& rhs) {
455 return lhs.has_value() && *lhs >= rhs;
456 }
457
458 template <typename T, typename U,
459 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() <= std::declval<U>()),
460 ::cpp17::internal::not_same_type<nullopt_t, T>> = true>
461 constexpr bool operator<=(const T& lhs, const optional<U>& rhs) {
462 return rhs.has_value() && lhs <= *rhs;
463 }
464 template <typename T, typename U,
465 ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() >= std::declval<U>()),
466 ::cpp17::internal::not_same_type<nullopt_t, T>> = true>
467 constexpr bool operator>=(const T& lhs, const optional<U>& rhs) {
468 return !rhs.has_value() || lhs >= *rhs;
469 }
470
471 } // namespace cpp17
472
473 #endif
474
475 #endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_OPTIONAL_H_
476