1 ////////////////////////////////////////////////////////////////////////////////
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_FLAT_TREE_HPP
12 #define BOOST_CONTAINER_FLAT_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
25 #include <boost/container/container_fwd.hpp>
26
27 #include <boost/move/utility_core.hpp>
28
29 #include <boost/container/detail/pair.hpp>
30 #include <boost/container/vector.hpp>
31 #include <boost/container/allocator_traits.hpp>
32
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>
43
44 #include <boost/intrusive/detail/minimal_pair_header.hpp> //pair
45
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>
51
52 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
53 #include <boost/move/detail/fwd_macros.hpp>
54 #endif
55
56 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
57
58 #if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
59 #pragma GCC diagnostic push
60 #pragma GCC diagnostic ignored "-Wunused-result"
61 #endif
62
63 //merge_unique
64 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME merge_unique
65 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
66 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
67 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 3
68 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 3
69 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
70
71 //merge_equal
72 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME merge
73 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
74 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
75 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 3
76 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 3
77 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
78
79 //index_of
80 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME index_of
81 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
82 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
83 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1
84 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1
85 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
86
87 //nth
88 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME nth
89 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
90 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
91 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1
92 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1
93 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
94
95 //reserve
96 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME reserve
97 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
98 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
99 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1
100 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1
101 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
102
103 //capacity
104 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME capacity
105 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl {
106 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
107 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0
108 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0
109 #include <boost/intrusive/detail/has_member_function_callable_with.hpp>
110
111 #if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
112 #pragma GCC diagnostic pop
113 #endif
114
115
116 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
117
118 namespace boost {
119 namespace container {
120 namespace dtl {
121
122 ///////////////////////////////////////
123 //
124 // Helper functions to merge elements
125 //
126 ///////////////////////////////////////
127
BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(stored_allocator_type)128 BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(stored_allocator_type)
129
130 ///////////////////////////////////////
131 //
132 // flat_tree_container_inplace_merge
133 //
134 ///////////////////////////////////////
135 template<class SequenceContainer, class Compare>
136 BOOST_CONTAINER_FORCEINLINE void flat_tree_container_inplace_merge //is_contiguous_container == true
137 (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::true_)
138 {
139 typedef typename SequenceContainer::value_type value_type;
140 value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin());
141 value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
142 value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
143 boost::movelib::adaptive_merge
144 (braw, iraw, eraw, comp, eraw, back_free_capacity<SequenceContainer>::get(dest));
145 }
146
147 template<class SequenceContainer, class Compare>
flat_tree_container_inplace_merge(SequenceContainer & dest,typename SequenceContainer::iterator it,Compare comp,dtl::false_)148 BOOST_CONTAINER_FORCEINLINE void flat_tree_container_inplace_merge //is_contiguous_container == false
149 (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::false_)
150 {
151 boost::movelib::adaptive_merge(dest.begin(), it, dest.end(), comp);
152 }
153
154 ///////////////////////////////////////
155 //
156 // flat_tree_container_inplace_sort_ending
157 //
158 ///////////////////////////////////////
159 template<class SequenceContainer, class Compare>
flat_tree_container_inplace_sort_ending(SequenceContainer & dest,typename SequenceContainer::iterator it,Compare comp,dtl::true_)160 BOOST_CONTAINER_FORCEINLINE void flat_tree_container_inplace_sort_ending //is_contiguous_container == true
161 (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::true_)
162 {
163 typedef typename SequenceContainer::value_type value_type;
164 value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
165 value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
166 boost::movelib::adaptive_sort
167 (iraw, eraw, comp, eraw, back_free_capacity<SequenceContainer>::get(dest));
168 }
169
170 template<class SequenceContainer, class Compare>
flat_tree_container_inplace_sort_ending(SequenceContainer & dest,typename SequenceContainer::iterator it,Compare comp,dtl::false_)171 BOOST_CONTAINER_FORCEINLINE void flat_tree_container_inplace_sort_ending //is_contiguous_container == false
172 (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::false_)
173 {
174 boost::movelib::adaptive_sort(it, dest.end(), comp);
175 }
176
177 ///////////////////////////////////////
178 //
179 // flat_tree_merge
180 //
181 ///////////////////////////////////////
182 template<class SequenceContainer, class Iterator, class Compare>
flat_tree_merge_equal(SequenceContainer & dest,Iterator first,Iterator last,Compare comp,dtl::true_)183 BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal
184 (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_)
185 {
186 dest.merge(first, last, comp);
187 }
188
189 template<class SequenceContainer, class Iterator, class Compare>
flat_tree_merge_equal(SequenceContainer & dest,Iterator first,Iterator last,Compare comp,dtl::false_)190 BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal //has_merge_unique == false
191 (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_)
192 {
193 typedef typename SequenceContainer::iterator iterator;
194 iterator const it = dest.insert( dest.end(), first, last );
195 dtl::bool_<is_contiguous_container<SequenceContainer>::value> contiguous_tag;
196 (flat_tree_container_inplace_merge)(dest, it, comp, contiguous_tag);
197 }
198
199 ///////////////////////////////////////
200 //
201 // flat_tree_merge_unique
202 //
203 ///////////////////////////////////////
204 template<class SequenceContainer, class Iterator, class Compare>
flat_tree_merge_unique(SequenceContainer & dest,Iterator first,Iterator last,Compare comp,dtl::true_)205 BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == true
206 (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_)
207 {
208 dest.merge_unique(first, last, comp);
209 }
210
211 template<class SequenceContainer, class Iterator, class Compare>
flat_tree_merge_unique(SequenceContainer & dest,Iterator first,Iterator last,Compare comp,dtl::false_)212 BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == false
213 (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_)
214 {
215 typedef typename SequenceContainer::iterator iterator;
216 typedef typename SequenceContainer::size_type size_type;
217
218 size_type const old_sz = dest.size();
219 iterator const first_new = dest.insert(dest.cend(), first, last );
220 iterator e = boost::movelib::inplace_set_unique_difference(first_new, dest.end(), dest.begin(), first_new, comp);
221 dest.erase(e, dest.end());
222 dtl::bool_<is_contiguous_container<SequenceContainer>::value> contiguous_tag;
223 (flat_tree_container_inplace_merge)(dest, dest.begin()+old_sz, comp, contiguous_tag);
224 }
225
226 ///////////////////////////////////////
227 //
228 // flat_tree_index_of
229 //
230 ///////////////////////////////////////
231 template<class SequenceContainer, class Iterator>
232 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
flat_tree_index_of(SequenceContainer & cont,Iterator p,dtl::true_)233 flat_tree_index_of // has_index_of == true
234 (SequenceContainer& cont, Iterator p, dtl::true_)
235 {
236 return cont.index_of(p);
237 }
238
239 template<class SequenceContainer, class Iterator>
240 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
flat_tree_index_of(SequenceContainer & cont,Iterator p,dtl::false_)241 flat_tree_index_of // has_index_of == false
242 (SequenceContainer& cont, Iterator p, dtl::false_)
243 {
244 typedef typename SequenceContainer::size_type size_type;
245 return static_cast<size_type>(p - cont.begin());
246 }
247
248 ///////////////////////////////////////
249 //
250 // flat_tree_nth
251 //
252 ///////////////////////////////////////
253 template<class Iterator, class SequenceContainer>
254 BOOST_CONTAINER_FORCEINLINE Iterator
flat_tree_nth(SequenceContainer & cont,typename SequenceContainer::size_type n,dtl::true_)255 flat_tree_nth // has_nth == true
256 (SequenceContainer& cont, typename SequenceContainer::size_type n, dtl::true_)
257 {
258 return cont.nth(n);
259 }
260
261 template<class Iterator, class SequenceContainer>
262 BOOST_CONTAINER_FORCEINLINE Iterator
flat_tree_nth(SequenceContainer & cont,typename SequenceContainer::size_type n,dtl::false_)263 flat_tree_nth // has_nth == false
264 (SequenceContainer& cont, typename SequenceContainer::size_type n, dtl::false_)
265 {
266 return cont.begin()+ n;
267 }
268
269 ///////////////////////////////////////
270 //
271 // flat_tree_get_stored_allocator
272 //
273 ///////////////////////////////////////
274 template<class SequenceContainer>
275 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::stored_allocator_type &
flat_tree_get_stored_allocator(SequenceContainer & cont,dtl::true_)276 flat_tree_get_stored_allocator // has_get_stored_allocator == true
277 (SequenceContainer& cont, dtl::true_)
278 {
279 return cont.get_stored_allocator();
280 }
281
282 template<class SequenceContainer>
283 BOOST_CONTAINER_FORCEINLINE const typename SequenceContainer::stored_allocator_type &
flat_tree_get_stored_allocator(const SequenceContainer & cont,dtl::true_)284 flat_tree_get_stored_allocator // has_get_stored_allocator == true
285 (const SequenceContainer& cont, dtl::true_)
286 {
287 return cont.get_stored_allocator();
288 }
289
290 template<class SequenceContainer>
291 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::allocator_type
flat_tree_get_stored_allocator(SequenceContainer & cont,dtl::false_)292 flat_tree_get_stored_allocator // has_get_stored_allocator == false
293 (SequenceContainer& cont, dtl::false_)
294 {
295 return cont.get_allocator();
296 }
297
298 ///////////////////////////////////////
299 //
300 // flat_tree_adopt_sequence_equal
301 //
302 ///////////////////////////////////////
303 template<class SequenceContainer, class Compare>
flat_tree_sort_contiguous_to_adopt(SequenceContainer & tseq,BOOST_RV_REF (SequenceContainer)seq,Compare comp)304 void flat_tree_sort_contiguous_to_adopt // is_contiguous_container == true
305 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp)
306 {
307 if(tseq.capacity() >= (seq.capacity() - seq.size())) {
308 tseq.clear();
309 boost::movelib::adaptive_sort
310 (boost::movelib::iterator_to_raw_pointer(seq.begin())
311 , boost::movelib::iterator_to_raw_pointer(seq.end())
312 , comp
313 , boost::movelib::iterator_to_raw_pointer(tseq.begin())
314 , tseq.capacity());
315 }
316 else{
317 boost::movelib::adaptive_sort
318 (boost::movelib::iterator_to_raw_pointer(seq.begin())
319 , boost::movelib::iterator_to_raw_pointer(seq.end())
320 , comp
321 , boost::movelib::iterator_to_raw_pointer(seq.end())
322 , seq.capacity() - seq.size());
323 }
324 }
325
326 template<class SequenceContainer, class Compare>
flat_tree_adopt_sequence_equal(SequenceContainer & tseq,BOOST_RV_REF (SequenceContainer)seq,Compare comp,dtl::true_)327 BOOST_CONTAINER_FORCEINLINE void flat_tree_adopt_sequence_equal // is_contiguous_container == true
328 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_)
329 {
330 flat_tree_sort_contiguous_to_adopt(tseq, boost::move(seq), comp);
331 tseq = boost::move(seq);
332 }
333
334 template<class SequenceContainer, class Compare>
flat_tree_adopt_sequence_equal(SequenceContainer & tseq,BOOST_RV_REF (SequenceContainer)seq,Compare comp,dtl::false_)335 BOOST_CONTAINER_FORCEINLINE void flat_tree_adopt_sequence_equal // is_contiguous_container == false
336 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::false_)
337 {
338 boost::movelib::adaptive_sort(seq.begin(), seq.end(), comp);
339 tseq = boost::move(seq);
340 }
341
342 ///////////////////////////////////////
343 //
344 // flat_tree_adopt_sequence_unique
345 //
346 ///////////////////////////////////////
347 template<class SequenceContainer, class Compare>
flat_tree_adopt_sequence_unique(SequenceContainer & tseq,BOOST_RV_REF (SequenceContainer)seq,Compare comp,dtl::true_)348 void flat_tree_adopt_sequence_unique// is_contiguous_container == true
349 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_)
350 {
351 boost::movelib::pdqsort
352 ( boost::movelib::iterator_to_raw_pointer(seq.begin())
353 , boost::movelib::iterator_to_raw_pointer(seq.end())
354 , comp);
355 seq.erase(boost::movelib::unique
356 (seq.begin(), seq.end(), boost::movelib::negate<Compare>(comp)), seq.cend());
357 tseq = boost::move(seq);
358 }
359
360 template<class SequenceContainer, class Compare>
flat_tree_adopt_sequence_unique(SequenceContainer & tseq,BOOST_RV_REF (SequenceContainer)seq,Compare comp,dtl::false_)361 void flat_tree_adopt_sequence_unique// is_contiguous_container == false
362 (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::false_)
363 {
364 boost::movelib::pdqsort(seq.begin(), seq.end(), comp);
365 seq.erase(boost::movelib::unique
366 (seq.begin(), seq.end(), boost::movelib::negate<Compare>(comp)), seq.cend());
367 tseq = boost::move(seq);
368 }
369
370 ///////////////////////////////////////
371 //
372 // flat_tree_reserve
373 //
374 ///////////////////////////////////////
375 template<class SequenceContainer>
376 BOOST_CONTAINER_FORCEINLINE void // has_reserve == true
flat_tree_reserve(SequenceContainer & tseq,typename SequenceContainer::size_type cap,dtl::true_)377 flat_tree_reserve(SequenceContainer &tseq, typename SequenceContainer::size_type cap, dtl::true_)
378 {
379 tseq.reserve(cap);
380 }
381
382 template<class SequenceContainer>
383 BOOST_CONTAINER_FORCEINLINE void // has_reserve == false
flat_tree_reserve(SequenceContainer &,typename SequenceContainer::size_type,dtl::false_)384 flat_tree_reserve(SequenceContainer &, typename SequenceContainer::size_type, dtl::false_)
385 {
386 }
387
388 ///////////////////////////////////////
389 //
390 // flat_tree_capacity
391 //
392 ///////////////////////////////////////
393 template<class SequenceContainer> // has_capacity == true
394 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
flat_tree_capacity(const SequenceContainer & tseq,dtl::true_)395 flat_tree_capacity(const SequenceContainer &tseq, dtl::true_)
396 {
397 return tseq.capacity();
398 }
399
400 template<class SequenceContainer> // has_capacity == false
401 BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
flat_tree_capacity(const SequenceContainer & tseq,dtl::false_)402 flat_tree_capacity(const SequenceContainer &tseq, dtl::false_)
403 {
404 return tseq.size();
405 }
406
407 ///////////////////////////////////////
408 //
409 // flat_tree_value_compare
410 //
411 ///////////////////////////////////////
412
413 template<class Compare, class Value, class KeyOfValue>
414 class flat_tree_value_compare
415 : private Compare
416 {
417 typedef Value first_argument_type;
418 typedef Value second_argument_type;
419 typedef bool return_type;
420 public:
flat_tree_value_compare()421 BOOST_CONTAINER_FORCEINLINE flat_tree_value_compare()
422 : Compare()
423 {}
424
flat_tree_value_compare(const Compare & pred)425 BOOST_CONTAINER_FORCEINLINE flat_tree_value_compare(const Compare &pred)
426 : Compare(pred)
427 {}
428
operator ()(const Value & lhs,const Value & rhs) const429 BOOST_CONTAINER_FORCEINLINE bool operator()(const Value& lhs, const Value& rhs) const
430 {
431 KeyOfValue key_extract;
432 return Compare::operator()(key_extract(lhs), key_extract(rhs));
433 }
434
get_comp() const435 BOOST_CONTAINER_FORCEINLINE const Compare &get_comp() const
436 { return *this; }
437
get_comp()438 BOOST_CONTAINER_FORCEINLINE Compare &get_comp()
439 { return *this; }
440 };
441
442
443 ///////////////////////////////////////
444 //
445 // select_container_type
446 //
447 ///////////////////////////////////////
448 template < class Value, class AllocatorOrContainer
449 , bool = boost::container::dtl::is_container<AllocatorOrContainer>::value
450 >
451 struct select_container_type
452 {
453 typedef AllocatorOrContainer type;
454 };
455
456 template <class Value, class AllocatorOrContainer>
457 struct select_container_type<Value, AllocatorOrContainer, false>
458 {
459 typedef boost::container::vector<Value, typename real_allocator<Value, AllocatorOrContainer>::type> type;
460 };
461
462
463 ///////////////////////////////////////
464 //
465 // flat_tree
466 //
467 ///////////////////////////////////////
468 template <class Value, class KeyOfValue,
469 class Compare, class AllocatorOrContainer>
470 class flat_tree
471 {
472 public:
473 typedef typename select_container_type<Value, AllocatorOrContainer>::type container_type;
474 typedef container_type sequence_type; //For backwards compatibility
475
476 private:
477 typedef typename container_type::allocator_type allocator_t;
478 typedef allocator_traits<allocator_t> allocator_traits_type;
479
480 public:
481 typedef flat_tree_value_compare<Compare, Value, KeyOfValue> value_compare;
482
483 private:
484
485 struct Data
486 //Inherit from value_compare to do EBO
487 : public value_compare
488 {
489 BOOST_COPYABLE_AND_MOVABLE(Data)
490
491 public:
Databoost::container::dtl::flat_tree::Data492 BOOST_CONTAINER_FORCEINLINE Data()
493 : value_compare(), m_seq()
494 {}
495
Databoost::container::dtl::flat_tree::Data496 BOOST_CONTAINER_FORCEINLINE explicit Data(const allocator_t &alloc)
497 : value_compare(), m_seq(alloc)
498 {}
499
Databoost::container::dtl::flat_tree::Data500 BOOST_CONTAINER_FORCEINLINE explicit Data(const Compare &comp)
501 : value_compare(comp), m_seq()
502 {}
503
Databoost::container::dtl::flat_tree::Data504 BOOST_CONTAINER_FORCEINLINE Data(const Compare &comp, const allocator_t &alloc)
505 : value_compare(comp), m_seq(alloc)
506 {}
507
Databoost::container::dtl::flat_tree::Data508 BOOST_CONTAINER_FORCEINLINE explicit Data(const Data &d)
509 : value_compare(static_cast<const value_compare&>(d)), m_seq(d.m_seq)
510 {}
511
Databoost::container::dtl::flat_tree::Data512 BOOST_CONTAINER_FORCEINLINE Data(BOOST_RV_REF(Data) d)
513 : value_compare(boost::move(static_cast<value_compare&>(d))), m_seq(boost::move(d.m_seq))
514 {}
515
Databoost::container::dtl::flat_tree::Data516 BOOST_CONTAINER_FORCEINLINE Data(const Data &d, const allocator_t &a)
517 : value_compare(static_cast<const value_compare&>(d)), m_seq(d.m_seq, a)
518 {}
519
Databoost::container::dtl::flat_tree::Data520 BOOST_CONTAINER_FORCEINLINE Data(BOOST_RV_REF(Data) d, const allocator_t &a)
521 : value_compare(boost::move(static_cast<value_compare&>(d))), m_seq(boost::move(d.m_seq), a)
522 {}
523
operator =boost::container::dtl::flat_tree::Data524 Data& operator=(BOOST_COPY_ASSIGN_REF(Data) d)
525 {
526 this->value_compare::operator=(d);
527 m_seq = d.m_seq;
528 return *this;
529 }
530
operator =boost::container::dtl::flat_tree::Data531 Data& operator=(BOOST_RV_REF(Data) d)
532 {
533 this->value_compare::operator=(boost::move(static_cast<value_compare &>(d)));
534 m_seq = boost::move(d.m_seq);
535 return *this;
536 }
537
swapboost::container::dtl::flat_tree::Data538 void swap(Data &d)
539 {
540 value_compare& mycomp = *this, & othercomp = d;
541 boost::adl_move_swap(mycomp, othercomp);
542 this->m_seq.swap(d.m_seq);
543 }
544
545 container_type m_seq;
546 };
547
548 Data m_data;
549 BOOST_COPYABLE_AND_MOVABLE(flat_tree)
550
551 public:
552
553 typedef typename container_type::value_type value_type;
554 typedef typename container_type::pointer pointer;
555 typedef typename container_type::const_pointer const_pointer;
556 typedef typename container_type::reference reference;
557 typedef typename container_type::const_reference const_reference;
558 typedef typename KeyOfValue::type key_type;
559 typedef Compare key_compare;
560 typedef typename container_type::allocator_type allocator_type;
561 typedef typename container_type::size_type size_type;
562 typedef typename container_type::difference_type difference_type;
563 typedef typename container_type::iterator iterator;
564 typedef typename container_type::const_iterator const_iterator;
565 typedef typename container_type::reverse_iterator reverse_iterator;
566 typedef typename container_type::const_reverse_iterator const_reverse_iterator;
567
568 //!Standard extension
569 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT
570 (boost::container::dtl::, container_type
571 ,stored_allocator_type, allocator_type) stored_allocator_type;
572
573 static const bool has_stored_allocator_type =
574 BOOST_INTRUSIVE_HAS_TYPE(boost::container::dtl::, container_type, stored_allocator_type);
575
576 private:
577 typedef allocator_traits<stored_allocator_type> stored_allocator_traits;
578
579 public:
580 typedef typename dtl::if_c
581 <has_stored_allocator_type, const stored_allocator_type &, allocator_type>::type get_stored_allocator_const_return_t;
582
583 typedef typename dtl::if_c
584 <has_stored_allocator_type, stored_allocator_type &, allocator_type>::type get_stored_allocator_noconst_return_t;
585
flat_tree()586 BOOST_CONTAINER_FORCEINLINE flat_tree()
587 : m_data()
588 { }
589
flat_tree(const Compare & comp)590 BOOST_CONTAINER_FORCEINLINE explicit flat_tree(const Compare& comp)
591 : m_data(comp)
592 { }
593
flat_tree(const allocator_type & a)594 BOOST_CONTAINER_FORCEINLINE explicit flat_tree(const allocator_type& a)
595 : m_data(a)
596 { }
597
flat_tree(const Compare & comp,const allocator_type & a)598 BOOST_CONTAINER_FORCEINLINE flat_tree(const Compare& comp, const allocator_type& a)
599 : m_data(comp, a)
600 { }
601
flat_tree(const flat_tree & x)602 BOOST_CONTAINER_FORCEINLINE flat_tree(const flat_tree& x)
603 : m_data(x.m_data)
604 { }
605
flat_tree(BOOST_RV_REF (flat_tree)x)606 BOOST_CONTAINER_FORCEINLINE flat_tree(BOOST_RV_REF(flat_tree) x)
607 BOOST_NOEXCEPT_IF(boost::container::dtl::is_nothrow_move_constructible<Compare>::value)
608 : m_data(boost::move(x.m_data))
609 { }
610
flat_tree(const flat_tree & x,const allocator_type & a)611 BOOST_CONTAINER_FORCEINLINE flat_tree(const flat_tree& x, const allocator_type &a)
612 : m_data(x.m_data, a)
613 { }
614
flat_tree(BOOST_RV_REF (flat_tree)x,const allocator_type & a)615 BOOST_CONTAINER_FORCEINLINE flat_tree(BOOST_RV_REF(flat_tree) x, const allocator_type &a)
616 : m_data(boost::move(x.m_data), a)
617 { }
618
619 template <class InputIterator>
620 BOOST_CONTAINER_FORCEINLINE
flat_tree(ordered_range_t,InputIterator first,InputIterator last)621 flat_tree( ordered_range_t, InputIterator first, InputIterator last)
622 : m_data()
623 {
624 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
625 BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
626 }
627
628 template <class InputIterator>
629 BOOST_CONTAINER_FORCEINLINE
flat_tree(ordered_range_t,InputIterator first,InputIterator last,const Compare & comp)630 flat_tree( ordered_range_t, InputIterator first, InputIterator last, const Compare& comp)
631 : m_data(comp)
632 {
633 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
634 BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
635 }
636
637 template <class InputIterator>
638 BOOST_CONTAINER_FORCEINLINE
flat_tree(ordered_range_t,InputIterator first,InputIterator last,const Compare & comp,const allocator_type & a)639 flat_tree( ordered_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a)
640 : m_data(comp, a)
641 {
642 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
643 BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
644 }
645
646 template <class InputIterator>
647 BOOST_CONTAINER_FORCEINLINE
flat_tree(ordered_unique_range_t,InputIterator first,InputIterator last)648 flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last)
649 : m_data()
650 {
651 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
652 BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
653 }
654
655 template <class InputIterator>
656 BOOST_CONTAINER_FORCEINLINE
flat_tree(ordered_unique_range_t,InputIterator first,InputIterator last,const Compare & comp)657 flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp)
658 : m_data(comp)
659 {
660 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
661 BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
662 }
663
664 template <class InputIterator>
665 BOOST_CONTAINER_FORCEINLINE
flat_tree(ordered_unique_range_t,InputIterator first,InputIterator last,const Compare & comp,const allocator_type & a)666 flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a)
667 : m_data(comp, a)
668 {
669 this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last);
670 BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp()));
671 }
672
673 template <class InputIterator>
674 BOOST_CONTAINER_FORCEINLINE
flat_tree(bool unique_insertion,InputIterator first,InputIterator last)675 flat_tree( bool unique_insertion, InputIterator first, InputIterator last)
676 : m_data()
677 {
678 this->priv_range_insertion_construct(unique_insertion, first, last);
679 }
680
681 template <class InputIterator>
682 BOOST_CONTAINER_FORCEINLINE
flat_tree(bool unique_insertion,InputIterator first,InputIterator last,const Compare & comp)683 flat_tree( bool unique_insertion, InputIterator first, InputIterator last
684 , const Compare& comp)
685 : m_data(comp)
686 {
687 this->priv_range_insertion_construct(unique_insertion, first, last);
688 }
689
690 template <class InputIterator>
691 BOOST_CONTAINER_FORCEINLINE
flat_tree(bool unique_insertion,InputIterator first,InputIterator last,const allocator_type & a)692 flat_tree( bool unique_insertion, InputIterator first, InputIterator last
693 , const allocator_type& a)
694 : m_data(a)
695 {
696 this->priv_range_insertion_construct(unique_insertion, first, last);
697 }
698
699 template <class InputIterator>
700 BOOST_CONTAINER_FORCEINLINE
flat_tree(bool unique_insertion,InputIterator first,InputIterator last,const Compare & comp,const allocator_type & a)701 flat_tree( bool unique_insertion, InputIterator first, InputIterator last
702 , const Compare& comp, const allocator_type& a)
703 : m_data(comp, a)
704 {
705 this->priv_range_insertion_construct(unique_insertion, first, last);
706 }
707
~flat_tree()708 BOOST_CONTAINER_FORCEINLINE ~flat_tree()
709 {}
710
operator =(BOOST_COPY_ASSIGN_REF (flat_tree)x)711 BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_COPY_ASSIGN_REF(flat_tree) x)
712 { m_data = x.m_data; return *this; }
713
operator =(BOOST_RV_REF (flat_tree)x)714 BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_RV_REF(flat_tree) x)
715 BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value ||
716 allocator_traits_type::is_always_equal::value) &&
717 boost::container::dtl::is_nothrow_move_assignable<Compare>::value)
718 { m_data = boost::move(x.m_data); return *this; }
719
priv_value_comp() const720 BOOST_CONTAINER_FORCEINLINE const value_compare &priv_value_comp() const
721 { return static_cast<const value_compare &>(this->m_data); }
722
priv_value_comp()723 BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp()
724 { return static_cast<value_compare &>(this->m_data); }
725
priv_key_comp() const726 BOOST_CONTAINER_FORCEINLINE const key_compare &priv_key_comp() const
727 { return this->priv_value_comp().get_comp(); }
728
priv_key_comp()729 BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp()
730 { return this->priv_value_comp().get_comp(); }
731
732 struct insert_commit_data
733 {
734 const_iterator position;
735 };
736
737 public:
738 // accessors:
739 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
key_comp() const740 Compare key_comp() const
741 { return this->m_data.get_comp(); }
742
743 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
value_comp() const744 value_compare value_comp() const
745 { return this->m_data; }
746
747 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
get_allocator() const748 allocator_type get_allocator() const
749 { return this->m_data.m_seq.get_allocator(); }
750
751 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
get_stored_allocator() const752 get_stored_allocator_const_return_t get_stored_allocator() const
753 {
754 return flat_tree_get_stored_allocator(this->m_data.m_seq, dtl::bool_<has_stored_allocator_type>());
755 }
756
757 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
get_stored_allocator()758 get_stored_allocator_noconst_return_t get_stored_allocator()
759 {
760 return flat_tree_get_stored_allocator(this->m_data.m_seq, dtl::bool_<has_stored_allocator_type>());
761 }
762
763 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
begin()764 iterator begin()
765 { return this->m_data.m_seq.begin(); }
766
767 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
begin() const768 const_iterator begin() const
769 { return this->cbegin(); }
770
771 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
cbegin() const772 const_iterator cbegin() const
773 { return this->m_data.m_seq.begin(); }
774
775 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
end()776 iterator end()
777 { return this->m_data.m_seq.end(); }
778
779 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
end() const780 const_iterator end() const
781 { return this->cend(); }
782
783 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
cend() const784 const_iterator cend() const
785 { return this->m_data.m_seq.end(); }
786
787 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
rbegin()788 reverse_iterator rbegin()
789 { return reverse_iterator(this->end()); }
790
791 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
rbegin() const792 const_reverse_iterator rbegin() const
793 { return this->crbegin(); }
794
795 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
crbegin() const796 const_reverse_iterator crbegin() const
797 { return const_reverse_iterator(this->cend()); }
798
799 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
rend()800 reverse_iterator rend()
801 { return reverse_iterator(this->begin()); }
802
803 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
rend() const804 const_reverse_iterator rend() const
805 { return this->crend(); }
806
807 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
crend() const808 const_reverse_iterator crend() const
809 { return const_reverse_iterator(this->cbegin()); }
810
811 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
empty() const812 bool empty() const
813 { return this->m_data.m_seq.empty(); }
814
815 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
size() const816 size_type size() const
817 { return this->m_data.m_seq.size(); }
818
819 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
max_size() const820 size_type max_size() const
821 { return this->m_data.m_seq.max_size(); }
822
swap(flat_tree & other)823 BOOST_CONTAINER_FORCEINLINE void swap(flat_tree& other)
824 BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value
825 && boost::container::dtl::is_nothrow_swappable<Compare>::value )
826 { this->m_data.swap(other.m_data); }
827
828 public:
829 // insert/erase
insert_unique(const value_type & val)830 std::pair<iterator,bool> insert_unique(const value_type& val)
831 {
832 std::pair<iterator,bool> ret;
833 insert_commit_data data;
834 ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data);
835 ret.first = ret.second ? this->priv_insert_commit(data, val)
836 : this->begin() + (data.position - this->cbegin());
837 //: iterator(vector_iterator_get_ptr(data.position));
838 return ret;
839 }
840
insert_unique(BOOST_RV_REF (value_type)val)841 std::pair<iterator,bool> insert_unique(BOOST_RV_REF(value_type) val)
842 {
843 std::pair<iterator,bool> ret;
844 insert_commit_data data;
845 ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data);
846 ret.first = ret.second ? this->priv_insert_commit(data, boost::move(val))
847 : this->begin() + (data.position - this->cbegin());
848 //: iterator(vector_iterator_get_ptr(data.position));
849 return ret;
850 }
851
insert_equal(const value_type & val)852 iterator insert_equal(const value_type& val)
853 {
854 iterator i = this->upper_bound(KeyOfValue()(val));
855 i = this->m_data.m_seq.insert(i, val);
856 return i;
857 }
858
insert_equal(BOOST_RV_REF (value_type)mval)859 iterator insert_equal(BOOST_RV_REF(value_type) mval)
860 {
861 iterator i = this->upper_bound(KeyOfValue()(mval));
862 i = this->m_data.m_seq.insert(i, boost::move(mval));
863 return i;
864 }
865
insert_unique(const_iterator hint,const value_type & val)866 iterator insert_unique(const_iterator hint, const value_type& val)
867 {
868 BOOST_ASSERT(this->priv_in_range_or_end(hint));
869 insert_commit_data data;
870 return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data)
871 ? this->priv_insert_commit(data, val)
872 : this->begin() + (data.position - this->cbegin());
873 //: iterator(vector_iterator_get_ptr(data.position));
874 }
875
insert_unique(const_iterator hint,BOOST_RV_REF (value_type)val)876 iterator insert_unique(const_iterator hint, BOOST_RV_REF(value_type) val)
877 {
878 BOOST_ASSERT(this->priv_in_range_or_end(hint));
879 insert_commit_data data;
880 return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data)
881 ? this->priv_insert_commit(data, boost::move(val))
882 : this->begin() + (data.position - this->cbegin());
883 //: iterator(vector_iterator_get_ptr(data.position));
884 }
885
insert_equal(const_iterator hint,const value_type & val)886 iterator insert_equal(const_iterator hint, const value_type& val)
887 {
888 BOOST_ASSERT(this->priv_in_range_or_end(hint));
889 insert_commit_data data;
890 this->priv_insert_equal_prepare(hint, val, data);
891 return this->priv_insert_commit(data, val);
892 }
893
insert_equal(const_iterator hint,BOOST_RV_REF (value_type)mval)894 iterator insert_equal(const_iterator hint, BOOST_RV_REF(value_type) mval)
895 {
896 BOOST_ASSERT(this->priv_in_range_or_end(hint));
897 insert_commit_data data;
898 this->priv_insert_equal_prepare(hint, mval, data);
899 return this->priv_insert_commit(data, boost::move(mval));
900 }
901
902 template <class InIt>
insert_unique(InIt first,InIt last)903 void insert_unique(InIt first, InIt last)
904 {
905 dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag;
906 container_type &seq = this->m_data.m_seq;
907 value_compare &val_cmp = this->priv_value_comp();
908
909 //Step 1: put new elements in the back
910 typename container_type::iterator const it = seq.insert(seq.cend(), first, last);
911
912 //Step 2: sort them
913 boost::movelib::pdqsort(it, seq.end(), val_cmp);
914
915 //Step 3: only left unique values from the back not already present in the original range
916 typename container_type::iterator const e = boost::movelib::inplace_set_unique_difference
917 (it, seq.end(), seq.begin(), it, val_cmp);
918
919 seq.erase(e, seq.cend());
920 //it might be invalidated by erasing [e, seq.end) if e == it
921 if (it != e)
922 {
923 //Step 4: merge both ranges
924 (flat_tree_container_inplace_merge)(seq, it, this->priv_value_comp(), contiguous_tag);
925 }
926 }
927
928 template <class InIt>
insert_equal(InIt first,InIt last)929 void insert_equal(InIt first, InIt last)
930 {
931 dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag;
932 container_type &seq = this->m_data.m_seq;
933 typename container_type::iterator const it = seq.insert(seq.cend(), first, last);
934 (flat_tree_container_inplace_sort_ending)(seq, it, this->priv_value_comp(), contiguous_tag);
935 (flat_tree_container_inplace_merge) (seq, it, this->priv_value_comp(), contiguous_tag);
936 }
937
938 //Ordered
939
940 template <class InIt>
insert_equal(ordered_range_t,InIt first,InIt last)941 void insert_equal(ordered_range_t, InIt first, InIt last)
942 {
943 const bool value = boost::container::dtl::
944 has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value;
945 (flat_tree_merge_equal)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_<value>());
946 }
947
948 template <class InIt>
insert_unique(ordered_unique_range_t,InIt first,InIt last)949 void insert_unique(ordered_unique_range_t, InIt first, InIt last)
950 {
951 const bool value = boost::container::dtl::
952 has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value;
953 (flat_tree_merge_unique)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_<value>());
954 }
955
956 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
957
958 template <class... Args>
emplace_unique(BOOST_FWD_REF (Args)...args)959 std::pair<iterator, bool> emplace_unique(BOOST_FWD_REF(Args)... args)
960 {
961 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;
962 value_type *pval = reinterpret_cast<value_type *>(v.data);
963 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();
964 stored_allocator_traits::construct(a, pval, ::boost::forward<Args>(args)... );
965 value_destructor<stored_allocator_type, value_type> d(a, *pval);
966 return this->insert_unique(::boost::move(*pval));
967 }
968
969 template <class... Args>
emplace_hint_unique(const_iterator hint,BOOST_FWD_REF (Args)...args)970 iterator emplace_hint_unique(const_iterator hint, BOOST_FWD_REF(Args)... args)
971 {
972 //hint checked in insert_unique
973 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;
974 value_type *pval = reinterpret_cast<value_type *>(v.data);
975 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();
976 stored_allocator_traits::construct(a, pval, ::boost::forward<Args>(args)... );
977 value_destructor<stored_allocator_type, value_type> d(a, *pval);
978 return this->insert_unique(hint, ::boost::move(*pval));
979 }
980
981 template <class... Args>
emplace_equal(BOOST_FWD_REF (Args)...args)982 iterator emplace_equal(BOOST_FWD_REF(Args)... args)
983 {
984 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;
985 value_type *pval = reinterpret_cast<value_type *>(v.data);
986 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();
987 stored_allocator_traits::construct(a, pval, ::boost::forward<Args>(args)... );
988 value_destructor<stored_allocator_type, value_type> d(a, *pval);
989 return this->insert_equal(::boost::move(*pval));
990 }
991
992 template <class... Args>
emplace_hint_equal(const_iterator hint,BOOST_FWD_REF (Args)...args)993 iterator emplace_hint_equal(const_iterator hint, BOOST_FWD_REF(Args)... args)
994 {
995 //hint checked in insert_equal
996 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;
997 value_type *pval = reinterpret_cast<value_type *>(v.data);
998 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();
999 stored_allocator_traits::construct(a, pval, ::boost::forward<Args>(args)... );
1000 value_destructor<stored_allocator_type, value_type> d(a, *pval);
1001 return this->insert_equal(hint, ::boost::move(*pval));
1002 }
1003
1004 template <class KeyType, class... Args>
try_emplace(const_iterator hint,BOOST_FWD_REF (KeyType)key,BOOST_FWD_REF (Args)...args)1005 BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> try_emplace
1006 (const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(Args)... args)
1007 {
1008 std::pair<iterator,bool> ret;
1009 insert_commit_data data;
1010 const key_type & k = key;
1011 ret.second = hint == const_iterator()
1012 ? this->priv_insert_unique_prepare(k, data)
1013 : this->priv_insert_unique_prepare(hint, k, data);
1014
1015 if(!ret.second){
1016 ret.first = this->nth(data.position - this->cbegin());
1017 }
1018 else{
1019 ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward<KeyType>(key), ::boost::forward<Args>(args)...);
1020 }
1021 return ret;
1022 }
1023
1024 #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1025
1026 #define BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE(N) \
1027 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1028 std::pair<iterator, bool> emplace_unique(BOOST_MOVE_UREF##N)\
1029 {\
1030 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
1031 value_type *pval = reinterpret_cast<value_type *>(v.data);\
1032 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\
1033 stored_allocator_traits::construct(a, pval BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1034 value_destructor<stored_allocator_type, value_type> d(a, *pval);\
1035 return this->insert_unique(::boost::move(*pval));\
1036 }\
1037 \
1038 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1039 iterator emplace_hint_unique(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1040 {\
1041 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
1042 value_type *pval = reinterpret_cast<value_type *>(v.data);\
1043 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\
1044 stored_allocator_traits::construct(a, pval BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1045 value_destructor<stored_allocator_type, value_type> d(a, *pval);\
1046 return this->insert_unique(hint, ::boost::move(*pval));\
1047 }\
1048 \
1049 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1050 iterator emplace_equal(BOOST_MOVE_UREF##N)\
1051 {\
1052 typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
1053 value_type *pval = reinterpret_cast<value_type *>(v.data);\
1054 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\
1055 stored_allocator_traits::construct(a, pval BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1056 value_destructor<stored_allocator_type, value_type> d(a, *pval);\
1057 return this->insert_equal(::boost::move(*pval));\
1058 }\
1059 \
1060 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1061 iterator emplace_hint_equal(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1062 {\
1063 typename dtl::aligned_storage <sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
1064 value_type *pval = reinterpret_cast<value_type *>(v.data);\
1065 get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\
1066 stored_allocator_traits::construct(a, pval BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1067 value_destructor<stored_allocator_type, value_type> d(a, *pval);\
1068 return this->insert_equal(hint, ::boost::move(*pval));\
1069 }\
1070 template <class KeyType BOOST_MOVE_I##N BOOST_MOVE_CLASS##N>\
1071 BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool>\
1072 try_emplace(const_iterator hint, BOOST_FWD_REF(KeyType) key BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1073 {\
1074 std::pair<iterator,bool> ret;\
1075 insert_commit_data data;\
1076 const key_type & k = key;\
1077 ret.second = hint == const_iterator()\
1078 ? this->priv_insert_unique_prepare(k, data)\
1079 : this->priv_insert_unique_prepare(hint, k, data);\
1080 \
1081 if(!ret.second){\
1082 ret.first = this->nth(data.position - this->cbegin());\
1083 }\
1084 else{\
1085 ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward<KeyType>(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1086 }\
1087 return ret;\
1088 }\
1089 //
BOOST_MOVE_ITERATE_0TO7(BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE)1090 BOOST_MOVE_ITERATE_0TO7(BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE)
1091 #undef BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE
1092
1093 #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1094
1095 template<class KeyType, class M>
1096 std::pair<iterator, bool> insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj)
1097 {
1098 const key_type& k = key;
1099 std::pair<iterator,bool> ret;
1100 insert_commit_data data;
1101 ret.second = hint == const_iterator()
1102 ? this->priv_insert_unique_prepare(k, data)
1103 : this->priv_insert_unique_prepare(hint, k, data);
1104 if(!ret.second){
1105 ret.first = this->nth(data.position - this->cbegin());
1106 ret.first->second = boost::forward<M>(obj);
1107 }
1108 else{
1109 ret.first = this->m_data.m_seq.emplace(data.position, boost::forward<KeyType>(key), boost::forward<M>(obj));
1110 }
1111 return ret;
1112 }
1113
erase(const_iterator position)1114 BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator position)
1115 { return this->m_data.m_seq.erase(position); }
1116
erase(const key_type & k)1117 size_type erase(const key_type& k)
1118 {
1119 std::pair<iterator,iterator > itp = this->equal_range(k);
1120 size_type ret = static_cast<size_type>(itp.second-itp.first);
1121 if (ret){
1122 this->m_data.m_seq.erase(itp.first, itp.second);
1123 }
1124 return ret;
1125 }
1126
erase(const_iterator first,const_iterator last)1127 BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator first, const_iterator last)
1128 { return this->m_data.m_seq.erase(first, last); }
1129
clear()1130 BOOST_CONTAINER_FORCEINLINE void clear()
1131 { this->m_data.m_seq.clear(); }
1132
1133 //! <b>Effects</b>: Tries to deallocate the excess of memory created
1134 // with previous allocations. The size of the vector is unchanged
1135 //!
1136 //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
1137 //!
1138 //! <b>Complexity</b>: Linear to size().
shrink_to_fit()1139 BOOST_CONTAINER_FORCEINLINE void shrink_to_fit()
1140 { this->m_data.m_seq.shrink_to_fit(); }
1141
nth(size_type n)1142 BOOST_CONTAINER_FORCEINLINE iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW
1143 {
1144 const bool value = boost::container::dtl::
1145 has_member_function_callable_with_nth<container_type, size_type>::value;
1146 return flat_tree_nth<iterator>(this->m_data.m_seq, n, dtl::bool_<value>());
1147 }
1148
1149 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
nth(size_type n) const1150 const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW
1151 {
1152 const bool value = boost::container::dtl::
1153 has_member_function_callable_with_nth<container_type, size_type>::value;
1154 return flat_tree_nth<const_iterator>(this->m_data.m_seq, n, dtl::bool_<value>());
1155 }
1156
1157 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
index_of(iterator p)1158 size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW
1159 {
1160 const bool value = boost::container::dtl::
1161 has_member_function_callable_with_index_of<container_type, iterator>::value;
1162 return flat_tree_index_of(this->m_data.m_seq, p, dtl::bool_<value>());
1163 }
1164
1165 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
index_of(const_iterator p) const1166 size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW
1167 {
1168 const bool value = boost::container::dtl::
1169 has_member_function_callable_with_index_of<container_type, const_iterator>::value;
1170 return flat_tree_index_of(this->m_data.m_seq, p, dtl::bool_<value>());
1171 }
1172
1173 // set operations:
1174 BOOST_CONTAINER_ATTRIBUTE_NODISCARD
find(const key_type & k)1175 iterator find(const key_type& k)
1176 {
1177 iterator i = this->lower_bound(k);
1178 iterator end_it = this->end();
1179 if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
1180 i = end_it;
1181 }
1182 return i;
1183 }
1184
1185 BOOST_CONTAINER_ATTRIBUTE_NODISCARD
find(const key_type & k) const1186 const_iterator find(const key_type& k) const
1187 {
1188 const_iterator i = this->lower_bound(k);
1189
1190 const_iterator end_it = this->cend();
1191 if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
1192 i = end_it;
1193 }
1194 return i;
1195 }
1196
1197 template<class K>
1198 BOOST_CONTAINER_ATTRIBUTE_NODISCARD
1199 typename dtl::enable_if_transparent<key_compare, K, iterator>::type
find(const K & k)1200 find(const K& k)
1201 {
1202 iterator i = this->lower_bound(k);
1203 iterator end_it = this->end();
1204 if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
1205 i = end_it;
1206 }
1207 return i;
1208 }
1209
1210 template<class K>
1211 BOOST_CONTAINER_ATTRIBUTE_NODISCARD
1212 typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
find(const K & k) const1213 find(const K& k) const
1214 {
1215 const_iterator i = this->lower_bound(k);
1216
1217 const_iterator end_it = this->cend();
1218 if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
1219 i = end_it;
1220 }
1221 return i;
1222 }
1223
1224 BOOST_CONTAINER_ATTRIBUTE_NODISCARD
count(const key_type & k) const1225 size_type count(const key_type& k) const
1226 {
1227 std::pair<const_iterator, const_iterator> p = this->equal_range(k);
1228 size_type n = p.second - p.first;
1229 return n;
1230 }
1231
1232 template<class K>
1233 BOOST_CONTAINER_ATTRIBUTE_NODISCARD
1234 typename dtl::enable_if_transparent<key_compare, K, size_type>::type
count(const K & k) const1235 count(const K& k) const
1236 {
1237 std::pair<const_iterator, const_iterator> p = this->equal_range(k);
1238 size_type n = p.second - p.first;
1239 return n;
1240 }
1241
contains(const key_type & x) const1242 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE bool contains(const key_type& x) const
1243 { return this->find(x) != this->cend(); }
1244
1245 template<typename K>
1246 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1247 typename dtl::enable_if_transparent<key_compare, K, bool>::type
contains(const K & x) const1248 contains(const K& x) const
1249 { return this->find(x) != this->cend(); }
1250
1251 template<class C2>
merge_unique(flat_tree<Value,KeyOfValue,C2,AllocatorOrContainer> & source)1252 BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source)
1253 {
1254 this->insert_unique( boost::make_move_iterator(source.begin())
1255 , boost::make_move_iterator(source.end()));
1256 }
1257
1258 template<class C2>
merge_equal(flat_tree<Value,KeyOfValue,C2,AllocatorOrContainer> & source)1259 BOOST_CONTAINER_FORCEINLINE void merge_equal(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source)
1260 {
1261 this->insert_equal( boost::make_move_iterator(source.begin())
1262 , boost::make_move_iterator(source.end()));
1263 }
1264
merge_unique(flat_tree & source)1265 BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree& source)
1266 {
1267 const bool value = boost::container::dtl::
1268 has_member_function_callable_with_merge_unique<container_type, iterator, iterator, value_compare>::value;
1269 (flat_tree_merge_unique)
1270 ( this->m_data.m_seq
1271 , boost::make_move_iterator(source.m_data.m_seq.begin())
1272 , boost::make_move_iterator(source.m_data.m_seq.end())
1273 , this->priv_value_comp()
1274 , dtl::bool_<value>());
1275 }
1276
merge_equal(flat_tree & source)1277 BOOST_CONTAINER_FORCEINLINE void merge_equal(flat_tree& source)
1278 {
1279 const bool value = boost::container::dtl::
1280 has_member_function_callable_with_merge<container_type, iterator, iterator, value_compare>::value;
1281 (flat_tree_merge_equal)
1282 ( this->m_data.m_seq
1283 , boost::make_move_iterator(source.m_data.m_seq.begin())
1284 , boost::make_move_iterator(source.m_data.m_seq.end())
1285 , this->priv_value_comp()
1286 , dtl::bool_<value>());
1287 }
1288
1289 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
lower_bound(const key_type & k)1290 iterator lower_bound(const key_type& k)
1291 { return this->priv_lower_bound(this->begin(), this->end(), k); }
1292
1293 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
lower_bound(const key_type & k) const1294 const_iterator lower_bound(const key_type& k) const
1295 { return this->priv_lower_bound(this->cbegin(), this->cend(), k); }
1296
1297 template<class K>
1298 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1299 typename dtl::enable_if_transparent<key_compare, K, iterator>::type
lower_bound(const K & k)1300 lower_bound(const K& k)
1301 { return this->priv_lower_bound(this->begin(), this->end(), k); }
1302
1303 template<class K>
1304 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1305 typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
lower_bound(const K & k) const1306 lower_bound(const K& k) const
1307 { return this->priv_lower_bound(this->cbegin(), this->cend(), k); }
1308
1309 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
upper_bound(const key_type & k)1310 iterator upper_bound(const key_type& k)
1311 { return this->priv_upper_bound(this->begin(), this->end(), k); }
1312
1313 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
upper_bound(const key_type & k) const1314 const_iterator upper_bound(const key_type& k) const
1315 { return this->priv_upper_bound(this->cbegin(), this->cend(), k); }
1316
1317 template<class K>
1318 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1319 typename dtl::enable_if_transparent<key_compare, K,iterator>::type
upper_bound(const K & k)1320 upper_bound(const K& k)
1321 { return this->priv_upper_bound(this->begin(), this->end(), k); }
1322
1323 template<class K>
1324 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1325 typename dtl::enable_if_transparent<key_compare, K,const_iterator>::type
upper_bound(const K & k) const1326 upper_bound(const K& k) const
1327 { return this->priv_upper_bound(this->cbegin(), this->cend(), k); }
1328
1329 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
equal_range(const key_type & k)1330 std::pair<iterator,iterator> equal_range(const key_type& k)
1331 { return this->priv_equal_range(this->begin(), this->end(), k); }
1332
1333 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
equal_range(const key_type & k) const1334 std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
1335 { return this->priv_equal_range(this->cbegin(), this->cend(), k); }
1336
1337 template<class K>
1338 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1339 typename dtl::enable_if_transparent<key_compare, K, std::pair<iterator,iterator> >::type
equal_range(const K & k)1340 equal_range(const K& k)
1341 { return this->priv_equal_range(this->begin(), this->end(), k); }
1342
1343 template<class K>
1344 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1345 typename dtl::enable_if_transparent<key_compare, K,std::pair<const_iterator,const_iterator> >::type
equal_range(const K & k) const1346 equal_range(const K& k) const
1347 { return this->priv_equal_range(this->cbegin(), this->cend(), k); }
1348
1349
1350 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
lower_bound_range(const key_type & k)1351 std::pair<iterator, iterator> lower_bound_range(const key_type& k)
1352 { return this->priv_lower_bound_range(this->begin(), this->end(), k); }
1353
1354 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
lower_bound_range(const key_type & k) const1355 std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const
1356 { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); }
1357
1358 template<class K>
1359 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1360 typename dtl::enable_if_transparent<key_compare, K,std::pair<iterator,iterator> >::type
lower_bound_range(const K & k)1361 lower_bound_range(const K& k)
1362 { return this->priv_lower_bound_range(this->begin(), this->end(), k); }
1363
1364 template<class K>
1365 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
1366 typename dtl::enable_if_transparent<key_compare, K,std::pair<const_iterator,const_iterator> >::type
lower_bound_range(const K & k) const1367 lower_bound_range(const K& k) const
1368 { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); }
1369
1370 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
capacity() const1371 size_type capacity() const
1372 {
1373 const bool value = boost::container::dtl::
1374 has_member_function_callable_with_capacity<container_type>::value;
1375 return (flat_tree_capacity)(this->m_data.m_seq, dtl::bool_<value>());
1376 }
1377
1378 BOOST_CONTAINER_FORCEINLINE
reserve(size_type cnt)1379 void reserve(size_type cnt)
1380 {
1381 const bool value = boost::container::dtl::
1382 has_member_function_callable_with_reserve<container_type, size_type>::value;
1383 (flat_tree_reserve)(this->m_data.m_seq, cnt, dtl::bool_<value>());
1384 }
1385
1386 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
extract_sequence()1387 container_type extract_sequence()
1388 {
1389 return boost::move(m_data.m_seq);
1390 }
1391
1392 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
get_sequence_ref()1393 container_type &get_sequence_ref()
1394 {
1395 return m_data.m_seq;
1396 }
1397
adopt_sequence_equal(BOOST_RV_REF (container_type)seq)1398 BOOST_CONTAINER_FORCEINLINE void adopt_sequence_equal(BOOST_RV_REF(container_type) seq)
1399 {
1400 (flat_tree_adopt_sequence_equal)( m_data.m_seq, boost::move(seq), this->priv_value_comp()
1401 , dtl::bool_<is_contiguous_container<container_type>::value>());
1402 }
1403
adopt_sequence_unique(BOOST_RV_REF (container_type)seq)1404 BOOST_CONTAINER_FORCEINLINE void adopt_sequence_unique(BOOST_RV_REF(container_type) seq)
1405 {
1406 (flat_tree_adopt_sequence_unique)(m_data.m_seq, boost::move(seq), this->priv_value_comp()
1407 , dtl::bool_<is_contiguous_container<container_type>::value>());
1408 }
1409
adopt_sequence_equal(ordered_range_t,BOOST_RV_REF (container_type)seq)1410 void adopt_sequence_equal(ordered_range_t, BOOST_RV_REF(container_type) seq)
1411 {
1412 BOOST_ASSERT((is_sorted)(seq.cbegin(), seq.cend(), this->priv_value_comp()));
1413 m_data.m_seq = boost::move(seq);
1414 }
1415
adopt_sequence_unique(ordered_unique_range_t,BOOST_RV_REF (container_type)seq)1416 void adopt_sequence_unique(ordered_unique_range_t, BOOST_RV_REF(container_type) seq)
1417 {
1418 BOOST_ASSERT((is_sorted_and_unique)(seq.cbegin(), seq.cend(), this->priv_value_comp()));
1419 m_data.m_seq = boost::move(seq);
1420 }
1421
1422 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator ==(const flat_tree & x,const flat_tree & y)1423 friend bool operator==(const flat_tree& x, const flat_tree& y)
1424 {
1425 return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin());
1426 }
1427
1428 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator <(const flat_tree & x,const flat_tree & y)1429 friend bool operator<(const flat_tree& x, const flat_tree& y)
1430 {
1431 return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
1432 }
1433
1434 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator !=(const flat_tree & x,const flat_tree & y)1435 friend bool operator!=(const flat_tree& x, const flat_tree& y)
1436 { return !(x == y); }
1437
1438 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator >(const flat_tree & x,const flat_tree & y)1439 friend bool operator>(const flat_tree& x, const flat_tree& y)
1440 { return y < x; }
1441
1442 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator <=(const flat_tree & x,const flat_tree & y)1443 friend bool operator<=(const flat_tree& x, const flat_tree& y)
1444 { return !(y < x); }
1445
1446 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator >=(const flat_tree & x,const flat_tree & y)1447 friend bool operator>=(const flat_tree& x, const flat_tree& y)
1448 { return !(x < y); }
1449
swap(flat_tree & x,flat_tree & y)1450 BOOST_CONTAINER_FORCEINLINE friend void swap(flat_tree& x, flat_tree& y)
1451 BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y)))
1452 { x.swap(y); }
1453
1454 private:
1455
1456 template <class InputIterator>
priv_range_insertion_construct(bool unique_insertion,InputIterator first,InputIterator last)1457 void priv_range_insertion_construct( bool unique_insertion, InputIterator first, InputIterator last)
1458 {
1459 //Use cend() as hint to achieve linear time for
1460 //ordered ranges as required by the standard
1461 //for the constructor
1462 //Call end() every iteration as reallocation might have invalidated iterators
1463 if(unique_insertion){
1464 this->insert_unique(first, last);
1465 }
1466 else{
1467 this->insert_equal (first, last);
1468 }
1469 }
1470
priv_in_range_or_end(const_iterator pos) const1471 BOOST_CONTAINER_FORCEINLINE bool priv_in_range_or_end(const_iterator pos) const
1472 {
1473 return (this->begin() <= pos) && (pos <= this->end());
1474 }
1475
1476 // insert/erase
priv_insert_equal_prepare(const_iterator pos,const value_type & val,insert_commit_data & data)1477 void priv_insert_equal_prepare
1478 (const_iterator pos, const value_type& val, insert_commit_data &data)
1479 {
1480 // N1780
1481 // To insert val at pos:
1482 // if pos == end || val <= *pos
1483 // if pos == begin || val >= *(pos-1)
1484 // insert val before pos
1485 // else
1486 // insert val before upper_bound(val)
1487 // else
1488 // insert val before lower_bound(val)
1489 const value_compare &val_cmp = this->m_data;
1490
1491 if(pos == this->cend() || !val_cmp(*pos, val)){
1492 if (pos == this->cbegin() || !val_cmp(val, pos[-1])){
1493 data.position = pos;
1494 }
1495 else{
1496 data.position =
1497 this->priv_upper_bound(this->cbegin(), pos, KeyOfValue()(val));
1498 }
1499 }
1500 else{
1501 data.position =
1502 this->priv_lower_bound(pos, this->cend(), KeyOfValue()(val));
1503 }
1504 }
1505
priv_insert_unique_prepare(const_iterator b,const_iterator e,const key_type & k,insert_commit_data & commit_data)1506 bool priv_insert_unique_prepare
1507 (const_iterator b, const_iterator e, const key_type& k, insert_commit_data &commit_data)
1508 {
1509 const key_compare &key_cmp = this->priv_key_comp();
1510 commit_data.position = this->priv_lower_bound(b, e, k);
1511 return commit_data.position == e || key_cmp(k, KeyOfValue()(*commit_data.position));
1512 }
1513
priv_insert_unique_prepare(const key_type & k,insert_commit_data & commit_data)1514 BOOST_CONTAINER_FORCEINLINE bool priv_insert_unique_prepare
1515 (const key_type& k, insert_commit_data &commit_data)
1516 { return this->priv_insert_unique_prepare(this->cbegin(), this->cend(), k, commit_data); }
1517
priv_insert_unique_prepare(const_iterator pos,const key_type & k,insert_commit_data & commit_data)1518 bool priv_insert_unique_prepare
1519 (const_iterator pos, const key_type& k, insert_commit_data &commit_data)
1520 {
1521 //N1780. Props to Howard Hinnant!
1522 //To insert k at pos:
1523 //if pos == end || k <= *pos
1524 // if pos == begin || k >= *(pos-1)
1525 // insert k before pos
1526 // else
1527 // insert k before upper_bound(k)
1528 //else if pos+1 == end || k <= *(pos+1)
1529 // insert k after pos
1530 //else
1531 // insert k before lower_bound(k)
1532 const key_compare &key_cmp = this->priv_key_comp();
1533 const const_iterator cend_it = this->cend();
1534 if(pos == cend_it || key_cmp(k, KeyOfValue()(*pos))){ //Check if k should go before end
1535 const const_iterator cbeg = this->cbegin();
1536 commit_data.position = pos;
1537 if(pos == cbeg){ //If container is empty then insert it in the beginning
1538 return true;
1539 }
1540 const_iterator prev(pos);
1541 --prev;
1542 if(key_cmp(KeyOfValue()(*prev), k)){ //If previous element was less, then it should go between prev and pos
1543 return true;
1544 }
1545 else if(!key_cmp(k, KeyOfValue()(*prev))){ //If previous was equal then insertion should fail
1546 commit_data.position = prev;
1547 return false;
1548 }
1549 else{ //Previous was bigger so insertion hint was pointless, dispatch to hintless insertion
1550 //but reduce the search between beg and prev as prev is bigger than k
1551 return this->priv_insert_unique_prepare(cbeg, prev, k, commit_data);
1552 }
1553 }
1554 else{
1555 //The hint is before the insertion position, so insert it
1556 //in the remaining range [pos, end)
1557 return this->priv_insert_unique_prepare(pos, cend_it, k, commit_data);
1558 }
1559 }
1560
1561 template<class Convertible>
priv_insert_commit(insert_commit_data & commit_data,BOOST_FWD_REF (Convertible)convertible)1562 BOOST_CONTAINER_FORCEINLINE iterator priv_insert_commit
1563 (insert_commit_data &commit_data, BOOST_FWD_REF(Convertible) convertible)
1564 {
1565 return this->m_data.m_seq.insert
1566 ( commit_data.position
1567 , boost::forward<Convertible>(convertible));
1568 }
1569
1570 template <class RanIt, class K>
priv_lower_bound(RanIt first,const RanIt last,const K & key) const1571 RanIt priv_lower_bound(RanIt first, const RanIt last,
1572 const K & key) const
1573 {
1574 const Compare &key_cmp = this->m_data.get_comp();
1575 KeyOfValue key_extract;
1576 size_type len = static_cast<size_type>(last - first);
1577 RanIt middle;
1578
1579 while (len) {
1580 size_type step = len >> 1;
1581 middle = first;
1582 middle += step;
1583
1584 if (key_cmp(key_extract(*middle), key)) {
1585 first = ++middle;
1586 len -= step + 1;
1587 }
1588 else{
1589 len = step;
1590 }
1591 }
1592 return first;
1593 }
1594
1595 template <class RanIt, class K>
priv_upper_bound(RanIt first,const RanIt last,const K & key) const1596 RanIt priv_upper_bound
1597 (RanIt first, const RanIt last,const K & key) const
1598 {
1599 const Compare &key_cmp = this->m_data.get_comp();
1600 KeyOfValue key_extract;
1601 size_type len = static_cast<size_type>(last - first);
1602 RanIt middle;
1603
1604 while (len) {
1605 size_type step = len >> 1;
1606 middle = first;
1607 middle += step;
1608
1609 if (key_cmp(key, key_extract(*middle))) {
1610 len = step;
1611 }
1612 else{
1613 first = ++middle;
1614 len -= step + 1;
1615 }
1616 }
1617 return first;
1618 }
1619
1620 template <class RanIt, class K>
1621 std::pair<RanIt, RanIt>
priv_equal_range(RanIt first,RanIt last,const K & key) const1622 priv_equal_range(RanIt first, RanIt last, const K& key) const
1623 {
1624 const Compare &key_cmp = this->m_data.get_comp();
1625 KeyOfValue key_extract;
1626 size_type len = static_cast<size_type>(last - first);
1627 RanIt middle;
1628
1629 while (len) {
1630 size_type step = len >> 1;
1631 middle = first;
1632 middle += step;
1633
1634 if (key_cmp(key_extract(*middle), key)){
1635 first = ++middle;
1636 len -= step + 1;
1637 }
1638 else if (key_cmp(key, key_extract(*middle))){
1639 len = step;
1640 }
1641 else {
1642 //Middle is equal to key
1643 last = first;
1644 last += len;
1645 RanIt const first_ret = this->priv_lower_bound(first, middle, key);
1646 return std::pair<RanIt, RanIt>
1647 ( first_ret, this->priv_upper_bound(++middle, last, key));
1648 }
1649 }
1650 return std::pair<RanIt, RanIt>(first, first);
1651 }
1652
1653 template<class RanIt, class K>
priv_lower_bound_range(RanIt first,RanIt last,const K & k) const1654 std::pair<RanIt, RanIt> priv_lower_bound_range(RanIt first, RanIt last, const K& k) const
1655 {
1656 const Compare &key_cmp = this->m_data.get_comp();
1657 KeyOfValue key_extract;
1658 RanIt lb(this->priv_lower_bound(first, last, k)), ub(lb);
1659 if(lb != last && !key_cmp(k, key_extract(*lb))){
1660 ++ub;
1661 }
1662 return std::pair<RanIt, RanIt>(lb, ub);
1663 }
1664 };
1665
1666 } //namespace dtl {
1667
1668 } //namespace container {
1669
1670 //!has_trivial_destructor_after_move<> == true_type
1671 //!specialization for optimizations
1672 template <class T, class KeyOfValue,
1673 class Compare, class AllocatorOrContainer>
1674 struct has_trivial_destructor_after_move<boost::container::dtl::flat_tree<T, KeyOfValue, Compare, AllocatorOrContainer> >
1675 {
1676 typedef boost::container::dtl::flat_tree<T, KeyOfValue, Compare, AllocatorOrContainer> flat_tree;
1677 typedef typename flat_tree::container_type container_type;
1678 typedef typename flat_tree::key_compare key_compare;
1679 static const bool value = ::boost::has_trivial_destructor_after_move<container_type>::value &&
1680 ::boost::has_trivial_destructor_after_move<key_compare>::value;
1681 };
1682
1683 } //namespace boost {
1684
1685 #include <boost/container/detail/config_end.hpp>
1686
1687 #endif // BOOST_CONTAINER_FLAT_TREE_HPP
1688