/
tree.h
2246 lines (1971 loc) · 54.1 KB
/
tree.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
© 2018-2023 FrankHB.
This file is part of the YSLib project, and may only be used,
modified, and distributed under the terms of the YSLib project
license, LICENSE.TXT. By continuing to use, modify, or distribute
this file you indicate that you have read the license and
understand and accept it fully.
*/
/*! \file tree.h
\ingroup YStandardEx
\brief 作为关联容器实现的树。
\version r4926
\author FrankHB <frankhb1989@gmail.com>
\since build 830
\par 创建时间:
2018-07-06 21:15:48 +0800
\par 修改时间:
2023-02-13 20:13 +0800
\par 文本编码:
UTF-8
\par 模块名称:
YStandardEx::Tree
关联容器的内部实现的搜索树接口。
设计和 libstdc++ 的 <bits/stl_tree.h> 中非公开接口类似,以红黑树作为内部数据结构,
可同时兼容 std::map 、std::set 、std::multimap 和 std::multiset 的容器。
接口支持 ISO C++17 模式下的容器功能,且支持不完整类型作为关联容器的键。
实现语言的特性要求和 YBase.YStandardEx 要求一致。
为便于参照和测试,实现也和 libstdc++ 在 ISO C++17 模式下的相似,
但充分利用了其它 YBase.YStandardEx 特性。
因为用于内部实现,接口主要在用于实现的特定命名空间内。
除另行指定的兼容性策略外,作为实现的接口不保证对外稳定。
*/
#ifndef YB_INC_ystdex_tree_h_
#define YB_INC_ystdex_tree_h_ 1
#include "node_handle.hpp" // for "node_handle.hpp" (implying "range.hpp"),
// size_t, typed_storage, std::allocator, bidirectional_iteratable,
// std::bidirectional_iterator_tag, ptrdiff_t, totally_ordered,
// is_unqualified_object, is_allocator_for, ystdex::reverse_iterator,
// rebind_alloc_t, node_handle, node_insert_return, cond_t, is_same, bool_,
// conditional_t, allocator_traits, and_, is_nothrow_default_constructible,
// is_nothrow_copy_constructible, false_, true_, std::addressof,
// ystdex::alloc_on_copy, is_nothrow_move_assignable, std::equal,
// std::lexicographical_compare, yassume, std::forward,
// is_throwing_move_copyable, ystdex::alloc_on_move,
// is_trivially_default_constructible, allocator_guard, ystdex::to_allocated,
// is_trivially_destructible, std::pointer_traits, is_invocable, std::pair,
// std::declval, enable_if_t, yconstraint, is_nothrow_swappable,
// ystdex::alloc_on_swap, YAssert, is_bitwise_swappable;
#include "base.h" // for noncopyable;
#include "compressed_pair.hpp" // for compressed_pair, value_init;
#include "functor.hpp" // for enable_if_transparent_t, ystdex::invoke;
#include <limits> // for std::numeric_limits;
#include "iterator_trait.hpp" // for has_iterator_value_type;
namespace ystdex
{
//! \since build 830
//!@{
namespace details
{
inline namespace rb_tree
{
enum class tree_color : bool
{
red = false,
black = true
};
//! \warning 非虚析构。
//!@{
struct tree_node_base
{
using base_ptr = tree_node_base*;
using const_base_ptr = const tree_node_base*;
// XXX: Uninitialized.
tree_color color;
base_ptr parent, left, right;
YB_ATTR_nodiscard YB_PURE static base_ptr
maximum(base_ptr x) ynothrow
{
while(x->right)
x = x->right;
return x;
}
YB_ATTR_nodiscard YB_PURE static const_base_ptr
maximum(const_base_ptr x) ynothrow
{
while(x->right)
x = x->right;
return x;
}
YB_ATTR_nodiscard YB_PURE static base_ptr
minimum(base_ptr x) ynothrow
{
while(x->left)
x = x->left;
return x;
}
YB_ATTR_nodiscard YB_PURE static const_base_ptr
minimum(const_base_ptr x) ynothrow
{
while(x->left)
x = x->left;
return x;
}
//! \since build 864
void
initialize() ynothrow
{
reset_links();
color = tree_color::red;
}
void
reset_links() ynothrow
{
parent = {};
left = this;
right = this;
}
};
struct tree_header : tree_node_base
{
size_t node_count;
tree_header() ynothrow
: node_count(0)
{
initialize();
}
tree_header(tree_header&& x) ynothrow
{
if(x.parent)
move_data(x);
else
{
initialize();
node_count = 0;
}
}
//! \since build 865
void
move_data(tree_header& from) ynothrow
{
base() = from.base();
yunseq(parent->parent = &base(), node_count = from.node_count);
from.reset();
}
//! \since build 865
void
reset() ynothrow
{
reset_links();
node_count = 0;
}
//! \since build 865
YB_ATTR_nodiscard YB_PURE tree_node_base&
base() ynothrow
{
return *this;
}
};
template<typename _type>
class tree_node : public tree_node_base, private typed_storage<_type>
{
public:
using typed_storage<_type>::access;
using typed_storage<_type>::access_ptr;
};
//!@}
/*!
\pre 断言:参数非空。
\since build 966
*/
//!@{
YB_API YB_NONNULL(1) YB_PURE tree_node_base*
tree_increment(tree_node_base*) ynothrowv;
YB_API YB_NONNULL(1) YB_PURE const tree_node_base*
tree_increment(const tree_node_base*) ynothrowv;
YB_API YB_NONNULL(1) YB_PURE tree_node_base*
tree_decrement(tree_node_base*) ynothrowv;
YB_API YB_NONNULL(1) YB_PURE const tree_node_base*
tree_decrement(const tree_node_base*) ynothrowv;
//!@}
//! \warning 非虚析构。
//!@{
template<typename, typename _type, class, typename,
class = std::allocator<_type>>
class tree;
template<typename>
class tree_const_iterator;
template<typename _type>
class tree_iterator
: public bidirectional_iteratable<tree_iterator<_type>, _type&>
{
// XXX: Partial specialization is not allowed here by ISO C++.
template<typename, typename, class, typename, class>
friend class tree;
template<typename>
friend class tree_const_iterator;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = _type;
using difference_type = ptrdiff_t;
using pointer = _type*;
using reference = _type&;
private:
//! \since build 864
using base_ptr = tree_node_base::base_ptr;
//! \since build 864
using link_type = tree_node<_type>*;
base_ptr p_node = {};
public:
tree_iterator() ynothrow = default;
explicit
tree_iterator(base_ptr x) ynothrow
: p_node(x)
{}
//! \since build 966
//!@{
YB_ATTR_nodiscard YB_PURE reference
operator*() const ynothrowv
{
return link_type(p_node)->access();
}
tree_iterator&
operator++() ynothrowv
{
p_node = tree_increment(p_node);
return *this;
}
tree_iterator&
operator--() ynothrowv
{
p_node = tree_decrement(p_node);
return *this;
}
//!@}
//! \since build 958
YB_ATTR_nodiscard YB_PURE friend bool
operator==(const tree_iterator& x, const tree_iterator& y) ynothrow
{
return x.p_node == y.p_node;
}
};
template<typename _type>
class tree_const_iterator
: public bidirectional_iteratable<tree_const_iterator<_type>, const _type&>
{
// XXX: Partial specialization is not allowed here by ISO C++.
template<typename, typename, class, typename, class>
friend class tree;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = _type;
using difference_type = ptrdiff_t;
using pointer = const _type*;
using reference = const _type&;
private:
//! \since build 864
using iterator = tree_iterator<_type>;
//! \since build 864
using base_ptr = tree_node_base::const_base_ptr;
//! \since build 864
using link_type = const tree_node<_type>*;
base_ptr p_node = {};
public:
tree_const_iterator() ynothrow = default;
explicit
tree_const_iterator(base_ptr x) ynothrow
: p_node(x)
{}
tree_const_iterator(const iterator& it) ynothrow
: p_node(it.p_node)
{}
YB_ATTR_nodiscard YB_PURE iterator
cast_mutable() const ynothrow
{
return iterator(const_cast<typename iterator::base_ptr>(p_node));
}
//! \since build 966
YB_ATTR_nodiscard YB_PURE reference
operator*() const ynothrowv
{
return link_type(p_node)->access();
}
tree_const_iterator&
operator++() ynothrow
{
p_node = tree_increment(p_node);
return *this;
}
tree_const_iterator&
operator--() ynothrow
{
p_node = tree_decrement(p_node);
return *this;
}
//! \since build 958
YB_ATTR_nodiscard YB_PURE friend bool
operator==(const tree_const_iterator& x, const tree_const_iterator& y)
ynothrow
{
return x.p_node == y.p_node;
}
};
//!@}
/*!
\pre 断言:指针参数非空。
\since build 966
*/
//!@{
YB_API YB_NONNULL(2, 3) void
tree_insert_and_rebalance(bool, tree_node_base*, tree_node_base*,
tree_node_base&) ynothrowv;
YB_ATTR_nodiscard YB_API YB_ATTR_returns_nonnull YB_NONNULL(1) tree_node_base*
tree_rebalance_for_erase(tree_node_base*, tree_node_base&) ynothrowv;
//!@}
YB_ATTR_nodiscard YB_API YB_PURE size_t
tree_black_count(const tree_node_base*, const tree_node_base*) ynothrow;
template<typename, typename>
struct tree_merge_helper
{
~tree_merge_helper() = delete;
};
//! \warning 非虚析构。
template<typename _tKey, typename _type, typename _fKeyOfValue, typename _fComp,
class _tAlloc>
class tree
: private totally_ordered<tree<_tKey, _type, _fKeyOfValue, _fComp, _tAlloc>>
{
template<typename, typename>
friend struct tree_merge_helper;
public:
using key_type = _tKey;
using value_type = _type;
/*!
\see ISO C++17 [allocator.requirements] 。
\see LWG 274 。
\see LWG 2447 。
*/
static_assert(is_unqualified_object<value_type>(),
"The value type for allocator shall be an unqualified object type.");
/*!
\see ISO C++17 [container.requirements.general]/15 。
\see WG21 P1463R1 。
*/
static_assert(is_allocator_for<_tAlloc, value_type>(),
"Value type mismatched to the allocator found.");
/*!
\brief 分配器类型。
\note 支持 uses-allocator 构造。
*/
using allocator_type = _tAlloc;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = size_t;
using difference_type = ptrdiff_t;
/*!
\warning 不检查 const 安全性。若修改键破坏类不变量,则行为未定义。
\note 对集合容器实现可调整 iterator 成员为 const_iterator 避免。
\see LWG 103 。
*/
using iterator = tree_iterator<value_type>;
using const_iterator = tree_const_iterator<value_type>;
using reverse_iterator = ystdex::reverse_iterator<iterator>;
using const_reverse_iterator = ystdex::reverse_iterator<const_iterator>;
private:
//! \since build 865
using value_node = tree_node<value_type>;
using node_allocator = rebind_alloc_t<_tAlloc, value_node>;
public:
using node_type = node_handle<_tKey, _type, node_allocator>;
//! \note 集合容器使用常量迭代器以避免修改键破坏类不变量。
using insert_return_type = node_insert_return<
cond_t<is_same<_tKey, _type>, const_iterator, iterator>, node_type>;
protected:
using base_ptr = tree_node_base*;
using const_base_ptr = const tree_node_base*;
using link_type = value_node*;
using const_link_type = const value_node*;
private:
//! \since build 864
using node_ator_traits = allocator_traits<node_allocator>;
//! \since build 966
using node_pointer = typename node_ator_traits::pointer;
//! \since build 865
using equal_alloc_or_pocma = bool_<node_ator_traits::is_always_equal::value
|| node_ator_traits::propagate_on_container_move_assignment::value>;
// XXX: See $2022-01 @ %Documentation::Workflow.
using allocator_reference = conditional_t<sizeof(node_allocator)
<= sizeof(void*), node_allocator, node_allocator&>;
struct alloc_node
{
tree& tree_ref;
alloc_node(tree& t)
: tree_ref(t)
{}
template<typename _tParam>
YB_ATTR_nodiscard YB_ATTR_returns_nonnull inline link_type
operator()(_tParam&& arg) const
{
return tree_ref.create_node(yforward(arg));
}
template<typename _tParam>
YB_ATTR_nodiscard link_type
reconstruct(base_ptr p, _tParam&& arg) const
{
const auto nd = link_type(p);
tree_ref.destroy_node(nd);
tree_ref.construct_node(std::pointer_traits<typename
node_ator_traits::pointer>::pointer_to(*nd), yforward(arg));
return nd;
}
};
struct reuse_or_alloc_node : protected alloc_node, private noncopyable
{
mutable base_ptr root;
mutable base_ptr nodes;
reuse_or_alloc_node(tree& t)
: alloc_node(t), root(t.root()), nodes(t.rightmost())
{
if(root)
{
root->parent = {};
if(nodes->left)
nodes = nodes->left;
}
else
nodes = {};
}
~reuse_or_alloc_node()
{
alloc_node::tree_ref.erase_node(link_type(root));
}
template<typename _tParam>
YB_ATTR_nodiscard YB_ATTR_returns_nonnull link_type
operator()(_tParam&& arg) const
{
if(nodes)
return alloc_node::reconstruct(adjust(), yforward(arg));
return alloc_node::operator()(yforward(arg));
}
//! \since build 866
base_ptr
adjust() const
{
auto node(nodes);
nodes = nodes->parent;
if(nodes)
{
if(nodes->right == node)
{
nodes->right = {};
if(nodes->left)
{
nodes = nodes->left;
while(nodes->right)
nodes = nodes->right;
if(nodes->left)
nodes = nodes->left;
}
}
else
nodes->left = {};
}
else
root = {};
return node;
}
};
template<typename _fComp2>
using compatible_tree_type
= tree<_tKey, _type, _fKeyOfValue, _fComp2, _tAlloc>;
protected:
template<typename _tKeyComp>
struct components : compressed_pair<node_allocator, _tKeyComp>
{
//! \since build 940
using base = compressed_pair<node_allocator, _tKeyComp>;
tree_header header{};
//! \since build 966
components()
ynoexcept(and_<is_nothrow_default_constructible<node_allocator>,
is_nothrow_default_constructible<_tKeyComp>>())
{}
//! \since build 867
explicit
components(node_allocator a) ynothrow
: base(std::move(a), value_init)
{}
components(const _tKeyComp& comp, node_allocator&& a)
: base(std::move(a), _tKeyComp(comp))
{}
components(const components& x)
: base(node_allocator(
node_ator_traits::select_on_container_copy_construction(x.first())),
x.get_key_comp())
{}
// NOTE: As per ISO C++17 [associative.reqmts], the comparison object
// shall be copy constructible. However, whether it should be copy is
// questionable, see LWG 2227. At current, follow the common practice
// in libstdc++ and Microsoft VC++'s STL by copying, but not moving in
// libc++.
// XXX: The comparion object is always copied even during moving.
/*!
\see LWG 2227 。
\since build 958
*/
components(components&& x)
ynoexcept(is_nothrow_copy_constructible<_tKeyComp>())
: base(std::move(x.first()), x.second()),
header(std::move(x.header))
{}
//! \since build 867
components(components&& x, node_allocator a)
: base(std::move(a), std::move(x)),
header(std::move(x.header))
{}
//! \since build 865
void
move_data(components& from) ynothrow
{
header.move_data(from.header);
}
YB_ATTR_nodiscard YB_PURE _tKeyComp&
get_key_comp() ynothrow
{
return base::second();
}
YB_ATTR_nodiscard YB_PURE const _tKeyComp&
get_key_comp() const ynothrow
{
return base::second();
}
};
components<_fComp> objects;
public:
tree() = default;
tree(const allocator_type& a)
: objects(node_allocator(a))
{}
tree(const _fComp& comp, const allocator_type& a = allocator_type())
: objects(comp, node_allocator(a))
{}
tree(const tree& x)
: objects(x.objects)
{
if(x.root())
root() = copy_node(x);
}
tree(const tree& x, const allocator_type& a)
: objects(x.objects.get_key_comp(), node_allocator(a))
{
if(x.root())
root() = copy_node(x);
}
tree(tree&&) = default;
tree(tree&& x, const allocator_type& a)
: tree(std::move(x), node_allocator(a))
{}
//! \since build 866
//!@{
tree(tree&& x, node_allocator&& a)
// XXX: %is_nothrow_constructible is not usable for the incomplete type.
ynoexcept_spec(tree(std::move(x), std::move(a),
typename node_ator_traits::is_always_equal()))
: tree(std::move(x), std::move(a),
typename node_ator_traits::is_always_equal())
{}
private:
//! \since build 867
tree(tree&& x, node_allocator a, false_)
: objects(x.objects.get_key_comp(), std::move(a))
{
if(x.root())
move_data(x, false_());
}
//! \since build 867
tree(tree&& x, node_allocator a, true_)
ynoexcept(is_nothrow_default_constructible<_fComp>())
: objects(std::move(x.objects), std::move(a))
{}
//!@}
public:
~tree() ynothrow
{
clear_nodes();
}
tree&
operator=(const tree& x)
{
if(std::addressof(x) != this)
{
if(node_ator_traits::propagate_on_container_copy_assignment::value)
{
auto& this_alloc(get_node_allocator());
const auto& that_alloc(x.get_node_allocator());
if(!node_ator_traits::is_always_equal::value
&& this_alloc != that_alloc)
clear();
ystdex::alloc_on_copy(this_alloc, that_alloc);
}
reuse_or_alloc_node roan(*this);
objects.header.reset();
objects.get_key_comp() = x.objects.get_key_comp();
if(x.root())
root() = copy_node<false>(x, roan);
}
return *this;
}
/*!
\see LWG 2839 。
\since build 864
*/
tree&
operator=(tree&& x) ynoexcept(
and_<equal_alloc_or_pocma, is_nothrow_move_assignable<_fComp>>())
{
// NOTE: As ISO C++ [res.on.arguments], moving same object to itself is
// not supported to meet the postcondition of the move assignment until
// the resolution of LWG 2839, which makes it valid but unspecified
// after the move. See %move_assign_elements for details.
// XXX: Moving from an ancestor to its subtree (composed by elements of
// recursive container type) is not supported and it would typically
// lead to resource leaks, however there is no check anyway. This is
// different to ISO C++ as associative containers do not support
// incomplete element types so the recursive container type itself
// causes undefined behavior in such cases. Use %swap if the operand
// can reference to the object itself or its subtrees thereby.
objects.get_key_comp() = std::move(x.objects.get_key_comp());
move_assign_elements(x, equal_alloc_or_pocma());
return *this;
}
YB_ATTR_nodiscard YB_PURE friend bool
operator==(const tree& x, const tree& y)
{
return x.size() == y.size()
&& std::equal(x.cbegin(), x.cend(), y.cbegin());
}
YB_ATTR_nodiscard YB_PURE friend bool
operator<(const tree& x, const tree& y)
{
return std::lexicographical_compare(x.cbegin(), x.cend(), y.cbegin(),
y.cend());
}
template<typename _tIter>
void
assign_unique(_tIter first, _tIter last)
{
reuse_or_alloc_node roan(*this);
objects.header.reset();
insert_range_unique(first, last, roan);
}
template<typename _tIter>
void
assign_equal(_tIter first, _tIter last)
{
reuse_or_alloc_node roan(*this);
objects.header.reset();
insert_range_equal(first, last, roan);
}
private:
//! \since build 958
template<bool _bMove, class _tNodeGen>
YB_ATTR_nodiscard link_type
copy_node(link_type x, base_ptr p, const _tNodeGen& node_gen)
{
yassume(x), yassume(p);
const auto clone_node([&]{
link_type nd(node_gen(std::forward<conditional_t<_bMove,
value_type&&, const value_type&>>(x->access())));
yunseq(nd->color = x->color, nd->left = {}, nd->right = {});
return nd;
});
const auto top(clone_node());
top->parent = p;
try
{
if(x->right)
top->right = copy_node<_bMove>(get_right(x), top, node_gen);
p = top;
x = get_left(x);
while(x)
{
const auto y(clone_node());
p->left = y;
y->parent = p;
if(x->right)
y->right = copy_node<_bMove>(get_right(x), y, node_gen);
p = y;
x = get_left(x);
}
}
catch(...)
{
erase_node(top);
throw;
}
return top;
}
template<bool _bMove, class _tNodeGen>
YB_ATTR_nodiscard link_type
copy_node(const tree& x, const _tNodeGen& node_gen)
{
const auto root(copy_node<_bMove>(x.node_mbegin(), node_end(),
node_gen));
yunseq(leftmost() = minimum(root), rightmost() = maximum(root),
objects.header.node_count = x.objects.header.node_count);
return root;
}
YB_ATTR_nodiscard link_type
copy_node(const tree& x)
{
alloc_node an(*this);
return copy_node<false>(x, an);
}
/*!
\brief 转移可能不相等分配器的容器元素。
\note 从不相等分配器转移元素结果是复制而不是转移对象。
*/
void
move_data(tree& x, false_)
{
if(get_node_allocator() == x.get_node_allocator())
move_data(x, true_());
else
{
// XXX: This requires %value_type complete.
yconstexpr const bool
move(!is_throwing_move_copyable<value_type>());
alloc_node an(*this);
root() = copy_node<move>(x, an);
yconstexpr_if(move)
x.clear();
}
}
/*!
\brief 转移相等分配器的容器元素。
\since build 865
*/
void
move_data(tree& x, true_) ynothrow
{
objects.move_data(x.objects);
}
/*!
\brief 转移赋值可能不相等的不在转移赋值时传播的分配器的容器元素。
\note 从不相等分配器转移元素可能复制而不是转移对象。
*/
void
move_assign_elements(tree& x, false_)
{
// NOTE: This just clears the elements for self-move. See also the
// comment in move %operator=.
if(get_node_allocator() == x.get_node_allocator())
move_assign_elements(x, true_());
else
{
// NOTE: Try to move reusing existing nodes.
reuse_or_alloc_node roan(*this);
objects.header.reset();
if(x.root())
{
root() = copy_node<true>(x, roan);
x.clear();
}
}
}
/*!
\brief 转移赋值相等或在转移赋值时传播的分配器的容器元素。
\since build 865
*/
void
move_assign_elements(tree& x, true_) ynothrow
{
// NOTE: Ditto.
clear_nodes();
if(x.root())
move_data(x, true_());
else
objects.header.reset();
ystdex::alloc_on_move(get_node_allocator(), x.get_node_allocator());
}
public:
YB_ATTR_nodiscard allocator_type
get_allocator() const ynothrow
{
return allocator_type(get_node_allocator());
}
YB_ATTR_nodiscard YB_PURE node_allocator&
get_node_allocator() ynothrow
{
return objects.first();
}
YB_ATTR_nodiscard YB_PURE const node_allocator&
get_node_allocator() const ynothrow
{
return objects.first();
}
protected:
//! \since build 865
// XXX: This implies %YB_ALLOCATOR and %YB_returns_nonnull for non-fancy
// pointers.
YB_ATTR_nodiscard node_pointer
allocate_node()
{
allocator_reference a(get_node_allocator());
return node_ator_traits::allocate(a, 1);
}
//! \since build 865
void
deallocate_node(node_pointer p) ynothrow
{
allocator_reference a(get_node_allocator());
node_ator_traits::deallocate(a, p, 1);
}
//! \pre 断言:第一参数非空。
template<typename... _tParams>
void
construct_node(node_pointer p, _tParams&&... args)
{
YAssertNonnull(p);
// NOTE: Unintialized data members are delayed to be overwritten by
// %tree_insert_and_rebalance after creation.
// XXX: Ensure no need to use placment new for the node, so there needs
// no try-catch block on allocation failure if WG21 P0593R6 is
// supported. This is a special case of the trait inWG21 P26740.
static_assert(is_trivially_default_constructible<value_node>(),
"Invalid node type found.");
allocator_reference a(get_node_allocator());
// NOTE: This should be same to %deallocate_node(p) on exception thrown.
allocator_guard<allocator_reference> gd(p, a);
const auto nd(ystdex::to_allocated(p));
#if __cplusplus < 202002L
try
{
// XXX: Data members are not initialized here. See above.
::new(nd) value_node;
node_ator_traits::construct(a, nd->access_ptr(), yforward(args)...);
}
catch(...)
{
nd->~value_node();
}
#else
node_ator_traits::construct(a, nd->access_ptr(), yforward(args)...);
#endif
gd.release();
}
template<typename... _tParams>
YB_ATTR_nodiscard YB_ATTR_returns_nonnull inline link_type
create_node(_tParams&&... args)
{
const auto p(allocate_node());
construct_node(p, yforward(args)...);
// XXX: Metadata in %p is dropped.
return ystdex::to_allocated(p);
}
void
destroy_node(link_type nd) ynothrow
{
// XXX: Ensure no need to use explicit destructor call for the node if
// WG21 P0593R6 is supported, although it is not acually used (see
// below). This is a special case of the trait inWG21 P26740.
static_assert(is_trivially_destructible<value_node>(),
"Invalid node type found.");
allocator_reference a(get_node_allocator());
node_ator_traits::destroy(a, nd->access_ptr());
#if __cplusplus < 202002L
// XXX: This is actually compatible to ISO C++20 because there are not
// data member accesses to the object pointed by %nd. It can be even a
// potiential hint to optimizing implementations. Nevertheless, leave
// it away right now to be more consistent with %construct_node.
nd->~value_node();
#endif
}
void
drop_node(link_type nd) ynothrow
{
destroy_node(nd);
deallocate_node(std::pointer_traits<typename
node_ator_traits::pointer>::pointer_to(*nd));
}