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