MongoDB C++ Driver mongocxx-3.11.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_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 <new>
90#include <stdexcept>
91#include <type_traits>
92#include <utility>
93
96
97namespace bsoncxx {
98
99namespace v_noabi {
100
101namespace stdx {
102
103template <typename T>
104class optional;
105
106BSONCXX_PUSH_WARNINGS();
107BSONCXX_DISABLE_WARNING(Clang("-Wweak-vtables"));
108// Exception type thrown upon attempted access to a value-less optional<T> via a throwing accessor
109// API.
110class bad_optional_access : public std::exception {
111 public:
112 const char* what() const noexcept override {
113 return "bad_optional_access()";
114 }
115};
116BSONCXX_POP_WARNINGS();
117
118// Tag type to represent an empty optional value.
119struct nullopt_t {
120 explicit constexpr nullopt_t(std::nullptr_t) noexcept {}
121};
122
123// Tag constant to construct or compare with an empty optional value.
124static constexpr nullopt_t nullopt{nullptr};
125
126// Tag used to call the emplacement-constructor of optional<T>.
127static constexpr struct in_place_t {
128} in_place;
129
130namespace detail {
131
132// Terminates the program when an illegal use of optional<T> is attempted.
133[[noreturn]] inline void terminate_disengaged_optional(const char* what) noexcept {
134 (void)std::fprintf(stderr, "%s: Invalid attempted use of disengaged optional<T>\n", what);
135 std::terminate();
136}
137
138// Throws bad_optional_access for throwing optional<T> member functions.
139[[noreturn]] inline void throw_bad_optional() {
140 throw bad_optional_access();
141}
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:
192 using value_type = T;
193 using reference = bsoncxx::detail::add_lvalue_reference_t<T>;
194 using const_reference =
195 bsoncxx::detail::add_lvalue_reference_t<bsoncxx::detail::add_const_t<T>>;
196 using rvalue_reference = bsoncxx::detail::add_rvalue_reference_t<T>;
197 using const_rvalue_reference =
198 bsoncxx::detail::add_rvalue_reference_t<bsoncxx::detail::add_const_t<T>>;
199 using pointer = bsoncxx::detail::add_pointer_t<T>;
200 using const_pointer = bsoncxx::detail::add_pointer_t<const T>;
201
202 // Constructors [1].
203
204 optional() = default;
205 constexpr optional(nullopt_t) noexcept {}
206
207 // Ctor [2] and [3] are provided by base classes.
208
209 optional(const optional&) = default;
210 optional(optional&&) = default;
211
212 // Same with assignments
213
214 optional& operator=(const optional&) = default;
215 optional& operator=(optional&&) = default;
216 ~optional() = default;
217
218 // In-place constructors
219
220 template <typename... Args>
221 bsoncxx_cxx14_constexpr explicit optional(in_place_t, Args&&... args) noexcept(
222 noexcept(T(BSONCXX_FWD(args)...))) {
223 this->emplace(BSONCXX_FWD(args)...);
224 }
225
226 template <typename U, typename... Args>
227 bsoncxx_cxx14_constexpr explicit optional(
228 in_place_t,
229 std::initializer_list<U> il,
230 Args&&... args) noexcept(noexcept(T(il, BSONCXX_FWD(args)...))) {
231 this->emplace(il, BSONCXX_FWD(args)...);
232 }
233
234 // Explicit converting constructor. Only available if implicit conversion is
235 // not possible.
236 template <
237 typename U = T,
238 bsoncxx::detail::requires_t<int,
239 detail::enable_opt_value_conversion<U&&, T>,
240 bsoncxx::detail::negation<std::is_convertible<U&&, T>>> = 0>
241 bsoncxx_cxx14_constexpr explicit optional(U&& arg) noexcept(
242 std::is_nothrow_constructible<T, U&&>::value)
243 : optional(in_place, BSONCXX_FWD(arg)) {}
244
245 // Implicit converting constructor. Only available if implicit conversion is
246 // possible.
247 template <typename U = T,
248 bsoncxx::detail::requires_t<int,
249 detail::enable_opt_value_conversion<U&&, T>,
250 std::is_convertible<U&&, T>> = 0>
251 bsoncxx_cxx14_constexpr optional(U&& arg) noexcept(std::is_nothrow_constructible<T, U&&>::value)
252 : optional(in_place, BSONCXX_FWD(arg)) {}
253
254 template <typename U,
255 bsoncxx::detail::requires_t<
256 int,
257 detail::enable_opt_conversion<T, const U&, U>,
258 bsoncxx::detail::negation<std::is_convertible<U const&, T>>> = 0>
259 bsoncxx_cxx14_constexpr explicit optional(optional<U> const& other) noexcept(
260 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<const U>>::value) {
261 if (other.has_value()) {
262 this->emplace(*other);
263 }
264 }
265
266 template <typename U,
267 bsoncxx::detail::requires_t<int,
268 detail::enable_opt_conversion<T, const U&, U>,
269 std::is_convertible<U const&, T>> = 0>
270 bsoncxx_cxx14_constexpr optional(optional<U> const& other) noexcept(
271 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<const U>>::value) {
272 if (other.has_value()) {
273 this->emplace(*other);
274 }
275 }
276
277 template <
278 typename U,
279 bsoncxx::detail::requires_t<int,
280 detail::enable_opt_conversion<T, U&&, U>,
281 bsoncxx::detail::negation<std::is_convertible<U&&, T>>> = 0>
282 bsoncxx_cxx14_constexpr explicit optional(optional<U>&& other) noexcept(
283 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<U&&>>::value) {
284 if (other.has_value()) {
285 this->emplace(*BSONCXX_FWD(other));
286 }
287 }
288
289 template <typename U,
290 bsoncxx::detail::requires_t<int,
291 detail::enable_opt_conversion<T, U&&, U>,
292 std::is_convertible<U&&, T>> = 0>
293 bsoncxx_cxx14_constexpr optional(optional<U>&& other) noexcept(
294 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<U&&>>::value) {
295 if (other.has_value()) {
296 this->emplace(*BSONCXX_FWD(other));
297 }
298 }
299
300 constexpr bool has_value() const noexcept {
301 return this->_has_value;
302 }
303 constexpr explicit operator bool() const noexcept {
304 return this->has_value();
305 }
306
307 // Unchecked dereference operators.
308
309 bsoncxx_cxx14_constexpr reference operator*() & noexcept {
310 _assert_has_value("operator*() &");
311 return this->_storage.value;
312 }
313 bsoncxx_cxx14_constexpr const_reference operator*() const& noexcept {
314 _assert_has_value("operator*() const&");
315 return this->_storage.value;
316 }
317 bsoncxx_cxx14_constexpr rvalue_reference operator*() && noexcept {
318 _assert_has_value("operator*() &&");
319 return static_cast<rvalue_reference>(**this);
320 }
321 bsoncxx_cxx14_constexpr const_rvalue_reference operator*() const&& noexcept {
322 _assert_has_value("operator*() const&&");
323 return static_cast<const_rvalue_reference>(**this);
324 }
325
326 // (Unchecked) member-access operators.
327
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
339 bsoncxx_cxx14_constexpr reference value() & {
340 _throw_if_empty();
341 return **this;
342 }
343 bsoncxx_cxx14_constexpr const_reference value() const& {
344 _throw_if_empty();
345 return **this;
346 }
347 bsoncxx_cxx14_constexpr rvalue_reference value() && {
348 _throw_if_empty();
349 return static_cast<rvalue_reference>(**this);
350 }
351 bsoncxx_cxx14_constexpr const_rvalue_reference value() const&& {
352 _throw_if_empty();
353 return static_cast<const_rvalue_reference>(**this);
354 }
355
356 // Checked value-or-alternative.
357
358 template <typename U>
359 bsoncxx_cxx14_constexpr value_type value_or(U&& dflt) const& {
360 if (has_value()) {
361 return **this;
362 } else {
363 return static_cast<value_type>(BSONCXX_FWD(dflt));
364 }
365 }
366
367 template <typename U>
368 bsoncxx_cxx14_constexpr value_type value_or(U&& dflt) && {
369 if (has_value()) {
370 return *std::move(*this);
371 } else {
372 return static_cast<value_type>(BSONCXX_FWD(dflt));
373 }
374 }
375
376 private:
377 bsoncxx_cxx14_constexpr void _assert_has_value(const char* msg) const noexcept {
378 if (!this->has_value()) {
379 detail::terminate_disengaged_optional(msg);
380 }
381 }
382
383 bsoncxx_cxx14_constexpr void _throw_if_empty() const {
384 if (!this->has_value()) {
385 detail::throw_bad_optional();
386 }
387 }
388};
389
390// Construct an optional by decay-copying the given value into a new optional<decay_t<T>>.
391//
392// @param value The value being made into an optional.
393template <typename T>
394bsoncxx_cxx14_constexpr optional<bsoncxx::detail::decay_t<T>> make_optional(T&& value) noexcept(
395 std::is_nothrow_constructible<bsoncxx::detail::decay_t<T>, T&&>::value) {
396 return optional<bsoncxx::detail::decay_t<T>>(BSONCXX_FWD(value));
397}
398
399// Emplace-construct a new optional of the given type with the given constructor arguments.
400//
401// @tparam T The type to be constructed
402// @param args Constructor arguments
403template <typename T, typename... Args>
404bsoncxx_cxx14_constexpr optional<T> make_optional(Args&&... args) noexcept(
405 std::is_nothrow_constructible<T, Args&&...>::value) {
406 return optional<T>(in_place, BSONCXX_FWD(args)...);
407}
408
409// Emplace-construct a new optional of the given type with the given arguments (accepts an init-list
410// as the first argument).
411template <typename T, typename U, typename... Args>
412bsoncxx_cxx14_constexpr optional<T>
413make_optional(std::initializer_list<U> il, Args&&... args) noexcept(
414 std::is_nothrow_constructible<T, std::initializer_list<U>, Args&&...>::value) {
415 return optional<T>(in_place, il, BSONCXX_FWD(args)...);
416}
417
418namespace detail {
419
420// Union template that defines the storage for an optional's data.
421template <typename T, bool = std::is_trivially_destructible<T>::value>
422union storage_for {
423 // Placeholder member for disengaged optional
424 char nothing;
425 // Member that holds the actual value
426 T value;
427
428 // Default-construct activates the placeholder
429 storage_for() noexcept : nothing(0) {}
430
431 // Empty special members allow the union to be used in semiregular contexts,
432 // but it is the responsibility of the using class to implement them properly
433 ~storage_for() {}
434 storage_for(const storage_for&) = delete;
435 storage_for& operator=(const storage_for&) = delete;
436};
437
438template <typename T>
439union storage_for<T, true /* Is trivially destructible */> {
440 char nothing;
441 T value;
442 storage_for() noexcept : nothing(0) {}
443 storage_for(const storage_for&) = delete;
444 storage_for& operator=(const storage_for&) = delete;
445};
446
447// Whether a type is copyable, moveable, or immobile.
448enum copymove_classification {
449 copyable,
450 movable,
451 immobile,
452};
453
454// Classify the constructibility of the given type.
455template <typename T,
456 bool CanCopy = std::is_copy_constructible<T>::value,
457 bool CanMove = std::is_move_constructible<T>::value>
458constexpr copymove_classification classify_construct() {
459 return CanCopy ? copyable : CanMove ? movable : immobile;
460}
461
462// Classify the assignability of the given type.
463template <typename T,
464 bool CanCopy = std::is_copy_assignable<T>::value,
465 bool CanMove = std::is_move_assignable<T>::value>
466constexpr copymove_classification classify_assignment() {
467 return CanCopy ? copyable : CanMove ? movable : immobile;
468}
469
470// Common base class for optional storage implementation
471//
472// @tparam T
473template <typename T>
474class optional_common_base;
475
476// Define the special member constructors for optional<T>.
477template <typename T, copymove_classification = classify_construct<T>()>
478struct optional_construct_base;
479
480// Define the special member assignment operators for optional<T>.
481template <typename T, copymove_classification = classify_assignment<T>()>
482struct optional_assign_base;
483
484template <bool TrivialDestruct>
485struct optional_destruct_helper;
486
487template <typename T>
488using optional_destruct_base =
489 typename optional_destruct_helper<std::is_trivially_destructible<T>::value>::template base<T>;
490
491template <typename T>
492struct optional_assign_base<T, copyable> : optional_construct_base<T> {};
493
494template <typename T>
495struct optional_assign_base<T, movable> : optional_construct_base<T> {
496 // Constructors defer to base.
497
498 optional_assign_base() = default;
499 optional_assign_base(optional_assign_base const&) = default;
500 optional_assign_base(optional_assign_base&&) = default;
501 ~optional_assign_base() = default;
502
503 // Disallow copies.
504
505 bsoncxx_cxx14_constexpr optional_assign_base& operator=(const optional_assign_base&) = delete;
506
507 // Allow move-assignment.
508
509 bsoncxx_cxx14_constexpr optional_assign_base& operator=(optional_assign_base&& other) = default;
510};
511
512template <typename T>
513struct optional_assign_base<T, immobile> : optional_construct_base<T> {
514 optional_assign_base() = default;
515 optional_assign_base(optional_assign_base const&) = default;
516 optional_assign_base(optional_assign_base&&) = default;
517 ~optional_assign_base() = default;
518
519 // No assignment at all
520 optional_assign_base& operator=(const optional_assign_base&) = delete;
521 optional_assign_base& operator=(optional_assign_base&&) = delete;
522};
523
524template <typename T>
525struct optional_construct_base<T, copyable> : optional_destruct_base<T> {};
526
527template <typename T>
528struct optional_construct_base<T, movable> : optional_destruct_base<T> {
529 optional_construct_base() = default;
530
531 optional_construct_base(const optional_construct_base&) = delete;
532 optional_construct_base(optional_construct_base&& other) = default;
533 optional_construct_base& operator=(const optional_construct_base&) = default;
534 optional_construct_base& operator=(optional_construct_base&&) = default;
535};
536
537template <typename T>
538struct optional_construct_base<T, immobile> : optional_destruct_base<T> {
539 optional_construct_base() = default;
540 optional_construct_base(const optional_construct_base&) = delete;
541 optional_construct_base& operator=(const optional_construct_base&) = default;
542 optional_construct_base& operator=(optional_construct_base&&) = default;
543};
544
545template <>
546struct optional_destruct_helper<false /* Non-trivial */> {
547 template <typename T>
548 struct base : optional_common_base<T> {
549 // Special members defer to base.
550
551 base() = default;
552 base(base const&) = default;
553 base(base&&) = default;
554 base& operator=(const base&) = default;
555 base& operator=(base&&) = default;
556
557 ~base() {
558 // Here we destroy the contained object during destruction.
559 this->reset();
560 }
561 };
562};
563
564template <>
565struct optional_destruct_helper<true /* Trivial */> {
566 // Just fall-through to the common base, which has no special destructor.
567
568 template <typename T>
569 using base = optional_common_base<T>;
570};
571
572// Optional's ADL-only operators are defined here.
573struct optional_operators_base {
574 template <typename T, typename U>
575 friend bsoncxx_cxx14_constexpr auto tag_invoke(bsoncxx::detail::equal_to,
576 optional<T> const& left,
577 optional<U> const& right) noexcept
578 -> bsoncxx::detail::requires_t<bool, bsoncxx::detail::is_equality_comparable<T, U>> {
579 if (left.has_value() != right.has_value()) {
580 return false;
581 }
582
583 BSONCXX_PUSH_WARNINGS();
584 BSONCXX_DISABLE_WARNING(GNU("-Wfloat-equal"));
585 return !left.has_value() || *left == *right;
586 BSONCXX_POP_WARNINGS();
587 }
588
589 template <typename T, typename U>
590 friend constexpr auto tag_invoke(bsoncxx::detail::equal_to,
591 optional<T> const& left,
592 U const& right) noexcept -> bsoncxx::detail::
593 requires_t<bool, not_an_optional<U>, bsoncxx::detail::is_equality_comparable<T, U>> {
594 BSONCXX_PUSH_WARNINGS();
595 BSONCXX_DISABLE_WARNING(GNU("-Wfloat-equal"));
596 return left.has_value() && *left == right;
597 BSONCXX_POP_WARNINGS();
598 }
599
600 template <typename T>
601 friend constexpr bool tag_invoke(bsoncxx::detail::equal_to,
602 optional<T> const& opt,
603 nullopt_t) noexcept {
604 return !opt.has_value();
605 }
606
607 template <typename T, typename U>
608 bsoncxx_cxx14_constexpr friend auto tag_invoke(bsoncxx::detail::compare_three_way compare,
609 optional<T> const& left,
610 optional<U> const& right)
611 -> bsoncxx::detail::requires_t<bsoncxx::detail::strong_ordering,
612 bsoncxx::detail::is_totally_ordered_with<T, U>> {
613 if (left.has_value()) {
614 if (right.has_value()) {
615 return compare(*left, *right);
616 } else {
617 // Non-null is greater than any null.
618 return bsoncxx::detail::strong_ordering::greater;
619 }
620 } else {
621 if (right.has_value()) {
622 // Null is less than any non-null.
623 return bsoncxx::detail::strong_ordering::less;
624 } else {
625 // Both are null.
626 return bsoncxx::detail::strong_ordering::equal;
627 }
628 }
629 }
630
631 template <typename T, typename U>
632 bsoncxx_cxx14_constexpr friend auto tag_invoke(bsoncxx::detail::compare_three_way compare,
633 optional<T> const& left,
634 U const& right)
635 -> bsoncxx::detail::requires_t<bsoncxx::detail::strong_ordering,
636 not_an_optional<U>,
637 bsoncxx::detail::is_totally_ordered_with<T, U>> {
638 if (left.has_value()) {
639 return compare(*left, right);
640 }
641 // Null optional is less-than any non-null value.
642 return bsoncxx::detail::strong_ordering::less;
643 }
644
645 template <typename T>
646 constexpr friend bsoncxx::detail::strong_ordering tag_invoke(
647 bsoncxx::detail::compare_three_way compare, optional<T> const& left, nullopt_t) {
648 return compare(left.has_value(), false);
649 }
650};
651
652// An ADL-visible swap() should only be available for swappable objects
653template <typename T, bool IsSwappable = bsoncxx::detail::is_swappable<T>::value>
654struct optional_swap_mixin {};
655
656template <typename T>
657struct optional_swap_mixin<T, true> {
658 bsoncxx_cxx14_constexpr friend void swap(optional<T>& left, optional<T>& right) noexcept(
659 std::is_nothrow_move_constructible<T>::value&&
660 bsoncxx::detail::is_nothrow_swappable<T>::value) {
661 left.swap(right);
662 }
663};
664
665// Common base class of all optionals.
666template <typename T>
667class optional_common_base : optional_operators_base, optional_swap_mixin<T> {
668 using storage_type = detail::storage_for<bsoncxx::detail::remove_const_t<T>>;
669
670 public:
671 optional_common_base() = default;
672 ~optional_common_base() = default;
673
674 optional_common_base(const optional_common_base& other) noexcept(
675 std::is_nothrow_copy_constructible<T>::value) {
676 if (other._has_value) {
677 this->emplace(other._storage.value);
678 }
679 }
680
681 optional_common_base(optional_common_base&& other) noexcept(
682 std::is_nothrow_move_constructible<T>::value) {
683 if (other._has_value) {
684 this->_emplace_construct_anew(std::move(other)._storage.value);
685 }
686 }
687
688 optional_common_base& operator=(const optional_common_base& other) noexcept(
689 std::is_nothrow_copy_assignable<T>::value) {
690 this->_assign(BSONCXX_FWD(other));
691 return *this;
692 }
693
694 optional_common_base& operator=(optional_common_base&& other) noexcept(
695 std::is_nothrow_move_assignable<T>::value) {
696 this->_assign(BSONCXX_FWD(other));
697 return *this;
698 }
699
700 // If the optional is holding a value, destroy that value and set ourselves null.
701 void reset() noexcept {
702 if (this->_has_value) {
703 this->_storage.value.~T();
704 }
705 this->_has_value = false;
706 }
707
708 // If the optional is holding a value, destroy that value. Construct a new value in-place using
709 // the given arguments.
710 template <typename... Args>
711 T& emplace(Args&&... args) {
712 this->reset();
713 this->_emplace_construct_anew(BSONCXX_FWD(args)...);
714 return this->_storage.value;
715 }
716
717 // If the optional is holding a value, destroy that value. Construct a new value in-place using
718 // the given arguments.
719 template <typename U, typename... Args>
720 T& emplace(std::initializer_list<U> il, Args&&... args) {
721 this->reset();
722 this->_emplace_construct_anew(il, BSONCXX_FWD(args)...);
723 return this->_storage.value;
724 }
725
726 // Special swap for optional values that removes need for a temporary.
727 bsoncxx_cxx14_constexpr void swap(optional_common_base& other) noexcept(
728 std::is_nothrow_move_constructible<T>::value&&
729 bsoncxx::detail::is_nothrow_swappable<T>::value) {
730 if (other._has_value) {
731 if (this->_has_value) {
732 using std::swap;
733 // Defer to the underlying swap.
734 swap(this->_storage.value, other._storage.value);
735 } else {
736 // "steal" the other's value.
737 this->emplace(std::move(other._storage.value));
738 other.reset();
739 }
740 } else if (this->_has_value) {
741 other.emplace(std::move(this->_storage.value));
742 this->reset();
743 } else {
744 // Neither optional has a value, so do nothing.
745 }
746 }
747
748 private:
749 friend optional<T>;
750 storage_type _storage;
751 bool _has_value = false;
752
753 // In-place construct a new value from the given arguments. Assumes that the optional does not
754 // have a live value.
755 template <typename... Args>
756 void _emplace_construct_anew(Args&&... args) noexcept(
757 std::is_nothrow_constructible<T, Args&&...>::value) {
758 new (std::addressof(this->_storage.value)) T(BSONCXX_FWD(args)...);
759 this->_has_value = true;
760 }
761
762 // Perform the semantics of the assignment operator.
763 template <typename U>
764 void _assign(U&& other_storage) {
765 if (other_storage._has_value) {
766 // We are receiving a value.
767 if (this->_has_value) {
768 // We already have a value. Invoke the underlying assignment.
769 this->_storage.value = BSONCXX_FWD(other_storage)._storage.value;
770 } else {
771 // We don't have a value. Use the constructor.
772 this->_emplace_construct_anew(BSONCXX_FWD(other_storage)._storage.value);
773 }
774 } else {
775 // We are receiving nullopt. Destroy our value, if present.
776 this->reset();
777 }
778 }
779};
780
781template <typename T>
782struct optional_base_class {
783 using type = optional_assign_base<T>;
784};
785
786template <typename T,
787 bool CanHash =
788 std::is_default_constructible<std::hash<bsoncxx::detail::remove_const_t<T>>>::value>
789struct optional_hash;
790
791// Hash is "disabled" if the underlying type is not hashable (disabled = cannot construct the hash
792// invocable).
793template <typename T>
794struct optional_hash<T, false> {
795 optional_hash() = delete;
796 optional_hash(const optional_hash&) = delete;
797};
798
799template <typename T>
800struct optional_hash<T, true> {
801 using Td = bsoncxx::detail::remove_const_t<T>;
802 constexpr std::size_t operator()(const optional<T>& opt) const
803 noexcept(noexcept(std::hash<Td>()(std::declval<Td const&>()))) {
804 return opt.has_value() ? std::hash<Td>()(*opt) //
805 : std::hash<void*>()(nullptr);
806 }
807};
808
809} // namespace detail
810
811} // namespace stdx
812
813} // namespace v_noabi
814
815} // namespace bsoncxx
816
817namespace std {
818
819template <typename T>
820struct hash<bsoncxx::v_noabi::stdx::optional<T>>
821 : bsoncxx::v_noabi::stdx::detail::optional_hash<T> {};
822
823} // namespace std
824
825#else
826#error "Cannot find a valid polyfill for optional"
827#endif
828
830
831namespace bsoncxx {
832namespace stdx {
833
834// Only Boost prior to 1.63 does not provide an `std::in_place` equivalent.
835#if !defined(BOOST_VERSION) || BOOST_VERSION >= 106300
836using ::bsoncxx::v_noabi::stdx::in_place;
837using ::bsoncxx::v_noabi::stdx::in_place_t;
838#endif
839
840using ::bsoncxx::v_noabi::stdx::make_optional;
841using ::bsoncxx::v_noabi::stdx::nullopt;
842using ::bsoncxx::v_noabi::stdx::nullopt_t;
843using ::bsoncxx::v_noabi::stdx::optional;
844
845} // namespace stdx
846} // namespace bsoncxx
847
859
860#if defined(BSONCXX_PRIVATE_DOXYGEN_PREPROCESSOR)
861
862namespace bsoncxx {
863namespace v_noabi {
864namespace stdx {
865
873template <typename T>
874class optional {};
875
876} // namespace stdx
877} // namespace v_noabi
878} // namespace bsoncxx
879
880#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:874
BSONCXX_DEPRECATED typedef types::bson_value::view value
Equivalent to bsoncxx::v_noabi::types::bson_value::view.
Definition value.hpp:30
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.