diff --git a/doc/container.qbk b/doc/container.qbk index 6c285a8..2b11b6e 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1237,6 +1237,8 @@ use [*Boost.Container]? There are several reasons for that: * ['vector] can now have options, using [classref boost::container::vector_options vector_options]. The growth factor and the stored size type can be specified. +* Improved range insertion in ['flat_[multi]map/set] containers overall complexity is reduced to O(NlogN). + * Fixed bugs: * [@https://github.com/boostorg/container/pull/64 GitHub #64: ['"Fix splice for slist"]]. diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 0758703..8cbb9c6 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -116,6 +116,56 @@ namespace dtl { BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(stored_allocator_type) +/////////////////////////////////////// +// +// flat_tree_container_inplace_merge +// +/////////////////////////////////////// +template +void flat_tree_container_inplace_merge //is_contiguous_container == true + (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::true_) +{ + typedef typename SequenceContainer::value_type value_type; + value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin()); + value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it); + value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end()); + boost::movelib::adaptive_merge(braw, iraw, eraw, comp, eraw, dest.capacity()- dest.size()); +} + +template +void flat_tree_container_inplace_merge //is_contiguous_container == false + (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::false_) +{ + boost::movelib::adaptive_merge(dest.begin(), it, dest.end(), comp); +} + +/////////////////////////////////////// +// +// flat_tree_container_inplace_sort_ending +// +/////////////////////////////////////// +template +void flat_tree_container_inplace_sort_ending //is_contiguous_container == true + (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::true_) +{ + typedef typename SequenceContainer::value_type value_type; + value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it); + value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end()); + boost::movelib::adaptive_sort(iraw, eraw, comp, eraw, dest.capacity()- dest.size()); +} + +template +void flat_tree_container_inplace_sort_ending //is_contiguous_container == false + (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::false_) +{ + boost::movelib::adaptive_sort(it, dest.end(), comp); +} + +/////////////////////////////////////// +// +// flat_tree_merge +// +/////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_) @@ -123,43 +173,21 @@ BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal dest.merge(first, last, comp); } -template -void aux_flat_tree_merge_equal_non_merge_member //is_contiguous_container == true - (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_) -{ - typedef typename SequenceContainer::iterator iterator; - typedef typename SequenceContainer::value_type value_type; - typedef typename SequenceContainer::size_type size_type; - - iterator const it = dest.insert( dest.end(), first, last ); - value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin()); - value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it); - value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end()); - value_type *const sraw = boost::movelib::iterator_to_raw_pointer(dest.begin())+dest.size(); - size_type const sraw_size = dest.capacity()- dest.size(); - boost::movelib::adaptive_sort(iraw, eraw, comp, sraw, sraw_size); - boost::movelib::adaptive_merge(braw, iraw, eraw, comp, sraw, sraw_size); -} - -template -void aux_flat_tree_merge_equal_non_merge_member //is_contiguous_container == false - (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_) -{ - typedef typename SequenceContainer::iterator iterator; - - iterator const it = dest.insert( dest.end(), first, last ); - boost::movelib::adaptive_sort(it, dest.end(), comp); - boost::movelib::adaptive_merge(dest.begin(), it, dest.end(), comp); -} - template BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal //has_merge_unique == false (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_) { - (aux_flat_tree_merge_equal_non_merge_member) - ( dest, first, last, comp, dtl::bool_::value>()); + typedef typename SequenceContainer::iterator iterator; + iterator const it = dest.insert( dest.end(), first, last ); + dtl::bool_::value> contiguous_tag; + (flat_tree_container_inplace_merge)(dest, it, comp, contiguous_tag); } +/////////////////////////////////////// +// +// flat_tree_merge_unique +// +/////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == true (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_) @@ -171,11 +199,22 @@ template BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == false (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_) { - (flat_tree_merge_equal)(dest, first, last, comp, dtl::false_()); - dest.erase(boost::movelib::unique - (dest.begin(), dest.end(), boost::movelib::negate(comp)), dest.cend()); + typedef typename SequenceContainer::iterator iterator; + typedef typename SequenceContainer::size_type size_type; + + size_type const old_sz = dest.size(); + iterator const first_new = dest.insert(dest.cend(), first, last ); + iterator e = boost::movelib::inplace_set_difference(first_new, dest.end(), dest.begin(), first_new, comp); + dest.erase(e, dest.end()); + dtl::bool_::value> contiguous_tag; + (flat_tree_container_inplace_merge)(dest, dest.begin()+old_sz, comp, contiguous_tag); } +/////////////////////////////////////// +// +// flat_tree_index_of +// +/////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type flat_tree_index_of // has_index_of == true @@ -193,6 +232,11 @@ BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type return static_cast(p - cont.begin()); } +/////////////////////////////////////// +// +// flat_tree_nth +// +/////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE Iterator flat_tree_nth // has_nth == true @@ -209,6 +253,11 @@ BOOST_CONTAINER_FORCEINLINE Iterator return cont.begin()+ n; } +/////////////////////////////////////// +// +// flat_tree_get_stored_allocator +// +/////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::stored_allocator_type & flat_tree_get_stored_allocator // has_get_stored_allocator == true @@ -233,17 +282,39 @@ BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::allocator_type return cont.get_allocator(); } +/////////////////////////////////////// +// +// flat_tree_adopt_sequence_equal +// +/////////////////////////////////////// +template +void flat_tree_sort_contiguous_to_adopt // is_contiguous_container == true + (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp) +{ + if(tseq.capacity() >= (seq.capacity() - seq.size())) { + tseq.clear(); + boost::movelib::adaptive_sort + (boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , comp + , boost::movelib::iterator_to_raw_pointer(tseq.begin()) + , tseq.capacity()); + } + else{ + boost::movelib::adaptive_sort + (boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , comp + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , seq.capacity() - seq.size()); + } +} + template void flat_tree_adopt_sequence_equal // is_contiguous_container == true (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_) { - tseq.clear(); - boost::movelib::adaptive_sort - (boost::movelib::iterator_to_raw_pointer(seq.begin()) - , boost::movelib::iterator_to_raw_pointer(seq.end()) - , comp - , boost::movelib::iterator_to_raw_pointer(tseq.begin() + tseq.size()) - , tseq.capacity() - tseq.size()); + flat_tree_sort_contiguous_to_adopt(tseq, boost::move(seq), comp); tseq = boost::move(seq); } @@ -255,10 +326,16 @@ void flat_tree_adopt_sequence_equal // is_contiguous_container == false tseq = boost::move(seq); } +/////////////////////////////////////// +// +// flat_tree_adopt_sequence_unique +// +/////////////////////////////////////// template void flat_tree_adopt_sequence_unique// is_contiguous_container == true (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_) { + tseq.clear(); boost::movelib::adaptive_sort ( boost::movelib::iterator_to_raw_pointer(seq.begin()) , boost::movelib::iterator_to_raw_pointer(seq.end()) @@ -281,6 +358,11 @@ void flat_tree_adopt_sequence_unique// is_contiguous_container == false tseq = boost::move(seq); } +/////////////////////////////////////// +// +// flat_tree_reserve +// +/////////////////////////////////////// template BOOST_CONTAINER_FORCEINLINE void // has_reserve == true flat_tree_reserve(SequenceContainer &tseq, typename SequenceContainer::size_type cap, dtl::true_) @@ -294,6 +376,11 @@ BOOST_CONTAINER_FORCEINLINE void // has_reserve == false { } +/////////////////////////////////////// +// +// flat_tree_capacity +// +/////////////////////////////////////// template // has_capacity == true BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type flat_tree_capacity(const SequenceContainer &tseq, dtl::true_) @@ -784,108 +871,50 @@ class flat_tree template void insert_unique(InIt first, InIt last) { - for ( ; first != last; ++first){ - this->insert_unique(*first); - } + dtl::bool_::value> contiguous_tag; + container_type &seq = this->m_data.m_seq; + value_compare &val_cmp = this->priv_value_comp(); + + //Step 1: put new elements in the back + typename container_type::iterator const it = seq.insert(seq.cend(), first, last); + + //Step 2: sort them + (flat_tree_container_inplace_sort_ending)(seq, it, val_cmp, contiguous_tag); + + //Step 3: only left unique values from the back not already present in the original range + typename container_type::iterator const e = boost::movelib::inplace_set_unique_difference + (it, seq.end(), seq.begin(), it, val_cmp); + seq.erase(e, seq.cend()); + + //Step 4: merge both ranges + (flat_tree_container_inplace_merge)(seq, it, this->priv_value_comp(), contiguous_tag); } template - void insert_equal(InIt first, InIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::enable_if_c - < dtl::is_input_iterator::value - >::type * = 0 - #endif - ) - { this->priv_insert_equal_loop(first, last); } - - template - void insert_equal(InIt first, InIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::enable_if_c - < !dtl::is_input_iterator::value - >::type * = 0 - #endif - ) + void insert_equal(InIt first, InIt last) { - const size_type len = static_cast(boost::container::iterator_distance(first, last)); - this->reserve(this->size()+len); - this->priv_insert_equal_loop(first, last); + dtl::bool_::value> contiguous_tag; + container_type &seq = this->m_data.m_seq; + typename container_type::iterator const it = seq.insert(seq.cend(), first, last); + (flat_tree_container_inplace_sort_ending)(seq, it, this->priv_value_comp(), contiguous_tag); + (flat_tree_container_inplace_merge) (seq, it, this->priv_value_comp(), contiguous_tag); } //Ordered template - void insert_equal(ordered_range_t, InIt first, InIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::enable_if_c - < dtl::is_input_iterator::value - >::type * = 0 - #endif - ) - { this->priv_insert_equal_loop_ordered(first, last); } - - template - void insert_equal(ordered_range_t, FwdIt first, FwdIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::enable_if_c - < !dtl::is_input_iterator::value && - dtl::is_forward_iterator::value - >::type * = 0 - #endif - ) - { - const size_type len = static_cast(boost::container::iterator_distance(first, last)); - this->reserve(this->size()+len); - this->priv_insert_equal_loop_ordered(first, last); - } - - template - void insert_equal(ordered_range_t, BidirIt first, BidirIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::disable_if_or - < void - , dtl::is_input_iterator - , dtl::is_forward_iterator - >::type * = 0 - #endif - ) + void insert_equal(ordered_range_t, InIt first, InIt last) { const bool value = boost::container::dtl:: - has_member_function_callable_with_merge_unique::value; + has_member_function_callable_with_merge_unique::value; (flat_tree_merge_equal)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_()); } template - void insert_unique(ordered_unique_range_t, InIt first, InIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::enable_if_or - < void - , dtl::is_input_iterator - , dtl::is_forward_iterator - >::type * = 0 - #endif - ) - { - const_iterator pos(this->cend()); - for ( ; first != last; ++first){ - pos = this->insert_unique(pos, *first); - ++pos; - } - } - - template - void insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::enable_if_c - < !(dtl::is_input_iterator::value || - dtl::is_forward_iterator::value) - >::type * = 0 - #endif - ) + void insert_unique(ordered_unique_range_t, InIt first, InIt last) { const bool value = boost::container::dtl:: - has_member_function_callable_with_merge_unique::value; + has_member_function_callable_with_merge_unique::value; (flat_tree_merge_unique)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_()); } @@ -1287,14 +1316,10 @@ class flat_tree //for the constructor //Call end() every iteration as reallocation might have invalidated iterators if(unique_insertion){ - for ( ; first != last; ++first){ - this->insert_unique(this->cend(), *first); - } + this->insert_unique(first, last); } else{ - for ( ; first != last; ++first){ - this->insert_equal(this->cend(), *first); - } + this->insert_equal (first, last); } } @@ -1491,27 +1516,6 @@ class flat_tree } return std::pair(lb, ub); } - - template - void priv_insert_equal_loop(InIt first, InIt last) - { - for ( ; first != last; ++first){ - this->insert_equal(*first); - } - } - - template - void priv_insert_equal_loop_ordered(InIt first, InIt last) - { - const_iterator pos(this->cend()); - for ( ; first != last; ++first){ - //If ordered, then try hint version - //to achieve constant-time complexity per insertion - //in some cases - pos = this->insert_equal(pos, *first); - ++pos; - } - } }; } //namespace dtl { diff --git a/include/boost/container/detail/iterator.hpp b/include/boost/container/detail/iterator.hpp index 8538acc..2ceaf26 100644 --- a/include/boost/container/detail/iterator.hpp +++ b/include/boost/container/detail/iterator.hpp @@ -22,6 +22,7 @@ #endif #include +#include namespace boost { namespace container { @@ -34,6 +35,35 @@ using ::boost::intrusive::iterator_enable_if_tag; using ::boost::intrusive::iterator_disable_if_tag; using ::boost::intrusive::iterator_arrow_result; +template +class back_emplacer +{ + private: + Container& container; + + public: + typedef std::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + back_emplacer(Container& x) + : container(x) + {} + + template + back_emplacer& operator=(BOOST_FWD_REF(U) value) + { + container.emplace_back(boost::forward(value)); + return *this; + } + back_emplacer& operator*() { return *this; } + back_emplacer& operator++() { return *this; } + back_emplacer& operator++(int){ return *this; } +}; + + } //namespace container { } //namespace boost { diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index d489d37..ffd0d05 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -1113,8 +1113,7 @@ class flat_map //! Effects: inserts each element from the range [first,last) if and only //! if there is no element with key equivalent to the key of that element. //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: N log(size()+N). //! //! Note: If an element is inserted it might invalidate elements. template @@ -1130,8 +1129,7 @@ class flat_map //! if there is no element with key equivalent to the key of that element. This //! function is more efficient than the normal range creation for ordered ranges. //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: Linear. //! //! Note: If an element is inserted it might invalidate elements. //! @@ -1144,8 +1142,7 @@ class flat_map //! Effects: inserts each element from the range [il.begin(), il.end()) if and only //! if there is no element with key equivalent to the key of that element. //! - //! Complexity: At most N log(size()+N) (N is the distance from il.first() to il.end()) - //! search time plus N*size() insertion time. + //! Complexity: N log(N). //! //! Note: If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) @@ -1161,8 +1158,7 @@ class flat_map //! if there is no element with key equivalent to the key of that element. This //! function is more efficient than the normal range creation for ordered ranges. //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: Linear. //! //! Note: If an element is inserted it might invalidate elements. //! @@ -2262,8 +2258,7 @@ class flat_multimap //! //! Effects: inserts each element from the range [first,last) . //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: N log(N). //! //! Note: If an element is inserted it might invalidate elements. template @@ -2278,8 +2273,7 @@ class flat_multimap //! if there is no element with key equivalent to the key of that element. This //! function is more efficient than the normal range creation for ordered ranges. //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: Linear. //! //! Note: If an element is inserted it might invalidate elements. //! @@ -2291,8 +2285,7 @@ class flat_multimap #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: inserts each element from the range [il.begin(), il.end()) . //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: N log(N). //! //! Note: If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) @@ -2307,8 +2300,7 @@ class flat_multimap //! if there is no element with key equivalent to the key of that element. This //! function is more efficient than the normal range creation for ordered ranges. //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: Linear. //! //! Note: If an element is inserted it might invalidate elements. //! diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 706f705..59ab573 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -687,8 +687,7 @@ class flat_set //! Effects: inserts each element from the range [first,last) if and only //! if there is no element with key equivalent to the key of that element. //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: N log(N). //! //! Note: If an element is inserted it might invalidate elements. template @@ -702,8 +701,7 @@ class flat_set //! Effects: inserts each element from the range [first,last) .This function //! is more efficient than the normal range creation for ordered ranges. //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: Linear. //! //! Note: Non-standard extension. If an element is inserted it might invalidate elements. template @@ -714,8 +712,7 @@ class flat_set //! Effects: inserts each element from the range [il.begin(), il.end()) if and only //! if there is no element with key equivalent to the key of that element. //! - //! Complexity: At most N log(size()+N) (N is the distance from il.begin() to il.end()) - //! search time plus N*size() insertion time. + //! Complexity: N log(N). //! //! Note: If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) @@ -727,8 +724,7 @@ class flat_set //! Effects: inserts each element from the range [il.begin(), il.end()) .This function //! is more efficient than the normal range creation for ordered ranges. //! - //! Complexity: At most N log(size()+N) (N is the distance from il.begin() to il.end()) - //! search time plus N*size() insertion time. + //! Complexity: Linear. //! //! Note: Non-standard extension. If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(ordered_unique_range_t, std::initializer_list il) @@ -1456,8 +1452,7 @@ class flat_multiset //! //! Effects: inserts each element from the range [first,last) . //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: N log(N). //! //! Note: If an element is inserted it might invalidate elements. template @@ -1470,8 +1465,7 @@ class flat_multiset //! Effects: inserts each element from the range [first,last) .This function //! is more efficient than the normal range creation for ordered ranges. //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: Linear. //! //! Note: Non-standard extension. If an element is inserted it might invalidate elements. template @@ -1481,8 +1475,7 @@ class flat_multiset #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: inserts each element from the range [il.begin(), il.end()). //! - //! Complexity: At most N log(size()+N) (N is the distance from first to last) - //! search time plus N*size() insertion time. + //! Complexity: N log(N). //! //! Note: If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) @@ -1493,8 +1486,7 @@ class flat_multiset //! Effects: inserts each element from the range [il.begin(), il.end()). This function //! is more efficient than the normal range creation for ordered ranges. //! - //! Complexity: At most N log(size()+N) (N is the distance from il.begin() to il.end()) - //! search time plus N*size() insertion time. + //! Complexity: Linear. //! //! Note: Non-standard extension. If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(ordered_range_t, std::initializer_list il) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 0d26181..a6a5335 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -60,6 +60,7 @@ #include #include #include +#include // other #include #include @@ -75,6 +76,7 @@ namespace container { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + template class vec_iterator { @@ -210,40 +212,6 @@ struct vector_insert_ordered_cursor BiDirValueIt last_value_it; }; -template -struct vector_merge_cursor -{ - typedef SizeType size_type; - typedef typename iterator_traits::reference reference; - - BOOST_CONTAINER_FORCEINLINE vector_merge_cursor(T *pbeg, T *plast, BiDirValueIt valueit, Comp &cmp) - : m_pbeg(pbeg), m_pcur(--plast), m_valueit(valueit), m_cmp(cmp) - {} - - void operator --() - { - --m_valueit; - const T &t = *m_valueit; - while((m_pcur + 1) != m_pbeg){ - if(!m_cmp(t, *m_pcur)){ - break; - } - --m_pcur; - } - } - - BOOST_CONTAINER_FORCEINLINE size_type get_pos() const - { return static_cast((m_pcur + 1) - m_pbeg); } - - BOOST_CONTAINER_FORCEINLINE reference get_val() - { return *m_valueit; } - - T *const m_pbeg; - T *m_pcur; - BiDirValueIt m_valueit; - Comp &m_cmp; -}; - struct initial_capacity_t{}; template @@ -508,10 +476,14 @@ struct vector_alloc_holder BOOST_CONTAINER_FORCEINLINE const Allocator &alloc() const BOOST_NOEXCEPT_OR_NOTHROW { return *this; } - const pointer &start() const BOOST_NOEXCEPT_OR_NOTHROW { return m_start; } - size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW { return m_capacity; } - void start(const pointer &p) BOOST_NOEXCEPT_OR_NOTHROW { m_start = p; } - void capacity(const size_type &c) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT( c <= stored_size_type(-1)); m_capacity = c; } + BOOST_CONTAINER_FORCEINLINE const pointer &start() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_start; } + BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_capacity; } + BOOST_CONTAINER_FORCEINLINE void start(const pointer &p) BOOST_NOEXCEPT_OR_NOTHROW + { m_start = p; } + BOOST_CONTAINER_FORCEINLINE void capacity(const size_type &c) BOOST_NOEXCEPT_OR_NOTHROW + { BOOST_ASSERT( c <= stored_size_type(-1)); m_capacity = c; } private: void priv_first_allocation(size_type cap) @@ -2191,21 +2163,45 @@ class vector return this->priv_insert_ordered_at(element_count, inserter_t(last_position_it, last_value_it)); } - template - BOOST_CONTAINER_FORCEINLINE void merge(BidirIt first, BidirIt last) + template + BOOST_CONTAINER_FORCEINLINE void merge(InputIt first, InputIt last) { this->merge(first, last, value_less_t()); } - template - BOOST_CONTAINER_FORCEINLINE void merge(BidirIt first, BidirIt last, Compare comp) - { this->priv_merge(dtl::false_type(), first, last, comp); } + template + BOOST_CONTAINER_FORCEINLINE void merge(InputIt first, InputIt last, Compare comp) + { + size_type const s = this->size(); + size_type const c = this->capacity(); + size_type n = 0; + size_type const free_cap = c - s; + //If not input iterator and new elements don't fit in the remaining capacity, merge in new buffer + if(!dtl::is_input_iterator::value && + free_cap < (n = static_cast(boost::container::iterator_distance(first, last)))){ + this->priv_merge_in_new_buffer(first, n, comp, alloc_version()); + } + else{ + iterator pos(this->insert(this->cend(), first, last)); + T *const raw_beg = this->priv_raw_begin(); + T *const raw_end = this->priv_raw_end(); + T *const raw_pos = raw_beg + s; + boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, free_cap - n); + } + } - template - BOOST_CONTAINER_FORCEINLINE void merge_unique(BidirIt first, BidirIt last) - { this->priv_merge(dtl::true_type(), first, last, value_less_t()); } + template + BOOST_CONTAINER_FORCEINLINE void merge_unique(InputIt first, InputIt last) + { this->merge_unique(first, last, value_less_t()); } - template - BOOST_CONTAINER_FORCEINLINE void merge_unique(BidirIt first, BidirIt last, Compare comp) - { this->priv_merge(dtl::true_type(), first, last, comp); } + template + BOOST_CONTAINER_FORCEINLINE void merge_unique(InputIt first, InputIt last, Compare comp) + { + size_type const s = this->size(); + this->priv_set_difference_back(first, last, comp); + T *const raw_beg = this->priv_raw_begin(); + T *const raw_end = this->priv_raw_end(); + T *raw_pos = raw_beg + s; + boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, this->capacity() - this->size()); + } private: template @@ -2265,43 +2261,48 @@ class vector } } - template - void priv_merge(UniqueBool, BidirIt first, BidirIt last, Compare comp) + template + void priv_set_difference_back(InputIt first1, InputIt last1, Compare comp) { - size_type const n = static_cast(boost::container::iterator_distance(first, last)); - size_type const s = this->size(); - if(BOOST_LIKELY(s)){ - size_type const c = this->capacity(); - size_type const free_c = (c - s); - //Use a new buffer if current one is too small for new elements - if(free_c < n){ - this->priv_merge_in_new_buffer(UniqueBool(), first, n, comp, alloc_version()); + T * old_first2 = this->priv_raw_begin(); + T * first2 = old_first2; + T * last2 = this->priv_raw_end(); + + while (first1 != last1) { + if (first2 == last2){ + this->insert(this->cend(), first1, last1); + return; } - else{ - T *raw_pos = boost::movelib::iterator_to_raw_pointer(this->insert(this->cend(), first, last)); - T *raw_beg = this->priv_raw_begin(); - T *raw_end = this->priv_raw_end(); - boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, free_c - n); - if(UniqueBool::value){ - size_type const count = - static_cast(raw_end - boost::movelib::unique(raw_beg, raw_end, boost::movelib::negate(comp))); - this->priv_destroy_last_n(count); + + if (comp(*first1, *first2)) { + this->emplace_back(*first1); + //Reallocation happened, update range + T * const raw_begin = this->priv_raw_begin(); + if(old_first2 != raw_begin){ + first2 = raw_begin + (first2 - old_first2); + last2 = first2 + (last2 - old_first2); + old_first2 = raw_begin; } + + ++first1; + } + else { + if (!comp(*first2, *first1)) { + ++first1; + } + ++first2; } - } - else{ - this->insert(this->cend(), n, first, last); } } - template - BOOST_CONTAINER_FORCEINLINE void priv_merge_in_new_buffer(UniqueBool, FwdIt, size_type, Compare, version_0) + template + BOOST_CONTAINER_FORCEINLINE void priv_merge_in_new_buffer(FwdIt, size_type, Compare, version_0) { throw_bad_alloc(); } - template - void priv_merge_in_new_buffer(UniqueBool, FwdIt first, size_type n, Compare comp, Version) + template + void priv_merge_in_new_buffer(FwdIt first, size_type n, Compare comp, Version) { size_type const new_size = this->size() + n; size_type new_cap = new_size; @@ -2335,11 +2336,6 @@ class vector --n; ++d_first; } - else if(UniqueBool::value && !comp(*pbeg, *first)){ - ++first; - --n; - --added; - } else{ allocator_traits_type::construct( this->m_holder.alloc(), d_first, boost::move(*pbeg) ); new_values_destroyer.increment_size(1u); diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index 4c02643..e23cf7a 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -316,6 +316,25 @@ bool flat_tree_ordered_insertion_test() int_set4.insert(int_even_set.begin(), int_even_set.end()); if(!CheckEqualContainers(int_set4, fset)) return false; + + //add even/odd values with not enough capacity + flat_set().swap(fset); + int_set4.clear(); + int_set.clear(); + + fset.reserve(int_even_set.size()); + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + + for(std::size_t i = 0; i < NumElements*2; i+=2){ + int_set.insert(static_cast(i)); + int_set.insert(static_cast(i+1)); + } + + fset.insert(ordered_unique_range, int_set.begin(), int_set.end()); + int_set4.insert(int_set.begin(), int_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; } return true; diff --git a/test/set_test.hpp b/test/set_test.hpp index 03e0bb9..b8ca649 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -388,12 +388,12 @@ int set_test () boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50); - boostmultiset.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(aux_vect3 + 50)); - stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); if(!CheckEqualContainers(boostset, stdset)){ - std::cout << "Error in boostset.insert(boost::make_move_iterator(&aux_vect[0])..." << std::endl; + std::cout << "Error in boostset.insert(boost::make_move_iterator(&aux_vect3[0])..." << std::endl; return 1; } + boostmultiset.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(aux_vect3 + 50)); + stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); if(!CheckEqualContainers(boostmultiset, stdmultiset)){ std::cout << "Error in boostmultiset.insert(boost::make_move_iterator(&aux_vect3[0]), ..." << std::endl; return 1; @@ -447,14 +447,14 @@ int set_test () boostset.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + 50)); stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50); stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50); - boostmultiset.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(&aux_vect4[0] + 50)); - boostmultiset.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(&aux_vect5[0] + 50)); - stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); - stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); if(!CheckEqualContainers(boostset, stdset)){ std::cout << "Error in boostset.insert(boost::make_move_iterator(&aux_vect3[0])..." << std::endl; return 1; } + boostmultiset.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(&aux_vect4[0] + 50)); + boostmultiset.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(&aux_vect5[0] + 50)); + stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); + stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); if(!CheckEqualContainers(boostmultiset, stdmultiset)){ std::cout << "Error in boostmultiset.insert(boost::make_move_iterator(&aux_vect5[0])..." << std::endl; return 1; @@ -462,12 +462,12 @@ int set_test () boostset.erase(*boostset.begin()); stdset.erase(*stdset.begin()); - boostmultiset.erase(*boostmultiset.begin()); - stdmultiset.erase(*stdmultiset.begin()); if(!CheckEqualContainers(boostset, stdset)){ std::cout << "Error in boostset.erase(*boostset.begin())" << std::endl; return 1; } + boostmultiset.erase(*boostmultiset.begin()); + stdmultiset.erase(*stdmultiset.begin()); if(!CheckEqualContainers(boostmultiset, stdmultiset)){ std::cout << "Error in boostmultiset.erase(*boostmultiset.begin())" << std::endl; return 1;