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