diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index ee926d9..958ee04 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -37,6 +37,7 @@ #include #endif #include +#include namespace boost { @@ -466,47 +467,7 @@ class flat_tree >::type * = 0 #endif ) - { - size_type len = static_cast(std::distance(first, last)); - const size_type BurstSize = 16; - size_type positions[BurstSize]; - - //Prereserve all memory so that iterators are not invalidated - this->reserve(this->size()+len); - const const_iterator b(this->cbegin()); - const_iterator pos(b); - //Loop in burst sizes - bool back_insert = false; - while(len && !back_insert){ - size_type burst = len < BurstSize ? len : BurstSize; - const const_iterator ce(this->cend()); - for(size_type i = 0; i != burst; ++i){ - //Get the insertion position for each key, use std::iterator_traits::value_type - //because it can be different from container::value_type - //(e.g. conversion between std::pair -> boost::container::pair - const typename std::iterator_traits::value_type & val = *first; - pos = const_cast(*this).priv_upper_bound(pos, ce, KeyOfValue()(val)); - if(pos == this->cend()){ //this element and the remaining should be back inserted - burst = i; - back_insert = true; - break; - } - else{ - positions[i] = static_cast(pos - b); - ++first; - --len; - } - } - //Insert all in a single step in the precalculated positions - this->m_data.m_vect.insert_ordered_at(burst, positions + burst, first); - //Next search position updated, iterator still valid because we've preserved the vector - pos += burst; - } - if(first != last){ - //The remaining range should be back inserted - this->m_data.m_vect.insert(this->m_data.m_vect.cend(), len, first, last); - } - } + { this->priv_insert_ordered_range(false, first, last); } template void insert_unique(ordered_unique_range_t, InIt first, InIt last @@ -534,61 +495,7 @@ class flat_tree >::type * = 0 #endif ) - { - size_type len = static_cast(std::distance(first, last)); - const size_type BurstSize = 16; - size_type positions[BurstSize]; - size_type skips[BurstSize]; - - //Prereserve all memory so that iterators are not invalidated - this->reserve(this->size()+len); - const const_iterator b(this->cbegin()); - const_iterator pos(b); - const value_compare &val_cmp = this->m_data; - skips[0u] = 0u; - //Loop in burst sizes - bool back_insert = false; - while(len && !back_insert){ - const size_type burst = len < BurstSize ? len : BurstSize; - size_type unique_burst = 0u; - const const_iterator ce(this->cend()); - while(unique_burst < burst && len > 0){ - //Get the insertion position for each key, use std::iterator_traits::value_type - //because it can be different from container::value_type - //(e.g. conversion between std::pair -> boost::container::pair - const typename std::iterator_traits::value_type & val = *first; - pos = const_cast(*this).priv_lower_bound(pos, ce, KeyOfValue()(val)); - //Check if already present - if (pos != ce){ - ++first; - --len; - if(!val_cmp(val, *pos)){ - if(unique_burst > 0){ - ++skips[unique_burst-1]; - } - continue; - } - //If not present, calculate position - positions[unique_burst] = static_cast(pos - b); - skips[unique_burst++] = 0u; - } - else{ //this element and the remaining should be back inserted - back_insert = true; - break; - } - } - if(unique_burst){ - //Insert all in a single step in the precalculated positions - this->m_data.m_vect.insert_ordered_at(unique_burst, positions + unique_burst, skips + unique_burst, first); - //Next search position updated, iterator still valid because we've preserved the vector - pos += unique_burst; - } - } - if(first != last){ - //The remaining range should be back inserted - this->m_data.m_vect.insert(this->m_data.m_vect.cend(), len, first, last); - } - } + { this->priv_insert_ordered_range(true, first, last); } #ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -1023,6 +930,71 @@ class flat_tree ++pos; } } + + template + void priv_insert_ordered_range(const bool unique_values, BidirIt first, BidirIt last) + { + size_type len = static_cast(std::distance(first, last)); + //Prereserve all memory so that iterators are not invalidated + this->reserve(this->size()+len); + //Auxiliary data for insertion positions. + const size_type BurstSize = len; + const ::boost::movelib::unique_ptr positions = + ::boost::movelib::make_unique_definit(BurstSize); + + const const_iterator b(this->cbegin()); + const const_iterator ce(this->cend()); + const_iterator pos(b); + const value_compare &val_cmp = this->m_data; + //Loop in burst sizes + bool back_insert = false; + while(len && !back_insert){ + const size_type burst = len < BurstSize ? len : BurstSize; + size_type unique_burst = 0u; + size_type checked = 0; + for(; checked != burst; ++checked){ + //Get the insertion position for each key, use std::iterator_traits::value_type + //because it can be different from container::value_type + //(e.g. conversion between std::pair -> boost::container::pair + const typename std::iterator_traits::value_type & val = *first; + pos = const_cast(*this).priv_lower_bound(pos, ce, KeyOfValue()(val)); + //Check if already present + if (pos != ce){ + ++first; + --len; + positions[checked] = (unique_values && !val_cmp(val, *pos)) ? + size_type(-1) : (++unique_burst, static_cast(pos - b)); + } + else{ //this element and the remaining should be back inserted + back_insert = true; + break; + } + } + if(unique_burst){ + //Insert all in a single step in the precalculated positions + this->m_data.m_vect.insert_ordered_at(unique_burst, positions.get() + checked, first); + //Next search position updated, iterator still valid because we've preserved the vector + pos += unique_burst; + } + } + //The remaining range should be back inserted + if(unique_values){ + while(len--){ + BidirIt next(first); + ++next; + if(next == last || val_cmp(*first, *next)){ + this->m_data.m_vect.push_back(*first); + } + first = next; + } + BOOST_ASSERT(first == last); + } + else{ + BOOST_ASSERT(size_type(std::distance(first, last)) == len); + if(len) + this->m_data.m_vect.insert(this->m_data.m_vect.cend(), len, first, last); + } + } }; } //namespace container_detail { diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index 01d4e8f..ec0ecc1 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -322,12 +322,74 @@ bool flat_tree_ordered_insertion_test() //Re-re-insertion of even std::set int_even_set; for(std::size_t i = 0; i < NumElements; i+=2){ - int_set.insert(static_cast(i)); + int_even_set.insert(static_cast(i)); } fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); int_set4.insert(int_even_set.begin(), int_even_set.end()); if(!CheckEqualContainers(&int_set4, &fset)) return false; + //Partial Re-re-insertion of even + int_even_set.clear(); + for(std::size_t i = 0; i < NumElements; i+=4){ + int_even_set.insert(static_cast(i)); + } + fset.clear(); + int_set4.clear(); + //insert 0,4,8,12... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(&int_set4, &fset)) + return false; + for(std::size_t i = 2; i < NumElements; i+=4){ + int_even_set.insert(static_cast(i)); + } + //insert 0,2,4,6,8,10,12... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(&int_set4, &fset)) + return false; + int_even_set.clear(); + for(std::size_t i = 0; i < NumElements; i+=8){ + int_even_set.insert(static_cast(i)); + } + fset.clear(); + int_set4.clear(); + //insert 0,8,16... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(&int_set4, &fset)) + return false; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_even_set.insert(static_cast(i)); + } + //insert 0,2,4,6,8,10,12... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(&int_set4, &fset)) + return false; + + + int_even_set.clear(); + for(std::size_t i = 0; i < NumElements; i+=8){ + int_even_set.insert(static_cast(i)); + int_even_set.insert(static_cast(i+2)); + } + int_even_set.insert(static_cast(NumElements-2)); + fset.clear(); + int_set4.clear(); + //insert 0,2,8,10... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(&int_set4, &fset)) + return false; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_even_set.insert(static_cast(i)); + } + //insert 0,2,4,6,8,10,12... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(&int_set4, &fset)) + return false; } return true;