@@ -887,6 +887,18 @@ public:
887887 }
888888
889889 _LIBCPP_HIDE_FROM_ABI __tree (const __tree& __t );
890+
891+ _LIBCPP_HIDE_FROM_ABI __tree (const __tree& __other, const allocator_type& __alloc)
892+ : __begin_node_(__end_node()), __node_alloc_(__alloc), __size_(0 ), __value_comp_(__other.value_comp()) {
893+ if (__other.size () == 0 )
894+ return ;
895+
896+ *__root_ptr () = static_cast <__node_base_pointer>(__copy_construct_tree (__other.__root ()));
897+ __root ()->__parent_ = __end_node ();
898+ __begin_node_ = static_cast <__end_node_pointer>(std::__tree_min (__end_node ()->__left_ ));
899+ __size_ = __other.size ();
900+ }
901+
890902 _LIBCPP_HIDE_FROM_ABI __tree& operator =(const __tree& __t );
891903 template <class _ForwardIterator >
892904 _LIBCPP_HIDE_FROM_ABI void __assign_unique (_ForwardIterator __first, _ForwardIterator __last);
@@ -995,27 +1007,6 @@ public:
9951007 std::forward<_Args>(__args)...);
9961008 }
9971009
998- template <class _ValueT = _Tp, __enable_if_t <__is_tree_value_type_v<_ValueT>, int > = 0 >
999- _LIBCPP_HIDE_FROM_ABI void
1000- __insert_unique_from_orphaned_node (const_iterator __p, __get_node_value_type_t <_Tp>&& __value) {
1001- __emplace_hint_unique (__p, const_cast <key_type&&>(__value.first ), std::move (__value.second ));
1002- }
1003-
1004- template <class _ValueT = _Tp, __enable_if_t <!__is_tree_value_type_v<_ValueT>, int > = 0 >
1005- _LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node (const_iterator __p, _Tp&& __value) {
1006- __emplace_hint_unique (__p, std::move (__value));
1007- }
1008-
1009- template <class _ValueT = _Tp, __enable_if_t <__is_tree_value_type_v<_ValueT>, int > = 0 >
1010- _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node (const_iterator __p, value_type&& __value) {
1011- __emplace_hint_multi (__p, const_cast <key_type&&>(__value.first ), std::move (__value.second ));
1012- }
1013-
1014- template <class _ValueT = _Tp, __enable_if_t <!__is_tree_value_type_v<_ValueT>, int > = 0 >
1015- _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node (const_iterator __p, _Tp&& __value) {
1016- __emplace_hint_multi (__p, std::move (__value));
1017- }
1018-
10191010 template <class _InIter , class _Sent >
10201011 _LIBCPP_HIDE_FROM_ABI void __insert_range_multi (_InIter __first, _Sent __last) {
10211012 if (__first == __last)
@@ -1388,19 +1379,19 @@ private:
13881379 // copy the exact structure 1:1. Since this is for copy construction _only_ we know that we get a correct tree. If we
13891380 // didn't get a correct tree, the invariants of __tree are broken and we have a much bigger problem than an improperly
13901381 // balanced tree.
1382+ template <class _NodeConstructor >
13911383#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
13921384 _LIBCPP_HIDE_FROM_ABI
13931385#endif
1394- __node_pointer
1395- __copy_construct_tree (__node_pointer __src) {
1386+ __node_pointer __construct_from_tree (__node_pointer __src, _NodeConstructor __construct) {
13961387 if (!__src)
13971388 return nullptr ;
13981389
1399- __node_holder __new_node = __construct_node (__src->__get_value ());
1390+ __node_holder __new_node = __construct (__src->__get_value ());
14001391
14011392 unique_ptr<__node, __tree_deleter> __left (
1402- __copy_construct_tree (static_cast <__node_pointer>(__src->__left_ )), __node_alloc_);
1403- __node_pointer __right = __copy_construct_tree (static_cast <__node_pointer>(__src->__right_ ));
1393+ __construct_from_tree (static_cast <__node_pointer>(__src->__left_ ), __construct ), __node_alloc_);
1394+ __node_pointer __right = __construct_from_tree (static_cast <__node_pointer>(__src->__right_ ), __construct );
14041395
14051396 __node_pointer __new_node_ptr = __new_node.release ();
14061397
@@ -1414,46 +1405,85 @@ private:
14141405 return __new_node_ptr;
14151406 }
14161407
1408+ _LIBCPP_HIDE_FROM_ABI __node_pointer __copy_construct_tree (__node_pointer __src) {
1409+ return __construct_from_tree (__src, [this ](const value_type& __val) { return __construct_node (__val); });
1410+ }
1411+
1412+ template <class _ValueT = _Tp, __enable_if_t <__is_tree_value_type_v<_ValueT>, int > = 0 >
1413+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_construct_tree (__node_pointer __src) {
1414+ return __construct_from_tree (__src, [this ](value_type& __val) {
1415+ return __construct_node (const_cast <key_type&&>(__val.first ), std::move (__val.second ));
1416+ });
1417+ }
1418+
1419+ template <class _ValueT = _Tp, __enable_if_t <!__is_tree_value_type_v<_ValueT>, int > = 0 >
1420+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_construct_tree (__node_pointer __src) {
1421+ return __construct_from_tree (__src, [this ](value_type& __val) { return __construct_node (std::move (__val)); });
1422+ }
1423+
1424+ template <class _Assignment , class _ConstructionAlg >
14171425 // This copy assignment will always produce a correct red-black-tree assuming the incoming tree is correct, since our
14181426 // own tree is a red-black-tree and the incoming tree is a red-black-tree. The invariants of a red-black-tree are
14191427 // temporarily not met until all of the incoming red-black tree is copied.
14201428#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
14211429 _LIBCPP_HIDE_FROM_ABI
14221430#endif
1423- __node_pointer
1424- __copy_assign_tree ( __node_pointer __dest, __node_pointer __src) {
1431+ __node_pointer __assign_from_tree (
1432+ __node_pointer __dest, __node_pointer __src, _Assignment __assign, _ConstructionAlg __continue_with_construct ) {
14251433 if (!__src) {
14261434 destroy (__dest);
14271435 return nullptr ;
14281436 }
14291437
1430- __assign_value (__dest->__get_value (), __src->__get_value ());
1438+ __assign (__dest->__get_value (), __src->__get_value ());
14311439 __dest->__is_black_ = __src->__is_black_ ;
14321440
14331441 // If we already have a left node in the destination tree, reuse it and copy-assign recursively
14341442 if (__dest->__left_ ) {
1435- __dest->__left_ = static_cast <__node_base_pointer>(__copy_assign_tree (
1436- static_cast <__node_pointer>(__dest->__left_ ), static_cast <__node_pointer>(__src->__left_ )));
1443+ __dest->__left_ = static_cast <__node_base_pointer>(__assign_from_tree (
1444+ static_cast <__node_pointer>(__dest->__left_ ),
1445+ static_cast <__node_pointer>(__src->__left_ ),
1446+ __assign,
1447+ __continue_with_construct));
14371448
14381449 // Otherwise, we must create new nodes; copy-construct from here on
14391450 } else if (__src->__left_ ) {
1440- auto __new_left = __copy_construct_tree (static_cast <__node_pointer>(__src->__left_ ));
1451+ auto __new_left = __continue_with_construct (static_cast <__node_pointer>(__src->__left_ ));
14411452 __dest->__left_ = static_cast <__node_base_pointer>(__new_left);
14421453 __new_left->__parent_ = static_cast <__end_node_pointer>(__dest);
14431454 }
14441455
14451456 // Identical to the left case above, just for the right nodes
14461457 if (__dest->__right_ ) {
1447- __dest->__right_ = static_cast <__node_base_pointer>(__copy_assign_tree (
1448- static_cast <__node_pointer>(__dest->__right_ ), static_cast <__node_pointer>(__src->__right_ )));
1458+ __dest->__right_ = static_cast <__node_base_pointer>(__assign_from_tree (
1459+ static_cast <__node_pointer>(__dest->__right_ ),
1460+ static_cast <__node_pointer>(__src->__right_ ),
1461+ __assign,
1462+ __continue_with_construct));
14491463 } else if (__src->__right_ ) {
1450- auto __new_right = __copy_construct_tree (static_cast <__node_pointer>(__src->__right_ ));
1464+ auto __new_right = __continue_with_construct (static_cast <__node_pointer>(__src->__right_ ));
14511465 __dest->__right_ = static_cast <__node_base_pointer>(__new_right);
14521466 __new_right->__parent_ = static_cast <__end_node_pointer>(__dest);
14531467 }
14541468
14551469 return __dest;
14561470 }
1471+
1472+ _LIBCPP_HIDE_FROM_ABI __node_pointer __copy_assign_tree (__node_pointer __dest, __node_pointer __src) {
1473+ return __assign_from_tree (
1474+ __dest,
1475+ __src,
1476+ [](value_type& __lhs, const value_type& __rhs) { __assign_value (__lhs, __rhs); },
1477+ [this ](__node_pointer __nd) { return __copy_construct_tree (__nd); });
1478+ }
1479+
1480+ _LIBCPP_HIDE_FROM_ABI __node_pointer __move_assign_tree (__node_pointer __dest, __node_pointer __src) {
1481+ return __assign_from_tree (
1482+ __dest,
1483+ __src,
1484+ [](value_type& __lhs, value_type& __rhs) { __assign_value (__lhs, std::move (__rhs)); },
1485+ [this ](__node_pointer __nd) { return __move_construct_tree (__nd); });
1486+ }
14571487};
14581488
14591489// Precondition: __size_ != 0
@@ -1594,21 +1624,26 @@ __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_(
15941624
15951625template <class _Tp , class _Compare , class _Allocator >
15961626__tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t , const allocator_type& __a)
1597- : __node_alloc_(__node_allocator(__a)), __size_(0 ), __value_comp_(std::move(__t .value_comp())) {
1627+ : __begin_node_(__end_node()),
1628+ __node_alloc_ (__node_allocator(__a)),
1629+ __size_(0 ),
1630+ __value_comp_(std::move(__t .value_comp())) {
1631+ if (__t .size () == 0 )
1632+ return ;
15981633 if (__a == __t .__alloc ()) {
1599- if (__t .__size_ == 0 )
1600- __begin_node_ = __end_node ();
1601- else {
1602- __begin_node_ = __t .__begin_node_ ;
1603- __end_node ()->__left_ = __t .__end_node ()->__left_ ;
1604- __end_node ()->__left_ ->__parent_ = static_cast <__end_node_pointer>(__end_node ());
1605- __size_ = __t .__size_ ;
1606- __t .__begin_node_ = __t .__end_node ();
1607- __t .__end_node ()->__left_ = nullptr ;
1608- __t .__size_ = 0 ;
1609- }
1634+ __begin_node_ = __t .__begin_node_ ;
1635+ __end_node ()->__left_ = __t .__end_node ()->__left_ ;
1636+ __end_node ()->__left_ ->__parent_ = static_cast <__end_node_pointer>(__end_node ());
1637+ __size_ = __t .__size_ ;
1638+ __t .__begin_node_ = __t .__end_node ();
1639+ __t .__end_node ()->__left_ = nullptr ;
1640+ __t .__size_ = 0 ;
16101641 } else {
1611- __begin_node_ = __end_node ();
1642+ *__root_ptr () = static_cast <__node_base_pointer>(__move_construct_tree (__t .__root ()));
1643+ __root ()->__parent_ = __end_node ();
1644+ __begin_node_ = static_cast <__end_node_pointer>(std::__tree_min (__end_node ()->__left_ ));
1645+ __size_ = __t .size ();
1646+ __t .clear (); // Ensure that __t is in a valid state after moving out the keys
16121647 }
16131648}
16141649
@@ -1633,22 +1668,21 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type)
16331668
16341669template <class _Tp , class _Compare , class _Allocator >
16351670void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t , false_type) {
1636- if (__node_alloc () == __t .__node_alloc ())
1671+ if (__node_alloc () == __t .__node_alloc ()) {
16371672 __move_assign (__t , true_type ());
1638- else {
1639- value_comp () = std::move (__t .value_comp ());
1640- const_iterator __e = end ();
1673+ } else {
1674+ value_comp () = std::move (__t .value_comp ());
16411675 if (__size_ != 0 ) {
1642- _DetachedTreeCache __cache (this );
1643- while (__cache.__get () != nullptr && __t .__size_ != 0 ) {
1644- __assign_value (__cache.__get ()->__get_value (), std::move (__t .remove (__t .begin ())->__get_value ()));
1645- __node_insert_multi (__cache.__get ());
1646- __cache.__advance ();
1647- }
1648- }
1649- while (__t .__size_ != 0 ) {
1650- __insert_multi_from_orphaned_node (__e, std::move (__t .remove (__t .begin ())->__get_value ()));
1676+ *__root_ptr () = static_cast <__node_base_pointer>(__move_assign_tree (__root (), __t .__root ()));
1677+ } else {
1678+ *__root_ptr () = static_cast <__node_base_pointer>(__move_construct_tree (__t .__root ()));
1679+ if (__root ())
1680+ __root ()->__parent_ = __end_node ();
16511681 }
1682+ __begin_node_ =
1683+ __end_node ()->__left_ ? static_cast <__end_node_pointer>(std::__tree_min (__end_node ()->__left_ )) : __end_node ();
1684+ __size_ = __t .size ();
1685+ __t .clear (); // Ensure that __t is in a valid state after moving out the keys
16521686 }
16531687}
16541688
0 commit comments