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