MongoDB C++ Driver mongocxx-4.0.0
Loading...
Searching...
No Matches
optional.hpp
Go to the documentation of this file.
1// Copyright 2009-present MongoDB, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://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,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
18
19#if defined(BSONCXX_POLY_USE_STD)
20
21#include <optional>
22
23namespace bsoncxx {
24namespace v_noabi {
25namespace stdx {
26
27using ::std::in_place;
28using ::std::in_place_t;
29using ::std::make_optional;
30using ::std::nullopt;
31using ::std::nullopt_t;
32using ::std::optional;
33
34} // namespace stdx
35} // namespace v_noabi
36} // namespace bsoncxx
37
38#elif defined(BSONCXX_POLY_USE_IMPLS)
39
40#include <cstddef>
41#include <cstdio>
42#include <exception>
43#include <initializer_list>
44#include <memory>
45#include <new>
46#include <stdexcept>
47#include <type_traits>
48#include <utility>
49
52
53namespace bsoncxx {
54
55namespace v_noabi {
56
57namespace stdx {
58
59template <typename T>
60class optional;
61
62BSONCXX_PUSH_WARNINGS();
63BSONCXX_DISABLE_WARNING(Clang("-Wweak-vtables"));
64// Exception type thrown upon attempted access to a value-less optional<T> via a throwing accessor
65// API.
66class bad_optional_access : public std::exception {
67 public:
68 const char* what() const noexcept override {
69 return "bad_optional_access()";
70 }
71};
72BSONCXX_POP_WARNINGS();
73
74// Tag type to represent an empty optional value.
75struct nullopt_t {
76 explicit constexpr nullopt_t(std::nullptr_t) noexcept {}
77};
78
79// Tag constant to construct or compare with an empty optional value.
80static constexpr nullopt_t nullopt{nullptr};
81
82// Tag used to call the emplacement-constructor of optional<T>.
83static constexpr struct in_place_t {
84} in_place;
85
86namespace detail {
87
88// Terminates the program when an illegal use of optional<T> is attempted.
89[[noreturn]] inline void terminate_disengaged_optional(const char* what) noexcept {
90 (void)std::fprintf(stderr, "%s: Invalid attempted use of disengaged optional<T>\n", what);
91 std::terminate();
92}
93
94// Throws bad_optional_access for throwing optional<T> member functions.
95[[noreturn]] inline void throw_bad_optional() {
96 throw bad_optional_access();
97}
98
99// Base class of std::optional. Implementation detail, defined later.
100template <typename T>
101struct optional_base_class;
102
103// Base case: Things are not optionals.
104template <typename T>
105std::true_type not_an_optional_f(const T&);
106// More-specialized if given an optional<T> or any class derived from a template
107// specialization thereof.
108template <typename T>
109std::false_type not_an_optional_f(const optional<T>&);
110
111// Utility trait to detect specializations of stdx::optional.
112template <typename T>
113struct not_an_optional : decltype(not_an_optional_f(std::declval<T const&>())) {};
114
115template <typename T, typename Ucvr, typename U>
116struct enable_opt_conversion
117 : bsoncxx::detail::conjunction< //
118 std::is_constructible<T, Ucvr>,
119 bsoncxx::detail::disjunction< //
120 std::is_same<T, bool>,
121 bsoncxx::detail::negation<
122 bsoncxx::detail::conjunction<std::is_constructible<T, optional<U>&>,
123 std::is_constructible<T, optional<U> const&>,
124 std::is_constructible<T, optional<U>&&>,
125 std::is_constructible<T, optional<U> const&&>,
126 std::is_convertible<optional<U>&, T>,
127 std::is_convertible<optional<U> const&, T>,
128 std::is_convertible<optional<U>&&, T>,
129 std::is_convertible<optional<U> const&&, T>>>>> {};
130
131template <typename From, typename To>
132struct enable_opt_value_conversion //
133 : bsoncxx::detail::conjunction< //
134 std::is_constructible<To, From&&>,
135 bsoncxx::detail::negation<bsoncxx::detail::is_alike<From, in_place_t>>,
136 bsoncxx::detail::negation<bsoncxx::detail::is_alike<From, optional<To>>>,
137 bsoncxx::detail::disjunction<
138 bsoncxx::detail::negation<bsoncxx::detail::is_alike<To, bool>>, //
139 detail::not_an_optional<bsoncxx::detail::remove_cvref_t<From>>>> {};
140
141} // namespace detail
142
143template <typename T>
144class optional : bsoncxx::detail::equality_operators,
145 bsoncxx::detail::ordering_operators,
146 public detail::optional_base_class<T>::type {
147 public:
148 using value_type = T;
149 using reference = bsoncxx::detail::add_lvalue_reference_t<T>;
150 using const_reference =
151 bsoncxx::detail::add_lvalue_reference_t<bsoncxx::detail::add_const_t<T>>;
152 using rvalue_reference = bsoncxx::detail::add_rvalue_reference_t<T>;
153 using const_rvalue_reference =
154 bsoncxx::detail::add_rvalue_reference_t<bsoncxx::detail::add_const_t<T>>;
155 using pointer = bsoncxx::detail::add_pointer_t<T>;
156 using const_pointer = bsoncxx::detail::add_pointer_t<const T>;
157
158 // Constructors [1].
159
160 optional() = default;
161 constexpr optional(nullopt_t) noexcept {}
162
163 // Ctor [2] and [3] are provided by base classes.
164
165 optional(const optional&) = default;
166 optional(optional&&) = default;
167
168 // Same with assignments
169
170 optional& operator=(const optional&) = default;
171 optional& operator=(optional&&) = default;
172 ~optional() = default;
173
174 // In-place constructors
175
176 template <typename... Args>
177 bsoncxx_cxx14_constexpr explicit optional(in_place_t, Args&&... args) noexcept(
178 noexcept(T(BSONCXX_FWD(args)...))) {
179 this->emplace(BSONCXX_FWD(args)...);
180 }
181
182 template <typename U, typename... Args>
183 bsoncxx_cxx14_constexpr explicit optional(
184 in_place_t,
185 std::initializer_list<U> il,
186 Args&&... args) noexcept(noexcept(T(il, BSONCXX_FWD(args)...))) {
187 this->emplace(il, BSONCXX_FWD(args)...);
188 }
189
190 // Explicit converting constructor. Only available if implicit conversion is
191 // not possible.
192 template <
193 typename U = T,
194 bsoncxx::detail::requires_t<int,
195 detail::enable_opt_value_conversion<U&&, T>,
196 bsoncxx::detail::negation<std::is_convertible<U&&, T>>> = 0>
197 bsoncxx_cxx14_constexpr explicit optional(U&& arg) noexcept(
198 std::is_nothrow_constructible<T, U&&>::value)
199 : optional(in_place, BSONCXX_FWD(arg)) {}
200
201 // Implicit converting constructor. Only available if implicit conversion is
202 // possible.
203 template <typename U = T,
204 bsoncxx::detail::requires_t<int,
205 detail::enable_opt_value_conversion<U&&, T>,
206 std::is_convertible<U&&, T>> = 0>
207 bsoncxx_cxx14_constexpr optional(U&& arg) noexcept(std::is_nothrow_constructible<T, U&&>::value)
208 : optional(in_place, BSONCXX_FWD(arg)) {}
209
210 template <typename U,
211 bsoncxx::detail::requires_t<
212 int,
213 detail::enable_opt_conversion<T, const U&, U>,
214 bsoncxx::detail::negation<std::is_convertible<U const&, T>>> = 0>
215 bsoncxx_cxx14_constexpr explicit optional(optional<U> const& other) noexcept(
216 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<const U>>::value) {
217 if (other.has_value()) {
218 this->emplace(*other);
219 }
220 }
221
222 template <typename U,
223 bsoncxx::detail::requires_t<int,
224 detail::enable_opt_conversion<T, const U&, U>,
225 std::is_convertible<U const&, T>> = 0>
226 bsoncxx_cxx14_constexpr optional(optional<U> const& other) noexcept(
227 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<const U>>::value) {
228 if (other.has_value()) {
229 this->emplace(*other);
230 }
231 }
232
233 template <
234 typename U,
235 bsoncxx::detail::requires_t<int,
236 detail::enable_opt_conversion<T, U&&, U>,
237 bsoncxx::detail::negation<std::is_convertible<U&&, T>>> = 0>
238 bsoncxx_cxx14_constexpr explicit optional(optional<U>&& other) noexcept(
239 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<U&&>>::value) {
240 if (other.has_value()) {
241 this->emplace(*BSONCXX_FWD(other));
242 }
243 }
244
245 template <typename U,
246 bsoncxx::detail::requires_t<int,
247 detail::enable_opt_conversion<T, U&&, U>,
248 std::is_convertible<U&&, T>> = 0>
249 bsoncxx_cxx14_constexpr optional(optional<U>&& other) noexcept(
250 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<U&&>>::value) {
251 if (other.has_value()) {
252 this->emplace(*BSONCXX_FWD(other));
253 }
254 }
255
256 constexpr bool has_value() const noexcept {
257 return this->_has_value;
258 }
259 constexpr explicit operator bool() const noexcept {
260 return this->has_value();
261 }
262
263 // Unchecked dereference operators.
264
265 bsoncxx_cxx14_constexpr reference operator*() & noexcept {
266 _assert_has_value("operator*() &");
267 return this->_storage.value;
268 }
269 bsoncxx_cxx14_constexpr const_reference operator*() const& noexcept {
270 _assert_has_value("operator*() const&");
271 return this->_storage.value;
272 }
273 bsoncxx_cxx14_constexpr rvalue_reference operator*() && noexcept {
274 _assert_has_value("operator*() &&");
275 return static_cast<rvalue_reference>(**this);
276 }
277 bsoncxx_cxx14_constexpr const_rvalue_reference operator*() const&& noexcept {
278 _assert_has_value("operator*() const&&");
279 return static_cast<const_rvalue_reference>(**this);
280 }
281
282 // (Unchecked) member-access operators.
283
284 bsoncxx_cxx14_constexpr pointer operator->() noexcept {
285 _assert_has_value("operator->()");
286 return std::addressof(**this);
287 }
288 bsoncxx_cxx14_constexpr const_pointer operator->() const noexcept {
289 _assert_has_value("operator->() const");
290 return std::addressof(**this);
291 }
292
293 // Checked accessors.
294
295 bsoncxx_cxx14_constexpr reference value() & {
296 _throw_if_empty();
297 return **this;
298 }
299 bsoncxx_cxx14_constexpr const_reference value() const& {
300 _throw_if_empty();
301 return **this;
302 }
303 bsoncxx_cxx14_constexpr rvalue_reference value() && {
304 _throw_if_empty();
305 return static_cast<rvalue_reference>(**this);
306 }
307 bsoncxx_cxx14_constexpr const_rvalue_reference value() const&& {
308 _throw_if_empty();
309 return static_cast<const_rvalue_reference>(**this);
310 }
311
312 // Checked value-or-alternative.
313
314 template <typename U>
315 bsoncxx_cxx14_constexpr value_type value_or(U&& dflt) const& {
316 if (has_value()) {
317 return **this;
318 } else {
319 return static_cast<value_type>(BSONCXX_FWD(dflt));
320 }
321 }
322
323 template <typename U>
324 bsoncxx_cxx14_constexpr value_type value_or(U&& dflt) && {
325 if (has_value()) {
326 return *std::move(*this);
327 } else {
328 return static_cast<value_type>(BSONCXX_FWD(dflt));
329 }
330 }
331
332 private:
333 bsoncxx_cxx14_constexpr void _assert_has_value(const char* msg) const noexcept {
334 if (!this->has_value()) {
335 detail::terminate_disengaged_optional(msg);
336 }
337 }
338
339 bsoncxx_cxx14_constexpr void _throw_if_empty() const {
340 if (!this->has_value()) {
341 detail::throw_bad_optional();
342 }
343 }
344};
345
346// Construct an optional by decay-copying the given value into a new optional<decay_t<T>>.
347//
348// @param value The value being made into an optional.
349template <typename T>
350bsoncxx_cxx14_constexpr optional<bsoncxx::detail::decay_t<T>> make_optional(T&& value) noexcept(
351 std::is_nothrow_constructible<bsoncxx::detail::decay_t<T>, T&&>::value) {
352 return optional<bsoncxx::detail::decay_t<T>>(BSONCXX_FWD(value));
353}
354
355// Emplace-construct a new optional of the given type with the given constructor arguments.
356//
357// @tparam T The type to be constructed
358// @param args Constructor arguments
359template <typename T, typename... Args>
360bsoncxx_cxx14_constexpr optional<T> make_optional(Args&&... args) noexcept(
361 std::is_nothrow_constructible<T, Args&&...>::value) {
362 return optional<T>(in_place, BSONCXX_FWD(args)...);
363}
364
365// Emplace-construct a new optional of the given type with the given arguments (accepts an init-list
366// as the first argument).
367template <typename T, typename U, typename... Args>
368bsoncxx_cxx14_constexpr optional<T>
369make_optional(std::initializer_list<U> il, Args&&... args) noexcept(
370 std::is_nothrow_constructible<T, std::initializer_list<U>, Args&&...>::value) {
371 return optional<T>(in_place, il, BSONCXX_FWD(args)...);
372}
373
374namespace detail {
375
376// Union template that defines the storage for an optional's data.
377template <typename T, bool = std::is_trivially_destructible<T>::value>
378union storage_for {
379 // Placeholder member for disengaged optional
380 char nothing;
381 // Member that holds the actual value
382 T value;
383
384 // Default-construct activates the placeholder
385 storage_for() noexcept : nothing(0) {}
386
387 // Empty special members allow the union to be used in semiregular contexts,
388 // but it is the responsibility of the using class to implement them properly
389 ~storage_for() {}
390 storage_for(const storage_for&) = delete;
391 storage_for& operator=(const storage_for&) = delete;
392};
393
394template <typename T>
395union storage_for<T, true /* Is trivially destructible */> {
396 char nothing;
397 T value;
398 storage_for() noexcept : nothing(0) {}
399 storage_for(const storage_for&) = delete;
400 storage_for& operator=(const storage_for&) = delete;
401};
402
403// Whether a type is copyable, moveable, or immobile.
404enum copymove_classification {
405 copyable,
406 movable,
407 immobile,
408};
409
410// Classify the constructibility of the given type.
411template <typename T,
412 bool CanCopy = std::is_copy_constructible<T>::value,
413 bool CanMove = std::is_move_constructible<T>::value>
414constexpr copymove_classification classify_construct() {
415 return CanCopy ? copyable : CanMove ? movable : immobile;
416}
417
418// Classify the assignability of the given type.
419template <typename T,
420 bool CanCopy = std::is_copy_assignable<T>::value,
421 bool CanMove = std::is_move_assignable<T>::value>
422constexpr copymove_classification classify_assignment() {
423 return CanCopy ? copyable : CanMove ? movable : immobile;
424}
425
426// Common base class for optional storage implementation
427//
428// @tparam T
429template <typename T>
430class optional_common_base;
431
432// Define the special member constructors for optional<T>.
433template <typename T, copymove_classification = classify_construct<T>()>
434struct optional_construct_base;
435
436// Define the special member assignment operators for optional<T>.
437template <typename T, copymove_classification = classify_assignment<T>()>
438struct optional_assign_base;
439
440template <bool TrivialDestruct>
441struct optional_destruct_helper;
442
443template <typename T>
444using optional_destruct_base =
445 typename optional_destruct_helper<std::is_trivially_destructible<T>::value>::template base<T>;
446
447template <typename T>
448struct optional_assign_base<T, copyable> : optional_construct_base<T> {};
449
450template <typename T>
451struct optional_assign_base<T, movable> : optional_construct_base<T> {
452 // Constructors defer to base.
453
454 optional_assign_base() = default;
455 optional_assign_base(optional_assign_base const&) = default;
456 optional_assign_base(optional_assign_base&&) = default;
457 ~optional_assign_base() = default;
458
459 // Disallow copies.
460
461 bsoncxx_cxx14_constexpr optional_assign_base& operator=(const optional_assign_base&) = delete;
462
463 // Allow move-assignment.
464
465 bsoncxx_cxx14_constexpr optional_assign_base& operator=(optional_assign_base&&) = default;
466};
467
468template <typename T>
469struct optional_assign_base<T, immobile> : optional_construct_base<T> {
470 optional_assign_base() = default;
471 optional_assign_base(optional_assign_base const&) = default;
472 optional_assign_base(optional_assign_base&&) = default;
473 ~optional_assign_base() = default;
474
475 // No assignment at all
476 optional_assign_base& operator=(const optional_assign_base&) = delete;
477 optional_assign_base& operator=(optional_assign_base&&) = delete;
478};
479
480template <typename T>
481struct optional_construct_base<T, copyable> : optional_destruct_base<T> {};
482
483template <typename T>
484struct optional_construct_base<T, movable> : optional_destruct_base<T> {
485 optional_construct_base() = default;
486
487 optional_construct_base(const optional_construct_base&) = delete;
488 optional_construct_base(optional_construct_base&&) = default;
489 optional_construct_base& operator=(const optional_construct_base&) = default;
490 optional_construct_base& operator=(optional_construct_base&&) = default;
491};
492
493template <typename T>
494struct optional_construct_base<T, immobile> : optional_destruct_base<T> {
495 optional_construct_base() = default;
496 optional_construct_base(const optional_construct_base&) = delete;
497 optional_construct_base& operator=(const optional_construct_base&) = default;
498 optional_construct_base& operator=(optional_construct_base&&) = default;
499};
500
501template <>
502struct optional_destruct_helper<false /* Non-trivial */> {
503 template <typename T>
504 struct base : optional_common_base<T> {
505 // Special members defer to base.
506
507 base() = default;
508 base(base const&) = default;
509 base(base&&) = default;
510 base& operator=(const base&) = default;
511 base& operator=(base&&) = default;
512
513 ~base() {
514 // Here we destroy the contained object during destruction.
515 this->reset();
516 }
517 };
518};
519
520template <>
521struct optional_destruct_helper<true /* Trivial */> {
522 // Just fall-through to the common base, which has no special destructor.
523
524 template <typename T>
525 using base = optional_common_base<T>;
526};
527
528// Optional's ADL-only operators are defined here.
529struct optional_operators_base {
530 template <typename T, typename U>
531 friend bsoncxx_cxx14_constexpr auto tag_invoke(bsoncxx::detail::equal_to,
532 optional<T> const& left,
533 optional<U> const& right) noexcept
534 -> bsoncxx::detail::requires_t<bool, bsoncxx::detail::is_equality_comparable<T, U>> {
535 if (left.has_value() != right.has_value()) {
536 return false;
537 }
538
539 BSONCXX_PUSH_WARNINGS();
540 BSONCXX_DISABLE_WARNING(GNU("-Wfloat-equal"));
541 return !left.has_value() || *left == *right;
542 BSONCXX_POP_WARNINGS();
543 }
544
545 template <typename T, typename U>
546 friend constexpr auto tag_invoke(bsoncxx::detail::equal_to,
547 optional<T> const& left,
548 U const& right) noexcept -> bsoncxx::detail::
549 requires_t<bool, not_an_optional<U>, bsoncxx::detail::is_equality_comparable<T, U>> {
550 BSONCXX_PUSH_WARNINGS();
551 BSONCXX_DISABLE_WARNING(GNU("-Wfloat-equal"));
552 return left.has_value() && *left == right;
553 BSONCXX_POP_WARNINGS();
554 }
555
556 template <typename T>
557 friend constexpr bool tag_invoke(bsoncxx::detail::equal_to,
558 optional<T> const& opt,
559 nullopt_t) noexcept {
560 return !opt.has_value();
561 }
562
563 template <typename T, typename U>
564 bsoncxx_cxx14_constexpr friend auto tag_invoke(bsoncxx::detail::compare_three_way compare,
565 optional<T> const& left,
566 optional<U> const& right)
567 -> bsoncxx::detail::requires_t<bsoncxx::detail::strong_ordering,
568 bsoncxx::detail::is_totally_ordered_with<T, U>> {
569 if (left.has_value()) {
570 if (right.has_value()) {
571 return compare(*left, *right);
572 } else {
573 // Non-null is greater than any null.
574 return bsoncxx::detail::strong_ordering::greater;
575 }
576 } else {
577 if (right.has_value()) {
578 // Null is less than any non-null.
579 return bsoncxx::detail::strong_ordering::less;
580 } else {
581 // Both are null.
582 return bsoncxx::detail::strong_ordering::equal;
583 }
584 }
585 }
586
587 template <typename T, typename U>
588 bsoncxx_cxx14_constexpr friend auto tag_invoke(bsoncxx::detail::compare_three_way compare,
589 optional<T> const& left,
590 U const& right)
591 -> bsoncxx::detail::requires_t<bsoncxx::detail::strong_ordering,
592 not_an_optional<U>,
593 bsoncxx::detail::is_totally_ordered_with<T, U>> {
594 if (left.has_value()) {
595 return compare(*left, right);
596 }
597 // Null optional is less-than any non-null value.
598 return bsoncxx::detail::strong_ordering::less;
599 }
600
601 template <typename T>
602 constexpr friend bsoncxx::detail::strong_ordering tag_invoke(
603 bsoncxx::detail::compare_three_way compare, optional<T> const& left, nullopt_t) {
604 return compare(left.has_value(), false);
605 }
606};
607
608// An ADL-visible swap() should only be available for swappable objects
609template <typename T, bool IsSwappable = bsoncxx::detail::is_swappable<T>::value>
610struct optional_swap_mixin {};
611
612template <typename T>
613struct optional_swap_mixin<T, true> {
614 bsoncxx_cxx14_constexpr friend void swap(optional<T>& left, optional<T>& right) noexcept(
615 std::is_nothrow_move_constructible<T>::value&&
616 bsoncxx::detail::is_nothrow_swappable<T>::value) {
617 left.swap(right);
618 }
619};
620
621// Common base class of all optionals.
622template <typename T>
623class optional_common_base : optional_operators_base, optional_swap_mixin<T> {
624 using storage_type = detail::storage_for<bsoncxx::detail::remove_const_t<T>>;
625
626 public:
627 optional_common_base() = default;
628 ~optional_common_base() = default;
629
630 optional_common_base(const optional_common_base& other) noexcept(
631 std::is_nothrow_copy_constructible<T>::value) {
632 if (other._has_value) {
633 this->emplace(other._storage.value);
634 }
635 }
636
637 optional_common_base(optional_common_base&& other) noexcept(
638 std::is_nothrow_move_constructible<T>::value) {
639 if (other._has_value) {
640 this->_emplace_construct_anew(std::move(other)._storage.value);
641 }
642 }
643
644 optional_common_base& operator=(const optional_common_base& other) noexcept(
645 std::is_nothrow_copy_assignable<T>::value) {
646 this->_assign(BSONCXX_FWD(other));
647 return *this;
648 }
649
650 optional_common_base& operator=(optional_common_base&& other) noexcept(
651 std::is_nothrow_move_assignable<T>::value) {
652 this->_assign(BSONCXX_FWD(other));
653 return *this;
654 }
655
656 // If the optional is holding a value, destroy that value and set ourselves null.
657 void reset() noexcept {
658 if (this->_has_value) {
659 this->_storage.value.~T();
660 }
661 this->_has_value = false;
662 }
663
664 // If the optional is holding a value, destroy that value. Construct a new value in-place using
665 // the given arguments.
666 template <typename... Args>
667 T& emplace(Args&&... args) {
668 this->reset();
669 this->_emplace_construct_anew(BSONCXX_FWD(args)...);
670 return this->_storage.value;
671 }
672
673 // If the optional is holding a value, destroy that value. Construct a new value in-place using
674 // the given arguments.
675 template <typename U, typename... Args>
676 T& emplace(std::initializer_list<U> il, Args&&... args) {
677 this->reset();
678 this->_emplace_construct_anew(il, BSONCXX_FWD(args)...);
679 return this->_storage.value;
680 }
681
682 // Special swap for optional values that removes need for a temporary.
683 bsoncxx_cxx14_constexpr void swap(optional_common_base& other) noexcept(
684 std::is_nothrow_move_constructible<T>::value&&
685 bsoncxx::detail::is_nothrow_swappable<T>::value) {
686 if (other._has_value) {
687 if (this->_has_value) {
688 using std::swap;
689 // Defer to the underlying swap.
690 swap(this->_storage.value, other._storage.value);
691 } else {
692 // "steal" the other's value.
693 this->emplace(std::move(other._storage.value));
694 other.reset();
695 }
696 } else if (this->_has_value) {
697 other.emplace(std::move(this->_storage.value));
698 this->reset();
699 } else {
700 // Neither optional has a value, so do nothing.
701 }
702 }
703
704 private:
705 friend optional<T>;
706 storage_type _storage;
707 bool _has_value = false;
708
709 // In-place construct a new value from the given arguments. Assumes that the optional does not
710 // have a live value.
711 template <typename... Args>
712 void _emplace_construct_anew(Args&&... args) noexcept(
713 std::is_nothrow_constructible<T, Args&&...>::value) {
714 new (std::addressof(this->_storage.value)) T(BSONCXX_FWD(args)...);
715 this->_has_value = true;
716 }
717
718 // Perform the semantics of the assignment operator.
719 template <typename U>
720 void _assign(U&& other_storage) {
721 if (other_storage._has_value) {
722 // We are receiving a value.
723 if (this->_has_value) {
724 // We already have a value. Invoke the underlying assignment.
725 this->_storage.value = BSONCXX_FWD(other_storage)._storage.value;
726 } else {
727 // We don't have a value. Use the constructor.
728 this->_emplace_construct_anew(BSONCXX_FWD(other_storage)._storage.value);
729 }
730 } else {
731 // We are receiving nullopt. Destroy our value, if present.
732 this->reset();
733 }
734 }
735};
736
737template <typename T>
738struct optional_base_class {
739 using type = optional_assign_base<T>;
740};
741
742template <typename T,
743 bool CanHash =
744 std::is_default_constructible<std::hash<bsoncxx::detail::remove_const_t<T>>>::value>
745struct optional_hash;
746
747// Hash is "disabled" if the underlying type is not hashable (disabled = cannot construct the hash
748// invocable).
749template <typename T>
750struct optional_hash<T, false> {
751 optional_hash() = delete;
752 optional_hash(const optional_hash&) = delete;
753};
754
755template <typename T>
756struct optional_hash<T, true> {
757 using Td = bsoncxx::detail::remove_const_t<T>;
758 constexpr std::size_t operator()(const optional<T>& opt) const
759 noexcept(noexcept(std::hash<Td>()(std::declval<Td const&>()))) {
760 return opt.has_value() ? std::hash<Td>()(*opt) //
761 : std::hash<void*>()(nullptr);
762 }
763};
764
765} // namespace detail
766
767} // namespace stdx
768
769} // namespace v_noabi
770
771} // namespace bsoncxx
772
773namespace std {
774
775template <typename T>
776struct hash<bsoncxx::v_noabi::stdx::optional<T>>
777 : bsoncxx::v_noabi::stdx::detail::optional_hash<T> {};
778
779} // namespace std
780
781#else
782#error "Cannot find a valid polyfill for optional"
783#endif
784
786
787namespace bsoncxx {
788namespace stdx {
789
790using ::bsoncxx::v_noabi::stdx::in_place;
791using ::bsoncxx::v_noabi::stdx::in_place_t;
792using ::bsoncxx::v_noabi::stdx::make_optional;
793using ::bsoncxx::v_noabi::stdx::nullopt;
794using ::bsoncxx::v_noabi::stdx::nullopt_t;
795using ::bsoncxx::v_noabi::stdx::optional;
796
797} // namespace stdx
798} // namespace bsoncxx
799
811
812#if defined(BSONCXX_PRIVATE_DOXYGEN_PREPROCESSOR)
813
814namespace bsoncxx {
815namespace v_noabi {
816namespace stdx {
817
825template <typename T>
826class optional {};
827
828} // namespace stdx
829} // namespace v_noabi
830} // namespace bsoncxx
831
832#endif // defined(BSONCXX_PRIVATE_DOXYGEN_PREPROCESSOR)
The bsoncxx macro guard postlude header.
The bsoncxx macro guard prelude header.
A polyfill for std::optional<T>.
Definition optional.hpp:826
type
An enumeration of each BSON type.
Definition types.hpp:43
The top-level namespace within which all bsoncxx library entities are declared.
The top-level namespace reserved for the C++ standard library.
Provides comparison-related utilities for internal use.
Provides <type_traits>-related polyfills for internal use.