blob: c32e992c838258a28709f35b6e648a84456b8a26 [file] [log] [blame]
Brian Silvermanfad8f552018-08-04 23:36:19 -07001//////////////////////////////////////////////////////////////////////////////
2//
3// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost
4// Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// See http://www.boost.org/libs/container for documentation.
8//
9//////////////////////////////////////////////////////////////////////////////
10
11#ifndef BOOST_CONTAINER_TREE_HPP
12#define BOOST_CONTAINER_TREE_HPP
13
14#ifndef BOOST_CONFIG_HPP
15# include <boost/config.hpp>
16#endif
17
18#if defined(BOOST_HAS_PRAGMA_ONCE)
19# pragma once
20#endif
21
22#include <boost/container/detail/config_begin.hpp>
23#include <boost/container/detail/workaround.hpp>
24// container
25#include <boost/container/allocator_traits.hpp>
26#include <boost/container/container_fwd.hpp>
27#include <boost/container/options.hpp>
28#include <boost/container/node_handle.hpp>
29
30// container/detail
31#include <boost/container/detail/algorithm.hpp> //algo_equal(), algo_lexicographical_compare
32#include <boost/container/detail/compare_functors.hpp>
33#include <boost/container/detail/destroyers.hpp>
34#include <boost/container/detail/iterator.hpp>
35#include <boost/container/detail/iterators.hpp>
36#include <boost/container/detail/node_alloc_holder.hpp>
37#include <boost/container/detail/pair.hpp>
38#include <boost/container/detail/type_traits.hpp>
39// intrusive
40#include <boost/intrusive/pointer_traits.hpp>
41#include <boost/intrusive/rbtree.hpp>
42#include <boost/intrusive/avltree.hpp>
43#include <boost/intrusive/splaytree.hpp>
44#include <boost/intrusive/sgtree.hpp>
45// intrusive/detail
46#include <boost/intrusive/detail/minimal_pair_header.hpp> //pair
47#include <boost/intrusive/detail/tree_value_compare.hpp> //tree_value_compare
48// move
49#include <boost/move/utility_core.hpp>
50// move/detail
51#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
52#include <boost/move/detail/fwd_macros.hpp>
53#endif
54#include <boost/move/detail/move_helpers.hpp>
55// other
56#include <boost/core/no_exceptions_support.hpp>
57
58
59
60#include <boost/container/detail/std_fwd.hpp>
61
62namespace boost {
63namespace container {
64namespace dtl {
65
66using boost::intrusive::tree_value_compare;
67
68template<class VoidPointer, boost::container::tree_type_enum tree_type_value, bool OptimizeSize>
69struct intrusive_tree_hook;
70
71template<class VoidPointer, bool OptimizeSize>
72struct intrusive_tree_hook<VoidPointer, boost::container::red_black_tree, OptimizeSize>
73{
74 typedef typename dtl::bi::make_set_base_hook
75 < dtl::bi::void_pointer<VoidPointer>
76 , dtl::bi::link_mode<dtl::bi::normal_link>
77 , dtl::bi::optimize_size<OptimizeSize>
78 >::type type;
79};
80
81template<class VoidPointer, bool OptimizeSize>
82struct intrusive_tree_hook<VoidPointer, boost::container::avl_tree, OptimizeSize>
83{
84 typedef typename dtl::bi::make_avl_set_base_hook
85 < dtl::bi::void_pointer<VoidPointer>
86 , dtl::bi::link_mode<dtl::bi::normal_link>
87 , dtl::bi::optimize_size<OptimizeSize>
88 >::type type;
89};
90
91template<class VoidPointer, bool OptimizeSize>
92struct intrusive_tree_hook<VoidPointer, boost::container::scapegoat_tree, OptimizeSize>
93{
94 typedef typename dtl::bi::make_bs_set_base_hook
95 < dtl::bi::void_pointer<VoidPointer>
96 , dtl::bi::link_mode<dtl::bi::normal_link>
97 >::type type;
98};
99
100template<class VoidPointer, bool OptimizeSize>
101struct intrusive_tree_hook<VoidPointer, boost::container::splay_tree, OptimizeSize>
102{
103 typedef typename dtl::bi::make_bs_set_base_hook
104 < dtl::bi::void_pointer<VoidPointer>
105 , dtl::bi::link_mode<dtl::bi::normal_link>
106 >::type type;
107};
108
109//This trait is used to type-pun std::pair because in C++03
110//compilers std::pair is useless for C++11 features
111template<class T>
112struct tree_internal_data_type
113{
114 typedef T type;
115};
116
117template<class T1, class T2>
118struct tree_internal_data_type< std::pair<T1, T2> >
119{
120 typedef pair<typename boost::move_detail::remove_const<T1>::type, T2> type;
121};
122
123//The node to be store in the tree
124template <class T, class VoidPointer, boost::container::tree_type_enum tree_type_value, bool OptimizeSize>
125struct tree_node
126 : public intrusive_tree_hook<VoidPointer, tree_type_value, OptimizeSize>::type
127{
128 private:
129 //BOOST_COPYABLE_AND_MOVABLE(tree_node)
130 tree_node();
131
132 public:
133 typedef typename intrusive_tree_hook
134 <VoidPointer, tree_type_value, OptimizeSize>::type hook_type;
135 typedef T value_type;
136 typedef typename tree_internal_data_type<T>::type internal_type;
137
138 typedef tree_node< T, VoidPointer
139 , tree_type_value, OptimizeSize> node_t;
140
141 BOOST_CONTAINER_FORCEINLINE T &get_data()
142 {
143 T* ptr = reinterpret_cast<T*>(&this->m_data);
144 return *ptr;
145 }
146
147 BOOST_CONTAINER_FORCEINLINE const T &get_data() const
148 {
149 const T* ptr = reinterpret_cast<const T*>(&this->m_data);
150 return *ptr;
151 }
152
153 internal_type m_data;
154
155 template<class T1, class T2>
156 BOOST_CONTAINER_FORCEINLINE void do_assign(const std::pair<const T1, T2> &p)
157 {
158 const_cast<T1&>(m_data.first) = p.first;
159 m_data.second = p.second;
160 }
161
162 template<class T1, class T2>
163 BOOST_CONTAINER_FORCEINLINE void do_assign(const pair<const T1, T2> &p)
164 {
165 const_cast<T1&>(m_data.first) = p.first;
166 m_data.second = p.second;
167 }
168
169 template<class V>
170 BOOST_CONTAINER_FORCEINLINE void do_assign(const V &v)
171 { m_data = v; }
172
173 template<class T1, class T2>
174 BOOST_CONTAINER_FORCEINLINE void do_move_assign(std::pair<const T1, T2> &p)
175 {
176 const_cast<T1&>(m_data.first) = ::boost::move(p.first);
177 m_data.second = ::boost::move(p.second);
178 }
179
180 template<class T1, class T2>
181 BOOST_CONTAINER_FORCEINLINE void do_move_assign(pair<const T1, T2> &p)
182 {
183 const_cast<T1&>(m_data.first) = ::boost::move(p.first);
184 m_data.second = ::boost::move(p.second);
185 }
186
187 template<class V>
188 BOOST_CONTAINER_FORCEINLINE void do_move_assign(V &v)
189 { m_data = ::boost::move(v); }
190};
191
192template <class T, class VoidPointer, boost::container::tree_type_enum tree_type_value, bool OptimizeSize>
193struct iiterator_node_value_type< tree_node<T, VoidPointer, tree_type_value, OptimizeSize> > {
194 typedef T type;
195};
196
197template<class Node, class Icont>
198class insert_equal_end_hint_functor
199{
200 Icont &icont_;
201
202 public:
203 BOOST_CONTAINER_FORCEINLINE insert_equal_end_hint_functor(Icont &icont)
204 : icont_(icont)
205 {}
206
207 BOOST_CONTAINER_FORCEINLINE void operator()(Node &n)
208 { this->icont_.insert_equal(this->icont_.cend(), n); }
209};
210
211template<class Node, class Icont>
212class push_back_functor
213{
214 Icont &icont_;
215
216 public:
217 BOOST_CONTAINER_FORCEINLINE push_back_functor(Icont &icont)
218 : icont_(icont)
219 {}
220
221 BOOST_CONTAINER_FORCEINLINE void operator()(Node &n)
222 { this->icont_.push_back(n); }
223};
224
225}//namespace dtl {
226
227namespace dtl {
228
229template< class NodeType, class NodeCompareType
230 , class SizeType, class HookType
231 , boost::container::tree_type_enum tree_type_value>
232struct intrusive_tree_dispatch;
233
234template<class NodeType, class NodeCompareType, class SizeType, class HookType>
235struct intrusive_tree_dispatch
236 <NodeType, NodeCompareType, SizeType, HookType, boost::container::red_black_tree>
237{
238 typedef typename dtl::bi::make_rbtree
239 <NodeType
240 ,dtl::bi::compare<NodeCompareType>
241 ,dtl::bi::base_hook<HookType>
242 ,dtl::bi::constant_time_size<true>
243 ,dtl::bi::size_type<SizeType>
244 >::type type;
245};
246
247template<class NodeType, class NodeCompareType, class SizeType, class HookType>
248struct intrusive_tree_dispatch
249 <NodeType, NodeCompareType, SizeType, HookType, boost::container::avl_tree>
250{
251 typedef typename dtl::bi::make_avltree
252 <NodeType
253 ,dtl::bi::compare<NodeCompareType>
254 ,dtl::bi::base_hook<HookType>
255 ,dtl::bi::constant_time_size<true>
256 ,dtl::bi::size_type<SizeType>
257 >::type type;
258};
259
260template<class NodeType, class NodeCompareType, class SizeType, class HookType>
261struct intrusive_tree_dispatch
262 <NodeType, NodeCompareType, SizeType, HookType, boost::container::scapegoat_tree>
263{
264 typedef typename dtl::bi::make_sgtree
265 <NodeType
266 ,dtl::bi::compare<NodeCompareType>
267 ,dtl::bi::base_hook<HookType>
268 ,dtl::bi::floating_point<true>
269 ,dtl::bi::size_type<SizeType>
270 >::type type;
271};
272
273template<class NodeType, class NodeCompareType, class SizeType, class HookType>
274struct intrusive_tree_dispatch
275 <NodeType, NodeCompareType, SizeType, HookType, boost::container::splay_tree>
276{
277 typedef typename dtl::bi::make_splaytree
278 <NodeType
279 ,dtl::bi::compare<NodeCompareType>
280 ,dtl::bi::base_hook<HookType>
281 ,dtl::bi::constant_time_size<true>
282 ,dtl::bi::size_type<SizeType>
283 >::type type;
284};
285
286template<class Allocator, class ValueCompare, boost::container::tree_type_enum tree_type_value, bool OptimizeSize>
287struct intrusive_tree_type
288{
289 private:
290 typedef typename boost::container::
291 allocator_traits<Allocator>::value_type value_type;
292 typedef typename boost::container::
293 allocator_traits<Allocator>::void_pointer void_pointer;
294 typedef typename boost::container::
295 allocator_traits<Allocator>::size_type size_type;
296 typedef typename dtl::tree_node
297 < value_type, void_pointer
298 , tree_type_value, OptimizeSize> node_t;
299 typedef value_to_node_compare
300 <node_t, ValueCompare> node_compare_type;
301 //Deducing the hook type from node_t (e.g. node_t::hook_type) would
302 //provoke an early instantiation of node_t that could ruin recursive
303 //tree definitions, so retype the complete type to avoid any problem.
304 typedef typename intrusive_tree_hook
305 <void_pointer, tree_type_value
306 , OptimizeSize>::type hook_type;
307 public:
308 typedef typename intrusive_tree_dispatch
309 < node_t, node_compare_type
310 , size_type, hook_type
311 , tree_type_value>::type type;
312};
313
314//Trait to detect manually rebalanceable tree types
315template<boost::container::tree_type_enum tree_type_value>
316struct is_manually_balanceable
317{ static const bool value = true; };
318
319template<> struct is_manually_balanceable<red_black_tree>
320{ static const bool value = false; };
321
322template<> struct is_manually_balanceable<avl_tree>
323{ static const bool value = false; };
324
325//Proxy traits to implement different operations depending on the
326//is_manually_balanceable<>::value
327template< boost::container::tree_type_enum tree_type_value
328 , bool IsManuallyRebalanceable = is_manually_balanceable<tree_type_value>::value>
329struct intrusive_tree_proxy
330{
331 template<class Icont>
332 BOOST_CONTAINER_FORCEINLINE static void rebalance(Icont &) {}
333};
334
335template<boost::container::tree_type_enum tree_type_value>
336struct intrusive_tree_proxy<tree_type_value, true>
337{
338 template<class Icont>
339 BOOST_CONTAINER_FORCEINLINE static void rebalance(Icont &c)
340 { c.rebalance(); }
341};
342
343} //namespace dtl {
344
345namespace dtl {
346
347//This functor will be used with Intrusive clone functions to obtain
348//already allocated nodes from a intrusive container instead of
349//allocating new ones. When the intrusive container runs out of nodes
350//the node holder is used instead.
351template<class AllocHolder, bool DoMove>
352class RecyclingCloner
353{
354 typedef typename AllocHolder::intrusive_container intrusive_container;
355 typedef typename AllocHolder::Node node_t;
356 typedef typename AllocHolder::NodePtr node_ptr_type;
357
358 public:
359 RecyclingCloner(AllocHolder &holder, intrusive_container &itree)
360 : m_holder(holder), m_icont(itree)
361 {}
362
363 BOOST_CONTAINER_FORCEINLINE static void do_assign(node_ptr_type &p, const node_t &other, bool_<true>)
364 { p->do_move_assign(const_cast<node_t &>(other).m_data); }
365
366 BOOST_CONTAINER_FORCEINLINE static void do_assign(node_ptr_type &p, const node_t &other, bool_<false>)
367 { p->do_assign(other.m_data); }
368
369 node_ptr_type operator()(const node_t &other) const
370 {
371 if(node_ptr_type p = m_icont.unlink_leftmost_without_rebalance()){
372 //First recycle a node (this can't throw)
373 BOOST_TRY{
374 //This can throw
375 this->do_assign(p, other, bool_<DoMove>());
376 return p;
377 }
378 BOOST_CATCH(...){
379 //If there is an exception destroy the whole source
380 m_holder.destroy_node(p);
381 while((p = m_icont.unlink_leftmost_without_rebalance())){
382 m_holder.destroy_node(p);
383 }
384 BOOST_RETHROW
385 }
386 BOOST_CATCH_END
387 }
388 else{
389 return m_holder.create_node(other.m_data);
390 }
391 }
392
393 AllocHolder &m_holder;
394 intrusive_container &m_icont;
395};
396
397
398template<class KeyCompare, class KeyOfValue>
399struct key_node_compare
400 : public boost::intrusive::detail::ebo_functor_holder<KeyCompare>
401{
402 BOOST_CONTAINER_FORCEINLINE explicit key_node_compare(const KeyCompare &comp)
403 : base_t(comp)
404 {}
405
406 typedef boost::intrusive::detail::ebo_functor_holder<KeyCompare> base_t;
407 typedef KeyCompare key_compare;
408 typedef KeyOfValue key_of_value;
409 typedef typename KeyOfValue::type key_type;
410
411
412 template <class T, class VoidPointer, boost::container::tree_type_enum tree_type_value, bool OptimizeSize>
413 BOOST_CONTAINER_FORCEINLINE static const key_type &
414 key_from(const tree_node<T, VoidPointer, tree_type_value, OptimizeSize> &n)
415 {
416 return key_of_value()(n.get_data());
417 }
418
419 template <class T>
420 BOOST_CONTAINER_FORCEINLINE static const T &
421 key_from(const T &t)
422 {
423 return t;
424 }
425
426 BOOST_CONTAINER_FORCEINLINE const key_compare &key_comp() const
427 { return static_cast<const key_compare &>(*this); }
428
429 BOOST_CONTAINER_FORCEINLINE key_compare &key_comp()
430 { return static_cast<key_compare &>(*this); }
431
432 BOOST_CONTAINER_FORCEINLINE bool operator()(const key_type &key1, const key_type &key2) const
433 { return this->key_comp()(key1, key2); }
434
435 template<class U>
436 BOOST_CONTAINER_FORCEINLINE bool operator()(const key_type &key1, const U &nonkey2) const
437 { return this->key_comp()(key1, this->key_from(nonkey2)); }
438
439 template<class U>
440 BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const key_type &key2) const
441 { return this->key_comp()(this->key_from(nonkey1), key2); }
442
443 template<class U, class V>
444 BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const V &nonkey2) const
445 { return this->key_comp()(this->key_from(nonkey1), this->key_from(nonkey2)); }
446};
447
448template<class Options>
449struct get_tree_opt
450{
451 typedef Options type;
452};
453
454template<>
455struct get_tree_opt<void>
456{
457 typedef tree_assoc_defaults type;
458};
459
460template <class T, class KeyOfValue, class Compare, class Allocator, class Options>
461class tree
462 : public dtl::node_alloc_holder
463 < Allocator
464 , typename dtl::intrusive_tree_type
465 < Allocator, tree_value_compare
466 <typename allocator_traits<Allocator>::pointer, Compare, KeyOfValue>
467 , get_tree_opt<Options>::type::tree_type
468 , get_tree_opt<Options>::type::optimize_size
469 >::type
470 >
471{
472 typedef tree_value_compare
473 < typename allocator_traits<Allocator>::pointer
474 , Compare, KeyOfValue> ValComp;
475 typedef typename get_tree_opt<Options>::type options_type;
476 typedef typename dtl::intrusive_tree_type
477 < Allocator, ValComp
478 , options_type::tree_type
479 , options_type::optimize_size
480 >::type Icont;
481 typedef dtl::node_alloc_holder
482 <Allocator, Icont> AllocHolder;
483 typedef typename AllocHolder::NodePtr NodePtr;
484 typedef tree < T, KeyOfValue
485 , Compare, Allocator, Options> ThisType;
486 typedef typename AllocHolder::NodeAlloc NodeAlloc;
487 typedef boost::container::
488 allocator_traits<NodeAlloc> allocator_traits_type;
489 typedef typename AllocHolder::ValAlloc ValAlloc;
490 typedef typename AllocHolder::Node Node;
491 typedef typename Icont::iterator iiterator;
492 typedef typename Icont::const_iterator iconst_iterator;
493 typedef dtl::allocator_destroyer<NodeAlloc> Destroyer;
494 typedef typename AllocHolder::alloc_version alloc_version;
495 typedef intrusive_tree_proxy<options_type::tree_type> intrusive_tree_proxy_t;
496
497 BOOST_COPYABLE_AND_MOVABLE(tree)
498
499 public:
500
501 typedef typename KeyOfValue::type key_type;
502 typedef T value_type;
503 typedef Allocator allocator_type;
504 typedef Compare key_compare;
505 typedef ValComp value_compare;
506 typedef typename boost::container::
507 allocator_traits<Allocator>::pointer pointer;
508 typedef typename boost::container::
509 allocator_traits<Allocator>::const_pointer const_pointer;
510 typedef typename boost::container::
511 allocator_traits<Allocator>::reference reference;
512 typedef typename boost::container::
513 allocator_traits<Allocator>::const_reference const_reference;
514 typedef typename boost::container::
515 allocator_traits<Allocator>::size_type size_type;
516 typedef typename boost::container::
517 allocator_traits<Allocator>::difference_type difference_type;
518 typedef dtl::iterator_from_iiterator
519 <iiterator, false> iterator;
520 typedef dtl::iterator_from_iiterator
521 <iiterator, true > const_iterator;
522 typedef boost::container::reverse_iterator
523 <iterator> reverse_iterator;
524 typedef boost::container::reverse_iterator
525 <const_iterator> const_reverse_iterator;
526 typedef node_handle
527 < NodeAlloc, void> node_type;
528 typedef insert_return_type_base
529 <iterator, node_type> insert_return_type;
530
531 typedef NodeAlloc stored_allocator_type;
532
533 private:
534
535 typedef key_node_compare<key_compare, KeyOfValue> KeyNodeCompare;
536
537 public:
538
539 BOOST_CONTAINER_FORCEINLINE tree()
540 : AllocHolder()
541 {}
542
543 BOOST_CONTAINER_FORCEINLINE explicit tree(const key_compare& comp)
544 : AllocHolder(ValComp(comp))
545 {}
546
547 BOOST_CONTAINER_FORCEINLINE explicit tree(const key_compare& comp, const allocator_type& a)
548 : AllocHolder(ValComp(comp), a)
549 {}
550
551 BOOST_CONTAINER_FORCEINLINE explicit tree(const allocator_type& a)
552 : AllocHolder(a)
553 {}
554
555 template <class InputIterator>
556 tree(bool unique_insertion, InputIterator first, InputIterator last)
557 : AllocHolder(value_compare(key_compare()))
558 {
559 this->tree_construct(unique_insertion, first, last);
560 //AllocHolder clears in case of exception
561 }
562
563 template <class InputIterator>
564 tree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp)
565 : AllocHolder(value_compare(comp))
566 {
567 this->tree_construct(unique_insertion, first, last);
568 //AllocHolder clears in case of exception
569 }
570
571 template <class InputIterator>
572 tree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, const allocator_type& a)
573 : AllocHolder(value_compare(comp), a)
574 {
575 this->tree_construct(unique_insertion, first, last);
576 //AllocHolder clears in case of exception
577 }
578
579 //construct with ordered range
580 template <class InputIterator>
581 tree( ordered_range_t, InputIterator first, InputIterator last)
582 : AllocHolder(value_compare(key_compare()))
583 {
584 this->tree_construct(ordered_range_t(), first, last);
585 }
586
587 template <class InputIterator>
588 tree( ordered_range_t, InputIterator first, InputIterator last, const key_compare& comp)
589 : AllocHolder(value_compare(comp))
590 {
591 this->tree_construct(ordered_range_t(), first, last);
592 }
593
594 template <class InputIterator>
595 tree( ordered_range_t, InputIterator first, InputIterator last
596 , const key_compare& comp, const allocator_type& a)
597 : AllocHolder(value_compare(comp), a)
598 {
599 this->tree_construct(ordered_range_t(), first, last);
600 }
601
602 private:
603
604 template <class InputIterator>
605 void tree_construct(bool unique_insertion, InputIterator first, InputIterator last)
606 {
607 //Use cend() as hint to achieve linear time for
608 //ordered ranges as required by the standard
609 //for the constructor
610 if(unique_insertion){
611 const const_iterator end_it(this->cend());
612 for ( ; first != last; ++first){
613 this->insert_unique_convertible(end_it, *first);
614 }
615 }
616 else{
617 this->tree_construct_non_unique(first, last);
618 }
619 }
620
621 template <class InputIterator>
622 void tree_construct_non_unique(InputIterator first, InputIterator last
623 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
624 , typename dtl::enable_if_or
625 < void
626 , dtl::is_same<alloc_version, version_1>
627 , dtl::is_input_iterator<InputIterator>
628 >::type * = 0
629 #endif
630 )
631 {
632 //Use cend() as hint to achieve linear time for
633 //ordered ranges as required by the standard
634 //for the constructor
635 const const_iterator end_it(this->cend());
636 for ( ; first != last; ++first){
637 this->insert_equal_convertible(end_it, *first);
638 }
639 }
640
641 template <class InputIterator>
642 void tree_construct_non_unique(InputIterator first, InputIterator last
643 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
644 , typename dtl::disable_if_or
645 < void
646 , dtl::is_same<alloc_version, version_1>
647 , dtl::is_input_iterator<InputIterator>
648 >::type * = 0
649 #endif
650 )
651 {
652 //Optimized allocation and construction
653 this->allocate_many_and_construct
654 ( first, boost::container::iterator_distance(first, last)
655 , insert_equal_end_hint_functor<Node, Icont>(this->icont()));
656 }
657
658 template <class InputIterator>
659 void tree_construct( ordered_range_t, InputIterator first, InputIterator last
660 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
661 , typename dtl::disable_if_or
662 < void
663 , dtl::is_same<alloc_version, version_1>
664 , dtl::is_input_iterator<InputIterator>
665 >::type * = 0
666 #endif
667 )
668 {
669 //Optimized allocation and construction
670 this->allocate_many_and_construct
671 ( first, boost::container::iterator_distance(first, last)
672 , dtl::push_back_functor<Node, Icont>(this->icont()));
673 //AllocHolder clears in case of exception
674 }
675
676 template <class InputIterator>
677 void tree_construct( ordered_range_t, InputIterator first, InputIterator last
678 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
679 , typename dtl::enable_if_or
680 < void
681 , dtl::is_same<alloc_version, version_1>
682 , dtl::is_input_iterator<InputIterator>
683 >::type * = 0
684 #endif
685 )
686 {
687 for ( ; first != last; ++first){
688 this->push_back_impl(*first);
689 }
690 }
691
692 public:
693
694 BOOST_CONTAINER_FORCEINLINE tree(const tree& x)
695 : AllocHolder(x, x.value_comp())
696 {
697 this->icont().clone_from
698 (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc()));
699 }
700
701 BOOST_CONTAINER_FORCEINLINE tree(BOOST_RV_REF(tree) x)
702 BOOST_NOEXCEPT_IF(boost::container::dtl::is_nothrow_move_constructible<Compare>::value)
703 : AllocHolder(BOOST_MOVE_BASE(AllocHolder, x), x.value_comp())
704 {}
705
706 BOOST_CONTAINER_FORCEINLINE tree(const tree& x, const allocator_type &a)
707 : AllocHolder(x.value_comp(), a)
708 {
709 this->icont().clone_from
710 (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc()));
711 //AllocHolder clears in case of exception
712 }
713
714 tree(BOOST_RV_REF(tree) x, const allocator_type &a)
715 : AllocHolder(x.value_comp(), a)
716 {
717 if(this->node_alloc() == x.node_alloc()){
718 this->icont().swap(x.icont());
719 }
720 else{
721 this->icont().clone_from
722 (boost::move(x.icont()), typename AllocHolder::move_cloner(*this), Destroyer(this->node_alloc()));
723 }
724 //AllocHolder clears in case of exception
725 }
726
727 BOOST_CONTAINER_FORCEINLINE ~tree()
728 {} //AllocHolder clears the tree
729
730 tree& operator=(BOOST_COPY_ASSIGN_REF(tree) x)
731 {
732 if (&x != this){
733 NodeAlloc &this_alloc = this->get_stored_allocator();
734 const NodeAlloc &x_alloc = x.get_stored_allocator();
735 dtl::bool_<allocator_traits<NodeAlloc>::
736 propagate_on_container_copy_assignment::value> flag;
737 if(flag && this_alloc != x_alloc){
738 this->clear();
739 }
740 this->AllocHolder::copy_assign_alloc(x);
741 //Transfer all the nodes to a temporary tree
742 //If anything goes wrong, all the nodes will be destroyed
743 //automatically
744 Icont other_tree(::boost::move(this->icont()));
745
746 //Now recreate the source tree reusing nodes stored by other_tree
747 this->icont().clone_from
748 (x.icont()
749 , RecyclingCloner<AllocHolder, false>(*this, other_tree)
750 , Destroyer(this->node_alloc()));
751
752 //If there are remaining nodes, destroy them
753 NodePtr p;
754 while((p = other_tree.unlink_leftmost_without_rebalance())){
755 AllocHolder::destroy_node(p);
756 }
757 }
758 return *this;
759 }
760
761 tree& operator=(BOOST_RV_REF(tree) x)
762 BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value ||
763 allocator_traits_type::is_always_equal::value) &&
764 boost::container::dtl::is_nothrow_move_assignable<Compare>::value)
765 {
766 BOOST_ASSERT(this != &x);
767 NodeAlloc &this_alloc = this->node_alloc();
768 NodeAlloc &x_alloc = x.node_alloc();
769 const bool propagate_alloc = allocator_traits<NodeAlloc>::
770 propagate_on_container_move_assignment::value;
771 const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
772 //Resources can be transferred if both allocators are
773 //going to be equal after this function (either propagated or already equal)
774 if(propagate_alloc || allocators_equal){
775 //Destroy
776 this->clear();
777 //Move allocator if needed
778 this->AllocHolder::move_assign_alloc(x);
779 //Obtain resources
780 this->icont() = boost::move(x.icont());
781 }
782 //Else do a one by one move
783 else{
784 //Transfer all the nodes to a temporary tree
785 //If anything goes wrong, all the nodes will be destroyed
786 //automatically
787 Icont other_tree(::boost::move(this->icont()));
788
789 //Now recreate the source tree reusing nodes stored by other_tree
790 this->icont().clone_from
791 (::boost::move(x.icont())
792 , RecyclingCloner<AllocHolder, true>(*this, other_tree)
793 , Destroyer(this->node_alloc()));
794
795 //If there are remaining nodes, destroy them
796 NodePtr p;
797 while((p = other_tree.unlink_leftmost_without_rebalance())){
798 AllocHolder::destroy_node(p);
799 }
800 }
801 return *this;
802 }
803
804 public:
805 // accessors:
806 BOOST_CONTAINER_FORCEINLINE value_compare value_comp() const
807 { return this->icont().value_comp().predicate(); }
808
809 BOOST_CONTAINER_FORCEINLINE key_compare key_comp() const
810 { return this->icont().value_comp().predicate().key_comp(); }
811
812 BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const
813 { return allocator_type(this->node_alloc()); }
814
815 BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const
816 { return this->node_alloc(); }
817
818 BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator()
819 { return this->node_alloc(); }
820
821 BOOST_CONTAINER_FORCEINLINE iterator begin()
822 { return iterator(this->icont().begin()); }
823
824 BOOST_CONTAINER_FORCEINLINE const_iterator begin() const
825 { return this->cbegin(); }
826
827 BOOST_CONTAINER_FORCEINLINE iterator end()
828 { return iterator(this->icont().end()); }
829
830 BOOST_CONTAINER_FORCEINLINE const_iterator end() const
831 { return this->cend(); }
832
833 BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin()
834 { return reverse_iterator(end()); }
835
836 BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const
837 { return this->crbegin(); }
838
839 BOOST_CONTAINER_FORCEINLINE reverse_iterator rend()
840 { return reverse_iterator(begin()); }
841
842 BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const
843 { return this->crend(); }
844
845 //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
846 //!
847 //! <b>Throws</b>: Nothing.
848 //!
849 //! <b>Complexity</b>: Constant.
850 BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const
851 { return const_iterator(this->non_const_icont().begin()); }
852
853 //! <b>Effects</b>: Returns a const_iterator to the end of the container.
854 //!
855 //! <b>Throws</b>: Nothing.
856 //!
857 //! <b>Complexity</b>: Constant.
858 BOOST_CONTAINER_FORCEINLINE const_iterator cend() const
859 { return const_iterator(this->non_const_icont().end()); }
860
861 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
862 //! of the reversed container.
863 //!
864 //! <b>Throws</b>: Nothing.
865 //!
866 //! <b>Complexity</b>: Constant.
867 BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const
868 { return const_reverse_iterator(cend()); }
869
870 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
871 //! of the reversed container.
872 //!
873 //! <b>Throws</b>: Nothing.
874 //!
875 //! <b>Complexity</b>: Constant.
876 BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const
877 { return const_reverse_iterator(cbegin()); }
878
879 BOOST_CONTAINER_FORCEINLINE bool empty() const
880 { return !this->size(); }
881
882 BOOST_CONTAINER_FORCEINLINE size_type size() const
883 { return this->icont().size(); }
884
885 BOOST_CONTAINER_FORCEINLINE size_type max_size() const
886 { return AllocHolder::max_size(); }
887
888 BOOST_CONTAINER_FORCEINLINE void swap(ThisType& x)
889 BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value
890 && boost::container::dtl::is_nothrow_swappable<Compare>::value )
891 { AllocHolder::swap(x); }
892
893 public:
894
895 typedef typename Icont::insert_commit_data insert_commit_data;
896
897 // insert/erase
898 std::pair<iterator,bool> insert_unique_check
899 (const key_type& key, insert_commit_data &data)
900 {
901 std::pair<iiterator, bool> ret =
902 this->icont().insert_unique_check(key, KeyNodeCompare(key_comp()), data);
903 return std::pair<iterator, bool>(iterator(ret.first), ret.second);
904 }
905
906 std::pair<iterator,bool> insert_unique_check
907 (const_iterator hint, const key_type& key, insert_commit_data &data)
908 {
909 BOOST_ASSERT((priv_is_linked)(hint));
910 std::pair<iiterator, bool> ret =
911 this->icont().insert_unique_check(hint.get(), key, KeyNodeCompare(key_comp()), data);
912 return std::pair<iterator, bool>(iterator(ret.first), ret.second);
913 }
914
915 template<class MovableConvertible>
916 iterator insert_unique_commit
917 (BOOST_FWD_REF(MovableConvertible) v, insert_commit_data &data)
918 {
919 NodePtr tmp = AllocHolder::create_node(boost::forward<MovableConvertible>(v));
920 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());
921 iterator ret(this->icont().insert_unique_commit(*tmp, data));
922 destroy_deallocator.release();
923 return ret;
924 }
925
926 template<class MovableConvertible>
927 std::pair<iterator,bool> insert_unique(BOOST_FWD_REF(MovableConvertible) v)
928 {
929 insert_commit_data data;
930 std::pair<iterator,bool> ret =
931 this->insert_unique_check(KeyOfValue()(v), data);
932 if(ret.second){
933 ret.first = this->insert_unique_commit(boost::forward<MovableConvertible>(v), data);
934 }
935 return ret;
936 }
937
938 private:
939
940 template<class KeyConvertible, class M>
941 iiterator priv_insert_or_assign_commit
942 (BOOST_FWD_REF(KeyConvertible) key, BOOST_FWD_REF(M) obj, insert_commit_data &data)
943 {
944 NodePtr tmp = AllocHolder::create_node(boost::forward<KeyConvertible>(key), boost::forward<M>(obj));
945 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());
946 iiterator ret(this->icont().insert_unique_commit(*tmp, data));
947 destroy_deallocator.release();
948 return ret;
949 }
950
951 bool priv_is_linked(const_iterator const position) const
952 {
953 iiterator const cur(position.get());
954 return cur == this->icont().end() ||
955 cur == this->icont().root() ||
956 iiterator(cur).go_parent().go_left() == cur ||
957 iiterator(cur).go_parent().go_right() == cur;
958 }
959
960 template<class MovableConvertible>
961 void push_back_impl(BOOST_FWD_REF(MovableConvertible) v)
962 {
963 NodePtr tmp(AllocHolder::create_node(boost::forward<MovableConvertible>(v)));
964 //push_back has no-throw guarantee so avoid any deallocator/destroyer
965 this->icont().push_back(*tmp);
966 }
967
968 std::pair<iterator, bool> emplace_unique_impl(NodePtr p)
969 {
970 value_type &v = p->get_data();
971 insert_commit_data data;
972 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(p, this->node_alloc());
973 std::pair<iterator,bool> ret =
974 this->insert_unique_check(KeyOfValue()(v), data);
975 if(!ret.second){
976 return ret;
977 }
978 //No throw insertion part, release rollback
979 destroy_deallocator.release();
980 return std::pair<iterator,bool>
981 ( iterator(this->icont().insert_unique_commit(*p, data))
982 , true );
983 }
984
985 iterator emplace_unique_hint_impl(const_iterator hint, NodePtr p)
986 {
987 BOOST_ASSERT((priv_is_linked)(hint));
988 value_type &v = p->get_data();
989 insert_commit_data data;
990 std::pair<iterator,bool> ret =
991 this->insert_unique_check(hint, KeyOfValue()(v), data);
992 if(!ret.second){
993 Destroyer(this->node_alloc())(p);
994 return ret.first;
995 }
996 return iterator(this->icont().insert_unique_commit(*p, data));
997 }
998
999 public:
1000
1001 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1002
1003 template <class... Args>
1004 BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> emplace_unique(BOOST_FWD_REF(Args)... args)
1005 { return this->emplace_unique_impl(AllocHolder::create_node(boost::forward<Args>(args)...)); }
1006
1007 template <class... Args>
1008 BOOST_CONTAINER_FORCEINLINE iterator emplace_hint_unique(const_iterator hint, BOOST_FWD_REF(Args)... args)
1009 { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(boost::forward<Args>(args)...)); }
1010
1011 template <class... Args>
1012 iterator emplace_equal(BOOST_FWD_REF(Args)... args)
1013 {
1014 NodePtr tmp(AllocHolder::create_node(boost::forward<Args>(args)...));
1015 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());
1016 iterator ret(this->icont().insert_equal(this->icont().end(), *tmp));
1017 destroy_deallocator.release();
1018 return ret;
1019 }
1020
1021 template <class... Args>
1022 iterator emplace_hint_equal(const_iterator hint, BOOST_FWD_REF(Args)... args)
1023 {
1024 BOOST_ASSERT((priv_is_linked)(hint));
1025 NodePtr tmp(AllocHolder::create_node(boost::forward<Args>(args)...));
1026 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());
1027 iterator ret(this->icont().insert_equal(hint.get(), *tmp));
1028 destroy_deallocator.release();
1029 return ret;
1030 }
1031
1032 template <class KeyType, class... Args>
1033 BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> try_emplace
1034 (const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(Args)... args)
1035 {
1036 insert_commit_data data;
1037 const key_type & k = key; //Support emulated rvalue references
1038 std::pair<iiterator, bool> ret =
1039 hint == const_iterator() ? this->icont().insert_unique_check( k, KeyNodeCompare(key_comp()), data)
1040 : this->icont().insert_unique_check(hint.get(), k, KeyNodeCompare(key_comp()), data);
1041 if(ret.second){
1042 ret.first = this->icont().insert_unique_commit
1043 (*AllocHolder::create_node(try_emplace_t(), boost::forward<KeyType>(key), boost::forward<Args>(args)...), data);
1044 }
1045 return std::pair<iterator, bool>(iterator(ret.first), ret.second);
1046 }
1047
1048 #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1049
1050 #define BOOST_CONTAINER_TREE_EMPLACE_CODE(N) \
1051 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1052 std::pair<iterator, bool> emplace_unique(BOOST_MOVE_UREF##N)\
1053 { return this->emplace_unique_impl(AllocHolder::create_node(BOOST_MOVE_FWD##N)); }\
1054 \
1055 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1056 iterator emplace_hint_unique(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1057 { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(BOOST_MOVE_FWD##N)); }\
1058 \
1059 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1060 iterator emplace_equal(BOOST_MOVE_UREF##N)\
1061 {\
1062 NodePtr tmp(AllocHolder::create_node(BOOST_MOVE_FWD##N));\
1063 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());\
1064 iterator ret(this->icont().insert_equal(this->icont().end(), *tmp));\
1065 destroy_deallocator.release();\
1066 return ret;\
1067 }\
1068 \
1069 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1070 iterator emplace_hint_equal(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1071 {\
1072 BOOST_ASSERT((priv_is_linked)(hint));\
1073 NodePtr tmp(AllocHolder::create_node(BOOST_MOVE_FWD##N));\
1074 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());\
1075 iterator ret(this->icont().insert_equal(hint.get(), *tmp));\
1076 destroy_deallocator.release();\
1077 return ret;\
1078 }\
1079 \
1080 template <class KeyType BOOST_MOVE_I##N BOOST_MOVE_CLASS##N>\
1081 BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool>\
1082 try_emplace(const_iterator hint, BOOST_FWD_REF(KeyType) key BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1083 {\
1084 insert_commit_data data;\
1085 const key_type & k = key;\
1086 std::pair<iiterator, bool> ret =\
1087 hint == const_iterator() ? this->icont().insert_unique_check( k, KeyNodeCompare(key_comp()), data)\
1088 : this->icont().insert_unique_check(hint.get(), k, KeyNodeCompare(key_comp()), data);\
1089 if(ret.second){\
1090 ret.first = this->icont().insert_unique_commit\
1091 (*AllocHolder::create_node(try_emplace_t(), boost::forward<KeyType>(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N), data);\
1092 }\
1093 return std::pair<iterator, bool>(iterator(ret.first), ret.second);\
1094 }\
1095 //
1096 BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_TREE_EMPLACE_CODE)
1097 #undef BOOST_CONTAINER_TREE_EMPLACE_CODE
1098
1099 #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1100
1101 template<class MovableConvertible>
1102 iterator insert_unique_convertible(const_iterator hint, BOOST_FWD_REF(MovableConvertible) v)
1103 {
1104 BOOST_ASSERT((priv_is_linked)(hint));
1105 insert_commit_data data;
1106 std::pair<iterator,bool> ret =
1107 this->insert_unique_check(hint, KeyOfValue()(v), data);
1108 if(!ret.second)
1109 return ret.first;
1110 return this->insert_unique_commit(boost::forward<MovableConvertible>(v), data);
1111 }
1112
1113 BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert_unique, value_type, iterator, this->insert_unique_convertible, const_iterator, const_iterator)
1114
1115 template <class InputIterator>
1116 void insert_unique(InputIterator first, InputIterator last)
1117 {
1118 for( ; first != last; ++first)
1119 this->insert_unique(*first);
1120 }
1121
1122 iterator insert_equal(const value_type& v)
1123 {
1124 NodePtr tmp(AllocHolder::create_node(v));
1125 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());
1126 iterator ret(this->icont().insert_equal(this->icont().end(), *tmp));
1127 destroy_deallocator.release();
1128 return ret;
1129 }
1130
1131 template<class MovableConvertible>
1132 iterator insert_equal(BOOST_FWD_REF(MovableConvertible) v)
1133 {
1134 NodePtr tmp(AllocHolder::create_node(boost::forward<MovableConvertible>(v)));
1135 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());
1136 iterator ret(this->icont().insert_equal(this->icont().end(), *tmp));
1137 destroy_deallocator.release();
1138 return ret;
1139 }
1140
1141 template<class MovableConvertible>
1142 iterator insert_equal_convertible(const_iterator hint, BOOST_FWD_REF(MovableConvertible) v)
1143 {
1144 BOOST_ASSERT((priv_is_linked)(hint));
1145 NodePtr tmp(AllocHolder::create_node(boost::forward<MovableConvertible>(v)));
1146 scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc());
1147 iterator ret(this->icont().insert_equal(hint.get(), *tmp));
1148 destroy_deallocator.release();
1149 return ret;
1150 }
1151
1152 BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert_equal, value_type, iterator, this->insert_equal_convertible, const_iterator, const_iterator)
1153
1154 template <class InputIterator>
1155 void insert_equal(InputIterator first, InputIterator last)
1156 {
1157 for( ; first != last; ++first)
1158 this->insert_equal(*first);
1159 }
1160
1161 template<class KeyType, class M>
1162 std::pair<iterator, bool> insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj)
1163 {
1164 insert_commit_data data;
1165 const key_type & k = key; //Support emulated rvalue references
1166 std::pair<iiterator, bool> ret =
1167 hint == const_iterator() ? this->icont().insert_unique_check(k, KeyNodeCompare(key_comp()), data)
1168 : this->icont().insert_unique_check(hint.get(), k, KeyNodeCompare(key_comp()), data);
1169 if(ret.second){
1170 ret.first = this->priv_insert_or_assign_commit(boost::forward<KeyType>(key), boost::forward<M>(obj), data);
1171 }
1172 else{
1173 ret.first->get_data().second = boost::forward<M>(obj);
1174 }
1175 return std::pair<iterator, bool>(iterator(ret.first), ret.second);
1176 }
1177
1178 iterator erase(const_iterator position)
1179 {
1180 BOOST_ASSERT(position != this->cend() && (priv_is_linked)(position));
1181 return iterator(this->icont().erase_and_dispose(position.get(), Destroyer(this->node_alloc())));
1182 }
1183
1184 BOOST_CONTAINER_FORCEINLINE size_type erase(const key_type& k)
1185 { return AllocHolder::erase_key(k, KeyNodeCompare(key_comp()), alloc_version()); }
1186
1187 iterator erase(const_iterator first, const_iterator last)
1188 {
1189 BOOST_ASSERT(first == last || (first != this->cend() && (priv_is_linked)(first)));
1190 BOOST_ASSERT(first == last || (priv_is_linked)(last));
1191 return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version()));
1192 }
1193
1194 node_type extract(const key_type& k)
1195 {
1196 iterator const it = this->find(k);
1197 if(this->end() != it){
1198 return this->extract(it);
1199 }
1200 return node_type();
1201 }
1202
1203 node_type extract(const_iterator position)
1204 {
1205 BOOST_ASSERT(position != this->cend() && (priv_is_linked)(position));
1206 iiterator const iit(position.get());
1207 this->icont().erase(iit);
1208 return node_type(iit.operator->(), this->node_alloc());
1209 }
1210
1211 insert_return_type insert_unique_node(BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh)
1212 {
1213 return this->insert_unique_node(this->end(), boost::move(nh));
1214 }
1215
1216 insert_return_type insert_unique_node(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh)
1217 {
1218 insert_return_type irt; //inserted == false, node.empty()
1219 if(!nh.empty()){
1220 insert_commit_data data;
1221 std::pair<iterator,bool> ret =
1222 this->insert_unique_check(hint, KeyOfValue()(nh.value()), data);
1223 if(ret.second){
1224 irt.inserted = true;
1225 irt.position = iterator(this->icont().insert_unique_commit(*nh.get(), data));
1226 nh.release();
1227 }
1228 else{
1229 irt.position = ret.first;
1230 irt.node = boost::move(nh);
1231 }
1232 }
1233 else{
1234 irt.position = this->end();
1235 }
1236 return BOOST_MOVE_RET(insert_return_type, irt);
1237 }
1238
1239 iterator insert_equal_node(BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh)
1240 {
1241 if(nh.empty()){
1242 return this->end();
1243 }
1244 else{
1245 NodePtr const p(nh.release());
1246 return iterator(this->icont().insert_equal(*p));
1247 }
1248 }
1249
1250 iterator insert_equal_node(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh)
1251 {
1252 if(nh.empty()){
1253 return this->end();
1254 }
1255 else{
1256 NodePtr const p(nh.release());
1257 return iterator(this->icont().insert_equal(hint.get(), *p));
1258 }
1259 }
1260
1261 template<class C2>
1262 BOOST_CONTAINER_FORCEINLINE void merge_unique(tree<T, KeyOfValue, C2, Allocator, Options>& source)
1263 { return this->icont().merge_unique(source.icont()); }
1264
1265 template<class C2>
1266 BOOST_CONTAINER_FORCEINLINE void merge_equal(tree<T, KeyOfValue, C2, Allocator, Options>& source)
1267 { return this->icont().merge_equal(source.icont()); }
1268 BOOST_CONTAINER_FORCEINLINE void clear()
1269 { AllocHolder::clear(alloc_version()); }
1270
1271 // search operations. Const and non-const overloads even if no iterator is returned
1272 // so splay implementations can to their rebalancing when searching in non-const versions
1273 BOOST_CONTAINER_FORCEINLINE iterator find(const key_type& k)
1274 { return iterator(this->icont().find(k, KeyNodeCompare(key_comp()))); }
1275
1276 BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& k) const
1277 { return const_iterator(this->non_const_icont().find(k, KeyNodeCompare(key_comp()))); }
1278
1279 template <class K>
1280 BOOST_CONTAINER_FORCEINLINE
1281 typename dtl::enable_if_transparent<key_compare, K, iterator>::type
1282 find(const K& k)
1283 { return iterator(this->icont().find(k, KeyNodeCompare(key_comp()))); }
1284
1285 template <class K>
1286 BOOST_CONTAINER_FORCEINLINE
1287 typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
1288 find(const K& k) const
1289 { return const_iterator(this->non_const_icont().find(k, KeyNodeCompare(key_comp()))); }
1290
1291 BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& k) const
1292 { return size_type(this->icont().count(k, KeyNodeCompare(key_comp()))); }
1293
1294 template <class K>
1295 BOOST_CONTAINER_FORCEINLINE
1296 typename dtl::enable_if_transparent<key_compare, K, size_type>::type
1297 count(const K& k) const
1298 { return size_type(this->icont().count(k, KeyNodeCompare(key_comp()))); }
1299
1300 BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k)
1301 { return iterator(this->icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
1302
1303 BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& k) const
1304 { return const_iterator(this->non_const_icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
1305
1306 template <class K>
1307 BOOST_CONTAINER_FORCEINLINE
1308 typename dtl::enable_if_transparent<key_compare, K, iterator>::type
1309 lower_bound(const K& k)
1310 { return iterator(this->icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
1311
1312 template <class K>
1313 BOOST_CONTAINER_FORCEINLINE
1314 typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
1315 lower_bound(const K& k) const
1316 { return const_iterator(this->non_const_icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
1317
1318 BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& k)
1319 { return iterator(this->icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
1320
1321 BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const
1322 { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
1323
1324 template <class K>
1325 BOOST_CONTAINER_FORCEINLINE
1326 typename dtl::enable_if_transparent<key_compare, K, iterator>::type
1327 upper_bound(const K& k)
1328 { return iterator(this->icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
1329
1330 template <class K>
1331 BOOST_CONTAINER_FORCEINLINE
1332 typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
1333 upper_bound(const K& k) const
1334 { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
1335
1336 std::pair<iterator,iterator> equal_range(const key_type& k)
1337 {
1338 std::pair<iiterator, iiterator> ret =
1339 this->icont().equal_range(k, KeyNodeCompare(key_comp()));
1340 return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second));
1341 }
1342
1343 std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
1344 {
1345 std::pair<iiterator, iiterator> ret =
1346 this->non_const_icont().equal_range(k, KeyNodeCompare(key_comp()));
1347 return std::pair<const_iterator,const_iterator>
1348 (const_iterator(ret.first), const_iterator(ret.second));
1349 }
1350
1351 template <class K>
1352 BOOST_CONTAINER_FORCEINLINE
1353 typename dtl::enable_if_transparent<key_compare, K, std::pair<iterator,iterator> >::type
1354 equal_range(const K& k)
1355 {
1356 std::pair<iiterator, iiterator> ret =
1357 this->icont().equal_range(k, KeyNodeCompare(key_comp()));
1358 return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second));
1359 }
1360
1361 template <class K>
1362 BOOST_CONTAINER_FORCEINLINE
1363 typename dtl::enable_if_transparent<key_compare, K, std::pair<const_iterator, const_iterator> >::type
1364 equal_range(const K& k) const
1365 {
1366 std::pair<iiterator, iiterator> ret =
1367 this->non_const_icont().equal_range(k, KeyNodeCompare(key_comp()));
1368 return std::pair<const_iterator,const_iterator>
1369 (const_iterator(ret.first), const_iterator(ret.second));
1370 }
1371
1372 std::pair<iterator,iterator> lower_bound_range(const key_type& k)
1373 {
1374 std::pair<iiterator, iiterator> ret =
1375 this->icont().lower_bound_range(k, KeyNodeCompare(key_comp()));
1376 return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second));
1377 }
1378
1379 std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const
1380 {
1381 std::pair<iiterator, iiterator> ret =
1382 this->non_const_icont().lower_bound_range(k, KeyNodeCompare(key_comp()));
1383 return std::pair<const_iterator,const_iterator>
1384 (const_iterator(ret.first), const_iterator(ret.second));
1385 }
1386
1387 template <class K>
1388 BOOST_CONTAINER_FORCEINLINE
1389 typename dtl::enable_if_transparent<key_compare, K, std::pair<iterator,iterator> >::type
1390 lower_bound_range(const K& k)
1391 {
1392 std::pair<iiterator, iiterator> ret =
1393 this->icont().lower_bound_range(k, KeyNodeCompare(key_comp()));
1394 return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second));
1395 }
1396
1397 template <class K>
1398 BOOST_CONTAINER_FORCEINLINE
1399 typename dtl::enable_if_transparent<key_compare, K, std::pair<const_iterator, const_iterator> >::type
1400 lower_bound_range(const K& k) const
1401 {
1402 std::pair<iiterator, iiterator> ret =
1403 this->non_const_icont().lower_bound_range(k, KeyNodeCompare(key_comp()));
1404 return std::pair<const_iterator,const_iterator>
1405 (const_iterator(ret.first), const_iterator(ret.second));
1406 }
1407
1408 BOOST_CONTAINER_FORCEINLINE void rebalance()
1409 { intrusive_tree_proxy_t::rebalance(this->icont()); }
1410
1411 BOOST_CONTAINER_FORCEINLINE friend bool operator==(const tree& x, const tree& y)
1412 { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); }
1413
1414 BOOST_CONTAINER_FORCEINLINE friend bool operator<(const tree& x, const tree& y)
1415 { return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
1416
1417 BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const tree& x, const tree& y)
1418 { return !(x == y); }
1419
1420 BOOST_CONTAINER_FORCEINLINE friend bool operator>(const tree& x, const tree& y)
1421 { return y < x; }
1422
1423 BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const tree& x, const tree& y)
1424 { return !(y < x); }
1425
1426 BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const tree& x, const tree& y)
1427 { return !(x < y); }
1428
1429 BOOST_CONTAINER_FORCEINLINE friend void swap(tree& x, tree& y)
1430 { x.swap(y); }
1431};
1432
1433} //namespace dtl {
1434} //namespace container {
1435
1436template <class T>
1437struct has_trivial_destructor_after_move;
1438
1439//!has_trivial_destructor_after_move<> == true_type
1440//!specialization for optimizations
1441template <class T, class KeyOfValue, class Compare, class Allocator, class Options>
1442struct has_trivial_destructor_after_move
1443 <
1444 ::boost::container::dtl::tree
1445 <T, KeyOfValue, Compare, Allocator, Options>
1446 >
1447{
1448 typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
1449 static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value &&
1450 ::boost::has_trivial_destructor_after_move<pointer>::value &&
1451 ::boost::has_trivial_destructor_after_move<Compare>::value;
1452};
1453
1454} //namespace boost {
1455
1456#include <boost/container/detail/config_end.hpp>
1457
1458#endif //BOOST_CONTAINER_TREE_HPP