@@ -1213,6 +1213,104 @@ private:
1213
1213
__node_pointer __cache_root_;
1214
1214
__node_pointer __cache_elem_;
1215
1215
};
1216
+
1217
+ class __tree_deleter {
1218
+ __node_allocator& __alloc_;
1219
+
1220
+ public:
1221
+ using pointer = __node_pointer;
1222
+
1223
+ _LIBCPP_HIDE_FROM_ABI __tree_deleter (__node_allocator& __alloc) : __alloc_(__alloc) {}
1224
+
1225
+ #ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
1226
+ _LIBCPP_HIDE_FROM_ABI
1227
+ #endif
1228
+ void
1229
+ operator ()(__node_pointer __ptr) {
1230
+ if (!__ptr)
1231
+ return ;
1232
+
1233
+ (*this )(static_cast <__node_pointer>(__ptr->__left_ ));
1234
+
1235
+ auto __right = __ptr->__right_ ;
1236
+
1237
+ __node_traits::destroy (__alloc_, std::addressof (__ptr->__value_ ));
1238
+ __node_traits::deallocate (__alloc_, __ptr, 1 );
1239
+
1240
+ (*this )(static_cast <__node_pointer>(__right));
1241
+ }
1242
+ };
1243
+
1244
+ // This copy construction will always produce a correct red-black-tree assuming the incoming tree is correct, since we
1245
+ // copy the exact structure 1:1. Since this is for copy construction _only_ we know that we get a correct tree. If we
1246
+ // didn't get a correct tree, the invariants of __tree are broken and we have a much bigger problem than an improperly
1247
+ // balanced tree.
1248
+ #ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
1249
+ _LIBCPP_HIDE_FROM_ABI
1250
+ #endif
1251
+ __node_pointer
1252
+ __copy_construct_tree (__node_pointer __src) {
1253
+ if (!__src)
1254
+ return nullptr ;
1255
+
1256
+ __node_holder __new_node = __construct_node (__src->__value_ );
1257
+
1258
+ unique_ptr<__node, __tree_deleter> __left (
1259
+ __copy_construct_tree (static_cast <__node_pointer>(__src->__left_ )), __node_alloc_);
1260
+ __node_pointer __right = __copy_construct_tree (static_cast <__node_pointer>(__src->__right_ ));
1261
+
1262
+ __node_pointer __new_node_ptr = __new_node.release ();
1263
+
1264
+ __new_node_ptr->__is_black_ = __src->__is_black_ ;
1265
+ __new_node_ptr->__left_ = static_cast <__node_base_pointer>(__left.release ());
1266
+ __new_node_ptr->__right_ = static_cast <__node_base_pointer>(__right);
1267
+ if (__new_node_ptr->__left_ )
1268
+ __new_node_ptr->__left_ ->__parent_ = static_cast <__end_node_pointer>(__new_node_ptr);
1269
+ if (__new_node_ptr->__right_ )
1270
+ __new_node_ptr->__right_ ->__parent_ = static_cast <__end_node_pointer>(__new_node_ptr);
1271
+ return __new_node_ptr;
1272
+ }
1273
+
1274
+ // This copy assignment will always produce a correct red-black-tree assuming the incoming tree is correct, since our
1275
+ // own tree is a red-black-tree and the incoming tree is a red-black-tree. The invariants of a red-black-tree are
1276
+ // temporarily not met until all of the incoming red-black tree is copied.
1277
+ #ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
1278
+ _LIBCPP_HIDE_FROM_ABI
1279
+ #endif
1280
+ __node_pointer
1281
+ __copy_assign_tree (__node_pointer __dest, __node_pointer __src) {
1282
+ if (!__src) {
1283
+ destroy (__dest);
1284
+ return nullptr ;
1285
+ }
1286
+
1287
+ __assign_value (__dest->__value_ , __src->__value_ );
1288
+ __dest->__is_black_ = __src->__is_black_ ;
1289
+
1290
+ // If we already have a left node in the destination tree, reuse it and copy-assign recursively
1291
+ if (__dest->__left_ ) {
1292
+ __dest->__left_ = static_cast <__node_base_pointer>(__copy_assign_tree (
1293
+ static_cast <__node_pointer>(__dest->__left_ ), static_cast <__node_pointer>(__src->__left_ )));
1294
+
1295
+ // Otherwise, we must create new nodes; copy-construct from here on
1296
+ } else if (__src->__left_ ) {
1297
+ auto __new_left = __copy_construct_tree (static_cast <__node_pointer>(__src->__left_ ));
1298
+ __dest->__left_ = static_cast <__node_base_pointer>(__new_left);
1299
+ __new_left->__parent_ = static_cast <__end_node_pointer>(__dest);
1300
+ }
1301
+
1302
+ // Identical to the left case above, just for the right nodes
1303
+ if (__dest->__right_ ) {
1304
+ __dest->__right_ = static_cast <__node_base_pointer>(__copy_assign_tree (
1305
+ static_cast <__node_pointer>(__dest->__right_ ), static_cast <__node_pointer>(__src->__right_ )));
1306
+ } else if (__src->__right_ ) {
1307
+ auto __new_right = __copy_construct_tree (static_cast <__node_pointer>(__src->__right_ ));
1308
+ __dest->__right_ = static_cast <__node_base_pointer>(__new_right);
1309
+ __new_right->__parent_ = static_cast <__end_node_pointer>(__dest);
1310
+ }
1311
+
1312
+ return __dest;
1313
+ }
1216
1314
};
1217
1315
1218
1316
template <class _Tp , class _Compare , class _Allocator >
@@ -1277,11 +1375,22 @@ __tree<_Tp, _Compare, _Allocator>::_DetachedTreeCache::__detach_next(__node_poin
1277
1375
1278
1376
template <class _Tp , class _Compare , class _Allocator >
1279
1377
__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator =(const __tree& __t ) {
1280
- if (this != std::addressof (__t )) {
1281
- value_comp () = __t .value_comp ();
1282
- __copy_assign_alloc (__t );
1283
- __assign_multi (__t .begin (), __t .end ());
1378
+ if (this == std::addressof (__t ))
1379
+ return *this ;
1380
+
1381
+ value_comp () = __t .value_comp ();
1382
+ __copy_assign_alloc (__t );
1383
+
1384
+ if (__size_ != 0 ) {
1385
+ *__root_ptr () = static_cast <__node_base_pointer>(__copy_assign_tree (__root (), __t .__root ()));
1386
+ } else {
1387
+ *__root_ptr () = static_cast <__node_base_pointer>(__copy_construct_tree (__t .__root ()));
1388
+ if (__root ())
1389
+ __root ()->__parent_ = __end_node ();
1284
1390
}
1391
+ __begin_node_ = static_cast <__end_node_pointer>(std::__tree_min (static_cast <__node_base_pointer>(__end_node ())));
1392
+ __size_ = __t .size ();
1393
+
1285
1394
return *this ;
1286
1395
}
1287
1396
@@ -1327,11 +1436,17 @@ void __tree<_Tp, _Compare, _Allocator>::__assign_multi(_InputIterator __first, _
1327
1436
1328
1437
template <class _Tp , class _Compare , class _Allocator >
1329
1438
__tree<_Tp, _Compare, _Allocator>::__tree(const __tree& __t )
1330
- : __begin_node_(),
1439
+ : __begin_node_(__end_node() ),
1331
1440
__node_alloc_ (__node_traits::select_on_container_copy_construction(__t .__node_alloc())),
1332
1441
__size_(0 ),
1333
1442
__value_comp_(__t .value_comp()) {
1334
- __begin_node_ = __end_node ();
1443
+ if (__t .size () == 0 )
1444
+ return ;
1445
+
1446
+ *__root_ptr () = static_cast <__node_base_pointer>(__copy_construct_tree (__t .__root ()));
1447
+ __root ()->__parent_ = __end_node ();
1448
+ __begin_node_ = static_cast <__end_node_pointer>(std::__tree_min (static_cast <__node_base_pointer>(__end_node ())));
1449
+ __size_ = __t .size ();
1335
1450
}
1336
1451
1337
1452
template <class _Tp , class _Compare , class _Allocator >
@@ -1430,13 +1545,7 @@ __tree<_Tp, _Compare, _Allocator>::~__tree() {
1430
1545
1431
1546
template <class _Tp , class _Compare , class _Allocator >
1432
1547
void __tree<_Tp, _Compare, _Allocator>::destroy(__node_pointer __nd) _NOEXCEPT {
1433
- if (__nd != nullptr ) {
1434
- destroy (static_cast <__node_pointer>(__nd->__left_ ));
1435
- destroy (static_cast <__node_pointer>(__nd->__right_ ));
1436
- __node_allocator& __na = __node_alloc ();
1437
- __node_traits::destroy (__na, std::addressof (__nd->__value_ ));
1438
- __node_traits::deallocate (__na, __nd, 1 );
1439
- }
1548
+ (__tree_deleter (__node_alloc_))(__nd);
1440
1549
}
1441
1550
1442
1551
template <class _Tp , class _Compare , class _Allocator >
0 commit comments