1 ////////////////////////////////////////////////////////////////////////////////
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)
7 // See http://www.boost.org/libs/container for documentation.
9 ////////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_CONTAINER_FLAT_TREE_HPP
12 #define BOOST_CONTAINER_FLAT_TREE_HPP
14 #ifndef BOOST_CONFIG_HPP
15 # include <boost/config.hpp>
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
22 #include <boost/container/detail/config_begin.hpp>
23 #include <boost/container/detail/workaround.hpp>
25 #include <boost/container/container_fwd.hpp>
27 #include <boost/move/utility_core.hpp>
29 #include <boost/container/detail/pair.hpp>
30 #include <boost/container/vector.hpp>
31 #include <boost/container/allocator_traits.hpp>
33 #include <boost/container/detail/value_init.hpp>
34 #include <boost/container/detail/destroyers.hpp>
35 #include <boost/container/detail/algorithm.hpp> //algo_equal(), algo_lexicographical_compare
36 #include <boost/container/detail/iterator.hpp>
37 #include <boost/container/detail/is_sorted.hpp>
38 #include <boost/container/detail/type_traits.hpp>
39 #include <boost/container/detail/iterators.hpp>
40 #include <boost/container/detail/mpl.hpp>
41 #include <boost/container/detail/is_contiguous_container.hpp>
42 #include <boost/container/detail/is_container.hpp>
44 #include <boost/intrusive/detail/minimal_pair_header.hpp> //pair
46 #include <boost/move/make_unique.hpp>
47 #include <boost/move/iterator.hpp>
48 #include <boost/move/adl_move_swap.hpp>
49 #include <boost/move/algo/adaptive_sort.hpp>
50 #include <boost/move/algo/detail/pdqsort.hpp>
52 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
53 #include <boost/move/detail/fwd_macros.hpp>
56 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
59 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME merge_unique
60 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
61 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
62 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 3
63 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 3
64 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
67 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME merge
68 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
69 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
70 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 3
71 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 3
72 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
75 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME index_of
76 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
77 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
78 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1
79 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1
80 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
83 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME nth
84 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
85 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
86 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1
87 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1
88 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
91 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME reserve
92 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
93 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
94 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1
95 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1
96 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
99 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME capacity
100 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
101 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
102 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0
103 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0
104 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
106 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
109 namespace container {
112 ///////////////////////////////////////
114 // Helper functions to merge elements
116 ///////////////////////////////////////
118 BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(stored_allocator_type)
120 ///////////////////////////////////////
122 // flat_tree_container_inplace_merge
124 ///////////////////////////////////////
125 template<class SequenceContainer, class Compare>
126 void flat_tree_container_inplace_merge //is_contiguous_container == true
127 (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::true_)
129 typedef typename SequenceContainer::value_type value_type;
130 value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin());
131 value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
132 value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
133 boost::movelib::adaptive_merge(braw, iraw, eraw, comp, eraw, dest.capacity()- dest.size());
136 template<class SequenceContainer, class Compare>
137 void flat_tree_container_inplace_merge //is_contiguous_container == false
138 (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::false_)
140 boost::movelib::adaptive_merge(dest.begin(), it, dest.end(), comp);
143 ///////////////////////////////////////
145 // flat_tree_container_inplace_sort_ending
147 ///////////////////////////////////////
148 template<class SequenceContainer, class Compare>
149 void flat_tree_container_inplace_sort_ending //is_contiguous_container == true
150 (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::true_)
152 typedef typename SequenceContainer::value_type value_type;
153 value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
154 value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
155 boost::movelib::adaptive_sort(iraw, eraw, comp, eraw, dest.capacity()- dest.size());
158 template<class SequenceContainer, class Compare>
159 void flat_tree_container_inplace_sort_ending //is_contiguous_container == false
160 (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::false_)
162 boost::movelib::adaptive_sort(it, dest.end(), comp);
165 ///////////////////////////////////////
169 ///////////////////////////////////////
170 template<class SequenceContainer, class Iterator, class Compare>
171 BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal
172 (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_)
174 dest.merge(first, last, comp);
177 template<class SequenceContainer, class Iterator, class Compare>
178 BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal //has_merge_unique == false
179 (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_)
181 typedef typename SequenceContainer::iterator iterator;
182 iterator const it = dest.insert( dest.end(), first, last );
183 dtl::bool_<is_contiguous_container<SequenceContainer>::value> contiguous_tag;
184 (flat_tree_container_inplace_merge)(dest, it, comp, contiguous_tag);
187 ///////////////////////////////////////
189 // flat_tree_merge_unique
191 ///////////////////////////////////////
192 template<class SequenceContainer, class Iterator, class Compare>
193 BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == true
194 (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_)
196 dest.merge_unique(first, last, comp);
199 template<class SequenceContainer, class Iterator, class Compare>
200 BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == false
201 (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_)
203 typedef typename SequenceContainer::iterator iterator;
204 typedef typename SequenceContainer::size_type size_type;
206 size_type const old_sz = dest.size();
207 iterator const first_new = dest.insert(dest.cend(), first, last );
208 iterator e = boost::movelib::inplace_set_unique_difference(first_new, dest.end(), dest.begin(), first_new, comp);
209 dest.erase(e, dest.end());
210 dtl::bool_<is_contiguous_container<SequenceContainer>::value> contiguous_tag;
211 (flat_tree_container_inplace_merge)(dest, dest.begin()+old_sz, comp, contiguous_tag);
214 ///////////////////////////////////////
216 // flat_tree_index_of
218 ///////////////////////////////////////
219 template<class SequenceContainer, class Iterator>
220 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
221 flat_tree_index_of // has_index_of == true
222 (SequenceContainer& cont, Iterator p, dtl::true_)
224 return cont.index_of(p);
227 template<class SequenceContainer, class Iterator>
228 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
229 flat_tree_index_of // has_index_of == false
230 (SequenceContainer& cont, Iterator p, dtl::false_)
232 typedef typename SequenceContainer::size_type size_type;
233 return static_cast<size_type>(p - cont.begin());
236 ///////////////////////////////////////
240 ///////////////////////////////////////
241 template<class Iterator, class SequenceContainer>
242 BOOST_CONTAINER_FORCEINLINE Iterator
243 flat_tree_nth // has_nth == true
244 (SequenceContainer& cont, typename SequenceContainer::size_type n, dtl::true_)
249 template<class Iterator, class SequenceContainer>
250 BOOST_CONTAINER_FORCEINLINE Iterator
251 flat_tree_nth // has_nth == false
252 (SequenceContainer& cont, typename SequenceContainer::size_type n, dtl::false_)
254 return cont.begin()+ n;
257 ///////////////////////////////////////
259 // flat_tree_get_stored_allocator
261 ///////////////////////////////////////
262 template<class SequenceContainer>
263 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::stored_allocator_type &
264 flat_tree_get_stored_allocator // has_get_stored_allocator == true
265 (SequenceContainer& cont, dtl::true_)
267 return cont.get_stored_allocator();
270 template<class SequenceContainer>
271 BOOST_CONTAINER_FORCEINLINE const typename SequenceContainer::stored_allocator_type &
272 flat_tree_get_stored_allocator // has_get_stored_allocator == true
273 (const SequenceContainer& cont, dtl::true_)
275 return cont.get_stored_allocator();
278 template<class SequenceContainer>
279 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::allocator_type
280 flat_tree_get_stored_allocator // has_get_stored_allocator == false
281 (SequenceContainer& cont, dtl::false_)
283 return cont.get_allocator();
286 ///////////////////////////////////////
288 // flat_tree_adopt_sequence_equal
290 ///////////////////////////////////////
291 template<class SequenceContainer, class Compare>
292 void flat_tree_sort_contiguous_to_adopt // is_contiguous_container == true
293 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp)
295 if(tseq.capacity() >= (seq.capacity() - seq.size())) {
297 boost::movelib::adaptive_sort
298 (boost::movelib::iterator_to_raw_pointer(seq.begin())
299 , boost::movelib::iterator_to_raw_pointer(seq.end())
301 , boost::movelib::iterator_to_raw_pointer(tseq.begin())
305 boost::movelib::adaptive_sort
306 (boost::movelib::iterator_to_raw_pointer(seq.begin())
307 , boost::movelib::iterator_to_raw_pointer(seq.end())
309 , boost::movelib::iterator_to_raw_pointer(seq.end())
310 , seq.capacity() - seq.size());
314 template<class SequenceContainer, class Compare>
315 void flat_tree_adopt_sequence_equal // is_contiguous_container == true
316 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_)
318 flat_tree_sort_contiguous_to_adopt(tseq, boost::move(seq), comp);
319 tseq = boost::move(seq);
322 template<class SequenceContainer, class Compare>
323 void flat_tree_adopt_sequence_equal // is_contiguous_container == false
324 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::false_)
326 boost::movelib::adaptive_sort(seq.begin(), seq.end(), comp);
327 tseq = boost::move(seq);
330 ///////////////////////////////////////
332 // flat_tree_adopt_sequence_unique
334 ///////////////////////////////////////
335 template<class SequenceContainer, class Compare>
336 void flat_tree_adopt_sequence_unique// is_contiguous_container == true
337 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_)
339 boost::movelib::pdqsort
340 ( boost::movelib::iterator_to_raw_pointer(seq.begin())
341 , boost::movelib::iterator_to_raw_pointer(seq.end())
343 seq.erase(boost::movelib::unique
344 (seq.begin(), seq.end(), boost::movelib::negate<Compare>(comp)), seq.cend());
345 tseq = boost::move(seq);
348 template<class SequenceContainer, class Compare>
349 void flat_tree_adopt_sequence_unique// is_contiguous_container == false
350 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::false_)
352 boost::movelib::pdqsort(seq.begin(), seq.end(), comp);
353 seq.erase(boost::movelib::unique
354 (seq.begin(), seq.end(), boost::movelib::negate<Compare>(comp)), seq.cend());
355 tseq = boost::move(seq);
358 ///////////////////////////////////////
362 ///////////////////////////////////////
363 template<class SequenceContainer>
364 BOOST_CONTAINER_FORCEINLINE void // has_reserve == true
365 flat_tree_reserve(SequenceContainer &tseq, typename SequenceContainer::size_type cap, dtl::true_)
370 template<class SequenceContainer>
371 BOOST_CONTAINER_FORCEINLINE void // has_reserve == false
372 flat_tree_reserve(SequenceContainer &, typename SequenceContainer::size_type, dtl::false_)
376 ///////////////////////////////////////
378 // flat_tree_capacity
380 ///////////////////////////////////////
381 template<class SequenceContainer> // has_capacity == true
382 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
383 flat_tree_capacity(const SequenceContainer &tseq, dtl::true_)
385 return tseq.capacity();
388 template<class SequenceContainer> // has_capacity == false
389 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
390 flat_tree_capacity(const SequenceContainer &tseq, dtl::false_)
395 ///////////////////////////////////////
397 // flat_tree_value_compare
399 ///////////////////////////////////////
401 template<class Compare, class Value, class KeyOfValue>
402 class flat_tree_value_compare
405 typedef Value first_argument_type;
406 typedef Value second_argument_type;
407 typedef bool return_type;
409 flat_tree_value_compare()
413 flat_tree_value_compare(const Compare &pred)
417 bool operator()(const Value& lhs, const Value& rhs) const
419 KeyOfValue key_extract;
420 return Compare::operator()(key_extract(lhs), key_extract(rhs));
423 const Compare &get_comp() const
431 ///////////////////////////////////////
433 // select_container_type
435 ///////////////////////////////////////
436 template < class Value, class AllocatorOrContainer
437 , bool = boost::container::dtl::is_container<AllocatorOrContainer>::value
439 struct select_container_type
441 typedef AllocatorOrContainer type;
444 template <class Value, class AllocatorOrContainer>
445 struct select_container_type<Value, AllocatorOrContainer, false>
447 typedef boost::container::vector<Value, typename real_allocator<Value, AllocatorOrContainer>::type> type;
451 ///////////////////////////////////////
455 ///////////////////////////////////////
456 template <class Value, class KeyOfValue,
457 class Compare, class AllocatorOrContainer>
461 typedef typename select_container_type<Value, AllocatorOrContainer>::type container_type;
462 typedef container_type sequence_type; //For backwards compatibility
465 typedef typename container_type::allocator_type allocator_t;
466 typedef allocator_traits<allocator_t> allocator_traits_type;
469 typedef flat_tree_value_compare<Compare, Value, KeyOfValue> value_compare;
474 //Inherit from value_compare to do EBO
475 : public value_compare
477 BOOST_COPYABLE_AND_MOVABLE(Data)
481 : value_compare(), m_seq()
484 explicit Data(const allocator_t &alloc)
485 : value_compare(), m_seq(alloc)
488 explicit Data(const Compare &comp)
489 : value_compare(comp), m_seq()
492 Data(const Compare &comp, const allocator_t &alloc)
493 : value_compare(comp), m_seq(alloc)
496 explicit Data(const Data &d)
497 : value_compare(static_cast<const value_compare&>(d)), m_seq(d.m_seq)
500 Data(BOOST_RV_REF(Data) d)
501 : value_compare(boost::move(static_cast<value_compare&>(d))), m_seq(boost::move(d.m_seq))
504 Data(const Data &d, const allocator_t &a)
505 : value_compare(static_cast<const value_compare&>(d)), m_seq(d.m_seq, a)
508 Data(BOOST_RV_REF(Data) d, const allocator_t &a)
509 : value_compare(boost::move(static_cast<value_compare&>(d))), m_seq(boost::move(d.m_seq), a)
512 Data& operator=(BOOST_COPY_ASSIGN_REF(Data) d)
514 this->value_compare::operator=(d);
519 Data& operator=(BOOST_RV_REF(Data) d)
521 this->value_compare::operator=(boost::move(static_cast<value_compare &>(d)));
522 m_seq = boost::move(d.m_seq);
528 value_compare& mycomp = *this, & othercomp = d;
529 boost::adl_move_swap(mycomp, othercomp);
530 this->m_seq.swap(d.m_seq);
533 container_type m_seq;
537 BOOST_COPYABLE_AND_MOVABLE(flat_tree)
541 typedef typename container_type::value_type value_type;
542 typedef typename container_type::pointer pointer;
543 typedef typename container_type::const_pointer const_pointer;
544 typedef typename container_type::reference reference;
545 typedef typename container_type::const_reference const_reference;
546 typedef typename KeyOfValue::type key_type;
547 typedef Compare key_compare;
548 typedef typename container_type::allocator_type allocator_type;
549 typedef typename container_type::size_type size_type;
550 typedef typename container_type::difference_type difference_type;
551 typedef typename container_type::iterator iterator;
552 typedef typename container_type::const_iterator const_iterator;
553 typedef typename container_type::reverse_iterator reverse_iterator;
554 typedef typename container_type::const_reverse_iterator const_reverse_iterator;
556 //!Standard extension
557 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT
558 (boost::container::dtl::, container_type
559 ,stored_allocator_type, allocator_type) stored_allocator_type;
561 static const bool has_stored_allocator_type =
562 BOOST_INTRUSIVE_HAS_TYPE(boost::container::dtl::, container_type, stored_allocator_type);
565 typedef allocator_traits<stored_allocator_type> stored_allocator_traits;
568 typedef typename dtl::if_c
569 <has_stored_allocator_type, const stored_allocator_type &, allocator_type>::type get_stored_allocator_const_return_t;
571 typedef typename dtl::if_c
572 <has_stored_allocator_type, stored_allocator_type &, allocator_type>::type get_stored_allocator_noconst_return_t;
574 BOOST_CONTAINER_FORCEINLINE flat_tree()
578 BOOST_CONTAINER_FORCEINLINE explicit flat_tree(const Compare& comp)
582 BOOST_CONTAINER_FORCEINLINE explicit flat_tree(const allocator_type& a)
586 BOOST_CONTAINER_FORCEINLINE flat_tree(const Compare& comp, const allocator_type& a)
590 BOOST_CONTAINER_FORCEINLINE flat_tree(const flat_tree& x)
594 BOOST_CONTAINER_FORCEINLINE flat_tree(BOOST_RV_REF(flat_tree) x)
595 BOOST_NOEXCEPT_IF(boost::container::dtl::is_nothrow_move_constructible<Compare>::value)
596 : m_data(boost::move(x.m_data))
599 BOOST_CONTAINER_FORCEINLINE flat_tree(const flat_tree& x, const allocator_type &a)
600 : m_data(x.m_data, a)
603 BOOST_CONTAINER_FORCEINLINE flat_tree(BOOST_RV_REF(flat_tree) x, const allocator_type &a)
604 : m_data(boost::move(x.m_data), a)
607 template <class InputIterator>
608 BOOST_CONTAINER_FORCEINLINE
609 flat_tree( ordered_range_t, InputIterator first, InputIterator last)
612 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
613 BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
616 template <class InputIterator>
617 BOOST_CONTAINER_FORCEINLINE
618 flat_tree( ordered_range_t, InputIterator first, InputIterator last, const Compare& comp)
621 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
622 BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
625 template <class InputIterator>
626 BOOST_CONTAINER_FORCEINLINE
627 flat_tree( ordered_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a)
630 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
631 BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
634 template <class InputIterator>
635 BOOST_CONTAINER_FORCEINLINE
636 flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last)
639 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
640 BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
643 template <class InputIterator>
644 BOOST_CONTAINER_FORCEINLINE
645 flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp)
648 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
649 BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
652 template <class InputIterator>
653 BOOST_CONTAINER_FORCEINLINE
654 flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a)
657 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
658 BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
661 template <class InputIterator>
662 BOOST_CONTAINER_FORCEINLINE
663 flat_tree( bool unique_insertion, InputIterator first, InputIterator last)
666 this->priv_range_insertion_construct(unique_insertion, first, last);
669 template <class InputIterator>
670 BOOST_CONTAINER_FORCEINLINE
671 flat_tree( bool unique_insertion, InputIterator first, InputIterator last
672 , const Compare& comp)
675 this->priv_range_insertion_construct(unique_insertion, first, last);
678 template <class InputIterator>
679 BOOST_CONTAINER_FORCEINLINE
680 flat_tree( bool unique_insertion, InputIterator first, InputIterator last
681 , const allocator_type& a)
684 this->priv_range_insertion_construct(unique_insertion, first, last);
687 template <class InputIterator>
688 BOOST_CONTAINER_FORCEINLINE
689 flat_tree( bool unique_insertion, InputIterator first, InputIterator last
690 , const Compare& comp, const allocator_type& a)
693 this->priv_range_insertion_construct(unique_insertion, first, last);
696 BOOST_CONTAINER_FORCEINLINE ~flat_tree()
699 BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_COPY_ASSIGN_REF(flat_tree) x)
700 { m_data = x.m_data; return *this; }
702 BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_RV_REF(flat_tree) x)
703 BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value ||
704 allocator_traits_type::is_always_equal::value) &&
705 boost::container::dtl::is_nothrow_move_assignable<Compare>::value)
706 { m_data = boost::move(x.m_data); return *this; }
708 BOOST_CONTAINER_FORCEINLINE const value_compare &priv_value_comp() const
709 { return static_cast<const value_compare &>(this->m_data); }
711 BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp()
712 { return static_cast<value_compare &>(this->m_data); }
714 BOOST_CONTAINER_FORCEINLINE const key_compare &priv_key_comp() const
715 { return this->priv_value_comp().get_comp(); }
717 BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp()
718 { return this->priv_value_comp().get_comp(); }
720 struct insert_commit_data
722 const_iterator position;
727 BOOST_CONTAINER_FORCEINLINE Compare key_comp() const
728 { return this->m_data.get_comp(); }
730 BOOST_CONTAINER_FORCEINLINE value_compare value_comp() const
731 { return this->m_data; }
733 BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const
734 { return this->m_data.m_seq.get_allocator(); }
736 BOOST_CONTAINER_FORCEINLINE get_stored_allocator_const_return_t get_stored_allocator() const
738 return flat_tree_get_stored_allocator(this->m_data.m_seq, dtl::bool_<has_stored_allocator_type>());
741 BOOST_CONTAINER_FORCEINLINE get_stored_allocator_noconst_return_t get_stored_allocator()
743 return flat_tree_get_stored_allocator(this->m_data.m_seq, dtl::bool_<has_stored_allocator_type>());
746 BOOST_CONTAINER_FORCEINLINE iterator begin()
747 { return this->m_data.m_seq.begin(); }
749 BOOST_CONTAINER_FORCEINLINE const_iterator begin() const
750 { return this->cbegin(); }
752 BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const
753 { return this->m_data.m_seq.begin(); }
755 BOOST_CONTAINER_FORCEINLINE iterator end()
756 { return this->m_data.m_seq.end(); }
758 BOOST_CONTAINER_FORCEINLINE const_iterator end() const
759 { return this->cend(); }
761 BOOST_CONTAINER_FORCEINLINE const_iterator cend() const
762 { return this->m_data.m_seq.end(); }
764 BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin()
765 { return reverse_iterator(this->end()); }
767 BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const
768 { return this->crbegin(); }
770 BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const
771 { return const_reverse_iterator(this->cend()); }
773 BOOST_CONTAINER_FORCEINLINE reverse_iterator rend()
774 { return reverse_iterator(this->begin()); }
776 BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const
777 { return this->crend(); }
779 BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const
780 { return const_reverse_iterator(this->cbegin()); }
782 BOOST_CONTAINER_FORCEINLINE bool empty() const
783 { return this->m_data.m_seq.empty(); }
785 BOOST_CONTAINER_FORCEINLINE size_type size() const
786 { return this->m_data.m_seq.size(); }
788 BOOST_CONTAINER_FORCEINLINE size_type max_size() const
789 { return this->m_data.m_seq.max_size(); }
791 BOOST_CONTAINER_FORCEINLINE void swap(flat_tree& other)
792 BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value
793 && boost::container::dtl::is_nothrow_swappable<Compare>::value )
794 { this->m_data.swap(other.m_data); }
798 std::pair<iterator,bool> insert_unique(const value_type& val)
800 std::pair<iterator,bool> ret;
801 insert_commit_data data;
802 ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data);
803 ret.first = ret.second ? this->priv_insert_commit(data, val)
804 : this->begin() + (data.position - this->cbegin());
805 //: iterator(vector_iterator_get_ptr(data.position));
809 std::pair<iterator,bool> insert_unique(BOOST_RV_REF(value_type) val)
811 std::pair<iterator,bool> ret;
812 insert_commit_data data;
813 ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data);
814 ret.first = ret.second ? this->priv_insert_commit(data, boost::move(val))
815 : this->begin() + (data.position - this->cbegin());
816 //: iterator(vector_iterator_get_ptr(data.position));
820 iterator insert_equal(const value_type& val)
822 iterator i = this->upper_bound(KeyOfValue()(val));
823 i = this->m_data.m_seq.insert(i, val);
827 iterator insert_equal(BOOST_RV_REF(value_type) mval)
829 iterator i = this->upper_bound(KeyOfValue()(mval));
830 i = this->m_data.m_seq.insert(i, boost::move(mval));
834 iterator insert_unique(const_iterator hint, const value_type& val)
836 BOOST_ASSERT(this->priv_in_range_or_end(hint));
837 insert_commit_data data;
838 return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data)
839 ? this->priv_insert_commit(data, val)
840 : this->begin() + (data.position - this->cbegin());
841 //: iterator(vector_iterator_get_ptr(data.position));
844 iterator insert_unique(const_iterator hint, BOOST_RV_REF(value_type) val)
846 BOOST_ASSERT(this->priv_in_range_or_end(hint));
847 insert_commit_data data;
848 return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data)
849 ? this->priv_insert_commit(data, boost::move(val))
850 : this->begin() + (data.position - this->cbegin());
851 //: iterator(vector_iterator_get_ptr(data.position));
854 iterator insert_equal(const_iterator hint, const value_type& val)
856 BOOST_ASSERT(this->priv_in_range_or_end(hint));
857 insert_commit_data data;
858 this->priv_insert_equal_prepare(hint, val, data);
859 return this->priv_insert_commit(data, val);
862 iterator insert_equal(const_iterator hint, BOOST_RV_REF(value_type) mval)
864 BOOST_ASSERT(this->priv_in_range_or_end(hint));
865 insert_commit_data data;
866 this->priv_insert_equal_prepare(hint, mval, data);
867 return this->priv_insert_commit(data, boost::move(mval));
870 template <class InIt>
871 void insert_unique(InIt first, InIt last)
873 dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag;
874 container_type &seq = this->m_data.m_seq;
875 value_compare &val_cmp = this->priv_value_comp();
877 //Step 1: put new elements in the back
878 typename container_type::iterator const it = seq.insert(seq.cend(), first, last);
881 boost::movelib::pdqsort(it, seq.end(), val_cmp);
883 //Step 3: only left unique values from the back not already present in the original range
884 typename container_type::iterator const e = boost::movelib::inplace_set_unique_difference
885 (it, seq.end(), seq.begin(), it, val_cmp);
887 seq.erase(e, seq.cend());
888 //it might be invalidated by erasing [e, seq.end) if e == it
891 //Step 4: merge both ranges
892 (flat_tree_container_inplace_merge)(seq, it, this->priv_value_comp(), contiguous_tag);
896 template <class InIt>
897 void insert_equal(InIt first, InIt last)
899 dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag;
900 container_type &seq = this->m_data.m_seq;
901 typename container_type::iterator const it = seq.insert(seq.cend(), first, last);
902 (flat_tree_container_inplace_sort_ending)(seq, it, this->priv_value_comp(), contiguous_tag);
903 (flat_tree_container_inplace_merge) (seq, it, this->priv_value_comp(), contiguous_tag);
908 template <class InIt>
909 void insert_equal(ordered_range_t, InIt first, InIt last)
911 const bool value = boost::container::dtl::
912 has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value;
913 (flat_tree_merge_equal)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_<value>());
916 template <class InIt>
917 void insert_unique(ordered_unique_range_t, InIt first, InIt last)
919 const bool value = boost::container::dtl::
920 has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value;
921 (flat_tree_merge_unique)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_<value>());
924 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
926 template <class... Args>
927 std::pair<iterator, bool> emplace_unique(BOOST_FWD_REF(Args)... args)
929 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;
930 value_type *pval = reinterpret_cast<value_type *>(v.data);
931 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();
932 stored_allocator_traits::construct(a, pval, ::boost::forward<Args>(args)... );
933 value_destructor<stored_allocator_type, value_type> d(a, *pval);
934 return this->insert_unique(::boost::move(*pval));
937 template <class... Args>
938 iterator emplace_hint_unique(const_iterator hint, BOOST_FWD_REF(Args)... args)
940 //hint checked in insert_unique
941 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;
942 value_type *pval = reinterpret_cast<value_type *>(v.data);
943 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();
944 stored_allocator_traits::construct(a, pval, ::boost::forward<Args>(args)... );
945 value_destructor<stored_allocator_type, value_type> d(a, *pval);
946 return this->insert_unique(hint, ::boost::move(*pval));
949 template <class... Args>
950 iterator emplace_equal(BOOST_FWD_REF(Args)... args)
952 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;
953 value_type *pval = reinterpret_cast<value_type *>(v.data);
954 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();
955 stored_allocator_traits::construct(a, pval, ::boost::forward<Args>(args)... );
956 value_destructor<stored_allocator_type, value_type> d(a, *pval);
957 return this->insert_equal(::boost::move(*pval));
960 template <class... Args>
961 iterator emplace_hint_equal(const_iterator hint, BOOST_FWD_REF(Args)... args)
963 //hint checked in insert_equal
964 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;
965 value_type *pval = reinterpret_cast<value_type *>(v.data);
966 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();
967 stored_allocator_traits::construct(a, pval, ::boost::forward<Args>(args)... );
968 value_destructor<stored_allocator_type, value_type> d(a, *pval);
969 return this->insert_equal(hint, ::boost::move(*pval));
972 template <class KeyType, class... Args>
973 BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> try_emplace
974 (const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(Args)... args)
976 std::pair<iterator,bool> ret;
977 insert_commit_data data;
978 const key_type & k = key;
979 ret.second = hint == const_iterator()
980 ? this->priv_insert_unique_prepare(k, data)
981 : this->priv_insert_unique_prepare(hint, k, data);
984 ret.first = this->nth(data.position - this->cbegin());
987 typedef typename emplace_functor_type<try_emplace_t, KeyType, Args...>::type func_t;
988 typedef emplace_iterator<value_type, func_t, difference_type> it_t;
989 func_t func(try_emplace_t(), ::boost::forward<KeyType>(key), ::boost::forward<Args>(args)...);
990 ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());
995 #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
997 #define BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE(N) \
998 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
999 std::pair<iterator, bool> emplace_unique(BOOST_MOVE_UREF##N)\
1001 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
1002 value_type *pval = reinterpret_cast<value_type *>(v.data);\
1003 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\
1004 stored_allocator_traits::construct(a, pval BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1005 value_destructor<stored_allocator_type, value_type> d(a, *pval);\
1006 return this->insert_unique(::boost::move(*pval));\
1009 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1010 iterator emplace_hint_unique(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1012 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
1013 value_type *pval = reinterpret_cast<value_type *>(v.data);\
1014 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\
1015 stored_allocator_traits::construct(a, pval BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1016 value_destructor<stored_allocator_type, value_type> d(a, *pval);\
1017 return this->insert_unique(hint, ::boost::move(*pval));\
1020 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1021 iterator emplace_equal(BOOST_MOVE_UREF##N)\
1023 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
1024 value_type *pval = reinterpret_cast<value_type *>(v.data);\
1025 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\
1026 stored_allocator_traits::construct(a, pval BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1027 value_destructor<stored_allocator_type, value_type> d(a, *pval);\
1028 return this->insert_equal(::boost::move(*pval));\
1031 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1032 iterator emplace_hint_equal(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1034 typename dtl::aligned_storage <sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
1035 value_type *pval = reinterpret_cast<value_type *>(v.data);\
1036 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\
1037 stored_allocator_traits::construct(a, pval BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1038 value_destructor<stored_allocator_type, value_type> d(a, *pval);\
1039 return this->insert_equal(hint, ::boost::move(*pval));\
1041 template <class KeyType BOOST_MOVE_I##N BOOST_MOVE_CLASS##N>\
1042 BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool>\
1043 try_emplace(const_iterator hint, BOOST_FWD_REF(KeyType) key BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1045 std::pair<iterator,bool> ret;\
1046 insert_commit_data data;\
1047 const key_type & k = key;\
1048 ret.second = hint == const_iterator()\
1049 ? this->priv_insert_unique_prepare(k, data)\
1050 : this->priv_insert_unique_prepare(hint, k, data);\
1053 ret.first = this->nth(data.position - this->cbegin());\
1056 typedef typename emplace_functor_type<try_emplace_t, KeyType BOOST_MOVE_I##N BOOST_MOVE_TARG##N>::type func_t;\
1057 typedef emplace_iterator<value_type, func_t, difference_type> it_t;\
1058 func_t func(try_emplace_t(), ::boost::forward<KeyType>(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1059 ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());\
1064 BOOST_MOVE_ITERATE_0TO7(BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE)
1065 #undef BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE
1067 #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1069 template<class KeyType, class M>
1070 std::pair<iterator, bool> insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj)
1072 const key_type& k = key;
1073 std::pair<iterator,bool> ret;
1074 insert_commit_data data;
1075 ret.second = hint == const_iterator()
1076 ? this->priv_insert_unique_prepare(k, data)
1077 : this->priv_insert_unique_prepare(hint, k, data);
1079 ret.first = this->nth(data.position - this->cbegin());
1080 ret.first->second = boost::forward<M>(obj);
1083 typedef typename emplace_functor_type<KeyType, M>::type func_t;
1084 typedef emplace_iterator<value_type, func_t, difference_type> it_t;
1085 func_t func(boost::forward<KeyType>(key), boost::forward<M>(obj));
1086 ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());
1091 BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator position)
1092 { return this->m_data.m_seq.erase(position); }
1094 size_type erase(const key_type& k)
1096 std::pair<iterator,iterator > itp = this->equal_range(k);
1097 size_type ret = static_cast<size_type>(itp.second-itp.first);
1099 this->m_data.m_seq.erase(itp.first, itp.second);
1104 BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator first, const_iterator last)
1105 { return this->m_data.m_seq.erase(first, last); }
1107 BOOST_CONTAINER_FORCEINLINE void clear()
1108 { this->m_data.m_seq.clear(); }
1110 //! <b>Effects</b>: Tries to deallocate the excess of memory created
1111 // with previous allocations. The size of the vector is unchanged
1113 //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
1115 //! <b>Complexity</b>: Linear to size().
1116 BOOST_CONTAINER_FORCEINLINE void shrink_to_fit()
1117 { this->m_data.m_seq.shrink_to_fit(); }
1119 BOOST_CONTAINER_FORCEINLINE iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW
1121 const bool value = boost::container::dtl::
1122 has_member_function_callable_with_nth<container_type, size_type>::value;
1123 return flat_tree_nth<iterator>(this->m_data.m_seq, n, dtl::bool_<value>());
1126 BOOST_CONTAINER_FORCEINLINE const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW
1128 const bool value = boost::container::dtl::
1129 has_member_function_callable_with_nth<container_type, size_type>::value;
1130 return flat_tree_nth<const_iterator>(this->m_data.m_seq, n, dtl::bool_<value>());
1133 BOOST_CONTAINER_FORCEINLINE size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW
1135 const bool value = boost::container::dtl::
1136 has_member_function_callable_with_index_of<container_type, iterator>::value;
1137 return flat_tree_index_of(this->m_data.m_seq, p, dtl::bool_<value>());
1140 BOOST_CONTAINER_FORCEINLINE size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW
1142 const bool value = boost::container::dtl::
1143 has_member_function_callable_with_index_of<container_type, const_iterator>::value;
1144 return flat_tree_index_of(this->m_data.m_seq, p, dtl::bool_<value>());
1148 iterator find(const key_type& k)
1150 iterator i = this->lower_bound(k);
1151 iterator end_it = this->end();
1152 if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
1158 const_iterator find(const key_type& k) const
1160 const_iterator i = this->lower_bound(k);
1162 const_iterator end_it = this->cend();
1163 if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
1170 typename dtl::enable_if_transparent<key_compare, K, iterator>::type
1173 iterator i = this->lower_bound(k);
1174 iterator end_it = this->end();
1175 if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
1182 typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
1183 find(const K& k) const
1185 const_iterator i = this->lower_bound(k);
1187 const_iterator end_it = this->cend();
1188 if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
1194 size_type count(const key_type& k) const
1196 std::pair<const_iterator, const_iterator> p = this->equal_range(k);
1197 size_type n = p.second - p.first;
1202 typename dtl::enable_if_transparent<key_compare, K, size_type>::type
1203 count(const K& k) const
1205 std::pair<const_iterator, const_iterator> p = this->equal_range(k);
1206 size_type n = p.second - p.first;
1210 BOOST_CONTAINER_FORCEINLINE bool contains(const key_type& x) const
1211 { return this->find(x) != this->cend(); }
1213 template<typename K>
1214 BOOST_CONTAINER_FORCEINLINE
1215 typename dtl::enable_if_transparent<key_compare, K, bool>::type
1216 contains(const K& x) const
1217 { return this->find(x) != this->cend(); }
1220 BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source)
1222 this->insert_unique( boost::make_move_iterator(source.begin())
1223 , boost::make_move_iterator(source.end()));
1227 BOOST_CONTAINER_FORCEINLINE void merge_equal(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source)
1229 this->insert_equal( boost::make_move_iterator(source.begin())
1230 , boost::make_move_iterator(source.end()));
1233 BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree& source)
1235 const bool value = boost::container::dtl::
1236 has_member_function_callable_with_merge_unique<container_type, iterator, iterator, value_compare>::value;
1237 (flat_tree_merge_unique)
1238 ( this->m_data.m_seq
1239 , boost::make_move_iterator(source.m_data.m_seq.begin())
1240 , boost::make_move_iterator(source.m_data.m_seq.end())
1241 , this->priv_value_comp()
1242 , dtl::bool_<value>());
1245 BOOST_CONTAINER_FORCEINLINE void merge_equal(flat_tree& source)
1247 const bool value = boost::container::dtl::
1248 has_member_function_callable_with_merge<container_type, iterator, iterator, value_compare>::value;
1249 (flat_tree_merge_equal)
1250 ( this->m_data.m_seq
1251 , boost::make_move_iterator(source.m_data.m_seq.begin())
1252 , boost::make_move_iterator(source.m_data.m_seq.end())
1253 , this->priv_value_comp()
1254 , dtl::bool_<value>());
1257 BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k)
1258 { return this->priv_lower_bound(this->begin(), this->end(), k); }
1260 BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& k) const
1261 { return this->priv_lower_bound(this->cbegin(), this->cend(), k); }
1264 BOOST_CONTAINER_FORCEINLINE
1265 typename dtl::enable_if_transparent<key_compare, K, iterator>::type
1266 lower_bound(const K& k)
1267 { return this->priv_lower_bound(this->begin(), this->end(), k); }
1270 BOOST_CONTAINER_FORCEINLINE
1271 typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
1272 lower_bound(const K& k) const
1273 { return this->priv_lower_bound(this->cbegin(), this->cend(), k); }
1275 BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& k)
1276 { return this->priv_upper_bound(this->begin(), this->end(), k); }
1278 BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const
1279 { return this->priv_upper_bound(this->cbegin(), this->cend(), k); }
1282 BOOST_CONTAINER_FORCEINLINE
1283 typename dtl::enable_if_transparent<key_compare, K,iterator>::type
1284 upper_bound(const K& k)
1285 { return this->priv_upper_bound(this->begin(), this->end(), k); }
1288 BOOST_CONTAINER_FORCEINLINE
1289 typename dtl::enable_if_transparent<key_compare, K,const_iterator>::type
1290 upper_bound(const K& k) const
1291 { return this->priv_upper_bound(this->cbegin(), this->cend(), k); }
1293 BOOST_CONTAINER_FORCEINLINE std::pair<iterator,iterator> equal_range(const key_type& k)
1294 { return this->priv_equal_range(this->begin(), this->end(), k); }
1296 BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
1297 { return this->priv_equal_range(this->cbegin(), this->cend(), k); }
1300 BOOST_CONTAINER_FORCEINLINE
1301 typename dtl::enable_if_transparent<key_compare, K,std::pair<iterator,iterator> >::type
1302 equal_range(const K& k)
1303 { return this->priv_equal_range(this->begin(), this->end(), k); }
1306 BOOST_CONTAINER_FORCEINLINE
1307 typename dtl::enable_if_transparent<key_compare, K,std::pair<const_iterator,const_iterator> >::type
1308 equal_range(const K& k) const
1309 { return this->priv_equal_range(this->cbegin(), this->cend(), k); }
1312 BOOST_CONTAINER_FORCEINLINE std::pair<iterator, iterator> lower_bound_range(const key_type& k)
1313 { return this->priv_lower_bound_range(this->begin(), this->end(), k); }
1315 BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const
1316 { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); }
1319 BOOST_CONTAINER_FORCEINLINE
1320 typename dtl::enable_if_transparent<key_compare, K,std::pair<iterator,iterator> >::type
1321 lower_bound_range(const K& k)
1322 { return this->priv_lower_bound_range(this->begin(), this->end(), k); }
1325 BOOST_CONTAINER_FORCEINLINE
1326 typename dtl::enable_if_transparent<key_compare, K,std::pair<const_iterator,const_iterator> >::type
1327 lower_bound_range(const K& k) const
1328 { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); }
1330 BOOST_CONTAINER_FORCEINLINE size_type capacity() const
1332 const bool value = boost::container::dtl::
1333 has_member_function_callable_with_capacity<container_type>::value;
1334 return (flat_tree_capacity)(this->m_data.m_seq, dtl::bool_<value>());
1337 BOOST_CONTAINER_FORCEINLINE void reserve(size_type cnt)
1339 const bool value = boost::container::dtl::
1340 has_member_function_callable_with_reserve<container_type, size_type>::value;
1341 (flat_tree_reserve)(this->m_data.m_seq, cnt, dtl::bool_<value>());
1344 BOOST_CONTAINER_FORCEINLINE container_type extract_sequence()
1346 return boost::move(m_data.m_seq);
1349 BOOST_CONTAINER_FORCEINLINE container_type &get_sequence_ref()
1351 return m_data.m_seq;
1354 BOOST_CONTAINER_FORCEINLINE void adopt_sequence_equal(BOOST_RV_REF(container_type) seq)
1356 (flat_tree_adopt_sequence_equal)( m_data.m_seq, boost::move(seq), this->priv_value_comp()
1357 , dtl::bool_<is_contiguous_container<container_type>::value>());
1360 BOOST_CONTAINER_FORCEINLINE void adopt_sequence_unique(BOOST_RV_REF(container_type) seq)
1362 (flat_tree_adopt_sequence_unique)(m_data.m_seq, boost::move(seq), this->priv_value_comp()
1363 , dtl::bool_<is_contiguous_container<container_type>::value>());
1366 void adopt_sequence_equal(ordered_range_t, BOOST_RV_REF(container_type) seq)
1368 BOOST_ASSERT((is_sorted)(seq.cbegin(), seq.cend(), this->priv_value_comp()));
1369 m_data.m_seq = boost::move(seq);
1372 void adopt_sequence_unique(ordered_unique_range_t, BOOST_RV_REF(container_type) seq)
1374 BOOST_ASSERT((is_sorted_and_unique)(seq.cbegin(), seq.cend(), this->priv_value_comp()));
1375 m_data.m_seq = boost::move(seq);
1378 BOOST_CONTAINER_FORCEINLINE friend bool operator==(const flat_tree& x, const flat_tree& y)
1380 return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin());
1383 BOOST_CONTAINER_FORCEINLINE friend bool operator<(const flat_tree& x, const flat_tree& y)
1385 return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
1388 BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const flat_tree& x, const flat_tree& y)
1389 { return !(x == y); }
1391 BOOST_CONTAINER_FORCEINLINE friend bool operator>(const flat_tree& x, const flat_tree& y)
1394 BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const flat_tree& x, const flat_tree& y)
1395 { return !(y < x); }
1397 BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const flat_tree& x, const flat_tree& y)
1398 { return !(x < y); }
1400 BOOST_CONTAINER_FORCEINLINE friend void swap(flat_tree& x, flat_tree& y)
1405 template <class InputIterator>
1406 void priv_range_insertion_construct( bool unique_insertion, InputIterator first, InputIterator last)
1408 //Use cend() as hint to achieve linear time for
1409 //ordered ranges as required by the standard
1410 //for the constructor
1411 //Call end() every iteration as reallocation might have invalidated iterators
1412 if(unique_insertion){
1413 this->insert_unique(first, last);
1416 this->insert_equal (first, last);
1420 BOOST_CONTAINER_FORCEINLINE bool priv_in_range_or_end(const_iterator pos) const
1422 return (this->begin() <= pos) && (pos <= this->end());
1426 void priv_insert_equal_prepare
1427 (const_iterator pos, const value_type& val, insert_commit_data &data)
1430 // To insert val at pos:
1431 // if pos == end || val <= *pos
1432 // if pos == begin || val >= *(pos-1)
1433 // insert val before pos
1435 // insert val before upper_bound(val)
1437 // insert val before lower_bound(val)
1438 const value_compare &val_cmp = this->m_data;
1440 if(pos == this->cend() || !val_cmp(*pos, val)){
1441 if (pos == this->cbegin() || !val_cmp(val, pos[-1])){
1442 data.position = pos;
1446 this->priv_upper_bound(this->cbegin(), pos, KeyOfValue()(val));
1451 this->priv_lower_bound(pos, this->cend(), KeyOfValue()(val));
1455 bool priv_insert_unique_prepare
1456 (const_iterator b, const_iterator e, const key_type& k, insert_commit_data &commit_data)
1458 const key_compare &key_cmp = this->priv_key_comp();
1459 commit_data.position = this->priv_lower_bound(b, e, k);
1460 return commit_data.position == e || key_cmp(k, KeyOfValue()(*commit_data.position));
1463 BOOST_CONTAINER_FORCEINLINE bool priv_insert_unique_prepare
1464 (const key_type& k, insert_commit_data &commit_data)
1465 { return this->priv_insert_unique_prepare(this->cbegin(), this->cend(), k, commit_data); }
1467 bool priv_insert_unique_prepare
1468 (const_iterator pos, const key_type& k, insert_commit_data &commit_data)
1470 //N1780. Props to Howard Hinnant!
1471 //To insert k at pos:
1472 //if pos == end || k <= *pos
1473 // if pos == begin || k >= *(pos-1)
1474 // insert k before pos
1476 // insert k before upper_bound(k)
1477 //else if pos+1 == end || k <= *(pos+1)
1478 // insert k after pos
1480 // insert k before lower_bound(k)
1481 const key_compare &key_cmp = this->priv_key_comp();
1482 const const_iterator cend_it = this->cend();
1483 if(pos == cend_it || key_cmp(k, KeyOfValue()(*pos))){ //Check if k should go before end
1484 const const_iterator cbeg = this->cbegin();
1485 commit_data.position = pos;
1486 if(pos == cbeg){ //If container is empty then insert it in the beginning
1489 const_iterator prev(pos);
1491 if(key_cmp(KeyOfValue()(*prev), k)){ //If previous element was less, then it should go between prev and pos
1494 else if(!key_cmp(k, KeyOfValue()(*prev))){ //If previous was equal then insertion should fail
1495 commit_data.position = prev;
1498 else{ //Previous was bigger so insertion hint was pointless, dispatch to hintless insertion
1499 //but reduce the search between beg and prev as prev is bigger than k
1500 return this->priv_insert_unique_prepare(cbeg, prev, k, commit_data);
1504 //The hint is before the insertion position, so insert it
1505 //in the remaining range [pos, end)
1506 return this->priv_insert_unique_prepare(pos, cend_it, k, commit_data);
1510 template<class Convertible>
1511 BOOST_CONTAINER_FORCEINLINE iterator priv_insert_commit
1512 (insert_commit_data &commit_data, BOOST_FWD_REF(Convertible) convertible)
1514 return this->m_data.m_seq.insert
1515 ( commit_data.position
1516 , boost::forward<Convertible>(convertible));
1519 template <class RanIt, class K>
1520 RanIt priv_lower_bound(RanIt first, const RanIt last,
1521 const K & key) const
1523 const Compare &key_cmp = this->m_data.get_comp();
1524 KeyOfValue key_extract;
1525 size_type len = static_cast<size_type>(last - first);
1529 size_type step = len >> 1;
1533 if (key_cmp(key_extract(*middle), key)) {
1544 template <class RanIt, class K>
1545 RanIt priv_upper_bound
1546 (RanIt first, const RanIt last,const K & key) const
1548 const Compare &key_cmp = this->m_data.get_comp();
1549 KeyOfValue key_extract;
1550 size_type len = static_cast<size_type>(last - first);
1554 size_type step = len >> 1;
1558 if (key_cmp(key, key_extract(*middle))) {
1569 template <class RanIt, class K>
1570 std::pair<RanIt, RanIt>
1571 priv_equal_range(RanIt first, RanIt last, const K& key) const
1573 const Compare &key_cmp = this->m_data.get_comp();
1574 KeyOfValue key_extract;
1575 size_type len = static_cast<size_type>(last - first);
1579 size_type step = len >> 1;
1583 if (key_cmp(key_extract(*middle), key)){
1587 else if (key_cmp(key, key_extract(*middle))){
1591 //Middle is equal to key
1594 RanIt const first_ret = this->priv_lower_bound(first, middle, key);
1595 return std::pair<RanIt, RanIt>
1596 ( first_ret, this->priv_upper_bound(++middle, last, key));
1599 return std::pair<RanIt, RanIt>(first, first);
1602 template<class RanIt, class K>
1603 std::pair<RanIt, RanIt> priv_lower_bound_range(RanIt first, RanIt last, const K& k) const
1605 const Compare &key_cmp = this->m_data.get_comp();
1606 KeyOfValue key_extract;
1607 RanIt lb(this->priv_lower_bound(first, last, k)), ub(lb);
1608 if(lb != last && !key_cmp(k, key_extract(*lb))){
1611 return std::pair<RanIt, RanIt>(lb, ub);
1617 } //namespace container {
1619 //!has_trivial_destructor_after_move<> == true_type
1620 //!specialization for optimizations
1621 template <class T, class KeyOfValue,
1622 class Compare, class AllocatorOrContainer>
1623 struct has_trivial_destructor_after_move<boost::container::dtl::flat_tree<T, KeyOfValue, Compare, AllocatorOrContainer> >
1625 typedef boost::container::dtl::flat_tree<T, KeyOfValue, Compare, AllocatorOrContainer> flat_tree;
1626 typedef typename flat_tree::container_type container_type;
1627 typedef typename flat_tree::key_compare key_compare;
1628 static const bool value = ::boost::has_trivial_destructor_after_move<container_type>::value &&
1629 ::boost::has_trivial_destructor_after_move<key_compare>::value;
1632 } //namespace boost {
1634 #include <boost/container/detail/config_end.hpp>
1636 #endif // BOOST_CONTAINER_FLAT_TREE_HPP