MongoDB C++ Driver 4.1.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
20
21#if defined(BSONCXX_POLY_USE_STD)
22
23#include <optional>
24
25namespace bsoncxx {
26namespace v1 {
27namespace stdx {
28
29using std::in_place;
30using std::in_place_t;
31using std::make_optional;
32using std::nullopt;
33using std::nullopt_t;
34using std::optional;
35
36} // namespace stdx
37} // namespace v1
38} // namespace bsoncxx
39
40#elif defined(BSONCXX_POLY_USE_IMPLS)
41
45
46#include <cstddef>
47#include <cstdio>
48#include <exception>
49#include <initializer_list>
50#include <memory>
51#include <new>
52#include <stdexcept>
53#include <type_traits>
54#include <utility>
55
56namespace bsoncxx {
57
58namespace v1 {
59
60namespace stdx {
61
62template <typename T>
63class optional;
64
65BSONCXX_PRIVATE_WARNINGS_PUSH();
66BSONCXX_PRIVATE_WARNINGS_DISABLE(Clang("-Wweak-vtables"));
67// Exception type thrown upon attempted access to a value-less optional<T> via a throwing accessor
68// API.
69class bad_optional_access : public std::exception {
70 public:
71 char const* what() const noexcept override {
72 return "bad_optional_access()";
73 }
74};
75BSONCXX_PRIVATE_WARNINGS_POP();
76
77// Tag type to represent an empty optional value.
78struct nullopt_t {
79 explicit constexpr nullopt_t(std::nullptr_t) noexcept {}
80};
81
82// Tag constant to construct or compare with an empty optional value.
83static constexpr nullopt_t nullopt{nullptr};
84
85// Tag used to call the emplacement-constructor of optional<T>.
86static constexpr struct in_place_t {
87} in_place;
88
89namespace detail {
90
91// Terminates the program when an illegal use of optional<T> is attempted.
92[[noreturn]] inline void terminate_disengaged_optional(char const* what) noexcept {
93 (void)std::fprintf(stderr, "%s: Invalid attempted use of disengaged optional<T>\n", what);
94 std::terminate();
95}
96
97// Throws bad_optional_access for throwing optional<T> member functions.
98[[noreturn]] inline void throw_bad_optional() {
99 throw bad_optional_access();
100}
101
102// Base class of std::optional. Implementation detail, defined later.
103template <typename T>
104struct optional_base_class;
105
106// Base case: Things are not optionals.
107template <typename T>
108std::true_type not_an_optional_f(T const&);
109// More-specialized if given an optional<T> or any class derived from a template
110// specialization thereof.
111template <typename T>
112std::false_type not_an_optional_f(optional<T> const&);
113
114// Utility trait to detect specializations of stdx::optional.
115template <typename T>
116struct not_an_optional : decltype(not_an_optional_f(std::declval<T const&>())){};
117
118template <typename T, typename Ucvr, typename U>
119struct enable_opt_conversion : bsoncxx::detail::conjunction<
120 std::is_constructible<T, Ucvr>,
121 bsoncxx::detail::disjunction<
122 std::is_same<T, bool>,
123 bsoncxx::detail::negation<bsoncxx::detail::conjunction<
124 std::is_constructible<T, optional<U>&>,
125 std::is_constructible<T, optional<U> const&>,
126 std::is_constructible<T, optional<U>&&>,
127 std::is_constructible<T, optional<U> const&&>,
128 std::is_convertible<optional<U>&, T>,
129 std::is_convertible<optional<U> const&, T>,
130 std::is_convertible<optional<U>&&, T>,
131 std::is_convertible<optional<U> const&&, T>>>>> {};
132
133template <typename From, typename To>
134struct enable_opt_value_conversion : bsoncxx::detail::conjunction<
135 std::is_constructible<To, From&&>,
136 bsoncxx::detail::negation<bsoncxx::detail::is_alike<From, in_place_t>>,
137 bsoncxx::detail::negation<bsoncxx::detail::is_alike<From, optional<To>>>,
138 bsoncxx::detail::disjunction<
139 bsoncxx::detail::negation<bsoncxx::detail::is_alike<To, bool>>,
140 detail::not_an_optional<bsoncxx::detail::remove_cvref_t<From>>>> {};
141
142} // namespace detail
143
144template <typename T>
145class optional : bsoncxx::detail::equality_operators,
146 bsoncxx::detail::ordering_operators,
147 public detail::optional_base_class<T>::type {
148 public:
149 using value_type = T;
150 using reference = bsoncxx::detail::add_lvalue_reference_t<T>;
151 using const_reference = 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 = bsoncxx::detail::add_rvalue_reference_t<bsoncxx::detail::add_const_t<T>>;
154 using pointer = bsoncxx::detail::add_pointer_t<T>;
155 using const_pointer = bsoncxx::detail::add_pointer_t<T const>;
156
157 // Constructors [1].
158
159 optional() = default;
160 constexpr optional(nullopt_t) noexcept {}
161
162 // Ctor [2] and [3] are provided by base classes.
163
164 optional(optional const&) = default;
165 optional(optional&&) = default;
166
167 // Same with assignments
168
169 optional& operator=(optional const&) = default;
170 optional& operator=(optional&&) = default;
171 ~optional() = default;
172
173 // In-place constructors
174
175 template <typename... Args>
176 BSONCXX_PRIVATE_CONSTEXPR_CXX14 explicit optional(in_place_t, Args&&... args) noexcept(
177 noexcept(T(BSONCXX_PRIVATE_FWD(args)...))) {
178 this->emplace(BSONCXX_PRIVATE_FWD(args)...);
179 }
180
181 template <typename U, typename... Args>
182 BSONCXX_PRIVATE_CONSTEXPR_CXX14 explicit optional(in_place_t, std::initializer_list<U> il, Args&&... args) noexcept(
183 noexcept(T(il, BSONCXX_PRIVATE_FWD(args)...))) {
184 this->emplace(il, BSONCXX_PRIVATE_FWD(args)...);
185 }
186
187 // Explicit converting constructor. Only available if implicit conversion is
188 // not possible.
189 template <
190 typename U = T,
191 bsoncxx::detail::requires_t<
192 int,
193 detail::enable_opt_value_conversion<U&&, T>,
194 bsoncxx::detail::negation<std::is_convertible<U&&, T>>> = 0>
195 BSONCXX_PRIVATE_CONSTEXPR_CXX14 explicit optional(U&& arg) noexcept(std::is_nothrow_constructible<T, U&&>::value)
196 : optional(in_place, BSONCXX_PRIVATE_FWD(arg)) {}
197
198 // Implicit converting constructor. Only available if implicit conversion is
199 // possible.
200 template <
201 typename U = T,
202 bsoncxx::detail::requires_t<int, detail::enable_opt_value_conversion<U&&, T>, std::is_convertible<U&&, T>> = 0>
203 BSONCXX_PRIVATE_CONSTEXPR_CXX14 optional(U&& arg) noexcept(std::is_nothrow_constructible<T, U&&>::value)
204 : optional(in_place, BSONCXX_PRIVATE_FWD(arg)) {}
205
206 template <
207 typename U,
208 bsoncxx::detail::requires_t<
209 int,
210 detail::enable_opt_conversion<T, U const&, U>,
211 bsoncxx::detail::negation<std::is_convertible<U const&, T>>> = 0>
212 BSONCXX_PRIVATE_CONSTEXPR_CXX14 explicit optional(optional<U> const& other) noexcept(
213 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<U const>>::value) {
214 if (other.has_value()) {
215 this->emplace(*other);
216 }
217 }
218
219 template <
220 typename U,
221 bsoncxx::detail::requires_t<
222 int,
223 detail::enable_opt_conversion<T, U const&, U>,
224 std::is_convertible<U const&, T>> = 0>
225 BSONCXX_PRIVATE_CONSTEXPR_CXX14 optional(optional<U> const& other) noexcept(
226 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<U const>>::value) {
227 if (other.has_value()) {
228 this->emplace(*other);
229 }
230 }
231
232 template <
233 typename U,
234 bsoncxx::detail::requires_t<
235 int,
236 detail::enable_opt_conversion<T, U&&, U>,
237 bsoncxx::detail::negation<std::is_convertible<U&&, T>>> = 0>
238 BSONCXX_PRIVATE_CONSTEXPR_CXX14 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_PRIVATE_FWD(other));
242 }
243 }
244
245 template <
246 typename U,
247 bsoncxx::detail::requires_t<int, detail::enable_opt_conversion<T, U&&, U>, std::is_convertible<U&&, T>> = 0>
248 BSONCXX_PRIVATE_CONSTEXPR_CXX14 optional(optional<U>&& other) noexcept(
249 std::is_nothrow_constructible<T, bsoncxx::detail::add_lvalue_reference_t<U&&>>::value) {
250 if (other.has_value()) {
251 this->emplace(*BSONCXX_PRIVATE_FWD(other));
252 }
253 }
254
255 constexpr bool has_value() const noexcept {
256 return this->_has_value;
257 }
258 constexpr explicit operator bool() const noexcept {
259 return this->has_value();
260 }
261
262 // Unchecked dereference operators.
263
264 BSONCXX_PRIVATE_CONSTEXPR_CXX14 reference operator*() & noexcept {
265 _assert_has_value("operator*() &");
266 return this->_storage.value;
267 }
268 BSONCXX_PRIVATE_CONSTEXPR_CXX14 const_reference operator*() const& noexcept {
269 _assert_has_value("operator*() const&");
270 return this->_storage.value;
271 }
272 BSONCXX_PRIVATE_CONSTEXPR_CXX14 rvalue_reference operator*() && noexcept {
273 _assert_has_value("operator*() &&");
274 return static_cast<rvalue_reference>(**this);
275 }
276 BSONCXX_PRIVATE_CONSTEXPR_CXX14 const_rvalue_reference operator*() const&& noexcept {
277 _assert_has_value("operator*() const&&");
278 return static_cast<const_rvalue_reference>(**this);
279 }
280
281 // (Unchecked) member-access operators.
282
283 BSONCXX_PRIVATE_CONSTEXPR_CXX14 pointer operator->() noexcept {
284 _assert_has_value("operator->()");
285 return std::addressof(**this);
286 }
287 BSONCXX_PRIVATE_CONSTEXPR_CXX14 const_pointer operator->() const noexcept {
288 _assert_has_value("operator->() const");
289 return std::addressof(**this);
290 }
291
292 // Checked accessors.
293
294 BSONCXX_PRIVATE_CONSTEXPR_CXX14 reference value() & {
295 _throw_if_empty();
296 return **this;
297 }
298 BSONCXX_PRIVATE_CONSTEXPR_CXX14 const_reference value() const& {
299 _throw_if_empty();
300 return **this;
301 }
302 BSONCXX_PRIVATE_CONSTEXPR_CXX14 rvalue_reference value() && {
303 _throw_if_empty();
304 return static_cast<rvalue_reference>(**this);
305 }
306 BSONCXX_PRIVATE_CONSTEXPR_CXX14 const_rvalue_reference value() const&& {
307 _throw_if_empty();
308 return static_cast<const_rvalue_reference>(**this);
309 }
310
311 // Checked value-or-alternative.
312
313 template <typename U>
314 BSONCXX_PRIVATE_CONSTEXPR_CXX14 value_type value_or(U&& dflt) const& {
315 if (has_value()) {
316 return **this;
317 } else {
318 return static_cast<value_type>(BSONCXX_PRIVATE_FWD(dflt));
319 }
320 }
321
322 template <typename U>
323 BSONCXX_PRIVATE_CONSTEXPR_CXX14 value_type value_or(U&& dflt) && {
324 if (has_value()) {
325 return *std::move(*this);
326 } else {
327 return static_cast<value_type>(BSONCXX_PRIVATE_FWD(dflt));
328 }
329 }
330
331 private:
332 BSONCXX_PRIVATE_CONSTEXPR_CXX14 void _assert_has_value(char const* msg) const noexcept {
333 if (!this->has_value()) {
334 detail::terminate_disengaged_optional(msg);
335 }
336 }
337
338 BSONCXX_PRIVATE_CONSTEXPR_CXX14 void _throw_if_empty() const {
339 if (!this->has_value()) {
340 detail::throw_bad_optional();
341 }
342 }
343};
344
345// Construct an optional by decay-copying the given value into a new optional<decay_t<T>>.
346//
347// @param value The value being made into an optional.
348template <typename T>
349BSONCXX_PRIVATE_CONSTEXPR_CXX14 optional<bsoncxx::detail::decay_t<T>> make_optional(T&& value) noexcept(
350 std::is_nothrow_constructible<bsoncxx::detail::decay_t<T>, T&&>::value) {
351 return optional<bsoncxx::detail::decay_t<T>>(BSONCXX_PRIVATE_FWD(value));
352}
353
354// Emplace-construct a new optional of the given type with the given constructor arguments.
355//
356// @tparam T The type to be constructed
357// @param args Constructor arguments
358template <typename T, typename... Args>
359BSONCXX_PRIVATE_CONSTEXPR_CXX14 optional<T> make_optional(Args&&... args) noexcept(
360 std::is_nothrow_constructible<T, Args&&...>::value) {
361 return optional<T>(in_place, BSONCXX_PRIVATE_FWD(args)...);
362}
363
364// Emplace-construct a new optional of the given type with the given arguments (accepts an init-list
365// as the first argument).
366template <typename T, typename U, typename... Args>
367BSONCXX_PRIVATE_CONSTEXPR_CXX14 optional<T> make_optional(std::initializer_list<U> il, Args&&... args) noexcept(
368 std::is_nothrow_constructible<T, std::initializer_list<U>, Args&&...>::value) {
369 return optional<T>(in_place, il, BSONCXX_PRIVATE_FWD(args)...);
370}
371
372namespace detail {
373
374// Union template that defines the storage for an optional's data.
375template <typename T, bool = std::is_trivially_destructible<T>::value>
376union storage_for {
377 // Placeholder member for disengaged optional
378 char nothing;
379 // Member that holds the actual value
380 T value;
381
382 // Default-construct activates the placeholder
383 storage_for() noexcept : nothing(0) {}
384
385 // Empty special members allow the union to be used in semiregular contexts,
386 // but it is the responsibility of the using class to implement them properly
387 ~storage_for() {}
388 storage_for(storage_for const&) = delete;
389 storage_for& operator=(storage_for const&) = delete;
390};
391
392template <typename T>
393union storage_for<T, true /* Is trivially destructible */> {
394 char nothing;
395 T value;
396 storage_for() noexcept : nothing(0) {}
397 storage_for(storage_for const&) = delete;
398 storage_for& operator=(storage_for const&) = delete;
399};
400
401// Whether a type is copyable, moveable, or immobile.
402enum copymove_classification {
403 copyable,
404 movable,
405 immobile,
406};
407
408// Classify the constructibility of the given type.
409template <
410 typename T,
411 bool CanCopy = std::is_copy_constructible<T>::value,
412 bool CanMove = std::is_move_constructible<T>::value>
413constexpr copymove_classification classify_construct() {
414 return CanCopy ? copyable : CanMove ? movable : immobile;
415}
416
417// Classify the assignability of the given type.
418template <
419 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_PRIVATE_CONSTEXPR_CXX14 optional_assign_base& operator=(optional_assign_base const&) = delete;
462
463 // Allow move-assignment.
464
465 BSONCXX_PRIVATE_CONSTEXPR_CXX14 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=(optional_assign_base const&) = 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(optional_construct_base const&) = delete;
488 optional_construct_base(optional_construct_base&&) = default;
489 optional_construct_base& operator=(optional_construct_base const&) = 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(optional_construct_base const&) = delete;
497 optional_construct_base& operator=(optional_construct_base const&) = 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=(base const&) = 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_PRIVATE_CONSTEXPR_CXX14 auto
532 tag_invoke(bsoncxx::detail::equal_to, optional<T> const& left, optional<U> const& right) noexcept
533 -> bsoncxx::detail::requires_t<bool, bsoncxx::detail::is_equality_comparable<T, U>> {
534 if (left.has_value() != right.has_value()) {
535 return false;
536 }
537
538 BSONCXX_PRIVATE_WARNINGS_PUSH();
539 BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal"));
540 return !left.has_value() || *left == *right;
541 BSONCXX_PRIVATE_WARNINGS_POP();
542 }
543
544 template <typename T, typename U>
545 friend constexpr auto tag_invoke(bsoncxx::detail::equal_to, optional<T> const& left, U const& right) noexcept
546 -> bsoncxx::detail::requires_t<bool, not_an_optional<U>, bsoncxx::detail::is_equality_comparable<T, U>> {
547 BSONCXX_PRIVATE_WARNINGS_PUSH();
548 BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal"));
549 return left.has_value() && *left == right;
550 BSONCXX_PRIVATE_WARNINGS_POP();
551 }
552
553 template <typename T>
554 friend constexpr bool tag_invoke(bsoncxx::detail::equal_to, optional<T> const& opt, nullopt_t) noexcept {
555 return !opt.has_value();
556 }
557
558 template <typename T, typename U>
559 BSONCXX_PRIVATE_CONSTEXPR_CXX14 friend auto
560 tag_invoke(bsoncxx::detail::compare_three_way compare, optional<T> const& left, optional<U> const& right)
561 -> bsoncxx::detail::requires_t<
562 bsoncxx::detail::strong_ordering,
563 bsoncxx::detail::is_totally_ordered_with<T, U>> {
564 if (left.has_value()) {
565 if (right.has_value()) {
566 return compare(*left, *right);
567 } else {
568 // Non-null is greater than any null.
569 return bsoncxx::detail::strong_ordering::greater;
570 }
571 } else {
572 if (right.has_value()) {
573 // Null is less than any non-null.
574 return bsoncxx::detail::strong_ordering::less;
575 } else {
576 // Both are null.
577 return bsoncxx::detail::strong_ordering::equal;
578 }
579 }
580 }
581
582 template <typename T, typename U>
583 BSONCXX_PRIVATE_CONSTEXPR_CXX14 friend auto
584 tag_invoke(bsoncxx::detail::compare_three_way compare, optional<T> const& left, U const& right)
585 -> bsoncxx::detail::requires_t<
586 bsoncxx::detail::strong_ordering,
587 not_an_optional<U>,
588 bsoncxx::detail::is_totally_ordered_with<T, U>> {
589 if (left.has_value()) {
590 return compare(*left, right);
591 }
592 // Null optional is less-than any non-null value.
593 return bsoncxx::detail::strong_ordering::less;
594 }
595
596 template <typename T>
597 constexpr friend bsoncxx::detail::strong_ordering
598 tag_invoke(bsoncxx::detail::compare_three_way compare, optional<T> const& left, nullopt_t) {
599 return compare(left.has_value(), false);
600 }
601};
602
603// An ADL-visible swap() should only be available for swappable objects
604template <typename T, bool IsSwappable = bsoncxx::detail::is_swappable<T>::value>
605struct optional_swap_mixin {};
606
607template <typename T>
608struct optional_swap_mixin<T, true> {
609 BSONCXX_PRIVATE_CONSTEXPR_CXX14 friend void swap(optional<T>& left, optional<T>& right) noexcept(
610 std::is_nothrow_move_constructible<T>::value && bsoncxx::detail::is_nothrow_swappable<T>::value) {
611 left.swap(right);
612 }
613};
614
615// Common base class of all optionals.
616template <typename T>
617class optional_common_base : optional_operators_base, optional_swap_mixin<T> {
618 using storage_type = detail::storage_for<bsoncxx::detail::remove_const_t<T>>;
619
620 public:
621 optional_common_base() = default;
622 ~optional_common_base() = default;
623
624 optional_common_base(optional_common_base const& other) noexcept(std::is_nothrow_copy_constructible<T>::value) {
625 if (other._has_value) {
626 this->emplace(other._storage.value);
627 }
628 }
629
630 optional_common_base(optional_common_base&& other) noexcept(std::is_nothrow_move_constructible<T>::value) {
631 if (other._has_value) {
632 this->_emplace_construct_anew(std::move(other)._storage.value);
633 }
634 }
635
636 optional_common_base& operator=(optional_common_base const& other) noexcept(
637 std::is_nothrow_copy_assignable<T>::value) {
638 this->_assign(BSONCXX_PRIVATE_FWD(other));
639 return *this;
640 }
641
642 optional_common_base& operator=(optional_common_base&& other) noexcept(std::is_nothrow_move_assignable<T>::value) {
643 this->_assign(BSONCXX_PRIVATE_FWD(other));
644 return *this;
645 }
646
647 // If the optional is holding a value, destroy that value and set ourselves null.
648 void reset() noexcept {
649 if (this->_has_value) {
650 this->_storage.value.~T();
651 }
652 this->_has_value = false;
653 }
654
655 // If the optional is holding a value, destroy that value. Construct a new value in-place using
656 // the given arguments.
657 template <typename... Args>
658 T& emplace(Args&&... args) {
659 this->reset();
660 this->_emplace_construct_anew(BSONCXX_PRIVATE_FWD(args)...);
661 return this->_storage.value;
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 U, typename... Args>
667 T& emplace(std::initializer_list<U> il, Args&&... args) {
668 this->reset();
669 this->_emplace_construct_anew(il, BSONCXX_PRIVATE_FWD(args)...);
670 return this->_storage.value;
671 }
672
673 // Special swap for optional values that removes need for a temporary.
674 BSONCXX_PRIVATE_CONSTEXPR_CXX14 void swap(optional_common_base& other) noexcept(
675 std::is_nothrow_move_constructible<T>::value && bsoncxx::detail::is_nothrow_swappable<T>::value) {
676 if (other._has_value) {
677 if (this->_has_value) {
678 using std::swap;
679 // Defer to the underlying swap.
680 swap(this->_storage.value, other._storage.value);
681 } else {
682 // "steal" the other's value.
683 this->emplace(std::move(other._storage.value));
684 other.reset();
685 }
686 } else if (this->_has_value) {
687 other.emplace(std::move(this->_storage.value));
688 this->reset();
689 } else {
690 // Neither optional has a value, so do nothing.
691 }
692 }
693
694 private:
695 friend optional<T>;
696 storage_type _storage;
697 bool _has_value = false;
698
699 // In-place construct a new value from the given arguments. Assumes that the optional does not
700 // have a live value.
701 template <typename... Args>
702 void _emplace_construct_anew(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args&&...>::value) {
703 new (std::addressof(this->_storage.value)) T(BSONCXX_PRIVATE_FWD(args)...);
704 this->_has_value = true;
705 }
706
707 // Perform the semantics of the assignment operator.
708 template <typename U>
709 void _assign(U&& other_storage) {
710 if (other_storage._has_value) {
711 // We are receiving a value.
712 if (this->_has_value) {
713 // We already have a value. Invoke the underlying assignment.
714 this->_storage.value = BSONCXX_PRIVATE_FWD(other_storage)._storage.value;
715 } else {
716 // We don't have a value. Use the constructor.
717 this->_emplace_construct_anew(BSONCXX_PRIVATE_FWD(other_storage)._storage.value);
718 }
719 } else {
720 // We are receiving nullopt. Destroy our value, if present.
721 this->reset();
722 }
723 }
724};
725
726template <typename T>
727struct optional_base_class {
728 using type = optional_assign_base<T>;
729};
730
731template <
732 typename T,
733 bool CanHash = std::is_default_constructible<std::hash<bsoncxx::detail::remove_const_t<T>>>::value>
734struct optional_hash;
735
736// Hash is "disabled" if the underlying type is not hashable (disabled = cannot construct the hash
737// invocable).
738template <typename T>
739struct optional_hash<T, false> {
740 optional_hash() = delete;
741 optional_hash(optional_hash const&) = delete;
742};
743
744template <typename T>
745struct optional_hash<T, true> {
746 using Td = bsoncxx::detail::remove_const_t<T>;
747 constexpr std::size_t operator()(optional<T> const& opt) const
748 noexcept(noexcept(std::hash<Td>()(std::declval<Td const&>()))) {
749 return opt.has_value() ? std::hash<Td>()(*opt) : std::hash<void*>()(nullptr);
750 }
751};
752
753} // namespace detail
754
755} // namespace stdx
756
757} // namespace v1
758
759} // namespace bsoncxx
760
761namespace std {
762
763template <typename T>
764struct hash<bsoncxx::v1::stdx::optional<T>> : bsoncxx::v1::stdx::detail::optional_hash<T> {};
765
766} // namespace std
767
768#else
769#error "Cannot find a valid polyfill for optional"
770#endif
771
773
785
786#if defined(BSONCXX_PRIVATE_DOXYGEN_PREPROCESSOR)
787
788namespace bsoncxx {
789namespace v1 {
790namespace stdx {
791
799template <typename T>
800class optional {};
801
802} // namespace stdx
803} // namespace v1
804} // namespace bsoncxx
805
806#endif // defined(BSONCXX_PRIVATE_DOXYGEN_PREPROCESSOR)
Provides macros describing the bsoncxx library configuration.
For internal use only!
The bsoncxx v1 macro guard postlude header.
The bsoncxx v1 macro guard prelude header.
A polyfill for std::optional<T>.
Definition optional.hpp:800
For internal use only!
Declares C++17 standard library polyfills.
Declares entities whose ABI stability is guaranteed for documented symbols.
type
An enumeration of each BSON type.
Definition types.hpp:43
The top-level namespace within which all bsoncxx library entities are declared.
For internal use only!