From 40451e4bf70b5813b4990adfdffe31f9ae0fc419 Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Mon, 8 May 2017 12:39:06 -0700 Subject: [PATCH] Add variant of map constructors to avoid useless extra allocator copy when using initializer list Many existing constructors have this form: map(std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) The issue is that a temporary allocator_type is constructed, and passed to the base class where it is used to copy-constructed the rebound allocator. This temporary allocator_type here is always destroyed at the end of the map() constructor. For stateful allocators this is not desirable. The solution is to adopt what libc++ is doing and have to constructors: map(std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a) and map(std::initializer_list il, const Compare& comp = Compare()) This way, unless an allocator is provided by the client, no extra temporary creation/destruction occurs. --- include/boost/container/detail/tree.hpp | 4 +- include/boost/container/map.hpp | 159 ++++++++++++++++++++++-- 2 files changed, 149 insertions(+), 14 deletions(-) diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 7b29467..2524eed 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -519,7 +519,7 @@ class tree template tree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, - const allocator_type& a + const allocator_type& a = allocator_type() #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) , typename container_detail::enable_if_or < void @@ -548,7 +548,7 @@ class tree template tree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, - const allocator_type& a + const allocator_type& a = allocator_type() #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) , typename container_detail::disable_if_or < void diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 56aefa4..fa095c4 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -153,13 +153,24 @@ class map //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE - explicit map(const Compare& comp, const allocator_type& a = allocator_type()) + explicit map(const Compare& comp, const allocator_type& a) : base_t(comp, a) { //A type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } + //! Effects: Constructs an empty map using the specified comparison object. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE + explicit map(const Compare& comp) + : base_t(comp) + { + //A type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + //! Effects: Constructs an empty map using the specified allocator. //! //! Complexity: Constant. @@ -178,14 +189,28 @@ class map //! comp and otherwise N logN, where N is last - first. template BOOST_CONTAINER_FORCEINLINE - map(InputIterator first, InputIterator last, const Compare& comp = Compare(), - const allocator_type& a = allocator_type()) + map(InputIterator first, InputIterator last, const Compare& comp, + const allocator_type& a) : base_t(true, first, last, comp, a) { //A type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } + //! Effects: Constructs an empty map using the specified comparison object and + //! inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + BOOST_CONTAINER_FORCEINLINE + map(InputIterator first, InputIterator last, const Compare& comp = Compare()) + : base_t(true, first, last, comp) + { + //A type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + //! Effects: Constructs an empty map using the specified //! allocator, and inserts elements from the range [first ,last ). //! @@ -213,13 +238,33 @@ class map template BOOST_CONTAINER_FORCEINLINE map( ordered_unique_range_t, InputIterator first, InputIterator last - , const Compare& comp = Compare(), const allocator_type& a = allocator_type()) + , const Compare& comp, const allocator_type& a) : base_t(ordered_range, first, last, comp, a) { //A type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } + //! Effects: Constructs an empty map using the specified comparison object and + //! inserts elements from the ordered unique range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! Requires: [first ,last) must be ordered according to the predicate and must be + //! unique values. + //! + //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. + template + BOOST_CONTAINER_FORCEINLINE + map( ordered_unique_range_t, InputIterator first, InputIterator last + , const Compare& comp = Compare()) + : base_t(ordered_range, first, last, comp) + { + //A type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: Constructs an empty map using the specified comparison object and //! allocator, and inserts elements from the range [il.begin(), il.end()). @@ -227,13 +272,26 @@ class map //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is il.first() - il.end(). BOOST_CONTAINER_FORCEINLINE - map(std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) + map(std::initializer_list il, const Compare& comp, const allocator_type& a) : base_t(true, il.begin(), il.end(), comp, a) { //A type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } + //! Effects: Constructs an empty map using the specified comparison object and + //! inserts elements from the range [il.begin(), il.end()). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is il.first() - il.end(). + BOOST_CONTAINER_FORCEINLINE + map(std::initializer_list il, const Compare& comp = Compare()) + : base_t(true, il.begin(), il.end(), comp) + { + //A type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + //! Effects: Constructs an empty map using the specified //! allocator, and inserts elements from the range [il.begin(), il.end()). //! @@ -259,12 +317,30 @@ class map //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE map(ordered_unique_range_t, std::initializer_list il, const Compare& comp = Compare(), - const allocator_type& a = allocator_type()) + const allocator_type& a) : base_t(ordered_range, il.begin(), il.end(), comp, a) { //A type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } + + //! Effects: Constructs an empty set using the specified comparison object and + //! allocator, and inserts elements from the ordered unique range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! Requires: [il.begin(), il.end()) must be ordered according to the predicate and must be + //! unique values. + //! + //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE + map(ordered_unique_range_t, std::initializer_list il, const Compare& comp = Compare()) + : base_t(ordered_range, il.begin(), il.end(), comp) + { + //A type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } #endif //! Effects: Copy constructs a map. @@ -1268,14 +1344,29 @@ class multimap template BOOST_CONTAINER_FORCEINLINE multimap(InputIterator first, InputIterator last, - const Compare& comp = Compare(), - const allocator_type& a = allocator_type()) + const Compare& comp, + const allocator_type& a) : base_t(false, first, last, comp, a) { //A type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } + //! Effects: Constructs an empty multimap using the specified comparison object and + //! inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + BOOST_CONTAINER_FORCEINLINE + multimap(InputIterator first, InputIterator last, + const Compare& comp = Compare()) + : base_t(false, first, last, comp) + { + //A type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + //! Effects: Constructs an empty multimap using the specified //! allocator, and inserts elements from the range [first ,last ). //! @@ -1299,11 +1390,25 @@ class multimap //! //! Note: Non-standard extension. template - BOOST_CONTAINER_FORCEINLINE multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp = Compare(), - const allocator_type& a = allocator_type()) + BOOST_CONTAINER_FORCEINLINE multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp, + const allocator_type& a) : base_t(ordered_range, first, last, comp, a) {} + //! Effects: Constructs an empty multimap using the specified comparison object and + //! inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! Requires: [first ,last) must be ordered according to the predicate. + //! + //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. + template + BOOST_CONTAINER_FORCEINLINE multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp = Compare()) + : base_t(ordered_range, first, last, comp) + {} + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: Constructs an empty multimap using the specified comparison object and //! allocator, and inserts elements from the range [il.begin(), il.end()). @@ -1312,13 +1417,26 @@ class multimap //! comp and otherwise N logN, where N is il.first() - il.end(). BOOST_CONTAINER_FORCEINLINE multimap(std::initializer_list il, const Compare& comp = Compare(), - const allocator_type& a = allocator_type()) + const allocator_type& a) : base_t(false, il.begin(), il.end(), comp, a) { //A type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } + //! Effects: Constructs an empty multimap using the specified comparison object and + //! inserts elements from the range [il.begin(), il.end()). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is il.first() - il.end(). + BOOST_CONTAINER_FORCEINLINE + multimap(std::initializer_list il, const Compare& comp = Compare()) + : base_t(false, il.begin(), il.end(), comp) + { + //A type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + //! Effects: Constructs an empty multimap using the specified //! allocator, and inserts elements from the range [il.begin(), il.end()). //! @@ -1343,12 +1461,29 @@ class multimap //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE multimap(ordered_range_t, std::initializer_list il, const Compare& comp = Compare(), - const allocator_type& a = allocator_type()) + const allocator_type& a) : base_t(ordered_range, il.begin(), il.end(), comp, a) { //A type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } + + //! Effects: Constructs an empty set using the specified comparison object and + //! inserts elements from the ordered range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! Requires: [il.begin(), il.end()) must be ordered according to the predicate. + //! + //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE + multimap(ordered_range_t, std::initializer_list il, const Compare& comp = Compare()) + : base_t(ordered_range, il.begin(), il.end(), comp) + { + //A type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } #endif //! Effects: Copy constructs a multimap.