@@ -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,19 @@ 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
1406- __node_pointer
1407- __copy_construct_tree (__node_pointer __src) {
1398+ __node_pointer __construct_from_tree (__node_pointer __src, _NodeConstructor __construct) {
14081399 if (!__src)
14091400 return nullptr ;
14101401
1411- __node_holder __new_node = __construct_node (__src->__get_value ());
1402+ __node_holder __new_node = __construct (__src->__get_value ());
14121403
14131404 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_ ));
1405+ __construct_from_tree (static_cast <__node_pointer>(__src->__left_ ), __construct ), __node_alloc_);
1406+ __node_pointer __right = __construct_from_tree (static_cast <__node_pointer>(__src->__right_ ), __construct );
14161407
14171408 __node_pointer __new_node_ptr = __new_node.release ();
14181409
@@ -1426,46 +1417,85 @@ private:
14261417 return __new_node_ptr;
14271418 }
14281419
1420+ _LIBCPP_HIDE_FROM_ABI __node_pointer __copy_construct_tree (__node_pointer __src) {
1421+ return __construct_from_tree (__src, [this ](const value_type& __val) { return __construct_node (__val); });
1422+ }
1423+
1424+ template <class _ValueT = _Tp, __enable_if_t <__is_tree_value_type_v<_ValueT>, int > = 0 >
1425+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_construct_tree (__node_pointer __src) {
1426+ return __construct_from_tree (__src, [this ](value_type& __val) {
1427+ return __construct_node (const_cast <key_type&&>(__val.first ), std::move (__val.second ));
1428+ });
1429+ }
1430+
1431+ template <class _ValueT = _Tp, __enable_if_t <!__is_tree_value_type_v<_ValueT>, int > = 0 >
1432+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_construct_tree (__node_pointer __src) {
1433+ return __construct_from_tree (__src, [this ](value_type& __val) { return __construct_node (std::move (__val)); });
1434+ }
1435+
1436+ template <class _Assignment , class _ConstructionAlg >
14291437 // This copy assignment will always produce a correct red-black-tree assuming the incoming tree is correct, since our
14301438 // own tree is a red-black-tree and the incoming tree is a red-black-tree. The invariants of a red-black-tree are
14311439 // temporarily not met until all of the incoming red-black tree is copied.
14321440#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
14331441 _LIBCPP_HIDE_FROM_ABI
14341442#endif
1435- __node_pointer
1436- __copy_assign_tree ( __node_pointer __dest, __node_pointer __src) {
1443+ __node_pointer __assign_from_tree (
1444+ __node_pointer __dest, __node_pointer __src, _Assignment __assign, _ConstructionAlg __continue_with_construct ) {
14371445 if (!__src) {
14381446 destroy (__dest);
14391447 return nullptr ;
14401448 }
14411449
1442- __assign_value (__dest->__get_value (), __src->__get_value ());
1450+ __assign (__dest->__get_value (), __src->__get_value ());
14431451 __dest->__is_black_ = __src->__is_black_ ;
14441452
14451453 // If we already have a left node in the destination tree, reuse it and copy-assign recursively
14461454 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_ )));
1455+ __dest->__left_ = static_cast <__node_base_pointer>(__assign_from_tree (
1456+ static_cast <__node_pointer>(__dest->__left_ ),
1457+ static_cast <__node_pointer>(__src->__left_ ),
1458+ __assign,
1459+ __continue_with_construct));
14491460
14501461 // Otherwise, we must create new nodes; copy-construct from here on
14511462 } else if (__src->__left_ ) {
1452- auto __new_left = __copy_construct_tree (static_cast <__node_pointer>(__src->__left_ ));
1463+ auto __new_left = __continue_with_construct (static_cast <__node_pointer>(__src->__left_ ));
14531464 __dest->__left_ = static_cast <__node_base_pointer>(__new_left);
14541465 __new_left->__parent_ = static_cast <__end_node_pointer>(__dest);
14551466 }
14561467
14571468 // Identical to the left case above, just for the right nodes
14581469 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_ )));
1470+ __dest->__right_ = static_cast <__node_base_pointer>(__assign_from_tree (
1471+ static_cast <__node_pointer>(__dest->__right_ ),
1472+ static_cast <__node_pointer>(__src->__right_ ),
1473+ __assign,
1474+ __continue_with_construct));
14611475 } else if (__src->__right_ ) {
1462- auto __new_right = __copy_construct_tree (static_cast <__node_pointer>(__src->__right_ ));
1476+ auto __new_right = __continue_with_construct (static_cast <__node_pointer>(__src->__right_ ));
14631477 __dest->__right_ = static_cast <__node_base_pointer>(__new_right);
14641478 __new_right->__parent_ = static_cast <__end_node_pointer>(__dest);
14651479 }
14661480
14671481 return __dest;
14681482 }
1483+
1484+ _LIBCPP_HIDE_FROM_ABI __node_pointer __copy_assign_tree (__node_pointer __dest, __node_pointer __src) {
1485+ return __assign_from_tree (
1486+ __dest,
1487+ __src,
1488+ [](value_type& __lhs, const value_type& __rhs) { __assign_value (__lhs, std::move (__rhs)); },
1489+ [this ](__node_pointer __nd) { return __copy_construct_tree (__nd); });
1490+ }
1491+
1492+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_assign_tree (__node_pointer __dest, __node_pointer __src) {
1493+ return __assign_from_tree (
1494+ __dest,
1495+ __src,
1496+ [](value_type& __lhs, value_type& __rhs) { __assign_value (__lhs, std::move (__rhs)); },
1497+ [this ](__node_pointer __nd) { return __move_construct_tree (__nd); });
1498+ }
14691499};
14701500
14711501// Precondition: __size_ != 0
@@ -1606,21 +1636,26 @@ __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_(
16061636
16071637template <class _Tp , class _Compare , class _Allocator >
16081638__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())) {
1639+ : __begin_node_(__end_node()),
1640+ __node_alloc_ (__node_allocator(__a)),
1641+ __size_(0 ),
1642+ __value_comp_(std::move(__t .value_comp())) {
1643+ if (__t .size () == 0 )
1644+ return ;
16101645 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- }
1646+ __begin_node_ = __t .__begin_node_ ;
1647+ __end_node ()->__left_ = __t .__end_node ()->__left_ ;
1648+ __end_node ()->__left_ ->__parent_ = static_cast <__end_node_pointer>(__end_node ());
1649+ __size_ = __t .__size_ ;
1650+ __t .__begin_node_ = __t .__end_node ();
1651+ __t .__end_node ()->__left_ = nullptr ;
1652+ __t .__size_ = 0 ;
16221653 } else {
1623- __begin_node_ = __end_node ();
1654+ *__root_ptr () = static_cast <__node_base_pointer>(__move_construct_tree (__t .__root ()));
1655+ __root ()->__parent_ = __end_node ();
1656+ __begin_node_ = static_cast <__end_node_pointer>(std::__tree_min (__end_node ()->__left_ ));
1657+ __size_ = __t .size ();
1658+ __t .clear (); // Ensure that __t is in a valid state after moving out the keys
16241659 }
16251660}
16261661
@@ -1645,22 +1680,21 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type)
16451680
16461681template <class _Tp , class _Compare , class _Allocator >
16471682void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t , false_type) {
1648- if (__node_alloc () == __t .__node_alloc ())
1683+ if (__node_alloc () == __t .__node_alloc ()) {
16491684 __move_assign (__t , true_type ());
1650- else {
1651- value_comp () = std::move (__t .value_comp ());
1652- const_iterator __e = end ();
1685+ } else {
1686+ value_comp () = std::move (__t .value_comp ());
16531687 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 ()));
1688+ *__root_ptr () = static_cast <__node_base_pointer>(__move_assign_tree (__root (), __t .__root ()));
1689+ } else {
1690+ *__root_ptr () = static_cast <__node_base_pointer>(__move_construct_tree (__t .__root ()));
1691+ if (__root ())
1692+ __root ()->__parent_ = __end_node ();
16631693 }
1694+ __begin_node_ =
1695+ __end_node ()->__left_ ? static_cast <__end_node_pointer>(std::__tree_min (__end_node ()->__left_ )) : __end_node ();
1696+ __size_ = __t .size ();
1697+ __t .clear (); // Ensure that __t is in a valid state after moving out the keys
16641698 }
16651699}
16661700
0 commit comments