@@ -899,6 +899,18 @@ public:
899899 }
900900
901901 _LIBCPP_HIDE_FROM_ABI __tree (const __tree& __t );
902+
903+ _LIBCPP_HIDE_FROM_ABI __tree (const __tree& __other, const allocator_type& __alloc)
904+ : __begin_node_(__end_node()), __node_alloc_(__alloc), __size_(0 ), __value_comp_(__other.value_comp()) {
905+ if (__other.size () == 0 )
906+ return ;
907+
908+ *__root_ptr () = static_cast <__node_base_pointer>(__copy_construct_tree (__other.__root ()));
909+ __root ()->__parent_ = __end_node ();
910+ __begin_node_ = static_cast <__end_node_pointer>(std::__tree_min (__end_node ()->__left_ ));
911+ __size_ = __other.size ();
912+ }
913+
902914 _LIBCPP_HIDE_FROM_ABI __tree& operator =(const __tree& __t );
903915 template <class _ForwardIterator >
904916 _LIBCPP_HIDE_FROM_ABI void __assign_unique (_ForwardIterator __first, _ForwardIterator __last);
@@ -1007,27 +1019,6 @@ public:
10071019 std::forward<_Args>(__args)...);
10081020 }
10091021
1010- template <class _ValueT = _Tp, __enable_if_t <__is_tree_value_type_v<_ValueT>, int > = 0 >
1011- _LIBCPP_HIDE_FROM_ABI void
1012- __insert_unique_from_orphaned_node (const_iterator __p, __get_node_value_type_t <_Tp>&& __value) {
1013- __emplace_hint_unique (__p, const_cast <key_type&&>(__value.first ), std::move (__value.second ));
1014- }
1015-
1016- template <class _ValueT = _Tp, __enable_if_t <!__is_tree_value_type_v<_ValueT>, int > = 0 >
1017- _LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node (const_iterator __p, _Tp&& __value) {
1018- __emplace_hint_unique (__p, std::move (__value));
1019- }
1020-
1021- template <class _ValueT = _Tp, __enable_if_t <__is_tree_value_type_v<_ValueT>, int > = 0 >
1022- _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node (const_iterator __p, value_type&& __value) {
1023- __emplace_hint_multi (__p, const_cast <key_type&&>(__value.first ), std::move (__value.second ));
1024- }
1025-
1026- template <class _ValueT = _Tp, __enable_if_t <!__is_tree_value_type_v<_ValueT>, int > = 0 >
1027- _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node (const_iterator __p, _Tp&& __value) {
1028- __emplace_hint_multi (__p, std::move (__value));
1029- }
1030-
10311022 template <class _InIter , class _Sent >
10321023 _LIBCPP_HIDE_FROM_ABI void __insert_range_multi (_InIter __first, _Sent __last) {
10331024 if (__first == __last)
@@ -1400,19 +1391,20 @@ private:
14001391 // copy the exact structure 1:1. Since this is for copy construction _only_ we know that we get a correct tree. If we
14011392 // didn't get a correct tree, the invariants of __tree are broken and we have a much bigger problem than an improperly
14021393 // balanced tree.
1394+ template <class _NodeConstructor >
14031395#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
14041396 _LIBCPP_HIDE_FROM_ABI
14051397#endif
14061398 __node_pointer
1407- __copy_construct_tree (__node_pointer __src) {
1399+ __construct_from_tree (__node_pointer __src, _NodeConstructor __construct ) {
14081400 if (!__src)
14091401 return nullptr ;
14101402
1411- __node_holder __new_node = __construct_node (__src->__get_value ());
1403+ __node_holder __new_node = __construct (__src->__get_value ());
14121404
14131405 unique_ptr<__node, __tree_deleter> __left (
1414- __copy_construct_tree (static_cast <__node_pointer>(__src->__left_ )), __node_alloc_);
1415- __node_pointer __right = __copy_construct_tree (static_cast <__node_pointer>(__src->__right_ ));
1406+ __construct_from_tree (static_cast <__node_pointer>(__src->__left_ ), __construct ), __node_alloc_);
1407+ __node_pointer __right = __construct_from_tree (static_cast <__node_pointer>(__src->__right_ ), __construct );
14161408
14171409 __node_pointer __new_node_ptr = __new_node.release ();
14181410
@@ -1426,46 +1418,85 @@ private:
14261418 return __new_node_ptr;
14271419 }
14281420
1421+ _LIBCPP_HIDE_FROM_ABI __node_pointer __copy_construct_tree (__node_pointer __src) {
1422+ return __construct_from_tree (__src, [this ](const value_type& __val) { return __construct_node (__val); });
1423+ }
1424+
1425+ template <class _ValueT = _Tp, __enable_if_t <__is_tree_value_type_v<_ValueT>, int > = 0 >
1426+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_construct_tree (__node_pointer __src) {
1427+ return __construct_from_tree (__src, [this ](value_type& __val) {
1428+ return __construct_node (const_cast <key_type&&>(__val.first ), std::move (__val.second ));
1429+ });
1430+ }
1431+
1432+ template <class _ValueT = _Tp, __enable_if_t <!__is_tree_value_type_v<_ValueT>, int > = 0 >
1433+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_construct_tree (__node_pointer __src) {
1434+ return __construct_from_tree (__src, [this ](value_type& __val) { return __construct_node (std::move (__val)); });
1435+ }
1436+
1437+ template <class _Assignment , class _ConstructionAlg >
14291438 // This copy assignment will always produce a correct red-black-tree assuming the incoming tree is correct, since our
14301439 // own tree is a red-black-tree and the incoming tree is a red-black-tree. The invariants of a red-black-tree are
14311440 // temporarily not met until all of the incoming red-black tree is copied.
14321441#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
14331442 _LIBCPP_HIDE_FROM_ABI
14341443#endif
1435- __node_pointer
1436- __copy_assign_tree ( __node_pointer __dest, __node_pointer __src) {
1444+ __node_pointer __assign_from_tree (
1445+ __node_pointer __dest, __node_pointer __src, _Assignment __assign, _ConstructionAlg __continue_with_construct ) {
14371446 if (!__src) {
14381447 destroy (__dest);
14391448 return nullptr ;
14401449 }
14411450
1442- __assign_value (__dest->__get_value (), __src->__get_value ());
1451+ __assign (__dest->__get_value (), __src->__get_value ());
14431452 __dest->__is_black_ = __src->__is_black_ ;
14441453
14451454 // If we already have a left node in the destination tree, reuse it and copy-assign recursively
14461455 if (__dest->__left_ ) {
1447- __dest->__left_ = static_cast <__node_base_pointer>(__copy_assign_tree (
1448- static_cast <__node_pointer>(__dest->__left_ ), static_cast <__node_pointer>(__src->__left_ )));
1456+ __dest->__left_ = static_cast <__node_base_pointer>(__assign_from_tree (
1457+ static_cast <__node_pointer>(__dest->__left_ ),
1458+ static_cast <__node_pointer>(__src->__left_ ),
1459+ __assign,
1460+ __continue_with_construct));
14491461
14501462 // Otherwise, we must create new nodes; copy-construct from here on
14511463 } else if (__src->__left_ ) {
1452- auto __new_left = __copy_construct_tree (static_cast <__node_pointer>(__src->__left_ ));
1464+ auto __new_left = __continue_with_construct (static_cast <__node_pointer>(__src->__left_ ));
14531465 __dest->__left_ = static_cast <__node_base_pointer>(__new_left);
14541466 __new_left->__parent_ = static_cast <__end_node_pointer>(__dest);
14551467 }
14561468
14571469 // Identical to the left case above, just for the right nodes
14581470 if (__dest->__right_ ) {
1459- __dest->__right_ = static_cast <__node_base_pointer>(__copy_assign_tree (
1460- static_cast <__node_pointer>(__dest->__right_ ), static_cast <__node_pointer>(__src->__right_ )));
1471+ __dest->__right_ = static_cast <__node_base_pointer>(__assign_from_tree (
1472+ static_cast <__node_pointer>(__dest->__right_ ),
1473+ static_cast <__node_pointer>(__src->__right_ ),
1474+ __assign,
1475+ __continue_with_construct));
14611476 } else if (__src->__right_ ) {
1462- auto __new_right = __copy_construct_tree (static_cast <__node_pointer>(__src->__right_ ));
1477+ auto __new_right = __continue_with_construct (static_cast <__node_pointer>(__src->__right_ ));
14631478 __dest->__right_ = static_cast <__node_base_pointer>(__new_right);
14641479 __new_right->__parent_ = static_cast <__end_node_pointer>(__dest);
14651480 }
14661481
14671482 return __dest;
14681483 }
1484+
1485+ _LIBCPP_HIDE_FROM_ABI __node_pointer __copy_assign_tree (__node_pointer __dest, __node_pointer __src) {
1486+ return __assign_from_tree (
1487+ __dest,
1488+ __src,
1489+ [](value_type& __lhs, const value_type& __rhs) { __assign_value (__lhs, std::move (__rhs)); },
1490+ [this ](__node_pointer __nd) { return __copy_construct_tree (__nd); });
1491+ }
1492+
1493+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_assign_tree (__node_pointer __dest, __node_pointer __src) {
1494+ return __assign_from_tree (
1495+ __dest,
1496+ __src,
1497+ [](value_type& __lhs, value_type& __rhs) { __assign_value (__lhs, std::move (__rhs)); },
1498+ [this ](__node_pointer __nd) { return __move_construct_tree (__nd); });
1499+ }
14691500};
14701501
14711502// Precondition: __size_ != 0
@@ -1606,21 +1637,26 @@ __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_(
16061637
16071638template <class _Tp , class _Compare , class _Allocator >
16081639__tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t , const allocator_type& __a)
1609- : __node_alloc_(__node_allocator(__a)), __size_(0 ), __value_comp_(std::move(__t .value_comp())) {
1640+ : __begin_node_(__end_node()),
1641+ __node_alloc_ (__node_allocator(__a)),
1642+ __size_(0 ),
1643+ __value_comp_(std::move(__t .value_comp())) {
1644+ if (__t .size () == 0 )
1645+ return ;
16101646 if (__a == __t .__alloc ()) {
1611- if (__t .__size_ == 0 )
1612- __begin_node_ = __end_node ();
1613- else {
1614- __begin_node_ = __t .__begin_node_ ;
1615- __end_node ()->__left_ = __t .__end_node ()->__left_ ;
1616- __end_node ()->__left_ ->__parent_ = static_cast <__end_node_pointer>(__end_node ());
1617- __size_ = __t .__size_ ;
1618- __t .__begin_node_ = __t .__end_node ();
1619- __t .__end_node ()->__left_ = nullptr ;
1620- __t .__size_ = 0 ;
1621- }
1647+ __begin_node_ = __t .__begin_node_ ;
1648+ __end_node ()->__left_ = __t .__end_node ()->__left_ ;
1649+ __end_node ()->__left_ ->__parent_ = static_cast <__end_node_pointer>(__end_node ());
1650+ __size_ = __t .__size_ ;
1651+ __t .__begin_node_ = __t .__end_node ();
1652+ __t .__end_node ()->__left_ = nullptr ;
1653+ __t .__size_ = 0 ;
16221654 } else {
1623- __begin_node_ = __end_node ();
1655+ *__root_ptr () = static_cast <__node_base_pointer>(__move_construct_tree (__t .__root ()));
1656+ __root ()->__parent_ = __end_node ();
1657+ __begin_node_ = static_cast <__end_node_pointer>(std::__tree_min (__end_node ()->__left_ ));
1658+ __size_ = __t .size ();
1659+ __t .clear (); // Ensure that __t is in a valid state after moving out the keys
16241660 }
16251661}
16261662
@@ -1645,22 +1681,21 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type)
16451681
16461682template <class _Tp , class _Compare , class _Allocator >
16471683void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t , false_type) {
1648- if (__node_alloc () == __t .__node_alloc ())
1684+ if (__node_alloc () == __t .__node_alloc ()) {
16491685 __move_assign (__t , true_type ());
1650- else {
1651- value_comp () = std::move (__t .value_comp ());
1652- const_iterator __e = end ();
1686+ } else {
1687+ value_comp () = std::move (__t .value_comp ());
16531688 if (__size_ != 0 ) {
1654- _DetachedTreeCache __cache (this );
1655- while (__cache.__get () != nullptr && __t .__size_ != 0 ) {
1656- __assign_value (__cache.__get ()->__get_value (), std::move (__t .remove (__t .begin ())->__get_value ()));
1657- __node_insert_multi (__cache.__get ());
1658- __cache.__advance ();
1659- }
1660- }
1661- while (__t .__size_ != 0 ) {
1662- __insert_multi_from_orphaned_node (__e, std::move (__t .remove (__t .begin ())->__get_value ()));
1689+ *__root_ptr () = static_cast <__node_base_pointer>(__move_assign_tree (__root (), __t .__root ()));
1690+ } else {
1691+ *__root_ptr () = static_cast <__node_base_pointer>(__move_construct_tree (__t .__root ()));
1692+ if (__root ())
1693+ __root ()->__parent_ = __end_node ();
16631694 }
1695+ __begin_node_ =
1696+ __end_node ()->__left_ ? static_cast <__end_node_pointer>(std::__tree_min (__end_node ()->__left_ )) : __end_node ();
1697+ __size_ = __t .size ();
1698+ __t .clear (); // Ensure that __t is in a valid state after moving out the keys
16641699 }
16651700}
16661701
0 commit comments