From 9b25c7134e9286fa5f7f252a7b53f810dff41f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 23 Apr 2014 23:18:18 +0200 Subject: [PATCH] * Fixed BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) missing ::value * Optimized insert_equal(ordered_range_t,...) and insert_unique(ordered_unique_range_t, ...) for elements to be inserted in the end. * Added range insertion overload (non-standard extension) to vector taking the number of elements to avoid reiterations with std::distance. --- include/boost/container/deque.hpp | 2 +- include/boost/container/detail/flat_tree.hpp | 54 ++++++++++++++------ include/boost/container/flat_map.hpp | 4 +- include/boost/container/flat_set.hpp | 4 +- include/boost/container/list.hpp | 2 +- include/boost/container/map.hpp | 2 +- include/boost/container/set.hpp | 2 +- include/boost/container/slist.hpp | 2 +- include/boost/container/stable_vector.hpp | 2 +- include/boost/container/string.hpp | 2 +- include/boost/container/vector.hpp | 30 ++++++++++- 11 files changed, 77 insertions(+), 29 deletions(-) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index b15ff1d..119d422 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -713,7 +713,7 @@ class deque : protected deque_base //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. deque& operator= (BOOST_RV_REF(deque) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { BOOST_ASSERT(this != &x); allocator_type &this_alloc = this->alloc(); diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 851e15f..1aa8dda 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -476,24 +476,36 @@ class flat_tree const const_iterator b(this->cbegin()); const_iterator pos(b); //Loop in burst sizes - while(len){ - const size_type burst = len < BurstSize ? len : BurstSize; + bool back_insert = false; + while(len && !back_insert){ + size_type burst = len < BurstSize ? len : BurstSize; const const_iterator ce(this->cend()); - len -= burst; 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)); - positions[i] = static_cast(pos - b); - ++first; + 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); + } } template @@ -535,7 +547,8 @@ class flat_tree const value_compare &val_cmp = this->m_data; skips[0u] = 0u; //Loop in burst sizes - while(len){ + 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()); @@ -544,20 +557,25 @@ class flat_tree //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; - ++first; - --len; pos = const_cast(*this).priv_lower_bound(pos, ce, KeyOfValue()(val)); //Check if already present - if (pos != ce && !val_cmp(val, *pos)){ - if(unique_burst > 0){ - ++skips[unique_burst-1]; + if (pos != ce){ + ++first; + --len; + if(!val_cmp(val, *pos)){ + if(unique_burst > 0){ + ++skips[unique_burst-1]; + } + continue; } - 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 not present, calculate position - positions[unique_burst] = static_cast(pos - b); - skips[unique_burst++] = 0u; } if(unique_burst){ //Insert all in a single step in the precalculated positions @@ -566,6 +584,10 @@ class flat_tree 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); + } } #ifdef BOOST_CONTAINER_PERFECT_FORWARDING diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 63d2d5e..bbe7396 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -283,7 +283,7 @@ class flat_map //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. flat_map& operator=(BOOST_RV_REF(flat_map) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { m_flat_tree = boost::move(x.m_flat_tree); return *this; } //! Effects: Returns a copy of the Allocator that @@ -1176,7 +1176,7 @@ class flat_multimap //! //! Complexity: Constant. flat_multimap& operator=(BOOST_RV_REF(flat_multimap) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { m_flat_tree = boost::move(x.m_flat_tree); return *this; } //! Effects: Returns a copy of the Allocator that diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 4bde4be..96f2a91 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -189,7 +189,7 @@ class flat_set //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. flat_set& operator=(BOOST_RV_REF(flat_set) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { return static_cast(this->base_t::operator=(boost::move(static_cast(x)))); } #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -810,7 +810,7 @@ class flat_multiset //! @copydoc ::boost::container::flat_set::operator=(flat_set &&) flat_multiset& operator=(BOOST_RV_REF(flat_multiset) mx) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { return static_cast(this->base_t::operator=(boost::move(static_cast(mx)))); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 4c01481..34ef678 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -344,7 +344,7 @@ class list //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. list& operator=(BOOST_RV_REF(list) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { BOOST_ASSERT(this != &x); NodeAlloc &this_alloc = this->node_alloc(); diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 6412f69..ec1c30a 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -240,7 +240,7 @@ class map //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. map& operator=(BOOST_RV_REF(map) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { return static_cast(this->base_t::operator=(boost::move(static_cast(x)))); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index acbfae0..93a02d0 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -192,7 +192,7 @@ class set //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. set& operator=(BOOST_RV_REF(set) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { return static_cast(this->base_t::operator=(boost::move(static_cast(x)))); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 252bc38..1ec8ee4 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -365,7 +365,7 @@ class slist //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. slist& operator= (BOOST_RV_REF(slist) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { BOOST_ASSERT(this != &x); NodeAlloc &this_alloc = this->node_alloc(); diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 69bfbaa..691cf58 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -750,7 +750,7 @@ class stable_vector //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. stable_vector& operator=(BOOST_RV_REF(stable_vector) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { //for move constructor, no aliasing (&x != this) is assummed. BOOST_ASSERT(this != &x); diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 9861653..116d8b5 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -742,7 +742,7 @@ class basic_string //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. basic_string& operator=(BOOST_RV_REF(basic_string) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { //for move constructor, no aliasing (&x != this) is assummed. BOOST_ASSERT(this != &x); diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 29590d2..8dc2e68 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -820,7 +820,7 @@ class vector //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. vector& operator=(BOOST_RV_REF(vector) x) - BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment) + BOOST_CONTAINER_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value) { this->priv_move_assign(boost::move(x)); return *this; @@ -1509,6 +1509,32 @@ class vector } #endif + //! Requires: p must be a valid iterator of *this. num, must + //! be equal to std::distance(first, last) + //! + //! Effects: Insert a copy of the [first, last) range before pos. + //! + //! Returns: an iterator to the first inserted element or pos if first == last. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws or T's copy/move constructor/assignment throws. + //! + //! Complexity: Linear to std::distance [first, last). + //! + //! Note: This function avoids a linear operation to calculate std::distance[first, last) + //! for forward and bidirectional iterators, and a one by one insertion for input iterators. This is a + //! a non-standard extension. + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator pos, size_type num, InIt first, InIt last) + { + BOOST_ASSERT(container_detail::is_input_iterator::value || + num == static_cast(std::distance(first, last))); + container_detail::insert_range_proxy proxy(first); + return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), num, proxy, alloc_version()); + } + #endif + //! Effects: Removes the last element from the vector. //! //! Throws: Nothing. @@ -1649,7 +1675,7 @@ class vector void insert_ordered_at(size_type element_count, BiDirPosConstIt last_position_it, BiDirValueIt last_value_it) { const size_type *dummy = 0; - this->priv_insert_ordered_at(element_count, last_position_it, false, &dummy[0], last_value_it); + this->priv_insert_ordered_at(element_count, last_position_it, false, dummy, last_value_it); } //Absolutely experimental. This function might change, disappear or simply crash!