From 1cf19898c01b49f09cfb9b6287e66ccf94d54a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 19 Oct 2019 22:55:46 +0200 Subject: [PATCH 01/61] Fixes #132: flat_map::lower_bound and upper_bound have wrong/misleading docs --- doc/container.qbk | 10 +++++- include/boost/container/flat_map.hpp | 44 ++++++++++++------------- include/boost/container/flat_set.hpp | 22 ++++++------- include/boost/container/map.hpp | 48 ++++++++++++++-------------- include/boost/container/set.hpp | 22 ++++++------- 5 files changed, 77 insertions(+), 69 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 644f510..95d58ee 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1319,6 +1319,14 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_72_00 Boost 1.72 Release] + +* Fixed bugs: + * [@https://github.com/boostorg/container/issues/132 GitHub #132: ['"flat_map::lower_bound and upper_bound have wrong/misleading docs"]]. + + +[endsect] + [section:release_notes_boost_1_71_00 Boost 1.71 Release] * Fixed bugs: @@ -1341,7 +1349,7 @@ use [*Boost.Container]? There are several reasons for that: * [classref boost::container::static_vector static_vector] can now have options, using [classref boost::container::static_vector_options static_vector_options]. Alignment and throwing behaviour can be be specified. - * [classref boost::container::small_vector small_vector] can now have options, using [classref boost::container::small_vector_options small_vector_options]. +* [classref boost::container::small_vector small_vector] can now have options, using [classref boost::container::small_vector_options small_vector_options]. Alignment and growth factor can be be specified. [endsect] diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index f1d5ed2..63e7ab1 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -1199,7 +1199,7 @@ class flat_map //! //! Throws: Nothing unless the comparison object throws. //! - //! Complexity: N log(a.size() + N) (N has the value source.size()) + //! Complexity: N log(size() + N) (N has the value source.size()) template BOOST_CONTAINER_FORCEINLINE void merge(flat_map& source) { m_flat_tree.merge_unique(source.tree()); } @@ -1269,7 +1269,7 @@ class flat_map && boost::container::dtl::is_nothrow_swappable::value ) { m_flat_tree.swap(x.m_flat_tree); } - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -1376,14 +1376,14 @@ class flat_map { return m_flat_tree.find(x) != m_flat_tree.end(); } //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& x) { return dtl::force_copy(m_flat_tree.lower_bound(x)); } //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& x) const @@ -1393,7 +1393,7 @@ class flat_map //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. template @@ -1404,22 +1404,22 @@ class flat_map //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const K& x) const { return dtl::force_copy(m_flat_tree.lower_bound(x)); } - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& x) { return dtl::force_copy(m_flat_tree.upper_bound(x)); } - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& x) const @@ -1428,7 +1428,7 @@ class flat_map //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. @@ -1439,8 +1439,8 @@ class flat_map //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. template @@ -2539,7 +2539,7 @@ class flat_multimap //! //! Throws: Nothing unless the comparison object throws. //! - //! Complexity: N log(a.size() + N) (N has the value source.size()) + //! Complexity: N log(size() + N) (N has the value source.size()) template BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap& source) { m_flat_tree.merge_equal(source.tree()); } @@ -2609,7 +2609,7 @@ class flat_multimap && boost::container::dtl::is_nothrow_swappable::value ) { m_flat_tree.swap(x.m_flat_tree); } - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -2714,14 +2714,14 @@ class flat_multimap { return m_flat_tree.find(x) != m_flat_tree.end(); } //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& x) { return dtl::force_copy(m_flat_tree.lower_bound(x)); } //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& x) const @@ -2731,7 +2731,7 @@ class flat_multimap //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -2742,14 +2742,14 @@ class flat_multimap //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const K& x) const { return dtl::force_copy(m_flat_tree.lower_bound(x)); } - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -2757,7 +2757,7 @@ class flat_multimap {return dtl::force_copy(m_flat_tree.upper_bound(x)); } //! Returns: A const iterator pointing to the first element with key - //! not less than x, or end() if such an element is not found. + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& x) const @@ -2766,7 +2766,7 @@ class flat_multimap //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -2778,7 +2778,7 @@ class flat_multimap //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key - //! not less than x, or end() if such an element is not found. + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 7cb1d5c..7af8395 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -808,7 +808,7 @@ class flat_set BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value && boost::container::dtl::is_nothrow_swappable::value ); - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -948,13 +948,13 @@ class flat_set bool contains(const K& x) const; //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x); //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; @@ -963,7 +963,7 @@ class flat_set //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -973,20 +973,20 @@ class flat_set //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template const_iterator lower_bound(const K& x) const; - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x); - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; @@ -994,7 +994,7 @@ class flat_set //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -1004,8 +1004,8 @@ class flat_set //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 447f4ad..477dcc1 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -993,7 +993,7 @@ class map //! //! Returns: A node_type owning the element if found, otherwise an empty node_type. //! - //! Complexity: log(a.size()). + //! Complexity: log(size()). node_type extract(const key_type& k) { typename base_t::node_type base_nh(this->base_t::extract(k)); @@ -1026,7 +1026,7 @@ class map //! //! Throws: Nothing unless the comparison object throws. //! - //! Complexity: N log(a.size() + N) (N has the value source.size()) + //! Complexity: N log(size() + N) (N has the value source.size()) template BOOST_CONTAINER_FORCEINLINE void merge(map& source) { @@ -1064,7 +1064,7 @@ class map BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value && boost::container::dtl::is_nothrow_swappable::value ) - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -1152,13 +1152,13 @@ class map bool contains(const K& x) const; //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x); //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; @@ -1167,7 +1167,7 @@ class map //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -1177,20 +1177,20 @@ class map //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template const_iterator lower_bound(const K& x) const; - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x); - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; @@ -1198,7 +1198,7 @@ class map //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -1208,8 +1208,8 @@ class map //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -1981,7 +1981,7 @@ class multimap //! //! Throws: Nothing unless the comparison object throws. //! - //! Complexity: N log(a.size() + N) (N has the value source.size()) + //! Complexity: N log(size() + N) (N has the value source.size()) template BOOST_CONTAINER_FORCEINLINE void merge(multimap& source) { @@ -2087,13 +2087,13 @@ class multimap bool contains(const K& x) const; //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x); //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; @@ -2102,7 +2102,7 @@ class multimap //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -2112,20 +2112,20 @@ class multimap //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template const_iterator lower_bound(const K& x) const; - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x); - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; @@ -2133,7 +2133,7 @@ class multimap //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -2143,8 +2143,8 @@ class multimap //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index ca6334f..b216c01 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -718,7 +718,7 @@ class set BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value && boost::container::dtl::is_nothrow_swappable::value ); - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -806,13 +806,13 @@ class set bool contains(const K& x) const; //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x); //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; @@ -821,7 +821,7 @@ class set //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -831,20 +831,20 @@ class set //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template const_iterator lower_bound(const K& x) const; - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x); - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; @@ -852,7 +852,7 @@ class set //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -862,8 +862,8 @@ class set //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template From 79ae525967284ea239d4a1bc0647ad95a39ff1a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 14 Nov 2019 15:25:22 +0100 Subject: [PATCH 02/61] Fixes #133 ("basic_string move constructor with allocator argument has incorrect allocator check") --- doc/container.qbk | 2 +- include/boost/container/string.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 95d58ee..68324ab 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1323,7 +1323,7 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs: * [@https://github.com/boostorg/container/issues/132 GitHub #132: ['"flat_map::lower_bound and upper_bound have wrong/misleading docs"]]. - + * [@https://github.com/boostorg/container/issues/133 GitHub #133: ['"basic_string move constructor with allocator argument has incorrect allocator check"]]. [endsect] diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 46ca567..516b701 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -712,7 +712,7 @@ class basic_string : base_t(a) { this->priv_terminate_string(); - if(a == this->alloc()){ + if(s.alloc() == this->alloc()){ this->swap_data(s); } else{ From e3f6dc44ad751e4c49a8776fd20d76aa3809bac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 14 Nov 2019 23:36:05 +0100 Subject: [PATCH 03/61] Fixes #127 ("Fix docs for static_vector::max_size() and capacity()") --- doc/container.qbk | 1 + include/boost/container/static_vector.hpp | 46 +++++++++++++---------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 68324ab..7ff3b0d 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1322,6 +1322,7 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_72_00 Boost 1.72 Release] * Fixed bugs: + * [@https://github.com/boostorg/container/issues/127 GitHub #127: ['"Fix docs for static_vector::max_size() and capacity()"]]. * [@https://github.com/boostorg/container/issues/132 GitHub #132: ['"flat_map::lower_bound and upper_bound have wrong/misleading docs"]]. * [@https://github.com/boostorg/container/issues/133 GitHub #133: ['"basic_string move constructor with allocator argument has incorrect allocator check"]]. diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index 2c08be8..6408c22 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -1116,27 +1116,33 @@ public: //! Constant O(1). const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW; - //! @brief Returns container's capacity. - //! - //! @return container's capacity. - //! - //! @par Throws - //! Nothing. - //! - //! @par Complexity - //! Constant O(1). - static size_type capacity() BOOST_NOEXCEPT_OR_NOTHROW; + #endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED - //! @brief Returns container's capacity. - //! - //! @return container's capacity. - //! - //! @par Throws - //! Nothing. - //! - //! @par Complexity - //! Constant O(1). - static size_type max_size() BOOST_NOEXCEPT_OR_NOTHROW; + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + BOOST_CONTAINER_FORCEINLINE static size_type capacity() BOOST_NOEXCEPT_OR_NOTHROW + { return static_capacity; } + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + BOOST_CONTAINER_FORCEINLINE static size_type max_size() BOOST_NOEXCEPT_OR_NOTHROW + { return static_capacity; } + + #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED //! @brief Returns the number of stored elements. //! From f7409fd6ed7347b2206fe588811d06bc38e768ab Mon Sep 17 00:00:00 2001 From: Bo Rydberg <2945606+bolry@users.noreply.github.com> Date: Thu, 5 Dec 2019 10:14:58 +0100 Subject: [PATCH 04/61] Missing BOOST_NORETURN for user defined functions BOOST_NORETURN is missing for the interface of the throwning methods when BOOST_CONTAINER_USER_DEFINED_THROW_CALLBACKS is defined. Without them you can get a `'noreturn' function does return` warning from g++ at `boost/container/static_vector.hpp:46:4`. --- include/boost/container/throw_exception.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/container/throw_exception.hpp b/include/boost/container/throw_exception.hpp index e09f423..59eaba6 100644 --- a/include/boost/container/throw_exception.hpp +++ b/include/boost/container/throw_exception.hpp @@ -37,15 +37,15 @@ namespace container { #if defined(BOOST_CONTAINER_USER_DEFINED_THROW_CALLBACKS) //The user must provide definitions for the following functions - void throw_bad_alloc(); + BOOST_NORETURN void throw_bad_alloc(); - void throw_out_of_range(const char* str); + BOOST_NORETURN void throw_out_of_range(const char* str); - void throw_length_error(const char* str); + BOOST_NORETURN void throw_length_error(const char* str); - void throw_logic_error(const char* str); + BOOST_NORETURN void throw_logic_error(const char* str); - void throw_runtime_error(const char* str); + BOOST_NORETURN void throw_runtime_error(const char* str); #elif defined(BOOST_NO_EXCEPTIONS) From 0fa5193cead1ced8577e2bb2ac6d39cfc369c6d9 Mon Sep 17 00:00:00 2001 From: Bo Rydberg <2945606+bolry@users.noreply.github.com> Date: Thu, 5 Dec 2019 17:49:58 +0100 Subject: [PATCH 05/61] Update throw tests to avoid segmentation violation --- test/throw_exception_test.cpp | 58 +++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/test/throw_exception_test.cpp b/test/throw_exception_test.cpp index 2cbabef..07a45eb 100644 --- a/test/throw_exception_test.cpp +++ b/test/throw_exception_test.cpp @@ -22,24 +22,50 @@ static bool length_error_called = false; static bool logic_error_called = false; static bool runtime_error_called = false; +BOOST_NORETURN static void validate_and_never_return() +{ + BOOST_TEST(bad_alloc_called == true); + BOOST_TEST(out_of_range_called == true); + BOOST_TEST(length_error_called == true); + BOOST_TEST(logic_error_called == true); + BOOST_TEST(runtime_error_called == true); + std::exit(::boost::report_errors()); +} + //User defined throw implementations namespace boost { namespace container { - void throw_bad_alloc() - { bad_alloc_called = true; } + BOOST_NORETURN void throw_bad_alloc() + { + bad_alloc_called = true; + throw_out_of_range("dummy"); + } - void throw_out_of_range(const char* str) - { (void)str; out_of_range_called = true; } + BOOST_NORETURN void throw_out_of_range(const char* str) + { + out_of_range_called = true; + throw_length_error(str); + } - void throw_length_error(const char* str) - { (void)str; length_error_called = true; } + BOOST_NORETURN void throw_length_error(const char* str) + { + length_error_called = true; + throw_logic_error(str); + } - void throw_logic_error(const char* str) - { (void)str; logic_error_called = true; } + BOOST_NORETURN void throw_logic_error(const char* str) + { + logic_error_called = true; + throw_runtime_error(str); + } - void throw_runtime_error(const char* str) - { (void)str; runtime_error_called = true; } + BOOST_NORETURN void throw_runtime_error(const char* str) + { + (void)str; + runtime_error_called = true; + validate_and_never_return(); + } }} //boost::container @@ -47,16 +73,8 @@ int main() { //Check user-defined throw callbacks are called throw_bad_alloc(); - BOOST_TEST(bad_alloc_called == true); - throw_out_of_range("dummy"); - BOOST_TEST(out_of_range_called == true); - throw_length_error("dummy"); - BOOST_TEST(length_error_called == true); - throw_logic_error("dummy"); - BOOST_TEST(logic_error_called == true); - throw_runtime_error("dummy"); - BOOST_TEST(runtime_error_called == true); - return ::boost::report_errors(); + //Never reached + std::abort(); } #include From dd158987e6bfbb83f82f35d6e34c93577bcb160b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 9 Dec 2019 13:43:30 +0100 Subject: [PATCH 06/61] Update changelist with #135 ("Missing BOOST_NORETURN for user defined functions"). --- doc/container.qbk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/container.qbk b/doc/container.qbk index 7ff3b0d..38b0cdf 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1319,6 +1319,14 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_73_00 Boost 1.73 Release] + +* Fixed bugs: + * [@https://github.com/boostorg/container/pull/135 GitHub #135: ['"Missing BOOST_NORETURN for user defined functions"]]. + +[endsect] + + [section:release_notes_boost_1_72_00 Boost 1.72 Release] * Fixed bugs: From 27c1fea452b3aa6150f09632f882839b89f9ade0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 19 Dec 2019 05:29:46 +0100 Subject: [PATCH 07/61] Fixes #136 ("List of non BOOST-prefixed macros") --- include/boost/container/adaptive_pool.hpp | 12 ++--- include/boost/container/allocator.hpp | 8 +-- include/boost/container/detail/alloc_lib.h | 8 +-- include/boost/container/node_allocator.hpp | 4 +- include/boost/container/stable_vector.hpp | 60 +++++++++++----------- src/dlmalloc_ext_2_8_6.c | 10 ++-- test/alloc_full_test.cpp | 8 +-- test/flat_map_test.cpp | 4 -- test/throw_exception_test.cpp | 6 +-- 9 files changed, 56 insertions(+), 64 deletions(-) diff --git a/include/boost/container/adaptive_pool.hpp b/include/boost/container/adaptive_pool.hpp index 8fcc126..b9037b7 100644 --- a/include/boost/container/adaptive_pool.hpp +++ b/include/boost/container/adaptive_pool.hpp @@ -251,7 +251,7 @@ class adaptive_pool BOOST_STATIC_ASSERT(( Version > 1 ));/* dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ boost::container::throw_bad_alloc(); } chain.incorporate_after(chain.before_begin() @@ -259,7 +259,7 @@ class adaptive_pool ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes - (n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + (n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ boost::container::throw_bad_alloc(); } } @@ -271,7 +271,7 @@ class adaptive_pool BOOST_STATIC_ASSERT(( Version > 1 ));/* dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ boost::container::throw_bad_alloc(); } chain.incorporate_after(chain.before_begin() @@ -279,7 +279,7 @@ class adaptive_pool ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays - (n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + (n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ boost::container::throw_bad_alloc(); } } @@ -536,7 +536,7 @@ class private_adaptive_pool { BOOST_STATIC_ASSERT(( Version > 1 )); if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes - (n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + (n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ boost::container::throw_bad_alloc(); } } @@ -547,7 +547,7 @@ class private_adaptive_pool { BOOST_STATIC_ASSERT(( Version > 1 )); if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays - (n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + (n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ boost::container::throw_bad_alloc(); } } diff --git a/include/boost/container/allocator.hpp b/include/boost/container/allocator.hpp index a14c59e..899f85e 100644 --- a/include/boost/container/allocator.hpp +++ b/include/boost/container/allocator.hpp @@ -287,7 +287,7 @@ class allocator BOOST_STATIC_ASSERT(( Version > 1 )); dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ + if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ boost::container::throw_bad_alloc(); } chain.incorporate_after(chain.before_begin() @@ -295,7 +295,7 @@ class allocator ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); /* - if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ + if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ boost::container::throw_bad_alloc(); }*/ } @@ -308,7 +308,7 @@ class allocator BOOST_STATIC_ASSERT(( Version > 1 )); dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ + if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ boost::container::throw_bad_alloc(); } chain.incorporate_after(chain.before_begin() @@ -316,7 +316,7 @@ class allocator ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); /* - if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ + if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ boost::container::throw_bad_alloc(); }*/ } diff --git a/include/boost/container/detail/alloc_lib.h b/include/boost/container/detail/alloc_lib.h index 950ff72..f5f505c 100644 --- a/include/boost/container/detail/alloc_lib.h +++ b/include/boost/container/detail/alloc_lib.h @@ -196,11 +196,11 @@ typedef struct boost_cont_memchain_impl /*!Indicates the all elements allocated by boost_cont_multialloc_nodes or boost_cont_multialloc_arrays must be contiguous.*/ -#define DL_MULTIALLOC_ALL_CONTIGUOUS ((size_t)(-1)) +#define BOOST_CONTAINER_DL_MULTIALLOC_ALL_CONTIGUOUS ((size_t)(-1)) /*!Indicates the number of contiguous elements allocated by boost_cont_multialloc_nodes or boost_cont_multialloc_arrays should be selected by those functions.*/ -#define DL_MULTIALLOC_DEFAULT_CONTIGUOUS ((size_t)(0)) +#define BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS ((size_t)(0)) typedef struct boost_cont_malloc_stats_impl { @@ -225,8 +225,8 @@ enum BOOST_CONTAINER_EXPAND_OR_NEW = BOOST_CONTAINER_ALLOCATE_NEW | BOOST_CONTAINER_EXPAND_BOTH }; -//#define BOOST_CONTAINERDLMALLOC__FOOTERS -#ifndef BOOST_CONTAINERDLMALLOC__FOOTERS +//#define BOOST_CONTAINER_DLMALLOC_FOOTERS +#ifndef BOOST_CONTAINER_DLMALLOC_FOOTERS enum { BOOST_CONTAINER_ALLOCATION_PAYLOAD = sizeof(size_t) }; #else enum { BOOST_CONTAINER_ALLOCATION_PAYLOAD = sizeof(size_t)*2 }; diff --git a/include/boost/container/node_allocator.hpp b/include/boost/container/node_allocator.hpp index b5c20a6..4ecb6f8 100644 --- a/include/boost/container/node_allocator.hpp +++ b/include/boost/container/node_allocator.hpp @@ -258,7 +258,7 @@ class node_allocator BOOST_STATIC_ASSERT(( Version > 1 )); dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ boost::container::throw_bad_alloc(); } chain.incorporate_after( chain.before_begin() @@ -273,7 +273,7 @@ class node_allocator { BOOST_STATIC_ASSERT(( Version > 1 )); dlmalloc_memchain ch; - dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch); + dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch); if(BOOST_UNLIKELY(BOOST_CONTAINER_MEMCHAIN_EMPTY(&ch))){ boost::container::throw_bad_alloc(); } diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 7d0c9b3..482c0cf 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -434,13 +434,13 @@ class stable_vector_iterator #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) - #define STABLE_VECTOR_CHECK_INVARIANT \ + #define BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT \ invariant_checker BOOST_JOIN(check_invariant_,__LINE__)(*this); \ BOOST_JOIN(check_invariant_,__LINE__).touch(); #else //STABLE_VECTOR_ENABLE_INVARIANT_CHECKING - #define STABLE_VECTOR_CHECK_INVARIANT + #define BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT #endif //#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) @@ -604,7 +604,7 @@ class stable_vector BOOST_CONTAINER_FORCEINLINE stable_vector() BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible::value) : internal_data(), index() { - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; } //! Effects: Constructs a stable_vector taking the allocator as parameter. @@ -615,7 +615,7 @@ class stable_vector BOOST_CONTAINER_FORCEINLINE explicit stable_vector(const allocator_type& al) BOOST_NOEXCEPT_OR_NOTHROW : internal_data(al), index(al) { - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; } //! Effects: Constructs a stable_vector @@ -630,7 +630,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); this->resize(n); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -648,7 +648,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); this->resize(n, default_init); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -664,7 +664,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); this->resize(n); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -682,7 +682,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); this->resize(n, default_init); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -698,7 +698,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); this->insert(this->cend(), n, t); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -715,7 +715,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); this->insert(this->cend(), first, last); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -732,7 +732,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); this->insert(this->cend(), x.begin(), x.end()); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -749,7 +749,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); insert(cend(), il.begin(), il.end()); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } #endif @@ -775,7 +775,7 @@ class stable_vector { stable_vector_detail::clear_on_destroy cod(*this); this->insert(this->cend(), x.begin(), x.end()); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -795,7 +795,7 @@ class stable_vector else{ stable_vector_detail::clear_on_destroy cod(*this); this->insert(this->cend(), boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } } @@ -822,7 +822,7 @@ class stable_vector //! Complexity: Linear to the number of elements in x. stable_vector& operator=(BOOST_COPY_ASSIGN_REF(stable_vector) x) { - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; if (BOOST_LIKELY(this != &x)) { node_allocator_type &this_alloc = this->priv_node_alloc(); const node_allocator_type &x_alloc = x.priv_node_alloc(); @@ -865,7 +865,7 @@ class stable_vector //Resources can be transferred if both allocators are //going to be equal after this function (either propagated or already equal) if(propagate_alloc || allocators_equal){ - STABLE_VECTOR_CHECK_INVARIANT + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT //Destroy objects but retain memory in case x reuses it in the future this->clear(); //Move allocator if needed @@ -889,7 +889,7 @@ class stable_vector //! Complexity: Linear to the range [il.begin(), il.end()). stable_vector& operator=(std::initializer_list il) { - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; assign(il.begin(), il.end()); return *this; } @@ -920,7 +920,7 @@ class stable_vector #endif assign(InputIterator first,InputIterator last) { - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; iterator first1 = this->begin(); iterator last1 = this->end(); for ( ; first1 != last1 && first != last; ++first1, ++first) @@ -941,7 +941,7 @@ class stable_vector //! BOOST_CONTAINER_FORCEINLINE void assign(std::initializer_list il) { - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; assign(il.begin(), il.end()); } #endif @@ -1124,7 +1124,7 @@ class stable_vector void resize(size_type n) { typedef value_init_construct_iterator value_init_iterator; - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; if(n > this->size()) this->insert(this->cend(), value_init_iterator(n - this->size()), value_init_iterator()); else if(n < this->size()) @@ -1142,7 +1142,7 @@ class stable_vector void resize(size_type n, default_init_t) { typedef default_init_construct_iterator default_init_iterator; - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; if(n > this->size()) this->insert(this->cend(), default_init_iterator(n - this->size()), default_init_iterator()); else if(n < this->size()) @@ -1157,7 +1157,7 @@ class stable_vector //! Complexity: Linear to the difference between size() and new_size. void resize(size_type n, const T& t) { - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; if(n > this->size()) this->insert(this->cend(), n - this->size(), t); else if(n < this->size()) @@ -1190,7 +1190,7 @@ class stable_vector //! Throws: If memory allocation allocation throws. void reserve(size_type n) { - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; if(n > this->max_size()){ throw_length_error("stable_vector::reserve max_size() exceeded"); } @@ -1562,7 +1562,7 @@ class stable_vector iterator insert(const_iterator p, size_type n, const T& t) { BOOST_ASSERT(this->priv_in_range_or_end(p)); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; typedef constant_iterator cvalue_iterator; return this->insert(p, cvalue_iterator(t, n), cvalue_iterator()); } @@ -1579,7 +1579,7 @@ class stable_vector BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, std::initializer_list il) { //Position checks done by insert() - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; return insert(p, il.begin(), il.end()); } #endif @@ -1608,7 +1608,7 @@ class stable_vector ) { BOOST_ASSERT(this->priv_in_range_or_end(p)); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; const size_type pos_n = p - this->cbegin(); for(; first != last; ++first){ this->emplace(p, *first); @@ -1678,7 +1678,7 @@ class stable_vector BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator p) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->priv_in_range(p)); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; const size_type d = p - this->cbegin(); index_iterator it = this->index.begin() + d; this->priv_delete_node(p.node_pointer()); @@ -1697,7 +1697,7 @@ class stable_vector { BOOST_ASSERT(first == last || (first < last && this->priv_in_range(first) && this->priv_in_range_or_end(last))); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; const const_iterator cbeg(this->cbegin()); const size_type d1 = static_cast(first - cbeg), d2 = static_cast(last - cbeg); @@ -1733,7 +1733,7 @@ class stable_vector BOOST_ASSERT(allocator_traits_type::propagate_on_container_swap::value || allocator_traits_type::is_always_equal::value || this->get_stored_allocator() == x.get_stored_allocator()); - STABLE_VECTOR_CHECK_INVARIANT; + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT; dtl::bool_ flag; dtl::swap_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); //vector's allocator is swapped here @@ -2174,7 +2174,7 @@ stable_vector(InputIterator, InputIterator, Allocator const&) -> #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -#undef STABLE_VECTOR_CHECK_INVARIANT +#undef BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT } //namespace container { diff --git a/src/dlmalloc_ext_2_8_6.c b/src/dlmalloc_ext_2_8_6.c index 918ce02..0b0101c 100644 --- a/src/dlmalloc_ext_2_8_6.c +++ b/src/dlmalloc_ext_2_8_6.c @@ -791,21 +791,21 @@ static int internal_node_multialloc /*Error if wrong element_size parameter */ if (!element_size || /*OR Error if n_elements less than contiguous_elements */ - ((contiguous_elements + 1) > (DL_MULTIALLOC_DEFAULT_CONTIGUOUS + 1) && n_elements < contiguous_elements) || + ((contiguous_elements + 1) > (BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS + 1) && n_elements < contiguous_elements) || /* OR Error if integer overflow */ (SQRT_MAX_SIZE_T < (element_req_size | contiguous_elements) && (MAX_SIZE_T / element_req_size) < contiguous_elements)) { return 0; } switch (contiguous_elements) { - case DL_MULTIALLOC_DEFAULT_CONTIGUOUS: + case BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS: { /* Default contiguous, just check that we can store at least one element */ elements_per_segment = INTERNAL_MULTIALLOC_DEFAULT_CONTIGUOUS_MEM / element_req_size; elements_per_segment += (size_t)(!elements_per_segment); } break; - case DL_MULTIALLOC_ALL_CONTIGUOUS: + case BOOST_CONTAINER_DL_MULTIALLOC_ALL_CONTIGUOUS: /* All elements should be allocated in a single call */ elements_per_segment = n_elements; break; @@ -1002,11 +1002,11 @@ static int internal_multialloc_arrays max_size = MAX_REQUEST/element_size; /* Different sizes*/ switch(contiguous_elements){ - case DL_MULTIALLOC_DEFAULT_CONTIGUOUS: + case BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS: /* Use default contiguous mem */ boost_cont_multialloc_segmented_malloc_size = INTERNAL_MULTIALLOC_DEFAULT_CONTIGUOUS_MEM; break; - case DL_MULTIALLOC_ALL_CONTIGUOUS: + case BOOST_CONTAINER_DL_MULTIALLOC_ALL_CONTIGUOUS: boost_cont_multialloc_segmented_malloc_size = MAX_REQUEST + CHUNK_OVERHEAD; break; default: diff --git a/test/alloc_full_test.cpp b/test/alloc_full_test.cpp index 54e1160..5e72536 100644 --- a/test/alloc_full_test.cpp +++ b/test/alloc_full_test.cpp @@ -512,7 +512,7 @@ bool test_many_equal_allocation() for(int i = 0; i != NumIt/10; ++i){ dlmalloc_memchain chain; BOOST_CONTAINER_MEMCHAIN_INIT(&chain); - dlmalloc_multialloc_nodes((i+1)*2, i+1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); + dlmalloc_multialloc_nodes((i+1)*2, i+1, BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); dlmalloc_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&chain); if(BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it)) break; @@ -624,7 +624,7 @@ bool test_many_different_allocation() for(int i = 0; i != NumIt; ++i){ dlmalloc_memchain chain; BOOST_CONTAINER_MEMCHAIN_INIT(&chain); - dlmalloc_multialloc_arrays(ArraySize, requested_sizes, 1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); + dlmalloc_multialloc_arrays(ArraySize, requested_sizes, 1, BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); dlmalloc_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&chain); if(BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it)) break; @@ -702,7 +702,7 @@ bool test_many_deallocation() for(int i = 0; i != NumIt; ++i){ dlmalloc_memchain chain; BOOST_CONTAINER_MEMCHAIN_INIT(&chain); - dlmalloc_multialloc_arrays(ArraySize, requested_sizes, 1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); + dlmalloc_multialloc_arrays(ArraySize, requested_sizes, 1, BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); dlmalloc_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&chain); if(BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it)) return false; @@ -720,7 +720,7 @@ bool test_many_deallocation() for(int i = 0; i != NumIt; ++i){ dlmalloc_memchain chain; BOOST_CONTAINER_MEMCHAIN_INIT(&chain); - dlmalloc_multialloc_nodes(ArraySize, i*4+1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); + dlmalloc_multialloc_nodes(ArraySize, i*4+1, BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); dlmalloc_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&chain); if(BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it)) return false; diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index f5caff7..e2042c2 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -7,8 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include - #include #include @@ -834,5 +832,3 @@ int main() return 0; } - -#include diff --git a/test/throw_exception_test.cpp b/test/throw_exception_test.cpp index 07a45eb..6e61ceb 100644 --- a/test/throw_exception_test.cpp +++ b/test/throw_exception_test.cpp @@ -9,8 +9,6 @@ ////////////////////////////////////////////////////////////////////////////// #define BOOST_CONTAINER_USER_DEFINED_THROW_CALLBACKS -#include - #include #include @@ -74,7 +72,5 @@ int main() //Check user-defined throw callbacks are called throw_bad_alloc(); //Never reached - std::abort(); + return 33; } - -#include From ac51b5b6d217870f49270d02836905ed529cda89 Mon Sep 17 00:00:00 2001 From: Robert Leahy Date: Sun, 22 Dec 2019 18:10:39 -0500 Subject: [PATCH 08/61] detail/value_functors.hpp: Add Namespacing value_less and value_equal are now boost::container::value_less & boost::container::value_equal respectively. --- include/boost/container/detail/value_functors.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/boost/container/detail/value_functors.hpp b/include/boost/container/detail/value_functors.hpp index a2c494c..961c9a8 100644 --- a/include/boost/container/detail/value_functors.hpp +++ b/include/boost/container/detail/value_functors.hpp @@ -18,6 +18,9 @@ # pragma once #endif +namespace boost { +namespace container { + //Functors for member algorithm defaults template struct value_less @@ -33,4 +36,7 @@ struct value_equal { return a == b; } }; +} //namespace container { +} //namespace boost { + #endif //BOOST_CONTAINER_DETAIL_VALUE_FUNCTORS_HPP From d4a0917821992fd0a1d900c9eca0d903dc7940d2 Mon Sep 17 00:00:00 2001 From: Robert Leahy Date: Sun, 22 Dec 2019 19:22:47 -0500 Subject: [PATCH 09/61] RandomAccessIterator + 0 Previously the iterators of boost::container::deque would assert when zero was added to them in at least the following situations: - The iterator was obtained by a call to boost::container::deque::begin and boost::container::deque::empty returns true - The iterator was default constructed This is inconsistent with the way in which the iterators of boost:: container::deque have behaved historically and is also inconsistent with an understanding of iterators developed by analogy with pointers: - Adding zero to a null pointer is valid despite the fact the null pointer cannot be dereferenced - Adding zero to a pointer that is one past the end yields a pointer which is still one past the end and thus which has well defined semantics Fixed this issue and codified the expected behavior in unit tests. --- include/boost/container/deque.hpp | 2 ++ test/null_iterators_test.cpp | 50 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index ae91106..cea31e3 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -234,6 +234,8 @@ class deque_iterator deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW { + if (!n) + return *this; BOOST_ASSERT(!!m_cur); difference_type offset = n + (this->m_cur - this->m_first); const difference_type block_size = this->m_last - this->m_first; diff --git a/test/null_iterators_test.cpp b/test/null_iterators_test.cpp index f081dbe..525d11d 100644 --- a/test/null_iterators_test.cpp +++ b/test/null_iterators_test.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include using namespace boost::container; @@ -56,6 +57,40 @@ BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(const_reverse_iterator) }}} //namespace boost::container::test { +template +void check_plus_zero_impl(RandomAccessIterator it) +{ + RandomAccessIterator cpy(it + 0); + BOOST_TEST(cpy == it); +} + +template +void check_plus_zero(const Category&) +{} + +template +void check_plus_zero(const std::random_access_iterator_tag&) +{ + check_plus_zero_impl(typename Container::iterator()); + check_plus_zero_impl(typename Container::const_iterator()); + check_plus_zero_impl(typename Container::reverse_iterator()); + check_plus_zero_impl(typename Container::const_reverse_iterator()); + Container c; + check_plus_zero_impl(c.begin()); + check_plus_zero_impl(c.cbegin()); + check_plus_zero_impl(c.rbegin()); + check_plus_zero_impl(c.crbegin()); +} + +template +void check_plus_zero() +{ + typedef typename Container::iterator iterator; + typedef typename std::iterator_traits::iterator_category category; + category tag; + check_plus_zero(tag); +} + template void check_null_iterators() { @@ -77,20 +112,35 @@ void check_null_iterators() int main() { check_null_iterators< vector >(); + check_plus_zero< vector >(); check_null_iterators< deque >(); + check_plus_zero< deque >(); check_null_iterators< stable_vector >(); + check_plus_zero< stable_vector >(); check_null_iterators< static_vector >(); + check_plus_zero< static_vector >(); check_null_iterators< string >(); + check_plus_zero< string >(); check_null_iterators< list >(); + check_plus_zero< list >(); check_null_iterators< slist >(); + check_plus_zero< slist >(); check_null_iterators< map >(); + check_plus_zero< map >(); check_null_iterators< multimap >(); + check_plus_zero< multimap >(); check_null_iterators< set >(); + check_plus_zero< set >(); check_null_iterators< multiset >(); + check_plus_zero< multiset >(); check_null_iterators< flat_set >(); + check_plus_zero< flat_set >(); check_null_iterators< flat_multiset >(); + check_plus_zero< flat_multiset >(); check_null_iterators< flat_map >(); + check_plus_zero< flat_map >(); check_null_iterators< flat_multimap >(); + check_plus_zero< flat_multimap >(); return boost::report_errors(); } From 3c50ab6d3a6b98187ce8a44e2242b9c5d24ae099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 13 Jan 2020 16:27:00 +0100 Subject: [PATCH 10/61] Update changelog with #138 ("Remove Classes from Global Namespace") --- doc/container.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/container.qbk b/doc/container.qbk index 38b0cdf..8308f69 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1323,6 +1323,7 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs: * [@https://github.com/boostorg/container/pull/135 GitHub #135: ['"Missing BOOST_NORETURN for user defined functions"]]. + * [@https://github.com/boostorg/container/pull/138 GitHub #138: ['"Remove Classes from Global Namespace"]]. [endsect] From 51d4d569ac6df2ea74f547d3566a443eb3690824 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 14 Jan 2020 00:54:45 +0900 Subject: [PATCH 11/61] fix a link in the documentation --- doc/container.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/container.qbk b/doc/container.qbk index 8308f69..c77c487 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -168,7 +168,7 @@ is used as a template argument when instantiating a template component, unless specifically allowed for that component]]. Finally C++17 added support for incomplete types in `std::vector`, `std::list` and `std::forward_list` -(see [@https://wg21.link/n4569 ['N4569: Minimal incomplete type support for standard containers, revision 4]] +(see [@https://wg21.link/n4510 ['N4510: Minimal incomplete type support for standard containers, revision 4]] for details), but no other containers like `std::set/map/unordered_set/unordered_map`, Fortunately all [*Boost.Container] containers except From 0020cbd1331f130fa46e924b7600ef5fa19cc28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 14 Feb 2020 05:10:29 +0100 Subject: [PATCH 12/61] Fixed #143 ("memset called with null pointer") --- doc/container.qbk | 1 + include/boost/container/detail/copy_move_algo.hpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index c77c487..0cc8bb4 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1324,6 +1324,7 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs: * [@https://github.com/boostorg/container/pull/135 GitHub #135: ['"Missing BOOST_NORETURN for user defined functions"]]. * [@https://github.com/boostorg/container/pull/138 GitHub #138: ['"Remove Classes from Global Namespace"]]. + * [@https://github.com/boostorg/container/issues/142 GitHub #142: ['"memset called with null pointer"]]. [endsect] diff --git a/include/boost/container/detail/copy_move_algo.hpp b/include/boost/container/detail/copy_move_algo.hpp index b71560d..cd55af4 100644 --- a/include/boost/container/detail/copy_move_algo.hpp +++ b/include/boost/container/detail/copy_move_algo.hpp @@ -587,8 +587,10 @@ inline typename dtl::enable_if_memzero_initializable::type uninitialized_value_init_alloc_n(Allocator &, typename boost::container::allocator_traits::size_type n, F r) { typedef typename boost::container::iterator_traits::value_type value_type; - std::memset((void*)boost::movelib::iterator_to_raw_pointer(r), 0, sizeof(value_type)*n); - boost::container::iterator_advance(r, n); + if (BOOST_LIKELY(n)){ + std::memset((void*)boost::movelib::iterator_to_raw_pointer(r), 0, sizeof(value_type)*n); + boost::container::iterator_advance(r, n); + } return r; } @@ -892,8 +894,10 @@ inline typename dtl::enable_if_memtransfer_copy_assignable::type { typedef typename boost::container::iterator_traits::value_type value_type; const typename boost::container::iterator_traits::difference_type n = boost::container::iterator_distance(f, l); - r -= n; - std::memmove((boost::movelib::iterator_to_raw_pointer)(r), (boost::movelib::iterator_to_raw_pointer)(f), sizeof(value_type)*n); + if (BOOST_LIKELY(n)){ + r -= n; + std::memmove((boost::movelib::iterator_to_raw_pointer)(r), (boost::movelib::iterator_to_raw_pointer)(f), sizeof(value_type)*n); + } return r; } From 756c4cdc6a44bff0908a64078054a585b8cbdff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 14 Feb 2020 05:10:29 +0100 Subject: [PATCH 13/61] Fixed #142 ("memset called with null pointer") --- doc/container.qbk | 1 + include/boost/container/detail/copy_move_algo.hpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index c77c487..0cc8bb4 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1324,6 +1324,7 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs: * [@https://github.com/boostorg/container/pull/135 GitHub #135: ['"Missing BOOST_NORETURN for user defined functions"]]. * [@https://github.com/boostorg/container/pull/138 GitHub #138: ['"Remove Classes from Global Namespace"]]. + * [@https://github.com/boostorg/container/issues/142 GitHub #142: ['"memset called with null pointer"]]. [endsect] diff --git a/include/boost/container/detail/copy_move_algo.hpp b/include/boost/container/detail/copy_move_algo.hpp index b71560d..cd55af4 100644 --- a/include/boost/container/detail/copy_move_algo.hpp +++ b/include/boost/container/detail/copy_move_algo.hpp @@ -587,8 +587,10 @@ inline typename dtl::enable_if_memzero_initializable::type uninitialized_value_init_alloc_n(Allocator &, typename boost::container::allocator_traits::size_type n, F r) { typedef typename boost::container::iterator_traits::value_type value_type; - std::memset((void*)boost::movelib::iterator_to_raw_pointer(r), 0, sizeof(value_type)*n); - boost::container::iterator_advance(r, n); + if (BOOST_LIKELY(n)){ + std::memset((void*)boost::movelib::iterator_to_raw_pointer(r), 0, sizeof(value_type)*n); + boost::container::iterator_advance(r, n); + } return r; } @@ -892,8 +894,10 @@ inline typename dtl::enable_if_memtransfer_copy_assignable::type { typedef typename boost::container::iterator_traits::value_type value_type; const typename boost::container::iterator_traits::difference_type n = boost::container::iterator_distance(f, l); - r -= n; - std::memmove((boost::movelib::iterator_to_raw_pointer)(r), (boost::movelib::iterator_to_raw_pointer)(f), sizeof(value_type)*n); + if (BOOST_LIKELY(n)){ + r -= n; + std::memmove((boost::movelib::iterator_to_raw_pointer)(r), (boost::movelib::iterator_to_raw_pointer)(f), sizeof(value_type)*n); + } return r; } From 5d526092fb68a38813b9bea7f5dd27ab91198cf4 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Thu, 23 Apr 2020 13:45:23 -0400 Subject: [PATCH 14/61] Addition needed for Embarcarder clang-based compilers. --- src/dlmalloc_2_8_6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dlmalloc_2_8_6.c b/src/dlmalloc_2_8_6.c index 7a53d35..d09464d 100644 --- a/src/dlmalloc_2_8_6.c +++ b/src/dlmalloc_2_8_6.c @@ -1515,7 +1515,7 @@ LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); #pragma intrinsic (_InterlockedExchange) #define interlockedcompareexchange _InterlockedCompareExchange #define interlockedexchange _InterlockedExchange -#elif defined(WIN32) && defined(__GNUC__) +#elif defined(WIN32) && (defined(__GNUC__) || defined(__clang__)) #define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) #define interlockedexchange __sync_lock_test_and_set #endif /* Win32 */ From cc5c59c7a5e2e871221714748fab19f3e79b51f1 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Fri, 24 Apr 2020 15:10:57 -0400 Subject: [PATCH 15/61] Inline friend function definitions for exported/imported classes must become declarations and inline definitions outside the class for Embarcadero C++ clang-based compilers. This bug has been reported to Embarcadero. --- .../boost/container/pmr/memory_resource.hpp | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/boost/container/pmr/memory_resource.hpp b/include/boost/container/pmr/memory_resource.hpp index 5ca2d73..2436bb0 100644 --- a/include/boost/container/pmr/memory_resource.hpp +++ b/include/boost/container/pmr/memory_resource.hpp @@ -52,6 +52,8 @@ class BOOST_CONTAINER_DECL memory_resource //! `return return do_is_equal(other);` bool is_equal(const memory_resource& other) const BOOST_NOEXCEPT { return this->do_is_equal(other); } + + #if !defined(BOOST_EMBTC) //! Returns: //! `&a == &b || a.is_equal(b)`. @@ -62,6 +64,18 @@ class BOOST_CONTAINER_DECL memory_resource //! !(a == b). friend bool operator!=(const memory_resource& a, const memory_resource& b) BOOST_NOEXCEPT { return !(a == b); } + + #else + + //! Returns: + //! `&a == &b || a.is_equal(b)`. + friend bool operator==(const memory_resource& a, const memory_resource& b) BOOST_NOEXCEPT; + + //! Returns: + //! !(a == b). + friend bool operator!=(const memory_resource& a, const memory_resource& b) BOOST_NOEXCEPT; + + #endif protected: //! Requires: Alignment shall be a power of two. @@ -93,6 +107,20 @@ class BOOST_CONTAINER_DECL memory_resource virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT = 0; }; +#if defined(BOOST_EMBTC) + +//! Returns: +//! `&a == &b || a.is_equal(b)`. +inline bool operator==(const memory_resource& a, const memory_resource& b) BOOST_NOEXCEPT +{ return &a == &b || a.is_equal(b); } + +//! Returns: +//! !(a == b). +inline bool operator!=(const memory_resource& a, const memory_resource& b) BOOST_NOEXCEPT +{ return !(a == b); } + +#endif + } //namespace pmr { } //namespace container { } //namespace boost { From 811dc94bb4360fd2a7d2d6c3de9f75a0f8665e4d Mon Sep 17 00:00:00 2001 From: Eugene Zelenko Date: Fri, 8 May 2020 09:28:49 -0700 Subject: [PATCH 16/61] Use BOOST_OVERRIDE to fix GCC -Wsuggest-override and Clang-tidy modernize-use-override warnings. --- .../pmr/monotonic_buffer_resource.hpp | 8 ++++---- .../pmr/synchronized_pool_resource.hpp | 8 ++++---- .../pmr/unsynchronized_pool_resource.hpp | 8 ++++---- src/global_resource.cpp | 18 +++++++++--------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/boost/container/pmr/monotonic_buffer_resource.hpp b/include/boost/container/pmr/monotonic_buffer_resource.hpp index 38b100a..89a796e 100644 --- a/include/boost/container/pmr/monotonic_buffer_resource.hpp +++ b/include/boost/container/pmr/monotonic_buffer_resource.hpp @@ -109,7 +109,7 @@ class BOOST_CONTAINER_DECL monotonic_buffer_resource //! Effects: Calls //! `this->release()`. - virtual ~monotonic_buffer_resource(); + ~monotonic_buffer_resource() BOOST_OVERRIDE; //! Effects: `upstream_resource()->deallocate()` as necessary to release all allocated memory. //! [Note: memory is released back to `upstream_resource()` even if some blocks that were allocated @@ -160,18 +160,18 @@ class BOOST_CONTAINER_DECL monotonic_buffer_resource //! then allocate the return block from the newly-allocated internal `current_buffer`. //! //! Throws: Nothing unless `upstream_resource()->allocate()` throws. - virtual void* do_allocate(std::size_t bytes, std::size_t alignment); + void* do_allocate(std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE; //! Effects: None //! //! Throws: Nothing //! //! Remarks: Memory used by this resource increases monotonically until its destruction. - virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_NOEXCEPT; + void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_NOEXCEPT BOOST_OVERRIDE; //! Returns: //! `this == dynamic_cast(&other)`. - virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT; + bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT BOOST_OVERRIDE; }; } //namespace pmr { diff --git a/include/boost/container/pmr/synchronized_pool_resource.hpp b/include/boost/container/pmr/synchronized_pool_resource.hpp index 516e6d2..31642e8 100644 --- a/include/boost/container/pmr/synchronized_pool_resource.hpp +++ b/include/boost/container/pmr/synchronized_pool_resource.hpp @@ -89,7 +89,7 @@ class BOOST_CONTAINER_DECL synchronized_pool_resource #endif //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::~unsynchronized_pool_resource() - virtual ~synchronized_pool_resource(); + ~synchronized_pool_resource() BOOST_OVERRIDE; //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::release() void release(); @@ -103,13 +103,13 @@ class BOOST_CONTAINER_DECL synchronized_pool_resource protected: //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::do_allocate() - virtual void* do_allocate(std::size_t bytes, std::size_t alignment); + void* do_allocate(std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE; //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::do_deallocate(void*,std::size_t,std::size_t) - virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment); + void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE; //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::do_is_equal(const memory_resource&)const - virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT; + bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT BOOST_OVERRIDE; //Non-standard observers public: diff --git a/include/boost/container/pmr/unsynchronized_pool_resource.hpp b/include/boost/container/pmr/unsynchronized_pool_resource.hpp index 21d30b1..1b2406d 100644 --- a/include/boost/container/pmr/unsynchronized_pool_resource.hpp +++ b/include/boost/container/pmr/unsynchronized_pool_resource.hpp @@ -103,7 +103,7 @@ class BOOST_CONTAINER_DECL unsynchronized_pool_resource //! Effects: Calls //! `this->release()`. - virtual ~unsynchronized_pool_resource(); + ~unsynchronized_pool_resource() BOOST_OVERRIDE; //! Effects: Calls Calls `upstream_resource()->deallocate()` as necessary //! to release all allocated memory. [ Note: memory is released back to @@ -134,18 +134,18 @@ class BOOST_CONTAINER_DECL unsynchronized_pool_resource //! using `upstream_resource()->allocate()`. //! //! Throws: Nothing unless `upstream_resource()->allocate()` throws. - virtual void* do_allocate(std::size_t bytes, std::size_t alignment); + void* do_allocate(std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE; //! Effects: Return the memory at p to the pool. It is unspecified if or under //! what circumstances this operation will result in a call to //! `upstream_resource()->deallocate()`. //! //! Throws: Nothing. - virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment); + void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE; //! Returns: //! `this == dynamic_cast(&other)`. - virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT; + bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT BOOST_OVERRIDE; //Non-standard observers public: diff --git a/src/global_resource.cpp b/src/global_resource.cpp index df9c688..1e771df 100644 --- a/src/global_resource.cpp +++ b/src/global_resource.cpp @@ -13,7 +13,7 @@ #include #include #include -#include //For global lock +#include // For global lock #include #include @@ -27,16 +27,16 @@ class new_delete_resource_imp { public: - virtual ~new_delete_resource_imp() + ~new_delete_resource_imp() BOOST_OVERRIDE {} - virtual void* do_allocate(std::size_t bytes, std::size_t alignment) + void* do_allocate(std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE { (void)bytes; (void)alignment; return new char[bytes]; } - virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) + void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE { (void)bytes; (void)alignment; delete[]((char*)p); } - virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT + bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT BOOST_OVERRIDE { return &other == this; } } new_delete_resource_instance; @@ -45,20 +45,20 @@ struct null_memory_resource_imp { public: - virtual ~null_memory_resource_imp() + ~null_memory_resource_imp() BOOST_OVERRIDE {} - virtual void* do_allocate(std::size_t bytes, std::size_t alignment) + void* do_allocate(std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE { (void)bytes; (void)alignment; throw_bad_alloc(); return 0; } - virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) + void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE { (void)p; (void)bytes; (void)alignment; } - virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT + bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT BOOST_OVERRIDE { return &other == this; } } null_memory_resource_instance; From 093467e1d3e05b93b48e38517750239c6649a63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 23 May 2020 23:38:58 +0200 Subject: [PATCH 17/61] Fixes #148 (Fix static initialization issues in pmr global resources) --- doc/container.qbk | 7 +++++++ src/global_resource.cpp | 12 +++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 0cc8bb4..8bdc11f 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1319,6 +1319,13 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_74_00 Boost 1.74 Release] + +* Fixed bugs: + * [@https://github.com/boostorg/container/pull/148 GitHub #148: ['"Fix static initialization issues in pmr global resources"]]. + +[endsect] + [section:release_notes_boost_1_73_00 Boost 1.73 Release] * Fixed bugs: diff --git a/src/global_resource.cpp b/src/global_resource.cpp index df9c688..6160cea 100644 --- a/src/global_resource.cpp +++ b/src/global_resource.cpp @@ -14,6 +14,7 @@ #include #include #include //For global lock +#include #include #include @@ -38,7 +39,7 @@ class new_delete_resource_imp virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT { return &other == this; } -} new_delete_resource_instance; +}; struct null_memory_resource_imp : public memory_resource @@ -60,19 +61,20 @@ struct null_memory_resource_imp virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT { return &other == this; } -} null_memory_resource_instance; +}; BOOST_CONTAINER_DECL memory_resource* new_delete_resource() BOOST_NOEXCEPT { - return &new_delete_resource_instance; + return &boost::container::dtl::singleton_default::instance(); } BOOST_CONTAINER_DECL memory_resource* null_memory_resource() BOOST_NOEXCEPT { - return &null_memory_resource_instance; + return &boost::container::dtl::singleton_default::instance(); } -static memory_resource *default_memory_resource = &new_delete_resource_instance; +static memory_resource *default_memory_resource = + &boost::container::dtl::singleton_default::instance(); BOOST_CONTAINER_DECL memory_resource* set_default_resource(memory_resource* r) BOOST_NOEXCEPT { From eff9bdfdaa63c97cde2ec0fa336e210fad2ef048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 24 May 2020 00:37:36 +0200 Subject: [PATCH 18/61] Fixes #148 again (Fix static initialization issues in pmr global resources) --- src/global_resource.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/global_resource.cpp b/src/global_resource.cpp index f92c923..a7f03f2 100644 --- a/src/global_resource.cpp +++ b/src/global_resource.cpp @@ -95,6 +95,10 @@ BOOST_CONTAINER_DECL memory_resource* get_default_resource() BOOST_NOEXCEPT //TO-DO: synchronizes-with part using atomics if(dlmalloc_global_sync_lock()){ memory_resource *current = default_memory_resource; + if(!current){ + //function called before main, default_memory resource was not initialied yet + current = new_delete_resource(); + } dlmalloc_global_sync_unlock(); return current; } From f3a949697b3ec82afe1c4c29f63cd8a08050b24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 24 May 2020 00:37:59 +0200 Subject: [PATCH 19/61] Update changelog with #144 --- doc/container.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/container.qbk b/doc/container.qbk index 8bdc11f..21450a3 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1322,6 +1322,7 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_74_00 Boost 1.74 Release] * Fixed bugs: + * [@https://github.com/boostorg/container/issues/144 GitHub #148: ['"GCC suggest-override warnings"]]. * [@https://github.com/boostorg/container/pull/148 GitHub #148: ['"Fix static initialization issues in pmr global resources"]]. [endsect] From 39edf046d5a785bd79316c3671e843cd189546e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 24 May 2020 19:00:19 +0200 Subject: [PATCH 20/61] Additional fix for #148 ("Fix static initialization issues in pmr global resources") in set_default_resource --- src/global_resource.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/global_resource.cpp b/src/global_resource.cpp index a7f03f2..015531f 100644 --- a/src/global_resource.cpp +++ b/src/global_resource.cpp @@ -81,6 +81,10 @@ BOOST_CONTAINER_DECL memory_resource* set_default_resource(memory_resource* r) B //TO-DO: synchronizes-with part using atomics if(dlmalloc_global_sync_lock()){ memory_resource *previous = default_memory_resource; + if(!previous){ + //function called before main, default_memory_resource is not initialized yet + previous = new_delete_resource(); + } default_memory_resource = r ? r : new_delete_resource(); dlmalloc_global_sync_unlock(); return previous; @@ -96,7 +100,7 @@ BOOST_CONTAINER_DECL memory_resource* get_default_resource() BOOST_NOEXCEPT if(dlmalloc_global_sync_lock()){ memory_resource *current = default_memory_resource; if(!current){ - //function called before main, default_memory resource was not initialied yet + //function called before main, default_memory_resource is not initialized yet current = new_delete_resource(); } dlmalloc_global_sync_unlock(); From 649d6d04785cb018ebd59d484727d5184c6851a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 25 May 2020 00:14:15 +0200 Subject: [PATCH 21/61] Add BOOST_CONTAINER_FORCEINLINE in more places --- .../boost/container/detail/alloc_helpers.hpp | 12 +- .../detail/dispatch_uses_allocator.hpp | 12 +- include/boost/container/list.hpp | 48 +++--- include/boost/container/scoped_allocator.hpp | 160 +++++++++--------- include/boost/container/vector.hpp | 4 +- 5 files changed, 118 insertions(+), 118 deletions(-) diff --git a/include/boost/container/detail/alloc_helpers.hpp b/include/boost/container/detail/alloc_helpers.hpp index 57c59e4..5ca2ca7 100644 --- a/include/boost/container/detail/alloc_helpers.hpp +++ b/include/boost/container/detail/alloc_helpers.hpp @@ -27,30 +27,30 @@ namespace container { namespace dtl { template -inline void swap_alloc(AllocatorType &, AllocatorType &, dtl::false_type) +BOOST_CONTAINER_FORCEINLINE void swap_alloc(AllocatorType &, AllocatorType &, dtl::false_type) BOOST_NOEXCEPT_OR_NOTHROW {} template -inline void swap_alloc(AllocatorType &l, AllocatorType &r, dtl::true_type) +BOOST_CONTAINER_FORCEINLINE void swap_alloc(AllocatorType &l, AllocatorType &r, dtl::true_type) { boost::adl_move_swap(l, r); } template -inline void assign_alloc(AllocatorType &, const AllocatorType &, dtl::false_type) +BOOST_CONTAINER_FORCEINLINE void assign_alloc(AllocatorType &, const AllocatorType &, dtl::false_type) BOOST_NOEXCEPT_OR_NOTHROW {} template -inline void assign_alloc(AllocatorType &l, const AllocatorType &r, dtl::true_type) +BOOST_CONTAINER_FORCEINLINE void assign_alloc(AllocatorType &l, const AllocatorType &r, dtl::true_type) { l = r; } template -inline void move_alloc(AllocatorType &, AllocatorType &, dtl::false_type) +BOOST_CONTAINER_FORCEINLINE void move_alloc(AllocatorType &, AllocatorType &, dtl::false_type) BOOST_NOEXCEPT_OR_NOTHROW {} template -inline void move_alloc(AllocatorType &l, AllocatorType &r, dtl::true_type) +BOOST_CONTAINER_FORCEINLINE void move_alloc(AllocatorType &l, AllocatorType &r, dtl::true_type) { l = ::boost::move(r); } } //namespace dtl { diff --git a/include/boost/container/detail/dispatch_uses_allocator.hpp b/include/boost/container/detail/dispatch_uses_allocator.hpp index ff88e27..e4ed7ab 100644 --- a/include/boost/container/detail/dispatch_uses_allocator.hpp +++ b/include/boost/container/detail/dispatch_uses_allocator.hpp @@ -110,7 +110,7 @@ template < typename ConstructAlloc , typename T , class ...Args > -inline typename dtl::enable_if_and +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and < void , dtl::is_not_pair , dtl::not_< uses_allocator > @@ -127,7 +127,7 @@ template < typename ConstructAlloc , typename T , class ...Args > -inline typename dtl::enable_if_and +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and < void , dtl::is_not_pair , uses_allocator @@ -146,7 +146,7 @@ template < typename ConstructAlloc , typename T , class ...Args > -inline typename dtl::enable_if_and +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and < void , dtl::is_not_pair , uses_allocator @@ -162,7 +162,7 @@ inline typename dtl::enable_if_and #define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ template \ - inline typename dtl::enable_if_and\ + BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and\ < void\ , dtl::is_not_pair\ , dtl::not_ >\ @@ -179,7 +179,7 @@ BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR #define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ template < typename ConstructAlloc, typename ArgAlloc, typename T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ - inline typename dtl::enable_if_and\ + BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and\ < void\ , dtl::is_not_pair\ , uses_allocator\ @@ -197,7 +197,7 @@ BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR #define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ template < typename ConstructAlloc, typename ArgAlloc, typename T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ - inline typename dtl::enable_if_and\ + BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and\ < void\ , dtl::is_not_pair\ , uses_allocator\ diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index f9ff663..2c25f4a 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -354,7 +354,7 @@ class list //! Throws: Nothing. //! //! Complexity: Linear to the number of elements. - ~list() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE ~list() BOOST_NOEXCEPT_OR_NOTHROW {} //AllocHolder clears the list //! Effects: Makes *this contain the same elements as x. @@ -430,9 +430,9 @@ class list //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to the number of elements in x. - list& operator=(std::initializer_list il) + BOOST_CONTAINER_FORCEINLINE list& operator=(std::initializer_list il) { - assign(il.begin(), il.end()); + this->assign(il.begin(), il.end()); return *this; } #endif @@ -442,7 +442,7 @@ class list //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. - void assign(size_type n, const T& val) + BOOST_CONTAINER_FORCEINLINE void assign(size_type n, const T& val) { typedef constant_iterator cvalue_iterator; return this->assign(cvalue_iterator(val, n), cvalue_iterator()); @@ -479,8 +479,8 @@ class list //! T's constructor from dereferencing std::initializer_list iterator throws. //! //! Complexity: Linear to n. - void assign(std::initializer_list il) - { assign(il.begin(), il.end()); } + BOOST_CONTAINER_FORCEINLINE void assign(std::initializer_list il) + { this->assign(il.begin(), il.end()); } #endif //! Effects: Returns a copy of the internal allocator. @@ -488,7 +488,7 @@ class list //! Throws: If allocator's copy constructor throws. //! //! Complexity: Constant. - allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW { return allocator_type(this->node_alloc()); } //! Effects: Returns a reference to the internal allocator. @@ -498,7 +498,7 @@ class list //! Complexity: Constant. //! //! Note: Non-standard extension. - stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW { return this->node_alloc(); } //! Effects: Returns a reference to the internal allocator. @@ -508,7 +508,7 @@ class list //! Complexity: Constant. //! //! Note: Non-standard extension. - const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW { return this->node_alloc(); } ////////////////////////////////////////////// @@ -522,7 +522,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - iterator begin() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE iterator begin() BOOST_NOEXCEPT_OR_NOTHROW { return iterator(this->icont().begin()); } //! Effects: Returns a const_iterator to the first element contained in the list. @@ -530,7 +530,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW { return this->cbegin(); } //! Effects: Returns an iterator to the end of the list. @@ -538,7 +538,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - iterator end() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE iterator end() BOOST_NOEXCEPT_OR_NOTHROW { return iterator(this->icont().end()); } //! Effects: Returns a const_iterator to the end of the list. @@ -546,7 +546,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW { return this->cend(); } //! Effects: Returns a reverse_iterator pointing to the beginning @@ -555,7 +555,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW { return reverse_iterator(end()); } //! Effects: Returns a const_reverse_iterator pointing to the beginning @@ -564,7 +564,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW { return this->crbegin(); } //! Effects: Returns a reverse_iterator pointing to the end @@ -573,7 +573,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW { return reverse_iterator(begin()); } //! Effects: Returns a const_reverse_iterator pointing to the end @@ -582,7 +582,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW { return this->crend(); } //! Effects: Returns a const_iterator to the first element contained in the list. @@ -590,7 +590,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW { return const_iterator(this->non_const_icont().begin()); } //! Effects: Returns a const_iterator to the end of the list. @@ -598,7 +598,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW { return const_iterator(this->non_const_icont().end()); } //! Effects: Returns a const_reverse_iterator pointing to the beginning @@ -607,7 +607,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW { return const_reverse_iterator(this->cend()); } //! Effects: Returns a const_reverse_iterator pointing to the end @@ -616,7 +616,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW { return const_reverse_iterator(this->cbegin()); } ////////////////////////////////////////////// @@ -630,7 +630,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - bool empty() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE bool empty() const BOOST_NOEXCEPT_OR_NOTHROW { return !this->size(); } //! Effects: Returns the number of the elements contained in the list. @@ -638,7 +638,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - size_type size() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type size() const BOOST_NOEXCEPT_OR_NOTHROW { return this->icont().size(); } //! Effects: Returns the largest possible size of the list. @@ -646,7 +646,7 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW { return AllocHolder::max_size(); } //! Effects: Inserts or erases elements at the end such that diff --git a/include/boost/container/scoped_allocator.hpp b/include/boost/container/scoped_allocator.hpp index 6cd69fe..e9720fe 100644 --- a/include/boost/container/scoped_allocator.hpp +++ b/include/boost/container/scoped_allocator.hpp @@ -79,10 +79,10 @@ struct outermost_allocator_imp { typedef MaybeScopedAlloc type; - static type &get(MaybeScopedAlloc &a) + BOOST_CONTAINER_FORCEINLINE static type &get(MaybeScopedAlloc &a) { return a; } - static const type &get(const MaybeScopedAlloc &a) + BOOST_CONTAINER_FORCEINLINE static const type &get(const MaybeScopedAlloc &a) { return a; } }; @@ -92,10 +92,10 @@ struct outermost_allocator_imp typedef typename MaybeScopedAlloc::outer_allocator_type outer_type; typedef typename outermost_allocator_type_impl::type type; - static type &get(MaybeScopedAlloc &a) + BOOST_CONTAINER_FORCEINLINE static type &get(MaybeScopedAlloc &a) { return outermost_allocator_imp::get(a.outer_allocator()); } - static const type &get(const MaybeScopedAlloc &a) + BOOST_CONTAINER_FORCEINLINE static const type &get(const MaybeScopedAlloc &a) { return outermost_allocator_imp::get(a.outer_allocator()); } }; @@ -112,12 +112,12 @@ struct outermost_allocator {}; template -typename outermost_allocator::type & +BOOST_CONTAINER_FORCEINLINE typename outermost_allocator::type & get_outermost_allocator(Allocator &a) { return outermost_allocator::get(a); } template -const typename outermost_allocator::type & +BOOST_CONTAINER_FORCEINLINE const typename outermost_allocator::type & get_outermost_allocator(const Allocator &a) { return outermost_allocator::get(a); } @@ -161,34 +161,34 @@ class scoped_allocator_adaptor_base inner_allocator_type::is_always_equal::value > is_always_equal; - scoped_allocator_adaptor_base() + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base() {} template - scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs &...args) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs &...args) : outer_allocator_type(::boost::forward(outerAlloc)) , m_inner(args...) {} - scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) : outer_allocator_type(other.outer_allocator()) , m_inner(other.inner_allocator()) {} - scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) : outer_allocator_type(::boost::move(other.outer_allocator())) , m_inner(::boost::move(other.inner_allocator())) {} template - scoped_allocator_adaptor_base + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base (const scoped_allocator_adaptor_base& other) : outer_allocator_type(other.outer_allocator()) , m_inner(other.inner_allocator()) {} template - scoped_allocator_adaptor_base + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base (BOOST_RV_REF_BEG scoped_allocator_adaptor_base BOOST_RV_REF_END other) : outer_allocator_type(other.outer_allocator()) @@ -199,7 +199,7 @@ class scoped_allocator_adaptor_base struct internal_type_t{}; template - scoped_allocator_adaptor_base + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base ( internal_type_t , BOOST_FWD_REF(OuterA2) outerAlloc , const inner_allocator_type &inner) @@ -209,7 +209,7 @@ class scoped_allocator_adaptor_base public: - scoped_allocator_adaptor_base &operator= + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base &operator= (BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other) { outer_allocator_type::operator=(other.outer_allocator()); @@ -217,35 +217,35 @@ class scoped_allocator_adaptor_base return *this; } - scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) { outer_allocator_type::operator=(boost::move(other.outer_allocator())); m_inner = ::boost::move(other.inner_allocator()); return *this; } - void swap(scoped_allocator_adaptor_base &r) + BOOST_CONTAINER_FORCEINLINE void swap(scoped_allocator_adaptor_base &r) { boost::adl_move_swap(this->outer_allocator(), r.outer_allocator()); boost::adl_move_swap(this->m_inner, r.inner_allocator()); } - friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r) + BOOST_CONTAINER_FORCEINLINE friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r) { l.swap(r); } - inner_allocator_type& inner_allocator() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE inner_allocator_type& inner_allocator() BOOST_NOEXCEPT_OR_NOTHROW { return m_inner; } - inner_allocator_type const& inner_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE inner_allocator_type const& inner_allocator() const BOOST_NOEXCEPT_OR_NOTHROW { return m_inner; } - outer_allocator_type & outer_allocator() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE outer_allocator_type & outer_allocator() BOOST_NOEXCEPT_OR_NOTHROW { return static_cast(*this); } - const outer_allocator_type &outer_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const outer_allocator_type &outer_allocator() const BOOST_NOEXCEPT_OR_NOTHROW { return static_cast(*this); } - scoped_allocator_type select_on_container_copy_construction() const + BOOST_CONTAINER_FORCEINLINE scoped_allocator_type select_on_container_copy_construction() const { return scoped_allocator_type (internal_type_t() @@ -304,33 +304,33 @@ class scoped_allocator_adaptor_base\ inner_allocator_type::is_always_equal::value\ > is_always_equal;\ \ - scoped_allocator_adaptor_base(){}\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(){}\ \ template \ - scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, BOOST_MOVE_CREF##N)\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, BOOST_MOVE_CREF##N)\ : outer_allocator_type(::boost::forward(outerAlloc))\ , m_inner(BOOST_MOVE_ARG##N)\ {}\ \ - scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other)\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other)\ : outer_allocator_type(other.outer_allocator())\ , m_inner(other.inner_allocator())\ {}\ \ - scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other)\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other)\ : outer_allocator_type(::boost::move(other.outer_allocator()))\ , m_inner(::boost::move(other.inner_allocator()))\ {}\ \ template \ - scoped_allocator_adaptor_base\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base\ (const scoped_allocator_adaptor_base& other)\ : outer_allocator_type(other.outer_allocator())\ , m_inner(other.inner_allocator())\ {}\ \ template \ - scoped_allocator_adaptor_base\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base\ (BOOST_RV_REF_BEG scoped_allocator_adaptor_base BOOST_RV_REF_END other)\ : outer_allocator_type(other.outer_allocator())\ , m_inner(other.inner_allocator())\ @@ -340,14 +340,14 @@ class scoped_allocator_adaptor_base\ struct internal_type_t{};\ \ template \ - scoped_allocator_adaptor_base\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base\ ( internal_type_t, BOOST_FWD_REF(OuterA2) outerAlloc, const inner_allocator_type &inner)\ : outer_allocator_type(::boost::forward(outerAlloc))\ , m_inner(inner)\ {}\ \ public:\ - scoped_allocator_adaptor_base &operator=\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base &operator=\ (BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other)\ {\ outer_allocator_type::operator=(other.outer_allocator());\ @@ -355,35 +355,35 @@ class scoped_allocator_adaptor_base\ return *this;\ }\ \ - scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other)\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other)\ {\ outer_allocator_type::operator=(boost::move(other.outer_allocator()));\ m_inner = ::boost::move(other.inner_allocator());\ return *this;\ }\ \ - void swap(scoped_allocator_adaptor_base &r)\ + BOOST_CONTAINER_FORCEINLINE void swap(scoped_allocator_adaptor_base &r)\ {\ boost::adl_move_swap(this->outer_allocator(), r.outer_allocator());\ boost::adl_move_swap(this->m_inner, r.inner_allocator());\ }\ \ - friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r)\ + BOOST_CONTAINER_FORCEINLINE friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r)\ { l.swap(r); }\ \ - inner_allocator_type& inner_allocator()\ + BOOST_CONTAINER_FORCEINLINE inner_allocator_type& inner_allocator()\ { return m_inner; }\ \ - inner_allocator_type const& inner_allocator() const\ + BOOST_CONTAINER_FORCEINLINE inner_allocator_type const& inner_allocator() const\ { return m_inner; }\ \ - outer_allocator_type & outer_allocator()\ + BOOST_CONTAINER_FORCEINLINE outer_allocator_type & outer_allocator()\ { return static_cast(*this); }\ \ - const outer_allocator_type &outer_allocator() const\ + BOOST_CONTAINER_FORCEINLINE const outer_allocator_type &outer_allocator() const\ { return static_cast(*this); }\ \ - scoped_allocator_type select_on_container_copy_construction() const\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_type select_on_container_copy_construction() const\ {\ return scoped_allocator_type\ (internal_type_t()\ @@ -440,30 +440,30 @@ class scoped_allocator_adaptor_base< OuterAlloc BOOST_CONTAINER_SCOPEDALLOC_DUMM typedef typename outer_traits_type:: is_always_equal is_always_equal; - scoped_allocator_adaptor_base() + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base() {} template - scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc) : outer_allocator_type(::boost::forward(outerAlloc)) {} - scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) : outer_allocator_type(other.outer_allocator()) {} - scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) : outer_allocator_type(::boost::move(other.outer_allocator())) {} template - scoped_allocator_adaptor_base + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base (const scoped_allocator_adaptor_base& other) : outer_allocator_type(other.outer_allocator()) {} template - scoped_allocator_adaptor_base + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base (BOOST_RV_REF_BEG scoped_allocator_adaptor_base BOOST_RV_REF_END other) : outer_allocator_type(other.outer_allocator()) {} @@ -472,44 +472,44 @@ class scoped_allocator_adaptor_base< OuterAlloc BOOST_CONTAINER_SCOPEDALLOC_DUMM struct internal_type_t{}; template - scoped_allocator_adaptor_base(internal_type_t, BOOST_FWD_REF(OuterA2) outerAlloc, const inner_allocator_type &) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base(internal_type_t, BOOST_FWD_REF(OuterA2) outerAlloc, const inner_allocator_type &) : outer_allocator_type(::boost::forward(outerAlloc)) {} public: - scoped_allocator_adaptor_base &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other) { outer_allocator_type::operator=(other.outer_allocator()); return *this; } - scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) { outer_allocator_type::operator=(boost::move(other.outer_allocator())); return *this; } - void swap(scoped_allocator_adaptor_base &r) + BOOST_CONTAINER_FORCEINLINE void swap(scoped_allocator_adaptor_base &r) { boost::adl_move_swap(this->outer_allocator(), r.outer_allocator()); } - friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r) + BOOST_CONTAINER_FORCEINLINE friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r) { l.swap(r); } - inner_allocator_type& inner_allocator() + BOOST_CONTAINER_FORCEINLINE inner_allocator_type& inner_allocator() { return static_cast(*this); } - inner_allocator_type const& inner_allocator() const + BOOST_CONTAINER_FORCEINLINE inner_allocator_type const& inner_allocator() const { return static_cast(*this); } - outer_allocator_type & outer_allocator() + BOOST_CONTAINER_FORCEINLINE outer_allocator_type & outer_allocator() { return static_cast(*this); } - const outer_allocator_type &outer_allocator() const + BOOST_CONTAINER_FORCEINLINE const outer_allocator_type &outer_allocator() const { return static_cast(*this); } - scoped_allocator_type select_on_container_copy_construction() const + BOOST_CONTAINER_FORCEINLINE scoped_allocator_type select_on_container_copy_construction() const { return scoped_allocator_type (internal_type_t() @@ -641,21 +641,21 @@ class scoped_allocator_adaptor //! Effects: value-initializes the OuterAlloc base class //! and the inner allocator object. - scoped_allocator_adaptor() + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor() {} - ~scoped_allocator_adaptor() + BOOST_CONTAINER_FORCEINLINE ~scoped_allocator_adaptor() {} //! Effects: initializes each allocator within the adaptor with //! the corresponding allocator from other. - scoped_allocator_adaptor(const scoped_allocator_adaptor& other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor(const scoped_allocator_adaptor& other) : base_type(other.base()) {} //! Effects: move constructs each allocator within the adaptor with //! the corresponding allocator from other. - scoped_allocator_adaptor(BOOST_RV_REF(scoped_allocator_adaptor) other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor(BOOST_RV_REF(scoped_allocator_adaptor) other) : base_type(::boost::move(other.base())) {} @@ -667,14 +667,14 @@ class scoped_allocator_adaptor //! with innerAllocs...(hence recursively initializing each allocator within the adaptor with the //! corresponding allocator from the argument list). template - scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs & ...innerAllocs) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs & ...innerAllocs) : base_type(::boost::forward(outerAlloc), innerAllocs...) {} #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #define BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_RELATED_ALLOCATOR_CONSTRUCTOR_CODE(N)\ template \ - scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc BOOST_MOVE_I##N BOOST_MOVE_CREF##N)\ + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc BOOST_MOVE_I##N BOOST_MOVE_CREF##N)\ : base_type(::boost::forward(outerAlloc) BOOST_MOVE_I##N BOOST_MOVE_ARG##N)\ {}\ // @@ -687,7 +687,7 @@ class scoped_allocator_adaptor //! //! Effects: initializes each allocator within the adaptor with the corresponding allocator from other. template - scoped_allocator_adaptor(const scoped_allocator_adaptor &other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor(const scoped_allocator_adaptor &other) : base_type(other.base()) {} @@ -696,15 +696,15 @@ class scoped_allocator_adaptor //! Effects: initializes each allocator within the adaptor with the corresponding allocator //! rvalue from other. template - scoped_allocator_adaptor(BOOST_RV_REF_BEG scoped_allocator_adaptor + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor(BOOST_RV_REF_BEG scoped_allocator_adaptor BOOST_RV_REF_END other) : base_type(::boost::move(other.base())) {} - scoped_allocator_adaptor &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor) other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor) other) { return static_cast(base_type::operator=(static_cast(other))); } - scoped_allocator_adaptor &operator=(BOOST_RV_REF(scoped_allocator_adaptor) other) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor &operator=(BOOST_RV_REF(scoped_allocator_adaptor) other) { return static_cast(base_type::operator=(boost::move(other.base()))); } #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -736,13 +736,13 @@ class scoped_allocator_adaptor //! Returns: //! allocator_traits:: max_size(outer_allocator()). - size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW { return outer_traits_type::max_size(this->outer_allocator()); } //! Effects: //! calls OUTERMOST_ALLOC_TRAITS(*this):: destroy(OUTERMOST(*this), p). template - void destroy(T* p) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE void destroy(T* p) BOOST_NOEXCEPT_OR_NOTHROW { allocator_traits::type> ::destroy(get_outermost_allocator(this->outer_allocator()), p); @@ -750,17 +750,17 @@ class scoped_allocator_adaptor //! Returns: //! allocator_traits::allocate(outer_allocator(), n). - pointer allocate(size_type n) + BOOST_CONTAINER_FORCEINLINE pointer allocate(size_type n) { return outer_traits_type::allocate(this->outer_allocator(), n); } //! Returns: //! allocator_traits::allocate(outer_allocator(), n, hint). - pointer allocate(size_type n, const_void_pointer hint) + BOOST_CONTAINER_FORCEINLINE pointer allocate(size_type n, const_void_pointer hint) { return outer_traits_type::allocate(this->outer_allocator(), n, hint); } //! Effects: //! allocator_traits::deallocate(outer_allocator(), p, n). - void deallocate(pointer p, size_type n) + BOOST_CONTAINER_FORCEINLINE void deallocate(pointer p, size_type n) { outer_traits_type::deallocate(this->outer_allocator(), p, n); } #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -772,9 +772,9 @@ class scoped_allocator_adaptor #endif //BOOST_CONTAINER_DOXYGEN_INVOKED #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - base_type &base() { return *this; } + BOOST_CONTAINER_FORCEINLINE base_type &base() { return *this; } - const base_type &base() const { return *this; } + BOOST_CONTAINER_FORCEINLINE const base_type &base() const { return *this; } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -808,7 +808,7 @@ class scoped_allocator_adaptor //! to true but the specific constructor does not take an allocator. This definition prevents a silent //! failure to pass an inner allocator to a contained element. -end note] template < typename T, class ...Args> - void construct(T* p, BOOST_FWD_REF(Args)...args) + BOOST_CONTAINER_FORCEINLINE void construct(T* p, BOOST_FWD_REF(Args)...args) { dtl::dispatch_uses_allocator ( (get_outermost_allocator)(this->outer_allocator()) @@ -821,7 +821,7 @@ class scoped_allocator_adaptor //overload selection problems when the first parameter is a pair. #define BOOST_CONTAINER_SCOPED_ALLOCATOR_CONSTRUCT_CODE(N) \ template < typename T BOOST_MOVE_I##N BOOST_MOVE_CLASSQ##N >\ - void construct(T* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\ + BOOST_CONTAINER_FORCEINLINE void construct(T* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\ {\ dtl::dispatch_uses_allocator\ ( (get_outermost_allocator)(this->outer_allocator())\ @@ -838,7 +838,7 @@ class scoped_allocator_adaptor public: //Internal function template - scoped_allocator_adaptor(internal_type_t, BOOST_FWD_REF(OuterA2) outer, const inner_allocator_type& inner) + BOOST_CONTAINER_FORCEINLINE scoped_allocator_adaptor(internal_type_t, BOOST_FWD_REF(OuterA2) outer, const inner_allocator_type& inner) : base_type(internal_type_t(), ::boost::forward(outer), inner) {} @@ -853,17 +853,17 @@ struct scoped_allocator_operator_equal //Optimize equal outer allocator types with //allocator_traits::equal which uses is_always_equal template - static bool equal_outer(const IA &l, const IA &r) + BOOST_CONTAINER_FORCEINLINE static bool equal_outer(const IA &l, const IA &r) { return allocator_traits::equal(l, r); } //Otherwise compare it normally template - static bool equal_outer(const IA1 &l, const IA2 &r) + BOOST_CONTAINER_FORCEINLINE static bool equal_outer(const IA1 &l, const IA2 &r) { return l == r; } //Otherwise compare it normally template - static bool equal_inner(const IA &l, const IA &r) + BOOST_CONTAINER_FORCEINLINE static bool equal_inner(const IA &l, const IA &r) { return allocator_traits::equal(l, r); } }; @@ -875,14 +875,14 @@ struct scoped_allocator_operator_equal //inner_allocator_type is the same as outer_allocator_type //so both types can be different in operator== template - static bool equal_inner(const IA1 &, const IA2 &) + BOOST_CONTAINER_FORCEINLINE static bool equal_inner(const IA1 &, const IA2 &) { return true; } }; /// @endcond template -inline bool operator==(const scoped_allocator_adaptor& a +BOOST_CONTAINER_FORCEINLINE bool operator==(const scoped_allocator_adaptor& a ,const scoped_allocator_adaptor& b) { #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -896,7 +896,7 @@ inline bool operator==(const scoped_allocator_adaptor -inline bool operator!=(const scoped_allocator_adaptor& a +BOOST_CONTAINER_FORCEINLINE bool operator!=(const scoped_allocator_adaptor& a ,const scoped_allocator_adaptor& b) { return !(a == b); } diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 099a878..1e3c8a6 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -288,7 +288,7 @@ struct vector_alloc_holder typedef typename allocator_traits_type::size_type size_type; typedef typename allocator_traits_type::value_type value_type; - static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator) + BOOST_CONTAINER_FORCEINLINE static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator) { (void)propagate_allocator; (void)p; (void)to_alloc; (void)from_alloc; const bool all_storage_propagable = !allocator_traits_type::is_partially_propagable::value || @@ -296,7 +296,7 @@ struct vector_alloc_holder return all_storage_propagable && (propagate_allocator || allocator_traits_type::equal(from_alloc, to_alloc)); } - static bool are_swap_propagable(const allocator_type &l_a, pointer l_p, const allocator_type &r_a, pointer r_p, bool const propagate_allocator) + BOOST_CONTAINER_FORCEINLINE static bool are_swap_propagable(const allocator_type &l_a, pointer l_p, const allocator_type &r_a, pointer r_p, bool const propagate_allocator) { (void)propagate_allocator; (void)l_p; (void)r_p; (void)l_a; (void)r_a; const bool all_storage_propagable = !allocator_traits_type::is_partially_propagable::value || From 52b9ae0e680060eddf2bac80dc92210e1e5bc935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 25 May 2020 00:35:07 +0200 Subject: [PATCH 22/61] Fixes #145 ("Allocations not handled correctly in some cases of vector move with unequal allocators") --- doc/container.qbk | 11 ++--- include/boost/container/vector.hpp | 36 ++------------ test/dummy_test_allocator.hpp | 20 +++++--- test/propagate_allocator_test.hpp | 15 ++++-- test/scoped_allocator_usage_test.cpp | 74 +++++++++++++++++++++------- 5 files changed, 91 insertions(+), 65 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 21450a3..1600767 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -73,12 +73,10 @@ instructions, that's already been done for you. [section:tested_compilers Tested compilers] -[*Boost.Container] requires a decent C++98 compatibility. Some compilers known to work are: +[*Boost.Container] requires a decent C++03 compatibility. Some compilers known to work are: -* Visual C++ >= 7.1. -* GCC >= 4.1. - -[warning GCC < 4.3 and MSVC < 9.0 are deprecated and will be removed in the next version.] +* Visual C++ >= 10.0 +* GCC >= 4.8 [endsect] @@ -1322,7 +1320,8 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_74_00 Boost 1.74 Release] * Fixed bugs: - * [@https://github.com/boostorg/container/issues/144 GitHub #148: ['"GCC suggest-override warnings"]]. + * [@https://github.com/boostorg/container/issues/144 GitHub #144: ['"GCC suggest-override warnings"]]. + * [@https://github.com/boostorg/container/issues/145 GitHub #145: ['"Allocations not handled correctly in some cases of vector move with unequal allocators"]]. * [@https://github.com/boostorg/container/pull/148 GitHub #148: ['"Fix static initialization issues in pmr global resources"]]. [endsect] diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 1e3c8a6..eabd2c6 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -359,35 +359,6 @@ struct vector_alloc_holder holder.m_size = holder.m_capacity = 0; } - vector_alloc_holder(initial_capacity_t, pointer p, size_type capacity, BOOST_RV_REF(vector_alloc_holder) holder) - : allocator_type(BOOST_MOVE_BASE(allocator_type, holder)) - , m_start(p) - , m_size(holder.m_size) - , m_capacity(static_cast(capacity)) - { - allocator_type &this_alloc = this->alloc(); - allocator_type &x_alloc = holder.alloc(); - if(this->is_propagable_from(x_alloc, holder.start(), this_alloc, true)){ - if(this->m_capacity){ - this->deallocate(this->m_start, this->m_capacity); - } - m_start = holder.m_start; - m_capacity = holder.m_capacity; - holder.m_start = pointer(); - holder.m_capacity = holder.m_size = 0; - } - else if(this->m_capacity < holder.m_size){ - size_type const n = holder.m_size; - pointer reuse = pointer(); - size_type final_cap = n; - m_start = this->allocation_command(allocate_new, n, final_cap, reuse); - m_capacity = static_cast(final_cap); - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - this->num_alloc += n != 0; - #endif - } - } - vector_alloc_holder(initial_capacity_t, pointer p, size_type n) BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible::value) : allocator_type() @@ -1081,10 +1052,12 @@ private: //! Complexity: Constant if a == x.get_allocator(), linear otherwise. vector(BOOST_RV_REF(vector) x, const allocator_type &a) : m_holder( vector_uninitialized_size, a - , is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, true) ? 0 : x.size() + //In this allocator move constructor the allocator won't be propagated --v + , is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, false) ? 0 : x.size() ) { - if(is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, true)){ + //In this allocator move constructor the allocator won't be propagated ---v + if(is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, false)){ this->m_holder.steal_resources(x.m_holder); } else{ @@ -2438,6 +2411,7 @@ private: allocator_type &x_alloc = x.m_holder.alloc(); const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; + //In this allocator move constructor the allocator maybe will be propagated -----------------------v const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc); //Resources can be transferred if both allocators are diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index 024ab0e..1c621ae 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -78,6 +78,7 @@ template< class T , bool PropagateOnContMoveAssign , bool PropagateOnContSwap , bool CopyOnPropagateOnContSwap + , bool EqualIfEqualIds > class propagation_test_allocator { @@ -99,7 +100,8 @@ class propagation_test_allocator , PropagateOnContCopyAssign , PropagateOnContMoveAssign , PropagateOnContSwap - , CopyOnPropagateOnContSwap> other; + , CopyOnPropagateOnContSwap + , EqualIfEqualIds> other; }; propagation_test_allocator select_on_container_copy_construction() const @@ -129,7 +131,8 @@ class propagation_test_allocator , PropagateOnContCopyAssign , PropagateOnContMoveAssign , PropagateOnContSwap - , CopyOnPropagateOnContSwap> &x) + , CopyOnPropagateOnContSwap + , EqualIfEqualIds> &x) : id_(x.id_) , ctr_copies_(x.ctr_copies_+1) , ctr_moves_(0) @@ -178,11 +181,11 @@ class propagation_test_allocator void deallocate(T*p, std::size_t) { delete[] ((char*)p);} - friend bool operator==(const propagation_test_allocator &, const propagation_test_allocator &) - { return true; } + friend bool operator==(const propagation_test_allocator &a, const propagation_test_allocator &b) + { return EqualIfEqualIds ? a.id_ == b.id_ : true; } - friend bool operator!=(const propagation_test_allocator &, const propagation_test_allocator &) - { return false; } + friend bool operator!=(const propagation_test_allocator &a, const propagation_test_allocator &b) + { return EqualIfEqualIds ? a.id_ != b.id_ : false; } void swap(propagation_test_allocator &r) { @@ -214,12 +217,15 @@ template< class T , bool PropagateOnContMoveAssign , bool PropagateOnContSwap , bool CopyOnPropagateOnContSwap + , bool EqualIfEqualIds > unsigned int propagation_test_allocator< T , PropagateOnContCopyAssign , PropagateOnContMoveAssign , PropagateOnContSwap - , CopyOnPropagateOnContSwap>::unique_id_ = 0; + , CopyOnPropagateOnContSwap + , EqualIfEqualIds + >::unique_id_ = 0; } //namespace test { diff --git a/test/propagate_allocator_test.hpp b/test/propagate_allocator_test.hpp index e3a5048..02937f4 100644 --- a/test/propagate_allocator_test.hpp +++ b/test/propagate_allocator_test.hpp @@ -110,7 +110,7 @@ template bool test_propagate_allocator() { { - typedef propagation_test_allocator AlwaysPropagate; + typedef propagation_test_allocator AlwaysPropagate; typedef alloc_propagate_wrapper PropagateCont; typedef typename get_real_stored_allocator::type StoredAllocator; { @@ -213,7 +213,7 @@ bool test_propagate_allocator() //Test NeverPropagate allocator propagation ////////////////////////////////////////// { - typedef propagation_test_allocator NeverPropagate; + typedef propagation_test_allocator NeverPropagate; typedef alloc_propagate_wrapper NoPropagateCont; typedef typename get_real_stored_allocator::type StoredAllocator; { @@ -281,6 +281,15 @@ bool test_propagate_allocator() BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); } + //And now allocator argument constructors + test_propagate_allocator_allocator_arg(); + } + { + //Don't use unequal ids as unequal allocators -------------------------|, + //because swap requires equal allocators v + typedef propagation_test_allocator NeverPropagate; + typedef alloc_propagate_wrapper NoPropagateCont; + typedef typename get_real_stored_allocator::type StoredAllocator; { //swap StoredAllocator::reset_unique_id(666); @@ -302,8 +311,6 @@ bool test_propagate_allocator() BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); BOOST_TEST (c.get_stored_allocator().swaps_ == 0); } - //And now allocator argument constructors - test_propagate_allocator_allocator_arg(); } return report_errors() == 0; diff --git a/test/scoped_allocator_usage_test.cpp b/test/scoped_allocator_usage_test.cpp index 6eb1438..d16a1ea 100644 --- a/test/scoped_allocator_usage_test.cpp +++ b/test/scoped_allocator_usage_test.cpp @@ -59,18 +59,18 @@ public: template friend class SimpleAllocator; - friend bool operator == (const SimpleAllocator &, const SimpleAllocator &) - { return true; } + friend bool operator == (const SimpleAllocator &a, const SimpleAllocator &b) + { return a.m_state == b.m_state; } - friend bool operator != (const SimpleAllocator &, const SimpleAllocator &) - { return false; } + friend bool operator != (const SimpleAllocator &a, const SimpleAllocator &b) + { return a.m_state != b.m_state; } }; class alloc_int { private: // Not copyable - BOOST_MOVABLE_BUT_NOT_COPYABLE(alloc_int) + BOOST_COPYABLE_AND_MOVABLE(alloc_int) public: typedef SimpleAllocator allocator_type; @@ -87,13 +87,30 @@ class alloc_int other.m_value = -1; } + alloc_int(const alloc_int &other) + : m_value(other.m_value), m_allocator(boost::move(other.m_allocator)) + { + } + + alloc_int(const alloc_int &other, const allocator_type &allocator) + : m_value(other.m_value), m_allocator(allocator) + { + } + alloc_int(int value, const allocator_type &allocator) : m_value(value), m_allocator(allocator) {} alloc_int & operator=(BOOST_RV_REF(alloc_int)other) { - other.m_value = other.m_value; + m_value = other.m_value; + other.m_value = -1; + return *this; + } + + alloc_int & operator=(const alloc_int &other) + { + m_value = other.m_value; return *this; } @@ -368,24 +385,47 @@ bool one_level_allocator_propagation_test() { allocator_type al(SimpleAllocator(4)); ContainerWrapper c2(al); + { + iterator it = c2.emplace(c2.cbegin(), 41); + if(!test_value_and_state_equals(*it, 41, 4)) + return false; + } + ContainerWrapper c(::boost::move(c2), allocator_type(SimpleAllocator(5))); - c.clear(); - iterator it = c.emplace(c.cbegin(), 42); - - if(!test_value_and_state_equals(*it, 42, 5)) + if(!test_value_and_state_equals(*c.begin(), 41, 5)) return false; - }/* + + { + c.clear(); + iterator it = c.emplace(c.cbegin(), 42); + + if(!test_value_and_state_equals(*it, 42, 5)) + return false; + } + } { - ContainerWrapper c2(allocator_type(SimpleAllocator(3))); + allocator_type al(SimpleAllocator(4)); + ContainerWrapper c2(al); + { + iterator it = c2.emplace(c2.cbegin(), 41); + if(!test_value_and_state_equals(*it, 41, 4)) + return false; + } + ContainerWrapper c(c2, allocator_type(SimpleAllocator(5))); - c.clear(); - iterator it = c.emplace(c.cbegin(), 42); - - if(!test_value_and_state_equals(*it, 42, 5)) + if(!test_value_and_state_equals(*c.begin(), 41, 5)) return false; - }*/ + + { + c.clear(); + iterator it = c.emplace(c.cbegin(), 42); + + if(!test_value_and_state_equals(*it, 42, 5)) + return false; + } + } return true; } From c064db0cb8e6a764828151d67972ba221528dbeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 25 May 2020 00:46:54 +0200 Subject: [PATCH 23/61] Update changelog with pull 146 --- doc/container.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/container.qbk b/doc/container.qbk index 1600767..3ff37f1 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1322,6 +1322,7 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs: * [@https://github.com/boostorg/container/issues/144 GitHub #144: ['"GCC suggest-override warnings"]]. * [@https://github.com/boostorg/container/issues/145 GitHub #145: ['"Allocations not handled correctly in some cases of vector move with unequal allocators"]]. + * [@https://github.com/boostorg/container/pull/146 GitHub #146: ['"Changes for Embarcadero C++ clang-based compilers, targeting Boost 1.74. Addition needed for Embarcardero clang-based compilers"]]. * [@https://github.com/boostorg/container/pull/148 GitHub #148: ['"Fix static initialization issues in pmr global resources"]]. [endsect] From 80d742f860953d2d9c476cdbcdce1db721d0aa40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 25 May 2020 01:50:23 +0200 Subject: [PATCH 24/61] Added C++03 portable aliases and tests. Fixes #129 ("Alias templates for small_flat_[multi]{set|map} using small_vector as container") --- doc/container.qbk | 3 +- include/boost/container/container_fwd.hpp | 46 +++++++++++++++++++++++ test/flat_map_adaptor_test.cpp | 15 ++++++++ test/flat_set_adaptor_test.cpp | 14 +++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/doc/container.qbk b/doc/container.qbk index 3ff37f1..44dcaf9 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1319,7 +1319,8 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_74_00 Boost 1.74 Release] -* Fixed bugs: +* Fixed bugs/issues: + * [@https://github.com/boostorg/container/issues/129 GitHub #129: ['"Alias templates for small_flat_[multi]{set|map} using small_vector as container"]]. * [@https://github.com/boostorg/container/issues/144 GitHub #144: ['"GCC suggest-override warnings"]]. * [@https://github.com/boostorg/container/issues/145 GitHub #145: ['"Allocations not handled correctly in some cases of vector move with unequal allocators"]]. * [@https://github.com/boostorg/container/pull/146 GitHub #146: ['"Changes for Embarcadero C++ clang-based compilers, targeting Boost 1.74. Addition needed for Embarcardero clang-based compilers"]]. diff --git a/include/boost/container/container_fwd.hpp b/include/boost/container/container_fwd.hpp index 95341d1..fb4d7bd 100644 --- a/include/boost/container/container_fwd.hpp +++ b/include/boost/container/container_fwd.hpp @@ -220,6 +220,52 @@ using small_flat_multimap = flat_multimap + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_set_of +{ + typedef flat_set > type; +}; + +//! A portable metafunction to obtain a small_flat_multiset +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_multiset_of +{ + typedef flat_multiset > type; +}; + +//! A portable metafunction to obtain a small_flat_map +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_map_of +{ + typedef flat_map, N, SmallVectorAllocator, SmallVectorOptions> > type; +}; + +//! A portable metafunction to obtain a small_flat_multimap +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_multimap_of +{ + typedef flat_multimap, N, SmallVectorAllocator, SmallVectorOptions> > type; +}; + template ,class Allocator = void > diff --git a/test/flat_map_adaptor_test.cpp b/test/flat_map_adaptor_test.cpp index 520ef3c..bc75949 100644 --- a/test/flat_map_adaptor_test.cpp +++ b/test/flat_map_adaptor_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -99,6 +100,20 @@ int main() return 1; } } + { + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef flat_map, small_vector, 10> > map_container_t; + typedef flat_multimap, small_vector, 10> > multimap_container_t; + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + + BOOST_STATIC_ASSERT(( is_same::type >::value )); + BOOST_STATIC_ASSERT(( is_same::type >::value )); + } return 0; } diff --git a/test/flat_set_adaptor_test.cpp b/test/flat_set_adaptor_test.cpp index b59ab17..6225bbf 100644 --- a/test/flat_set_adaptor_test.cpp +++ b/test/flat_set_adaptor_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -96,6 +97,19 @@ int main() return 1; } } + { + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef flat_set, small_vector > set_container_t; + typedef flat_multiset, small_vector > multiset_container_t; + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + BOOST_STATIC_ASSERT(( is_same::type >::value )); + BOOST_STATIC_ASSERT(( is_same::type >::value )); + } return 0; } From 4070eddb5b9c0c457a42cce811c6a47ec18eb72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 25 May 2020 02:01:27 +0200 Subject: [PATCH 25/61] Update changelog for 1.74, no fixes were released in 1.73 --- doc/container.qbk | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 44dcaf9..b1f38a2 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1321,6 +1321,10 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs/issues: * [@https://github.com/boostorg/container/issues/129 GitHub #129: ['"Alias templates for small_flat_[multi]{set|map} using small_vector as container"]]. + * [@https://github.com/boostorg/container/pull/135 GitHub #135: ['"Missing BOOST_NORETURN for user defined functions"]]. + * [@https://github.com/boostorg/container/pull/137 GitHub #137: ['"RandomAccessIterator + 0"]]. + * [@https://github.com/boostorg/container/pull/138 GitHub #138: ['"Remove Classes from Global Namespace"]]. + * [@https://github.com/boostorg/container/issues/142 GitHub #142: ['"memset called with null pointer"]]. * [@https://github.com/boostorg/container/issues/144 GitHub #144: ['"GCC suggest-override warnings"]]. * [@https://github.com/boostorg/container/issues/145 GitHub #145: ['"Allocations not handled correctly in some cases of vector move with unequal allocators"]]. * [@https://github.com/boostorg/container/pull/146 GitHub #146: ['"Changes for Embarcadero C++ clang-based compilers, targeting Boost 1.74. Addition needed for Embarcardero clang-based compilers"]]. @@ -1328,16 +1332,6 @@ use [*Boost.Container]? There are several reasons for that: [endsect] -[section:release_notes_boost_1_73_00 Boost 1.73 Release] - -* Fixed bugs: - * [@https://github.com/boostorg/container/pull/135 GitHub #135: ['"Missing BOOST_NORETURN for user defined functions"]]. - * [@https://github.com/boostorg/container/pull/138 GitHub #138: ['"Remove Classes from Global Namespace"]]. - * [@https://github.com/boostorg/container/issues/142 GitHub #142: ['"memset called with null pointer"]]. - -[endsect] - - [section:release_notes_boost_1_72_00 Boost 1.72 Release] * Fixed bugs: From 5d8e008c50572ac47bec1b49a2bee59f7559b244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 12 Jul 2020 11:05:34 +0200 Subject: [PATCH 26/61] Fix initializer_list contructor allocation count --- include/boost/container/vector.hpp | 49 ++++++++++++------------------ 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index eabd2c6..e82f278 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -713,19 +713,19 @@ public: // types // ////////////////////////////////////////////// - typedef T value_type; + typedef T value_type; typedef BOOST_CONTAINER_IMPDEF - (typename real_allocator::type) allocator_type; - typedef ::boost::container::allocator_traits allocator_traits_t; - typedef typename allocator_traits::pointer pointer; - typedef typename allocator_traits::const_pointer const_pointer; - typedef typename allocator_traits::reference reference; - typedef typename allocator_traits::const_reference const_reference; - typedef typename allocator_traits::size_type size_type; - typedef typename allocator_traits::difference_type difference_type; - typedef allocator_type stored_allocator_type; - typedef BOOST_CONTAINER_IMPDEF(vec_iterator) iterator; - typedef BOOST_CONTAINER_IMPDEF(vec_iterator) const_iterator; + (typename real_allocator::type) allocator_type; + typedef ::boost::container::allocator_traits allocator_traits_t; + typedef typename allocator_traits::pointer pointer; + typedef typename allocator_traits::const_pointer const_pointer; + typedef typename allocator_traits::reference reference; + typedef typename allocator_traits::const_reference const_reference; + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::difference_type difference_type; + typedef allocator_type stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(vec_iterator) iterator; + typedef BOOST_CONTAINER_IMPDEF(vec_iterator) const_iterator; typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) reverse_iterator; typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) const_reverse_iterator; @@ -946,12 +946,6 @@ private: //! throws or T's constructor taking a dereferenced InIt throws. //! //! Complexity: Linear to the range [first, last). -// template -// vector(InIt first, InIt last, const allocator_type& a -// BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_c -// < dtl::is_convertible::value -// BOOST_MOVE_I dtl::nat >::type * = 0) -// ) -> vector::value_type, new_allocator::value_type>>; template vector(InIt first, InIt last, const allocator_type& a BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_c @@ -999,9 +993,14 @@ private: //! //! Complexity: Linear to the range [il.begin(), il.end()). vector(std::initializer_list il, const allocator_type& a = allocator_type()) - : m_holder(a) + : m_holder(vector_uninitialized_size, a, il.size()) { - this->assign(il.begin(), il.end()); + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + this->num_alloc += il.size() != 0; + #endif + ::boost::container::uninitialized_copy_alloc_n_source + ( this->m_holder.alloc(), il.begin() + , il.size(), this->priv_raw_begin()); } #endif @@ -2113,15 +2112,7 @@ private: //! //! Complexity: Linear to the number of elements in the container. friend bool operator<(const vector& x, const vector& y) - { - const_iterator first1(x.cbegin()), first2(y.cbegin()); - const const_iterator last1(x.cend()), last2(y.cend()); - for ( ; (first1 != last1) && (first2 != last2); ++first1, ++first2 ) { - if (*first1 < *first2) return true; - if (*first2 < *first1) return false; - } - return (first1 == last1) && (first2 != last2); - } + { return boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } //! Effects: Returns true if x is greater than y //! From 4f37a023b0fbc266a51aa332de188e55a96d7eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 12 Jul 2020 11:06:01 +0200 Subject: [PATCH 27/61] Enable user warnings in tests to be able to fix them. --- test/allocator_traits_test.cpp | 2 -- test/deque_test.cpp | 4 ---- test/list_test.cpp | 3 --- test/map_test.cpp | 3 --- test/pair_test.cpp | 3 --- test/scoped_allocator_adaptor_test.cpp | 2 -- test/scoped_allocator_usage_test.cpp | 3 --- test/set_test.cpp | 3 --- test/slist_test.cpp | 4 ---- test/stable_vector_test.cpp | 3 --- test/static_vector_test.cpp | 2 -- test/string_test.cpp | 3 --- test/uses_allocator_test.cpp | 2 -- test/vector_test.cpp | 24 ++++++++++++------------ 14 files changed, 12 insertions(+), 49 deletions(-) diff --git a/test/allocator_traits_test.cpp b/test/allocator_traits_test.cpp index 4014424..eb42e56 100644 --- a/test/allocator_traits_test.cpp +++ b/test/allocator_traits_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include #include #include @@ -444,4 +443,3 @@ int main() return ::boost::report_errors(); } -#include diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 22b87f4..6d5ed74 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -7,8 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// - -#include #include #include #include @@ -442,5 +440,3 @@ int main () return 0; } - -#include diff --git a/test/list_test.cpp b/test/list_test.cpp index c4f9f41..821f7b0 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -8,7 +8,6 @@ // ////////////////////////////////////////////////////////////////////////////// -#include #include #include @@ -282,5 +281,3 @@ int main () return 0; } - -#include diff --git a/test/map_test.cpp b/test/map_test.cpp index 7448303..c36581b 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include #include @@ -689,5 +688,3 @@ int main () return 0; } - -#include diff --git a/test/pair_test.cpp b/test/pair_test.cpp index 5ead7a4..59dfd5e 100644 --- a/test/pair_test.cpp +++ b/test/pair_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include #include "movable_int.hpp" #include "emplace_test.hpp" @@ -152,5 +151,3 @@ int main () #endif //#!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) return ::boost::report_errors(); } - -#include diff --git a/test/scoped_allocator_adaptor_test.cpp b/test/scoped_allocator_adaptor_test.cpp index 6a051e2..042820d 100644 --- a/test/scoped_allocator_adaptor_test.cpp +++ b/test/scoped_allocator_adaptor_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include // container/detail @@ -1374,4 +1373,3 @@ int main() return ::boost::report_errors(); } -#include diff --git a/test/scoped_allocator_usage_test.cpp b/test/scoped_allocator_usage_test.cpp index d16a1ea..019c0a4 100644 --- a/test/scoped_allocator_usage_test.cpp +++ b/test/scoped_allocator_usage_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include #include @@ -464,5 +463,3 @@ int main() return 1; return 0; } - -#include diff --git a/test/set_test.cpp b/test/set_test.cpp index a7d0b47..a6d1f58 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include #include #include @@ -651,5 +650,3 @@ int main () return 0; } - -#include diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 0894344..8cc64bd 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include #include @@ -285,6 +284,3 @@ int main () return 0; } - -#include - diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index e0fb586..77a4aac 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -8,7 +8,6 @@ // ////////////////////////////////////////////////////////////////////////////// #define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING -#include #include #include @@ -223,5 +222,3 @@ int main() return 0; } - -#include diff --git a/test/static_vector_test.cpp b/test/static_vector_test.cpp index f47df2e..539eea8 100644 --- a/test/static_vector_test.cpp +++ b/test/static_vector_test.cpp @@ -7,7 +7,6 @@ // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include #include #include #include @@ -824,4 +823,3 @@ int main(int, char* []) return boost::report_errors(); } -#include diff --git a/test/string_test.cpp b/test/string_test.cpp index b2d17f6..48b5784 100644 --- a/test/string_test.cpp +++ b/test/string_test.cpp @@ -8,7 +8,6 @@ // ////////////////////////////////////////////////////////////////////////////// -#include #include #include #include @@ -592,5 +591,3 @@ int main() return boost::report_errors(); } - -#include diff --git a/test/uses_allocator_test.cpp b/test/uses_allocator_test.cpp index 39807f0..cb88a2b 100644 --- a/test/uses_allocator_test.cpp +++ b/test/uses_allocator_test.cpp @@ -7,9 +7,7 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include - #include #include "propagation_test_allocator.hpp" diff --git a/test/vector_test.cpp b/test/vector_test.cpp index c9b82cc..398eaa3 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -340,24 +340,24 @@ int main() typedef boost::container::vector cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG + ( !boost::has_trivial_destructor_after_move::value || + (boost::has_trivial_destructor_after_move::value == + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(default allocator) test failed" + ); } // std::allocator { typedef boost::container::vector > cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG + ( !boost::has_trivial_destructor_after_move::value || + (boost::has_trivial_destructor_after_move::value == + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(std::allocator) test failed" + ); } return 0; From 90de9533ecef08e98d82e8f8c26fad57839e4184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 12 Jul 2020 11:07:50 +0200 Subject: [PATCH 28/61] Fixes #151 ("Buffer overflow in monotonic_buffer_resource::do_allocate"). --- doc/container.qbk | 1 + src/monotonic_buffer_resource.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/doc/container.qbk b/doc/container.qbk index b1f38a2..fab8d94 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1329,6 +1329,7 @@ use [*Boost.Container]? There are several reasons for that: * [@https://github.com/boostorg/container/issues/145 GitHub #145: ['"Allocations not handled correctly in some cases of vector move with unequal allocators"]]. * [@https://github.com/boostorg/container/pull/146 GitHub #146: ['"Changes for Embarcadero C++ clang-based compilers, targeting Boost 1.74. Addition needed for Embarcardero clang-based compilers"]]. * [@https://github.com/boostorg/container/pull/148 GitHub #148: ['"Fix static initialization issues in pmr global resources"]]. + * [@https://github.com/boostorg/container/issues/151 GitHub #151: ['"Buffer overflow in monotonic_buffer_resource::do_allocate"]]. [endsect] diff --git a/src/monotonic_buffer_resource.cpp b/src/monotonic_buffer_resource.cpp index 29ffde1..c676992 100644 --- a/src/monotonic_buffer_resource.cpp +++ b/src/monotonic_buffer_resource.cpp @@ -141,6 +141,9 @@ void* monotonic_buffer_resource::do_allocate(std::size_t bytes, std::size_t alig //See if there is room in current buffer std::size_t aligner = 0u; if(this->remaining_storage(alignment, aligner) < bytes){ + //The new buffer will be aligned to the strictest alignment so reset + //the aligner, which was needed for the old buffer. + aligner = 0u; //Update next_buffer_size to at least bytes this->increase_next_buffer_at_least_to(bytes); //Now allocate and update internal data From 98b59db5fd036d359410d84f8c98926b87ce63dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 12 Jul 2020 12:44:31 +0200 Subject: [PATCH 29/61] Fixes #149: ("InitializeCriticalSectionEx returns "BOOL" (int)") --- doc/container.qbk | 1 + include/boost/container/detail/thread_mutex.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/container.qbk b/doc/container.qbk index fab8d94..308b296 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1329,6 +1329,7 @@ use [*Boost.Container]? There are several reasons for that: * [@https://github.com/boostorg/container/issues/145 GitHub #145: ['"Allocations not handled correctly in some cases of vector move with unequal allocators"]]. * [@https://github.com/boostorg/container/pull/146 GitHub #146: ['"Changes for Embarcadero C++ clang-based compilers, targeting Boost 1.74. Addition needed for Embarcardero clang-based compilers"]]. * [@https://github.com/boostorg/container/pull/148 GitHub #148: ['"Fix static initialization issues in pmr global resources"]]. + * [@https://github.com/boostorg/container/pull/149 GitHub #149: ['"InitializeCriticalSectionEx returns "BOOL" (int)"]]. * [@https://github.com/boostorg/container/issues/151 GitHub #151: ['"Buffer overflow in monotonic_buffer_resource::do_allocate"]]. [endsect] diff --git a/include/boost/container/detail/thread_mutex.hpp b/include/boost/container/detail/thread_mutex.hpp index 4027ff2..0f15c68 100644 --- a/include/boost/container/detail/thread_mutex.hpp +++ b/include/boost/container/detail/thread_mutex.hpp @@ -104,7 +104,7 @@ namespace container { namespace dtl { #ifdef BOOST_PLAT_WINDOWS_UWP -extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSectionEx(::_RTL_CRITICAL_SECTION *, unsigned long, unsigned long); +extern "C" __declspec(dllimport) int __stdcall InitializeCriticalSectionEx(::_RTL_CRITICAL_SECTION *, unsigned long, unsigned long); #else extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(::_RTL_CRITICAL_SECTION *); #endif From 069351adfc1b54955151b25e15429956dc98ee24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 12 Jul 2020 12:53:47 +0200 Subject: [PATCH 30/61] Fixes #126 ("flat_set.hpp and set.hpp in pmr have the same header guard") --- doc/container.qbk | 1 + include/boost/container/pmr/flat_set.hpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 308b296..76a0fdf 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1320,6 +1320,7 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_74_00 Boost 1.74 Release] * Fixed bugs/issues: + * [@https://github.com/boostorg/container/issues/126 GitHub #126: ['"flat_set.hpp and set.hpp in pmr have the same header guard"]]. * [@https://github.com/boostorg/container/issues/129 GitHub #129: ['"Alias templates for small_flat_[multi]{set|map} using small_vector as container"]]. * [@https://github.com/boostorg/container/pull/135 GitHub #135: ['"Missing BOOST_NORETURN for user defined functions"]]. * [@https://github.com/boostorg/container/pull/137 GitHub #137: ['"RandomAccessIterator + 0"]]. diff --git a/include/boost/container/pmr/flat_set.hpp b/include/boost/container/pmr/flat_set.hpp index f072c95..c9e26b7 100644 --- a/include/boost/container/pmr/flat_set.hpp +++ b/include/boost/container/pmr/flat_set.hpp @@ -8,8 +8,8 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_CONTAINER_PMR_SET_HPP -#define BOOST_CONTAINER_PMR_SET_HPP +#ifndef BOOST_CONTAINER_PMR_FLAT_SET_HPP +#define BOOST_CONTAINER_PMR_FLAT_SET_HPP #if defined (_MSC_VER) # pragma once @@ -56,4 +56,4 @@ struct flat_multiset_of } //namespace container { } //namespace boost { -#endif //BOOST_CONTAINER_PMR_SET_HPP +#endif //BOOST_CONTAINER_PMR_FLAT_SET_HPP From 2d9d28b81e560cfa2202e31ad37c2335d4730f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 12 Jul 2020 13:48:38 +0200 Subject: [PATCH 31/61] Fixed #128 ("moved from small_vector and static_vector calls destructor on elements in static part") --- doc/container.qbk | 1 + include/boost/container/small_vector.hpp | 1 + include/boost/container/vector.hpp | 10 +++++++++- test/static_vector_test.cpp | 6 ++---- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 76a0fdf..71bb14e 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1321,6 +1321,7 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs/issues: * [@https://github.com/boostorg/container/issues/126 GitHub #126: ['"flat_set.hpp and set.hpp in pmr have the same header guard"]]. + * [@https://github.com/boostorg/container/issues/128 GitHub #128: ['"moved from small_vector and static_vector calls destructor on elements in static part"]]. * [@https://github.com/boostorg/container/issues/129 GitHub #129: ['"Alias templates for small_flat_[multi]{set|map} using small_vector as container"]]. * [@https://github.com/boostorg/container/pull/135 GitHub #135: ['"Missing BOOST_NORETURN for user defined functions"]]. * [@https://github.com/boostorg/container/pull/137 GitHub #137: ['"RandomAccessIterator + 0"]]. diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 6529a82..fcdf3f2 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -460,6 +460,7 @@ class small_vector_base this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end ())) ); + x.clear(); } } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index e82f278..8000017 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -591,6 +591,9 @@ struct vector_alloc_holder { ::boost::container::uninitialized_move_alloc_n (this->alloc(), boost::movelib::to_raw_pointer(holder.start()), m_size, boost::movelib::to_raw_pointer(this->start())); + ::boost::container::destroy_alloc_n + (this->alloc(), boost::movelib::to_raw_pointer(holder.start()), m_size); + holder.m_size = 0; } template @@ -2385,6 +2388,9 @@ private: const size_type other_sz = static_cast(x.m_holder.m_size); boost::container::move_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); this->m_holder.m_size = other_sz; + //Not emptying the source container seems to be confusing for users as drop-in + //replacement for non-static vectors, so clear it. + x.clear(); } template @@ -2413,11 +2419,13 @@ private: this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity); this->m_holder.steal_resources(x.m_holder); } - //Else do a one by one move + //Else do a one by one move. Also, clear the source as users find confusing + //elements are still alive in the source container. else{ this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end() )) ); + x.clear(); } //Move allocator if needed dtl::move_alloc(this_alloc, x_alloc, dtl::bool_()); diff --git a/test/static_vector_test.cpp b/test/static_vector_test.cpp index 539eea8..9527190 100644 --- a/test/static_vector_test.cpp +++ b/test/static_vector_test.cpp @@ -495,11 +495,9 @@ void test_swap_and_move_nd() BOOST_TEST(v1.size() == N/2); BOOST_TEST(s1.size() == N); - //iG moving does not imply emptying source - //BOOST_TEST(v2.size() == 0); + BOOST_TEST(v2.size() == 0); BOOST_TEST(s2.size() == N); - //iG moving does not imply emptying source - //BOOST_TEST(v3.size() == 0); + BOOST_TEST(v3.size() == 0); BOOST_TEST(s3.size() == N); BOOST_TEST(v4.size() == N/2); BOOST_TEST(s4.size() == N); From 06417de498fbfd6f6684efe85a99c6adcc0721a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 13 Jul 2020 12:31:58 +0200 Subject: [PATCH 32/61] Fixes #125 ("flat_map doc misleading complexity"). --- doc/container.qbk | 1 + include/boost/container/flat_map.hpp | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 71bb14e..64cc808 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1320,6 +1320,7 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_74_00 Boost 1.74 Release] * Fixed bugs/issues: + * [@https://github.com/boostorg/container/issues/125 GitHub #125: ['"flat_map doc misleading complexity"]]. * [@https://github.com/boostorg/container/issues/126 GitHub #126: ['"flat_set.hpp and set.hpp in pmr have the same header guard"]]. * [@https://github.com/boostorg/container/issues/128 GitHub #128: ['"moved from small_vector and static_vector calls destructor on elements in static part"]]. * [@https://github.com/boostorg/container/issues/129 GitHub #129: ['"Alias templates for small_flat_[multi]{set|map} using small_vector as container"]]. diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 63e7ab1..88b32c0 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -713,7 +713,7 @@ class flat_map //! //! Returns: A reference to the mapped_type corresponding to x in *this. //! - //! Complexity: Logarithmic. + //! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present. mapped_type &operator[](const key_type& k); //! Effects: If there is no key equivalent to x in the flat_map, inserts @@ -721,8 +721,8 @@ class flat_map //! //! Returns: A reference to the mapped_type corresponding to x in *this. //! - //! Complexity: Logarithmic. - mapped_type &operator[](key_type &&k) ; + //! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present. + mapped_type &operator[](key_type &&k); #elif defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN) //in compilers like GCC 3.4, we can't catch temporaries BOOST_CONTAINER_FORCEINLINE mapped_type& operator[](const key_type &k) { return this->priv_subscript(k); } @@ -742,7 +742,7 @@ class flat_map //! Returns: The bool component is true if the insertion took place and false if the assignment //! took place. The iterator component is pointing at the element that was inserted or updated. //! - //! Complexity: Logarithmic in the size of the container. + //! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present. template BOOST_CONTAINER_FORCEINLINE std::pair insert_or_assign(const key_type& k, BOOST_FWD_REF(M) obj) { @@ -955,7 +955,7 @@ class flat_map //! Returns: The bool component of the returned pair is true if and only if the //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. //! - //! Complexity: Logarithmic. + //! Complexity: Logarithmic search time plus linear insertion time in case the key is not present. template BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) { @@ -973,7 +973,7 @@ class flat_map //! Returns: The returned iterator points to the map element whose key is equivalent to k. //! //! Complexity: Logarithmic in general, but amortized constant if value - //! is inserted right before p. + //! is inserted right before p. Linear insertion time in case no equivalent key is present. template BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) { From 974e8e641a5bab9f6c52a9d666015411caaa72b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:21:46 +0200 Subject: [PATCH 33/61] Fix "-Wdeprecated-copy" warnings --- test/deque_test.cpp | 24 +++++++++--------- test/list_test.cpp | 22 ++++++++-------- test/map_test.cpp | 50 ++++++++++++++++++++++--------------- test/set_test.cpp | 50 ++++++++++++++++++++++--------------- test/slist_test.cpp | 22 ++++++++-------- test/stable_vector_test.cpp | 22 ++++++++-------- test/static_vector_test.hpp | 7 +++++- test/vector_test.cpp | 4 +++ 8 files changed, 118 insertions(+), 83 deletions(-) diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 6d5ed74..a90ef51 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -98,6 +98,10 @@ class recursive_deque { public: + recursive_deque (const recursive_deque &x) + : deque_(x.deque_) + {} + recursive_deque & operator=(const recursive_deque &x) { this->deque_ = x.deque_; return *this; } @@ -418,24 +422,20 @@ int main () typedef boost::container::deque cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG(!(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(std::allocator) test failed"); } // std::allocator { typedef boost::container::deque > cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG(!(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(std::allocator) test failed"); } return 0; diff --git a/test/list_test.cpp b/test/list_test.cpp index 821f7b0..c4ec219 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -54,6 +54,10 @@ public: list::reverse_iterator rit_; list::const_reverse_iterator crit_; + recursive_list(const recursive_list &o) + : list_(o.list_) + {} + recursive_list &operator=(const recursive_list &o) { list_ = o.list_; return *this; } }; @@ -259,24 +263,22 @@ int main () typedef boost::container::list cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; - return 1; - } + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(default allocator) test failed"); } // std::allocator { typedef boost::container::list > cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; - return 1; - } + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(std::allocator) test failed"); } return 0; diff --git a/test/map_test.cpp b/test/map_test.cpp index c36581b..67f893c 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -27,6 +27,13 @@ typedef std::pair cont; typedef boost::container::dtl::tree, void, void> tree; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(map, default allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(map, default allocator) test failed"); } // std::allocator { typedef boost::container::map, std::allocator > cont; typedef boost::container::dtl::tree, std::allocator, void> tree; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(map, std::allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(map, std::allocator) test failed"); } // // multimap @@ -668,21 +680,19 @@ int main () // default allocator typedef boost::container::multimap cont; typedef boost::container::dtl::tree, void, void> tree; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(multimap, default allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(multimap, default allocator) test failed"); } // std::allocator { typedef boost::container::multimap, std::allocator > cont; typedef boost::container::dtl::tree, std::allocator, void> tree; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(multimap, std::allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(multimap, std::allocator) test failed"); } } diff --git a/test/set_test.cpp b/test/set_test.cpp index a6d1f58..a9c9815 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -25,6 +25,13 @@ using namespace boost::container; class recursive_set { public: + recursive_set() + {} + + recursive_set(const recursive_set &x) + : set_(x.set_) + {} + recursive_set & operator=(const recursive_set &x) { id_ = x.id_; set_ = x.set_; return *this; } @@ -43,6 +50,13 @@ public: class recursive_multiset { public: + recursive_multiset() + {} + + recursive_multiset(const recursive_multiset &x) + : multiset_(x.multiset_) + {} + recursive_multiset & operator=(const recursive_multiset &x) { id_ = x.id_; multiset_ = x.multiset_; return *this; } @@ -611,41 +625,37 @@ int main () { typedef boost::container::set cont; typedef boost::container::dtl::tree, void, void> tree; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(set, default allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(set, default allocator) test failed"); } // set, std::allocator { typedef boost::container::set, std::allocator > cont; typedef boost::container::dtl::tree, std::allocator, void> tree; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(set, std::allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(set, std::allocator) test failed"); } // multiset, default allocator { typedef boost::container::multiset cont; typedef boost::container::dtl::tree, void, void> tree; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(multiset, default allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(multiset, default allocator) test failed"); } // multiset, std::allocator { typedef boost::container::multiset, std::allocator > cont; typedef boost::container::dtl::tree, std::allocator, void> tree; - if (boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(multiset, std::allocator) test failed" << std::endl; - return 1; - } + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(multiset, std::allocator) test failed"); } return 0; diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 8cc64bd..16fd8a0 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -30,6 +30,10 @@ public: recursive_slist &operator=(const recursive_slist &o) { slist_ = o.slist_; return *this; } + + recursive_slist (const recursive_slist &o) + : slist_(o.slist_) + {} }; void recursive_slist_test()//Test for recursive types @@ -262,24 +266,22 @@ int main () typedef boost::container::slist cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; - return 1; - } + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(default allocator) test failed"); } // std::allocator { typedef boost::container::slist > cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; - return 1; - } + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(std::allocator) test failed"); } return 0; diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index 77a4aac..93b6ce7 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -35,6 +35,10 @@ class recursive_vector stable_vector::reverse_iterator rit_; stable_vector::const_reverse_iterator crit_; + recursive_vector (const recursive_vector &o) + : vector_(o.vector_) + {} + recursive_vector &operator=(const recursive_vector &o) { vector_ = o.vector_; return *this; } }; @@ -200,24 +204,22 @@ int main() typedef boost::container::stable_vector cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; - return 1; - } + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(default allocator) test failed"); } // std::allocator { typedef boost::container::stable_vector > cont; typedef cont::allocator_type allocator_type; typedef boost::container::allocator_traits::pointer pointer; - if (boost::has_trivial_destructor_after_move::value != + BOOST_STATIC_ASSERT_MSG( + !(boost::has_trivial_destructor_after_move::value != boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) { - std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; - return 1; - } + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(std::allocator) test failed"); } return 0; diff --git a/test/static_vector_test.hpp b/test/static_vector_test.hpp index ab931b2..f279a01 100644 --- a/test/static_vector_test.hpp +++ b/test/static_vector_test.hpp @@ -48,11 +48,12 @@ class value_nc public: explicit value_nc(int a = 0) : aa(a) {} ~value_nc() {} + value_nc & operator=(int a){ aa = a; return *this; } bool operator==(value_nc const& v) const { return aa == v.aa; } bool operator<(value_nc const& v) const { return aa < v.aa; } private: value_nc(value_nc const&) {} - value_nc & operator=(value_ndc const&) { return *this; } + value_nc & operator=(value_nc const&) { return *this; } int aa; }; @@ -66,6 +67,7 @@ public: counting_value(BOOST_RV_REF(counting_value) p) : aa(p.aa), bb(p.bb) { p.aa = 0; p.bb = 0; ++c(); } // Move constructor counting_value& operator=(BOOST_RV_REF(counting_value) p) { aa = p.aa; p.aa = 0; bb = p.bb; p.bb = 0; return *this; } // Move assignment counting_value& operator=(BOOST_COPY_ASSIGN_REF(counting_value) p) { aa = p.aa; bb = p.bb; return *this; } // Copy assignment + counting_value& operator=(int a) { aa =a; return *this; } // Copy assignment ~counting_value() { --c(); } bool operator==(counting_value const& v) const { return aa == v.aa && bb == v.bb; } bool operator<(counting_value const& v) const { return aa < v.aa || ( aa == v.aa && bb < v.bb ); } @@ -94,6 +96,9 @@ class shptr_value typedef boost::shared_ptr Ptr; public: explicit shptr_value(int a = 0) : m_ptr(new int(a)) {} + shptr_value & operator=(int a) + { m_ptr.reset(new int(a)); return *this; } + bool operator==(shptr_value const& v) const { return *m_ptr == *(v.m_ptr); } bool operator<(shptr_value const& v) const { return *m_ptr < *(v.m_ptr); } private: diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 398eaa3..136b471 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -82,6 +82,10 @@ bool test_smart_ref_type() class recursive_vector { public: + recursive_vector (const recursive_vector &x) + : vector_(x.vector_) + {} + recursive_vector & operator=(const recursive_vector &x) { this->vector_ = x.vector_; return *this; } From b946b779e6b0d995c9ff1a14181d3b440e06d380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:23:13 +0200 Subject: [PATCH 34/61] Remove unused include --- test/deque_options_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/deque_options_test.cpp b/test/deque_options_test.cpp index 9a7a43a..65f7371 100644 --- a/test/deque_options_test.cpp +++ b/test/deque_options_test.cpp @@ -8,7 +8,6 @@ // ////////////////////////////////////////////////////////////////////////////// #include -#include #include using namespace boost::container; From 52aae65fcdc3b2d1a95a2b7e15a1eea3aa8719a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:23:26 +0200 Subject: [PATCH 35/61] Fix unreachable code warning --- test/expand_bwd_test_allocator.hpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 60b3283..4d50fbb 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -142,15 +142,12 @@ class expand_bwd_test_allocator reuse = 0; return (mp_buffer + m_offset); } - else if(m_allocations == 1){ - if(limit_size > m_size){ - assert(0); - } - ++m_allocations; - return mp_buffer; - } else{ - throw_bad_alloc(); + if(m_allocations != 1){ + throw_bad_alloc(); + } + assert(limit_size <= m_size); + ++m_allocations; return mp_buffer; } } From 0143caf985cfb3b45df8aa1089714fba4e13b656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:23:56 +0200 Subject: [PATCH 36/61] Explicitly instantiate "stored_size" option to catch conversion warnings --- test/explicit_inst_vector_test.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/explicit_inst_vector_test.cpp b/test/explicit_inst_vector_test.cpp index 619dfc9..c6700fe 100644 --- a/test/explicit_inst_vector_test.cpp +++ b/test/explicit_inst_vector_test.cpp @@ -38,6 +38,12 @@ template class boost::container::vector template class vec_iterator; template class vec_iterator; +//Test stored_size option +template class boost::container::vector< test::movable_and_copyable_int + , new_allocator + , vector_options< stored_size >::type + >; + } //namespace boost { } //namespace container { From f99da8551be52a7c514c9a42eb400338db1dce1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:24:13 +0200 Subject: [PATCH 37/61] Use boost::container::vector/list instead of std --- test/static_vector_test.cpp | 81 ++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/test/static_vector_test.cpp b/test/static_vector_test.cpp index 9527190..fcc5358 100644 --- a/test/static_vector_test.cpp +++ b/test/static_vector_test.cpp @@ -10,13 +10,10 @@ #include #include #include -#include +#include #include #include "../../intrusive/test/iterator_test.hpp" -#include -#include - #include "static_vector_test.hpp" @@ -42,12 +39,10 @@ void test_ctor_nc(size_t n) BOOST_TEST_THROWS( s.at(n), std::out_of_range ); if ( 1 < n ) { - T val10(10); - s[0] = val10; + s[0] = 10; BOOST_TEST(T(10) == s[0]); BOOST_TEST(T(10) == s.at(0)); - T val20(20); - s.at(1) = val20; + s.at(1) = 20; BOOST_TEST(T(20) == s[1]); BOOST_TEST(T(20) == s.at(1)); } @@ -122,12 +117,10 @@ void test_resize_nc(size_t n) BOOST_TEST_THROWS( s.at(n), std::out_of_range ); if ( 1 < n ) { - T val10(10); - s[0] = val10; + s[0] = 10; BOOST_TEST(T(10) == s[0]); BOOST_TEST(T(10) == s.at(0)); - T val20(20); - s.at(1) = val20; + s.at(1) = 20; BOOST_TEST(T(20) == s[1]); BOOST_TEST(T(20) == s.at(1)); } @@ -231,8 +224,8 @@ template void test_copy_and_assign_nd(T const& val) { static_vector s; - std::vector v; - std::list l; + vector v; + list l; for ( size_t i = 0 ; i < N ; ++i ) { @@ -265,22 +258,17 @@ void test_copy_and_assign_nd(T const& val) { static_vector s1(s); test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); - std::vector a(N, val); + vector a(N, val); s1.assign(N, val); test_compare_ranges(a.begin(), a.end(), s1.begin(), s1.end()); } - - stable_vector bsv(s.begin(), s.end()); - vector bv(s.begin(), s.end()); - test_copy_and_assign(bsv); - test_copy_and_assign(bv); } template void test_iterators_nd() { static_vector s; - std::vector v; + vector v; for ( size_t i = 0 ; i < N ; ++i ) { @@ -370,8 +358,8 @@ void test_insert_nd(T const& val) size_t h = N/2; static_vector s, ss; - std::vector v; - std::list l; + vector v; + list l; typedef typename static_vector::iterator It; @@ -419,11 +407,6 @@ void test_insert_nd(T const& val) test_insert(s, ss); test_insert(s, v); test_insert(s, l); - - stable_vector bsv(ss.begin(), ss.end()); - vector bv(ss.begin(), ss.end()); - test_insert(s, bv); - test_insert(s, bsv); } template @@ -821,3 +804,45 @@ int main(int, char* []) return boost::report_errors(); } +/* + +#include +#include + +struct S_trivial { +int i; +}; +static_assert(std::is_nothrow_move_constructible::value, ""); +static_assert(std::is_nothrow_move_assignable::value, ""); + +struct S1 { +int i = 0; +}; +static_assert(std::is_nothrow_move_constructible::value, ""); +static_assert(std::is_nothrow_move_assignable::value, ""); + +struct S2 { +int i = 0; +S2(S2&&) noexcept; +S2& operator=(S2&&) noexcept; +}; +static_assert(std::is_nothrow_move_constructible::value, ""); +static_assert(std::is_nothrow_move_assignable::value, ""); + +// Succeed +static_assert(std::is_nothrow_move_constructible>::value, ""); +static_assert(std::is_nothrow_move_assignable>::value, ""); + +// Fail +static_assert(std::is_nothrow_move_constructible>::value, ""); +static_assert(std::is_nothrow_move_assignable>::value, ""); + +// Fail +static_assert(std::is_nothrow_move_constructible>::value, ""); +static_assert(std::is_nothrow_move_assignable>::value, ""); + +int main() +{ + return 0; +} +*/ From 716ade8e5605282b39a18058ef3afe3a49a34df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:25:31 +0200 Subject: [PATCH 38/61] Add BOOST_CONTAINER_FORCEINLINE to destroyers' trivial functions --- include/boost/container/detail/destroyers.hpp | 65 ++++++++++--------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/include/boost/container/detail/destroyers.hpp b/include/boost/container/detail/destroyers.hpp index 9b0be44..ab492f5 100644 --- a/include/boost/container/detail/destroyers.hpp +++ b/include/boost/container/detail/destroyers.hpp @@ -183,28 +183,31 @@ struct scoped_destructor_n typedef typename AllocTraits::value_type value_type; typedef typename AllocTraits::size_type size_type; - scoped_destructor_n(pointer p, Allocator& a, size_type n) + BOOST_CONTAINER_FORCEINLINE scoped_destructor_n(pointer p, Allocator& a, size_type n) : m_p(p), m_a(a), m_n(n) {} - void release() - { m_p = 0; } + BOOST_CONTAINER_FORCEINLINE void release() + { m_p = 0; m_n = 0; } - void increment_size(size_type inc) + BOOST_CONTAINER_FORCEINLINE void increment_size(size_type inc) { m_n += inc; } - void increment_size_backwards(size_type inc) + BOOST_CONTAINER_FORCEINLINE void increment_size_backwards(size_type inc) { m_n += inc; m_p -= inc; } - void shrink_forward(size_type inc) + BOOST_CONTAINER_FORCEINLINE void shrink_forward(size_type inc) { m_n -= inc; m_p += inc; } ~scoped_destructor_n() { - if(!m_p) return; - value_type *raw_ptr = boost::movelib::to_raw_pointer(m_p); - while(m_n--){ - AllocTraits::destroy(m_a, raw_ptr++); + if(m_n){ + value_type *raw_ptr = boost::movelib::to_raw_pointer(m_p); + do { + --m_n; + AllocTraits::destroy(m_a, raw_ptr); + ++raw_ptr; + } while(m_n); } } @@ -223,19 +226,19 @@ struct null_scoped_destructor_n typedef typename AllocTraits::pointer pointer; typedef typename AllocTraits::size_type size_type; - null_scoped_destructor_n(pointer, Allocator&, size_type) + BOOST_CONTAINER_FORCEINLINE null_scoped_destructor_n(pointer, Allocator&, size_type) {} - void increment_size(size_type) + BOOST_CONTAINER_FORCEINLINE void increment_size(size_type) {} - void increment_size_backwards(size_type) + BOOST_CONTAINER_FORCEINLINE void increment_size_backwards(size_type) {} - void shrink_forward(size_type) + BOOST_CONTAINER_FORCEINLINE void shrink_forward(size_type) {} - void release() + BOOST_CONTAINER_FORCEINLINE void release() {} }; @@ -245,24 +248,24 @@ class scoped_destructor typedef boost::container::allocator_traits AllocTraits; public: typedef typename Allocator::value_type value_type; - scoped_destructor(Allocator &a, value_type *pv) + BOOST_CONTAINER_FORCEINLINE scoped_destructor(Allocator &a, value_type *pv) : pv_(pv), a_(a) {} - ~scoped_destructor() + BOOST_CONTAINER_FORCEINLINE ~scoped_destructor() { if(pv_){ AllocTraits::destroy(a_, pv_); } } - void release() + BOOST_CONTAINER_FORCEINLINE void release() { pv_ = 0; } - void set(value_type *ptr) { pv_ = ptr; } + BOOST_CONTAINER_FORCEINLINE void set(value_type *ptr) { pv_ = ptr; } - value_type *get() const { return pv_; } + BOOST_CONTAINER_FORCEINLINE value_type *get() const { return pv_; } private: value_type *pv_; @@ -276,11 +279,11 @@ class value_destructor typedef boost::container::allocator_traits AllocTraits; public: typedef Value value_type; - value_destructor(Allocator &a, value_type &rv) + BOOST_CONTAINER_FORCEINLINE value_destructor(Allocator &a, value_type &rv) : rv_(rv), a_(a) {} - ~value_destructor() + BOOST_CONTAINER_FORCEINLINE ~value_destructor() { AllocTraits::destroy(a_, &rv_); } @@ -304,18 +307,18 @@ class allocator_destroyer Allocator & a_; private: - void priv_deallocate(const pointer &p, version_1) + BOOST_CONTAINER_FORCEINLINE void priv_deallocate(const pointer &p, version_1) { AllocTraits::deallocate(a_,p, 1); } - void priv_deallocate(const pointer &p, version_2) + BOOST_CONTAINER_FORCEINLINE void priv_deallocate(const pointer &p, version_2) { a_.deallocate_one(p); } public: - explicit allocator_destroyer(Allocator &a) + BOOST_CONTAINER_FORCEINLINE explicit allocator_destroyer(Allocator &a) : a_(a) {} - void operator()(const pointer &p) + BOOST_CONTAINER_FORCEINLINE void operator()(const pointer &p) { AllocTraits::destroy(a_, boost::movelib::to_raw_pointer(p)); this->priv_deallocate(p, alloc_version()); @@ -333,11 +336,11 @@ class allocator_destroyer_and_chain_builder multiallocation_chain &c_; public: - allocator_destroyer_and_chain_builder(Allocator &a, multiallocation_chain &c) + BOOST_CONTAINER_FORCEINLINE allocator_destroyer_and_chain_builder(Allocator &a, multiallocation_chain &c) : a_(a), c_(c) {} - void operator()(const typename Allocator::pointer &p) + BOOST_CONTAINER_FORCEINLINE void operator()(const typename Allocator::pointer &p) { allocator_traits::destroy(a_, boost::movelib::to_raw_pointer(p)); c_.push_back(p); @@ -356,14 +359,14 @@ class allocator_multialloc_chain_node_deallocator multiallocation_chain c_; public: - allocator_multialloc_chain_node_deallocator(Allocator &a) + BOOST_CONTAINER_FORCEINLINE allocator_multialloc_chain_node_deallocator(Allocator &a) : a_(a), c_() {} - chain_builder get_chain_builder() + BOOST_CONTAINER_FORCEINLINE chain_builder get_chain_builder() { return chain_builder(a_, c_); } - ~allocator_multialloc_chain_node_deallocator() + BOOST_CONTAINER_FORCEINLINE ~allocator_multialloc_chain_node_deallocator() { a_.deallocate_individual(c_); } From e0c7cb99b380b7ff03a8c57c32140c68c21ee8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:26:34 +0200 Subject: [PATCH 39/61] Fix possible unsigned underflow warnings. --- .../boost/container/detail/copy_move_algo.hpp | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/include/boost/container/detail/copy_move_algo.hpp b/include/boost/container/detail/copy_move_algo.hpp index cd55af4..cb21cc1 100644 --- a/include/boost/container/detail/copy_move_algo.hpp +++ b/include/boost/container/detail/copy_move_algo.hpp @@ -341,7 +341,8 @@ inline typename dtl::disable_if_memtransfer_copy_constructible::type { F back = r; BOOST_TRY{ - while (n--) { + while (n) { + --n; allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), boost::move(*f)); ++f; ++r; } @@ -386,7 +387,8 @@ inline typename dtl::disable_if_memtransfer_copy_constructible::type { F back = r; BOOST_TRY{ - while (n--) { + while (n) { + --n; allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), boost::move(*f)); ++f; ++r; } @@ -476,7 +478,8 @@ inline typename dtl::disable_if_memtransfer_copy_constructible::type { F back = r; BOOST_TRY{ - while (n--) { + while (n) { + --n; allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), *f); ++f; ++r; } @@ -565,7 +568,8 @@ inline typename dtl::disable_if_memzero_initializable::type { F back = r; BOOST_TRY{ - while (n--) { + while (n) { + --n; allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r)); ++r; } @@ -614,7 +618,8 @@ inline F uninitialized_default_init_alloc_n(Allocator &a, typename boost::contai { F back = r; BOOST_TRY{ - while (n--) { + while (n) { + --n; allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), default_init); ++r; } @@ -686,7 +691,8 @@ inline F uninitialized_fill_alloc_n(Allocator &a, const T &v, typename boost::co { F back = r; BOOST_TRY{ - while (n--) { + while (n) { + --n; allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), v); ++r; } @@ -769,7 +775,8 @@ typename F> // F models ForwardIterator inline typename dtl::disable_if_memtransfer_copy_assignable::type copy_n_source(I f, U n, F r) { - while (n--) { + while (n) { + --n; boost::container::assign_in_place(r, f); ++f; ++r; } @@ -797,7 +804,8 @@ typename F> // F models ForwardIterator inline typename dtl::disable_if_memtransfer_copy_assignable::type copy_n_source_dest(I f, U n, F &r) { - while (n--) { + while (n) { + --n; *r = *f; ++f; ++r; } @@ -851,7 +859,8 @@ typename F> // F models ForwardIterator inline typename dtl::disable_if_memtransfer_copy_assignable::type move_n(I f, U n, F r) { - while (n--) { + while (n) { + --n; *r = ::boost::move(*f); ++f; ++r; } @@ -914,7 +923,8 @@ template inline typename dtl::disable_if_memtransfer_copy_assignable::type move_n_source_dest(I f, U n, F &r) { - while (n--) { + while (n) { + --n; *r = ::boost::move(*f); ++f; ++r; } @@ -942,7 +952,8 @@ template inline typename dtl::disable_if_memtransfer_copy_assignable::type move_n_source(I f, U n, F r) { - while (n--) { + while (n) { + --n; *r = ::boost::move(*f); ++f; ++r; } From c08ead7f4b4e4aa5674151e180f05fcc0a05e644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:27:12 +0200 Subject: [PATCH 40/61] Add BOOST_CONTAINER_DISABLE_NOINLINE --- include/boost/container/detail/workaround.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/container/detail/workaround.hpp b/include/boost/container/detail/workaround.hpp index 83aacef..b74e0fc 100644 --- a/include/boost/container/detail/workaround.hpp +++ b/include/boost/container/detail/workaround.hpp @@ -108,6 +108,15 @@ #define BOOST_CONTAINER_FORCEINLINE BOOST_FORCEINLINE #endif +//#define BOOST_CONTAINER_DISABLE_NOINLINE + +#if defined(BOOST_CONTAINER_DISABLE_NOINLINE) + #define BOOST_CONTAINER_NOINLINE +#else + #define BOOST_CONTAINER_NOINLINE BOOST_NOINLINE +#endif + + #if !defined(__has_feature) #define BOOST_CONTAINER_HAS_FEATURE(feature) 0 #else From 4eb93761db27c68b88ef4d7fd8793335fe3313c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:28:07 +0200 Subject: [PATCH 41/61] Fix "-Wdeprecated-copy" warnings --- include/boost/container/adaptive_pool.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/container/adaptive_pool.hpp b/include/boost/container/adaptive_pool.hpp index b9037b7..08e4f62 100644 --- a/include/boost/container/adaptive_pool.hpp +++ b/include/boost/container/adaptive_pool.hpp @@ -132,6 +132,10 @@ class adaptive_pool adaptive_pool(const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW {} + //!Copy assignment from other adaptive_pool. + adaptive_pool & operator=(const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + { return *this; } + //!Copy constructor from related adaptive_pool. template adaptive_pool @@ -442,6 +446,10 @@ class private_adaptive_pool private_adaptive_pool(const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW {} + //!Copy assignment from other adaptive_pool. + private_adaptive_pool & operator=(const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + { return *this; } + //!Copy constructor from related private_adaptive_pool. template private_adaptive_pool From cc51aa2e495ac6cf27375a53335cad0f8976bea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:45:13 +0200 Subject: [PATCH 42/61] Add BOOST_CONTAINER_FORCEINLINE to trivial functions and add is_single_value_proxy attribute to single value proxies. This trait can be used by insertion functions to optimize operations at compile time. --- .../container/detail/advanced_insert_int.hpp | 145 +++++++++++++----- 1 file changed, 105 insertions(+), 40 deletions(-) diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index 28e7ae9..b130993 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -49,17 +49,17 @@ struct move_insert_range_proxy typedef typename allocator_traits::size_type size_type; typedef typename allocator_traits::value_type value_type; - explicit move_insert_range_proxy(FwdIt first) + BOOST_CONTAINER_FORCEINLINE explicit move_insert_range_proxy(FwdIt first) : first_(first) {} - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) { this->first_ = ::boost::container::uninitialized_move_alloc_n_source (a, this->first_, n, p); } - void copy_n_and_update(Allocator &, Iterator p, size_type n) + BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, size_type n) { this->first_ = ::boost::container::move_n_source(this->first_, n, p); } @@ -74,16 +74,16 @@ struct insert_range_proxy typedef typename allocator_traits::size_type size_type; typedef typename allocator_traits::value_type value_type; - explicit insert_range_proxy(FwdIt first) + BOOST_CONTAINER_FORCEINLINE explicit insert_range_proxy(FwdIt first) : first_(first) {} - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) { this->first_ = ::boost::container::uninitialized_copy_alloc_n_source(a, this->first_, n, p); } - void copy_n_and_update(Allocator &, Iterator p, size_type n) + BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, size_type n) { this->first_ = ::boost::container::copy_n_source(this->first_, n, p); } @@ -98,14 +98,14 @@ struct insert_n_copies_proxy typedef typename allocator_traits::size_type size_type; typedef typename allocator_traits::value_type value_type; - explicit insert_n_copies_proxy(const value_type &v) + BOOST_CONTAINER_FORCEINLINE explicit insert_n_copies_proxy(const value_type &v) : v_(v) {} - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { boost::container::uninitialized_fill_alloc_n(a, v_, n, p); } - void copy_n_and_update(Allocator &, Iterator p, size_type n) const + BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, size_type n) const { for (; 0 < n; --n, ++p){ *p = v_; @@ -122,7 +122,7 @@ struct insert_value_initialized_n_proxy typedef typename allocator_traits::size_type size_type; typedef typename allocator_traits::value_type value_type; - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { boost::container::uninitialized_value_init_alloc_n(a, n, p); } void copy_n_and_update(Allocator &a, Iterator p, size_type n) const @@ -144,7 +144,7 @@ struct insert_default_initialized_n_proxy typedef typename allocator_traits::size_type size_type; typedef typename allocator_traits::value_type value_type; - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { boost::container::uninitialized_default_init_alloc_n(a, n, p); } void copy_n_and_update(Allocator &a, Iterator p, size_type n) const @@ -168,17 +168,19 @@ struct insert_copy_proxy typedef typename alloc_traits::size_type size_type; typedef typename alloc_traits::value_type value_type; - explicit insert_copy_proxy(const value_type &v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_copy_proxy(const value_type &v) : v_(v) {} - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), v_); } - void copy_n_and_update(Allocator &, Iterator p, size_type n) const + BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; *p = v_; @@ -195,6 +197,8 @@ struct insert_move_proxy typedef typename alloc_traits::size_type size_type; typedef typename alloc_traits::value_type value_type; + static const bool single_value = true; + BOOST_CONTAINER_FORCEINLINE explicit insert_move_proxy(value_type &v) : v_(v) {} @@ -215,13 +219,13 @@ struct insert_move_proxy }; template -insert_move_proxy get_insert_value_proxy(BOOST_RV_REF(typename boost::container::iterator_traits::value_type) v) +BOOST_CONTAINER_FORCEINLINE insert_move_proxy get_insert_value_proxy(BOOST_RV_REF(typename boost::container::iterator_traits::value_type) v) { return insert_move_proxy(v); } template -insert_copy_proxy get_insert_value_proxy(const typename boost::container::iterator_traits::value_type &v) +BOOST_CONTAINER_FORCEINLINE insert_copy_proxy get_insert_value_proxy(const typename boost::container::iterator_traits::value_type &v) { return insert_copy_proxy(v); } @@ -243,19 +247,20 @@ struct insert_nonmovable_emplace_proxy typedef boost::container::allocator_traits alloc_traits; typedef typename alloc_traits::size_type size_type; typedef typename alloc_traits::value_type value_type; - typedef typename build_number_seq::type index_tuple_t; - explicit insert_nonmovable_emplace_proxy(BOOST_FWD_REF(Args)... args) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_nonmovable_emplace_proxy(BOOST_FWD_REF(Args)... args) : args_(args...) {} - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) { this->priv_uninitialized_copy_some_and_update(a, index_tuple_t(), p, n); } private: template - void priv_uninitialized_copy_some_and_update(Allocator &a, const index_tuple&, Iterator p, size_type n) + BOOST_CONTAINER_FORCEINLINE void priv_uninitialized_copy_some_and_update(Allocator &a, const index_tuple&, Iterator p, size_type n) { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::forward(get(this->args_))... ); @@ -275,23 +280,24 @@ struct insert_emplace_proxy typedef typename base_t::size_type size_type; typedef typename base_t::index_tuple_t index_tuple_t; - explicit insert_emplace_proxy(BOOST_FWD_REF(Args)... args) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(BOOST_FWD_REF(Args)... args) : base_t(::boost::forward(args)...) {} - void copy_n_and_update(Allocator &a, Iterator p, size_type n) + BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &a, Iterator p, size_type n) { this->priv_copy_some_and_update(a, index_tuple_t(), p, n); } private: template - void priv_copy_some_and_update(Allocator &a, const index_tuple&, Iterator p, size_type n) + BOOST_CONTAINER_FORCEINLINE void priv_copy_some_and_update(Allocator &a, const index_tuple&, Iterator p, size_type n) { BOOST_ASSERT(n ==1); (void)n; typename dtl::aligned_storage::value>::type v; value_type *vp = reinterpret_cast(v.data); - alloc_traits::construct(a, vp, - ::boost::forward(get(this->args_))...); + alloc_traits::construct(a, vp, ::boost::forward(get(this->args_))...); BOOST_TRY{ *p = ::boost::move(*vp); } @@ -309,7 +315,9 @@ template struct insert_emplace_proxy::value_type> : public insert_move_proxy { - explicit insert_emplace_proxy(typename boost::container::allocator_traits::value_type &&v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(typename boost::container::allocator_traits::value_type &&v) : insert_move_proxy(v) {} }; @@ -323,7 +331,10 @@ struct insert_emplace_proxy : public insert_copy_proxy { - explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) + + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) : insert_copy_proxy(v) {} }; @@ -332,7 +343,9 @@ template struct insert_emplace_proxy::value_type &> : public insert_copy_proxy { - explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) : insert_copy_proxy(v) {} }; @@ -343,7 +356,9 @@ struct insert_emplace_proxy : public insert_copy_proxy { - explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) : insert_copy_proxy(v) {} }; @@ -366,16 +381,18 @@ struct insert_nonmovable_emplace_proxy##N\ typedef typename alloc_traits::size_type size_type;\ typedef typename alloc_traits::value_type value_type;\ \ - explicit insert_nonmovable_emplace_proxy##N(BOOST_MOVE_UREF##N)\ + static const bool single_value = true;\ + \ + BOOST_CONTAINER_FORCEINLINE explicit insert_nonmovable_emplace_proxy##N(BOOST_MOVE_UREF##N)\ BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N {}\ \ - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n)\ + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n)\ {\ BOOST_ASSERT(n == 1); (void)n;\ alloc_traits::construct(a, boost::movelib::iterator_to_raw_pointer(p) BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ }\ \ - void copy_n_and_update(Allocator &, Iterator, size_type)\ + BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator, size_type)\ { BOOST_ASSERT(false); }\ \ protected:\ @@ -392,10 +409,12 @@ struct insert_emplace_proxy_arg##N\ typedef typename base_t::size_type size_type;\ typedef boost::container::allocator_traits alloc_traits;\ \ - explicit insert_emplace_proxy_arg##N(BOOST_MOVE_UREF##N)\ + static const bool single_value = true;\ + \ + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg##N(BOOST_MOVE_UREF##N)\ : base_t(BOOST_MOVE_FWD##N){}\ \ - void copy_n_and_update(Allocator &a, Iterator p, size_type n)\ + BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &a, Iterator p, size_type n)\ {\ BOOST_ASSERT(n == 1); (void)n;\ typename dtl::aligned_storage::value>::type v;\ @@ -424,7 +443,9 @@ template struct insert_emplace_proxy_arg1::value_type> > : public insert_move_proxy { - explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits::value_type &v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits::value_type &v) : insert_move_proxy(v) {} }; @@ -433,7 +454,9 @@ template struct insert_emplace_proxy_arg1::value_type> : public insert_copy_proxy { - explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) : insert_copy_proxy(v) {} }; @@ -445,7 +468,9 @@ template struct insert_emplace_proxy_arg1::value_type> : public insert_move_proxy { - explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits::value_type &&v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits::value_type &&v) : insert_move_proxy(v) {} }; @@ -459,7 +484,9 @@ struct insert_emplace_proxy_arg1 : public insert_copy_proxy { - explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) : insert_copy_proxy(v) {} }; @@ -468,7 +495,9 @@ template struct insert_emplace_proxy_arg1::value_type &> : public insert_copy_proxy { - explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) : insert_copy_proxy(v) {} }; @@ -479,7 +508,9 @@ struct insert_emplace_proxy_arg1 : public insert_copy_proxy { - explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) + static const bool single_value = true; + + BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) : insert_copy_proxy(v) {} }; @@ -490,6 +521,40 @@ struct insert_emplace_proxy_arg1 +struct has_single_value +{ + private: + struct two {char array_[2];}; + template struct wrapper; + template static two test(int, ...); + template static char test(int, const wrapper*); + public: + static const bool value = sizeof(test(0, 0)) == 1; + void dummy(){} +}; + +template::value> +struct is_single_value_proxy_impl +{ + static const bool value = InsertionProxy::single_value; +}; + +template +struct is_single_value_proxy_impl +{ + static const bool value = false; +}; + +template +struct is_single_value_proxy + : is_single_value_proxy_impl +{}; + +}}} //namespace boost { namespace container { namespace dtl { + #include #endif //#ifndef BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP From 978f1c426d5a8d5e851952209abc4ab254055672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:47:41 +0200 Subject: [PATCH 43/61] Generalize "clamp_by_stored_size_type" to be able to reuse it in other containers --- include/boost/container/detail/next_capacity.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/boost/container/detail/next_capacity.hpp b/include/boost/container/detail/next_capacity.hpp index 7e6554d..12fc35e 100644 --- a/include/boost/container/detail/next_capacity.hpp +++ b/include/boost/container/detail/next_capacity.hpp @@ -18,6 +18,9 @@ # pragma once #endif +#include +#include + // container #include // container/detail @@ -71,7 +74,20 @@ struct growth_factor_100 : dtl::grow_factor_ratio<0, 2, 1> {}; +template +BOOST_CONTAINER_FORCEINLINE void clamp_by_stored_size_type(SizeType &, SizeType) +{} + +template +BOOST_CONTAINER_FORCEINLINE void clamp_by_stored_size_type(SizeType &s, SomeStoredSizeType) +{ + if (s >= SomeStoredSizeType(-1) ) + s = SomeStoredSizeType(-1); +} + } //namespace container { } //namespace boost { +#include + #endif //#ifndef BOOST_CONTAINER_DETAIL_NEXT_CAPACITY_HPP From c48edfe7bdcf3102037f252ecf8d679847055712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:49:15 +0200 Subject: [PATCH 44/61] Reenabled the following warnings in MSVC to detect errors in the implementation: 4244 // possible loss of data 4267 // conversion from "X" to "Y", possible loss of data 4702 // unreachable code --- include/boost/container/detail/config_begin.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/boost/container/detail/config_begin.hpp b/include/boost/container/detail/config_begin.hpp index 4df9e35..172e685 100644 --- a/include/boost/container/detail/config_begin.hpp +++ b/include/boost/container/detail/config_begin.hpp @@ -20,9 +20,7 @@ #pragma warning (disable : 4127) // conditional expression is constant #pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned #pragma warning (disable : 4197) // top-level volatile in cast is ignored - #pragma warning (disable : 4244) // possible loss of data #pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2" - #pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data #pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier" #pragma warning (disable : 4284) // odd return type for operator-> #pragma warning (disable : 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow) @@ -42,7 +40,6 @@ #pragma warning (disable : 4671) // the copy constructor is inaccessible #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site #pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter - #pragma warning (disable : 4702) // unreachable code #pragma warning (disable : 4706) // assignment within conditional expression #pragma warning (disable : 4710) // function not inlined #pragma warning (disable : 4714) // "function": marked as __forceinline not inlined From d271c6384d62015e7096fbfd5ec0fc700f727337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:54:24 +0200 Subject: [PATCH 45/61] Use "set_stored_size" to avoid conversion warnings when updating member "stored_size_type types. --- include/boost/container/vector.hpp | 87 +++++++++++++++--------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 8000017..26db7ae 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -329,7 +329,7 @@ struct vector_alloc_holder pointer reuse = pointer(); size_type final_cap = initial_size; m_start = this->allocation_command(allocate_new, initial_size, final_cap, reuse); - m_capacity = static_cast(final_cap); + this->set_stored_capacity(final_cap); } } @@ -345,7 +345,7 @@ struct vector_alloc_holder pointer reuse = pointer(); size_type final_cap = initial_size; m_start = this->allocation_command(allocate_new, initial_size, final_cap, reuse); - m_capacity = static_cast(final_cap); + this->set_stored_capacity(final_cap); } } @@ -383,6 +383,12 @@ struct vector_alloc_holder } } + BOOST_CONTAINER_FORCEINLINE void set_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size = static_cast(s); } + + BOOST_CONTAINER_FORCEINLINE void set_stored_capacity(size_type c) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_capacity = static_cast(c); } + BOOST_CONTAINER_FORCEINLINE pointer allocation_command(boost::container::allocation_type command, size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) { @@ -427,7 +433,7 @@ struct vector_alloc_holder { BOOST_ASSERT(additional_objects > size_type(this->m_capacity - this->m_size)); size_type max = allocator_traits_type::max_size(this->alloc()); - (clamp_by_stored_size_type)(max, stored_size_type()); + (clamp_by_stored_size_type)(max, stored_size_type()); const size_type remaining_cap = max - size_type(this->m_capacity); const size_type min_additional_cap = additional_objects - size_type(this->m_capacity - this->m_size); @@ -470,7 +476,7 @@ struct vector_alloc_holder 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; } + { BOOST_ASSERT( c <= stored_size_type(-1)); this->set_stored_capacity(c); } static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow() { } @@ -488,16 +494,6 @@ struct vector_alloc_holder } } - BOOST_CONTAINER_FORCEINLINE static void clamp_by_stored_size_type(size_type &, size_type) - {} - - template - BOOST_CONTAINER_FORCEINLINE static void clamp_by_stored_size_type(size_type &s, SomeStoredSizeType) - { - if (s >= SomeStoredSizeType(-1) ) - s = SomeStoredSizeType(-1); - } - BOOST_CONTAINER_FORCEINLINE pointer priv_allocation_command(version_1, boost::container::allocation_type command, size_type limit_size, size_type &prefer_in_recvd_out_size, @@ -510,7 +506,7 @@ struct vector_alloc_holder if (limit_size > stored_size_type(-1)){ boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); } - (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); + (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); pointer const p = this->allocate(prefer_in_recvd_out_size); reuse = pointer(); return p; @@ -525,11 +521,11 @@ struct vector_alloc_holder if (limit_size > stored_size_type(-1)){ boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); } - (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); + (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); //Allocate memory pointer p = this->alloc().allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); //If after allocation prefer_in_recvd_out_size is not representable by stored_size_type, truncate it. - (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); + (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); return p; } }; @@ -611,6 +607,9 @@ struct vector_alloc_holder static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow() { allocator_type::on_capacity_overflow(); } + BOOST_CONTAINER_FORCEINLINE void set_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size = static_cast(s); } + BOOST_CONTAINER_FORCEINLINE void priv_first_allocation(size_type cap) { if(cap > allocator_type::internal_capacity){ @@ -1282,7 +1281,7 @@ private: } boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), first, input_sz, this->priv_raw_begin(), this->size()); - this->m_holder.m_size = input_sz; + m_holder.set_stored_size(input_sz); } //! Effects: Assigns the n copies of val to *this. @@ -1351,9 +1350,9 @@ private: //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE iterator end() BOOST_NOEXCEPT_OR_NOTHROW { - pointer const bg = this->m_holder.start(); - size_type const sz = this->m_holder.m_size; - return iterator(BOOST_LIKELY(sz) ? bg + sz : bg); //Avoid UB on null-pointer arithmetic + iterator it (this->m_holder.start()); + it += this->m_holder.m_size; + return it; //Adding zero to null pointer is allowed (non-UB) } //! Effects: Returns a const_iterator to the end of the vector. @@ -1415,11 +1414,10 @@ private: //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW { - pointer const bg = this->m_holder.start(); - size_type const sz = this->m_holder.m_size; - return const_iterator(BOOST_LIKELY(sz) ? bg + sz : bg); //Avoid UB on null-pointer arithmetic + const_iterator it (this->m_holder.start()); + it += this->m_holder.m_size; + return it; //Adding zero to null pointer is allowed (non-UB) } - //{ return const_iterator(this->m_holder.start() + this->m_holder.m_size); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed vector. @@ -2245,14 +2243,14 @@ private: else{ //Hole was just filled, disable exception rollback and change vector size past_hole_values_destroyer.release(); - this->m_holder.m_size += element_count; + this->m_holder.set_stored_size(this->size() + element_count); } } else{ if(old_hole_size){ //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size past_hole_values_destroyer.release(); - this->m_holder.m_size += element_count; + this->m_holder.set_stored_size(this->size() + element_count); } //Insert the new value in the already constructed range begin_ptr[pos + insertions_left - 1] = position_value.get_val(); @@ -2353,7 +2351,7 @@ private: if (old_cap > 0) { this->m_holder.deallocate(old_p, old_cap); } - this->m_holder.m_size = old_size + added; + m_holder.set_stored_size(old_size + added); this->m_holder.start(new_storage); this->m_holder.capacity(new_cap); new_buffer_deallocator.release(); @@ -2387,7 +2385,7 @@ private: const size_type this_sz = m_holder.m_size; const size_type other_sz = static_cast(x.m_holder.m_size); boost::container::move_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); - this->m_holder.m_size = other_sz; + m_holder.set_stored_size(other_sz); //Not emptying the source container seems to be confusing for users as drop-in //replacement for non-static vectors, so clear it. x.clear(); @@ -2445,7 +2443,7 @@ private: const size_type this_sz = m_holder.m_size; const size_type other_sz = static_cast(x.m_holder.m_size); boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); - this->m_holder.m_size = other_sz; + m_holder.set_stored_size(other_sz); } template @@ -2520,6 +2518,9 @@ private: //There is not enough memory, allocate a new buffer //Pass the hint so that allocators can take advantage of this. pointer const p = this->m_holder.allocate(new_cap); + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif //We will reuse insert code, so create a dummy input iterator this->priv_forward_range_insert_new_allocation ( boost::movelib::to_raw_pointer(p), new_cap, this->priv_raw_end(), 0, this->priv_dummy_empty_proxy()); @@ -2580,7 +2581,7 @@ private: T* const destroy_pos = this->priv_raw_begin() + (this->m_holder.m_size-n); boost::container::destroy_alloc_n(this->get_stored_allocator(), destroy_pos, n); } - this->m_holder.m_size -= n; + this->m_holder.set_stored_size(this->size() - n); } template @@ -2588,7 +2589,7 @@ private: { T* const old_end_pos = this->priv_raw_end(); T* const new_end_pos = boost::container::uninitialized_copy_alloc(this->m_holder.alloc(), first, last, old_end_pos); - this->m_holder.m_size += new_end_pos - old_end_pos; + this->m_holder.set_stored_size(this->size() + new_end_pos - old_end_pos); } void priv_destroy_all() BOOST_NOEXCEPT_OR_NOTHROW @@ -3040,9 +3041,9 @@ private: //Copy first old values before pos, after that the new objects T *const new_elem_pos = ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), old_start, pos, new_start); - this->m_holder.m_size = elemsbefore; + this->m_holder.set_stored_size(elemsbefore); insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_elem_pos, n); - this->m_holder.m_size = before_plus_new; + this->m_holder.set_stored_size(before_plus_new); const size_type new_size = old_size + n; //Check if s_before is so big that even copying the old data + new data //there is a gap between the new data and the old data @@ -3062,7 +3063,7 @@ private: ::boost::container::uninitialized_move_alloc (this->m_holder.alloc(), pos, old_finish, new_start + before_plus_new); //All new elements correctly constructed, avoid new element destruction - this->m_holder.m_size = new_size; + this->m_holder.set_stored_size(new_size); } //Old values destroyed automatically with "old_values_destroyer" //when "old_values_destroyer" goes out of scope unless the have trivial @@ -3093,7 +3094,7 @@ private: //Now we have a contiguous buffer so program trailing element destruction //and update size to the final size. old_values_destroyer.shrink_forward(new_size-s_before); - this->m_holder.m_size = new_size; + this->m_holder.set_stored_size(new_size); //Now move remaining last objects in the old buffer begin T * const remaining_pos = pos + raw_gap; if(remaining_pos != old_start){ //Make sure data has to be moved @@ -3107,7 +3108,7 @@ private: else{ //If trivial destructor, we can uninitialized copy + copy in a single uninitialized copy ::boost::container::uninitialized_move_alloc_n (this->m_holder.alloc(), pos, static_cast(old_finish - pos), new_start + before_plus_new); - this->m_holder.m_size = new_size; + this->m_holder.set_stored_size(new_size); old_values_destroyer.release(); } } @@ -3180,7 +3181,7 @@ private: old_values_destroyer.shrink_forward(old_size - (s_before - n)); } } - this->m_holder.m_size = old_size + new_1st_range; + this->m_holder.set_stored_size(old_size + new_1st_range); //Now copy the second part of old_begin overwriting itself T *const next = ::boost::container::move(old_start + s_before, pos, old_start); //Now copy the new_beg elements @@ -3221,12 +3222,12 @@ private: //First copy whole old_begin and part of new to raw_mem T * const new_pos = ::boost::container::uninitialized_move_alloc (this->m_holder.alloc(), old_start, pos, new_start); - this->m_holder.m_size = elemsbefore; + this->m_holder.set_stored_size(elemsbefore); const size_type mid_n = s_before - elemsbefore; insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_pos, mid_n); //The buffer is all constructed until old_end, //release destroyer - this->m_holder.m_size = old_size + s_before; + this->m_holder.set_stored_size(old_size + s_before); old_values_destroyer.release(); if(do_after){ @@ -3246,7 +3247,7 @@ private: size_type n_destroy = s_before - n; if(!value_traits::trivial_dctr_after_move) boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); - this->m_holder.m_size -= n_destroy; + this->m_holder.set_stored_size(this->size() - n_destroy); } } @@ -3290,7 +3291,7 @@ private: T* finish_n = old_finish - n_after; ::boost::container::uninitialized_move_alloc (this->m_holder.alloc(), finish_n, old_finish, old_finish); - this->m_holder.m_size += n_after; + this->m_holder.set_stored_size(this->size() + n_after); //Displace the rest of old_end to the new position boost::container::move_backward(pos, finish_n, old_finish); //Now overwrite with new_end @@ -3325,7 +3326,7 @@ private: insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, elemsafter); //Copy the rest to the uninitialized zone filling the gap insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, mid_last_dist); - this->m_holder.m_size += n_after; + this->m_holder.set_stored_size(this->size() + n_after); old_end_destroyer.release(); } } From e02b5c9bde9eec69bd18a7ac309ae6cfbb12b87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 9 Aug 2020 23:54:52 +0200 Subject: [PATCH 46/61] Add "back_free_capacity" utility --- .../detail/is_contiguous_container.hpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/boost/container/detail/is_contiguous_container.hpp b/include/boost/container/detail/is_contiguous_container.hpp index 528aeee..47ab363 100644 --- a/include/boost/container/detail/is_contiguous_container.hpp +++ b/include/boost/container/detail/is_contiguous_container.hpp @@ -26,6 +26,14 @@ #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 #include +//back_free_capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME back_free_capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace back_free_capacity_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include + namespace boost { namespace container { namespace dtl { @@ -40,6 +48,23 @@ struct is_contiguous_container has_member_function_callable_with_data::value; }; + +template < class Container + , bool = boost::container::back_free_capacity_detail:: + has_member_function_callable_with_back_free_capacity::value> +struct back_free_capacity +{ + static typename Container::size_type get(const Container &c) + { return c.back_free_capacity(); } +}; + +template < class Container> +struct back_free_capacity +{ + static typename Container::size_type get(const Container &c) + { return c.capacity() - c.size(); } +}; + } //namespace dtl { } //namespace container { } //namespace boost { From bff516315b20e515a49fbb2d4f772626079d21b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 10 Aug 2020 00:00:51 +0200 Subject: [PATCH 47/61] Add BOOST_CONTAINER_FORCEINLINE to more trivial functions --- include/boost/container/vector.hpp | 58 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 26db7ae..9d0f271 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -1473,8 +1473,8 @@ private: //! Throws: If memory allocation throws, or T's copy/move or value initialization throws. //! //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { this->priv_resize(new_size, value_init); } + BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size) + { this->priv_resize(new_size, value_init, alloc_version()); } //! Effects: Inserts or erases elements at the end such that //! the size becomes n. New elements are default initialized. @@ -1484,8 +1484,8 @@ private: //! Complexity: Linear to the difference between size() and new_size. //! //! Note: Non-standard extension - void resize(size_type new_size, default_init_t) - { this->priv_resize(new_size, default_init); } + BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size, default_init_t) + { this->priv_resize(new_size, default_init, alloc_version()); } //! Effects: Inserts or erases elements at the end such that //! the size becomes n. New elements are copy constructed from x. @@ -1493,8 +1493,8 @@ private: //! Throws: If memory allocation throws, or T's copy/move constructor throws. //! //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { this->priv_resize(new_size, x); } + BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size, const T& x) + { this->priv_resize(new_size, x, alloc_version()); } //! Effects: Number of elements for which memory has been allocated. //! capacity() is always greater than or equal to size(). @@ -1541,7 +1541,7 @@ private: //! Throws: Nothing. //! //! Complexity: Constant. - reference front() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE reference front() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); return *this->m_holder.start(); @@ -1555,7 +1555,7 @@ private: //! Throws: Nothing. //! //! Complexity: Constant. - const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); return *this->m_holder.start(); @@ -1569,7 +1569,7 @@ private: //! Throws: Nothing. //! //! Complexity: Constant. - reference back() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE reference back() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); return this->m_holder.start()[this->m_holder.m_size - 1]; @@ -1583,7 +1583,7 @@ private: //! Throws: Nothing. //! //! Complexity: Constant. - const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); return this->m_holder.start()[this->m_holder.m_size - 1]; @@ -1597,7 +1597,7 @@ private: //! Throws: Nothing. //! //! Complexity: Constant. - reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->m_holder.m_size > n); return this->m_holder.start()[n]; @@ -1611,7 +1611,7 @@ private: //! Throws: Nothing. //! //! Complexity: Constant. - const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->m_holder.m_size > n); return this->m_holder.start()[n]; @@ -1628,7 +1628,7 @@ private: //! Complexity: Constant. //! //! Note: Non-standard extension - iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->m_holder.m_size >= n); return iterator(this->m_holder.start()+n); @@ -1645,7 +1645,7 @@ private: //! Complexity: Constant. //! //! Note: Non-standard extension - const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->m_holder.m_size >= n); return const_iterator(this->m_holder.start()+n); @@ -1661,7 +1661,7 @@ private: //! Complexity: Constant. //! //! Note: Non-standard extension - size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW { //Range check assert done in priv_index_of return this->priv_index_of(vector_iterator_get_ptr(p)); @@ -1677,7 +1677,7 @@ private: //! Complexity: Constant. //! //! Note: Non-standard extension - size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW { //Range check assert done in priv_index_of return this->priv_index_of(vector_iterator_get_ptr(p)); @@ -1691,7 +1691,7 @@ private: //! Throws: std::range_error if n >= size() //! //! Complexity: Constant. - reference at(size_type n) + BOOST_CONTAINER_FORCEINLINE reference at(size_type n) { this->priv_throw_if_out_of_range(n); return this->m_holder.start()[n]; @@ -1705,7 +1705,7 @@ private: //! Throws: std::range_error if n >= size() //! //! Complexity: Constant. - const_reference at(size_type n) const + BOOST_CONTAINER_FORCEINLINE const_reference at(size_type n) const { this->priv_throw_if_out_of_range(n); return this->m_holder.start()[n]; @@ -1723,7 +1723,7 @@ private: //! Throws: Nothing. //! //! Complexity: Constant. - T* data() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE T* data() BOOST_NOEXCEPT_OR_NOTHROW { return this->priv_raw_begin(); } //! Returns: A pointer such that [data(),data() + size()) is a valid range. @@ -1732,7 +1732,7 @@ private: //! Throws: Nothing. //! //! Complexity: Constant. - const T * data() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const T * data() const BOOST_NOEXCEPT_OR_NOTHROW { return this->priv_raw_begin(); } ////////////////////////////////////////////// @@ -1799,7 +1799,7 @@ private: //! Complexity: If position is end(), amortized constant time //! Linear time otherwise. template - iterator emplace(const_iterator position, BOOST_FWD_REF(Args) ...args) + BOOST_CONTAINER_FORCEINLINE iterator emplace(const_iterator position, BOOST_FWD_REF(Args) ...args) { BOOST_ASSERT(this->priv_in_range_or_end(position)); //Just call more general insert(pos, size, value) and return iterator @@ -1841,7 +1841,7 @@ private: }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + BOOST_CONTAINER_FORCEINLINE iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ BOOST_ASSERT(this->priv_in_range_or_end(pos));\ typedef dtl::insert_emplace_proxy_arg##N type;\ @@ -1907,7 +1907,7 @@ private: //! Throws: If memory allocation throws or T's copy/move constructor throws. //! //! Complexity: Linear to n. - iterator insert(const_iterator p, size_type n, const T& x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, size_type n, const T& x) { BOOST_ASSERT(this->priv_in_range_or_end(p)); dtl::insert_n_copies_proxy proxy(x); @@ -1947,7 +1947,7 @@ private: #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template - iterator insert(const_iterator pos, FwdIt first, FwdIt last + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator pos, FwdIt first, FwdIt last , typename dtl::disable_if_or < void , dtl::is_convertible @@ -1978,7 +1978,7 @@ private: //! a non-standard extension. #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template - iterator insert(const_iterator pos, size_type num, InIt first, InIt last) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator pos, size_type num, InIt first, InIt last) { BOOST_ASSERT(this->priv_in_range_or_end(pos)); BOOST_ASSERT(dtl::is_input_iterator::value || @@ -2364,7 +2364,7 @@ private: BOOST_CONTAINER_FORCEINLINE pointer back_ptr() const { return this->m_holder.start() + this->m_holder.m_size; } - size_type priv_index_of(pointer p) const + BOOST_CONTAINER_FORCEINLINE size_type priv_index_of(pointer p) const { BOOST_ASSERT(this->m_holder.start() <= p); BOOST_ASSERT(p <= (this->m_holder.start()+this->size())); @@ -2467,7 +2467,7 @@ private: } template //Template it to avoid it in explicit instantiations - void priv_swap(Vector &x, dtl::true_type) //version_0 + BOOST_CONTAINER_FORCEINLINE void priv_swap(Vector &x, dtl::true_type) //version_0 { this->m_holder.deep_swap(x.m_holder); } template //Template it to avoid it in explicit instantiations @@ -2507,7 +2507,7 @@ private: void priv_reserve_no_capacity(size_type, version_0) { alloc_holder_t::on_capacity_overflow(); } - dtl::insert_range_proxy, T*> priv_dummy_empty_proxy() + BOOST_CONTAINER_FORCEINLINE dtl::insert_range_proxy, T*> priv_dummy_empty_proxy() { return dtl::insert_range_proxy, T*> (::boost::make_move_iterator((T *)0)); @@ -2614,7 +2614,7 @@ private: { return dtl::insert_move_proxy (x); } template - void priv_push_back(BOOST_FWD_REF(U) u) + BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u) { if (BOOST_LIKELY(this->room_enough())){ //There is more memory, just construct a new object at the end From 844b779a7d9581e7b3e0aac6e8b8fbcd18ae77eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 10 Aug 2020 00:02:26 +0200 Subject: [PATCH 48/61] Clean-up insertion code and speed upt single value insertion for proxies having that trait. --- include/boost/container/vector.hpp | 330 ++++++++++++++--------------- 1 file changed, 156 insertions(+), 174 deletions(-) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 9d0f271..f8f264a 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -1514,7 +1514,7 @@ private: BOOST_CONTAINER_FORCEINLINE void reserve(size_type new_cap) { if (this->capacity() < new_cap){ - this->priv_reserve_no_capacity(new_cap, alloc_version()); + this->priv_move_to_new_buffer(new_cap, alloc_version()); } } @@ -1762,9 +1762,9 @@ private: return *p; } else{ - typedef dtl::insert_emplace_proxy type; - return *this->priv_forward_range_insert_no_capacity - (this->back_ptr(), 1, type(::boost::forward(args)...), alloc_version()); + typedef dtl::insert_emplace_proxy proxy_t; + return *this->priv_insert_forward_range_no_capacity + (this->back_ptr(), 1, proxy_t(::boost::forward(args)...), alloc_version()); } } @@ -1803,9 +1803,9 @@ private: { BOOST_ASSERT(this->priv_in_range_or_end(position)); //Just call more general insert(pos, size, value) and return iterator - typedef dtl::insert_emplace_proxy type; - return this->priv_forward_range_insert( vector_iterator_get_ptr(position), 1 - , type(::boost::forward(args)...)); + typedef dtl::insert_emplace_proxy proxy_t; + return this->priv_insert_forward_range( vector_iterator_get_ptr(position), 1 + , proxy_t(::boost::forward(args)...)); } #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -1822,9 +1822,9 @@ private: return *p;\ }\ else{\ - typedef dtl::insert_emplace_proxy_arg##N type;\ - return *this->priv_forward_range_insert_no_capacity\ - ( this->back_ptr(), 1, type(BOOST_MOVE_FWD##N), alloc_version());\ + typedef dtl::insert_emplace_proxy_arg##N proxy_t;\ + return *this->priv_insert_forward_range_no_capacity\ + ( this->back_ptr(), 1, proxy_t(BOOST_MOVE_FWD##N), alloc_version());\ }\ }\ \ @@ -1844,8 +1844,8 @@ private: BOOST_CONTAINER_FORCEINLINE iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ BOOST_ASSERT(this->priv_in_range_or_end(pos));\ - typedef dtl::insert_emplace_proxy_arg##N type;\ - return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), 1, type(BOOST_MOVE_FWD##N));\ + typedef dtl::insert_emplace_proxy_arg##N proxy_t;\ + return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), 1, proxy_t(BOOST_MOVE_FWD##N));\ }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_VECTOR_EMPLACE_CODE) @@ -1911,7 +1911,7 @@ private: { BOOST_ASSERT(this->priv_in_range_or_end(p)); dtl::insert_n_copies_proxy proxy(x); - return this->priv_forward_range_insert(vector_iterator_get_ptr(p), n, proxy); + return this->priv_insert_forward_range(vector_iterator_get_ptr(p), n, proxy); } //! Requires: p must be a valid iterator of *this. @@ -1957,7 +1957,7 @@ private: { BOOST_ASSERT(this->priv_in_range_or_end(pos)); dtl::insert_range_proxy proxy(first); - return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), boost::container::iterator_distance(first, last), proxy); + return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), boost::container::iterator_distance(first, last), proxy); } #endif @@ -1985,7 +1985,7 @@ private: num == static_cast(boost::container::iterator_distance(first, last))); (void)last; dtl::insert_range_proxy proxy(first); - return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), num, proxy); + return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), num, proxy); } #endif @@ -2504,7 +2504,7 @@ private: dtl::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), dtl::bool_()); } - void priv_reserve_no_capacity(size_type, version_0) + BOOST_CONTAINER_FORCEINLINE void priv_move_to_new_buffer(size_type, version_0) { alloc_holder_t::on_capacity_overflow(); } BOOST_CONTAINER_FORCEINLINE dtl::insert_range_proxy, T*> priv_dummy_empty_proxy() @@ -2513,7 +2513,7 @@ private: (::boost::make_move_iterator((T *)0)); } - void priv_reserve_no_capacity(size_type new_cap, version_1) + BOOST_CONTAINER_FORCEINLINE void priv_move_to_new_buffer(size_type new_cap, version_1) { //There is not enough memory, allocate a new buffer //Pass the hint so that allocators can take advantage of this. @@ -2522,11 +2522,11 @@ private: ++this->num_alloc; #endif //We will reuse insert code, so create a dummy input iterator - this->priv_forward_range_insert_new_allocation + this->priv_insert_forward_range_new_allocation ( boost::movelib::to_raw_pointer(p), new_cap, this->priv_raw_end(), 0, this->priv_dummy_empty_proxy()); } - void priv_reserve_no_capacity(size_type new_cap, version_2) + void priv_move_to_new_buffer(size_type new_cap, version_2) { //There is not enough memory, allocate a new //buffer or expand the old one. @@ -2550,14 +2550,14 @@ private: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_expand_bwd; #endif - this->priv_forward_range_insert_expand_backwards + this->priv_insert_forward_range_expand_backwards ( new_mem , real_cap, ins_pos, 0, this->priv_dummy_empty_proxy()); } else{ //New buffer #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif - this->priv_forward_range_insert_new_allocation + this->priv_insert_forward_range_new_allocation ( new_mem, real_cap, ins_pos, 0, this->priv_dummy_empty_proxy()); } } @@ -2600,19 +2600,17 @@ private: } template - iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) x) + BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) u) { BOOST_ASSERT(this->priv_in_range_or_end(p)); - return this->priv_forward_range_insert - ( vector_iterator_get_ptr(p), 1, dtl::get_insert_value_proxy(::boost::forward(x))); + typedef typename dtl::if_c < boost::move_detail::is_rvalue_reference::value + , dtl::insert_move_proxy + , dtl::insert_copy_proxy + >::type proxy_t; + return this->priv_insert_forward_range + ( vector_iterator_get_ptr(p), 1, proxy_t((reference)u)); } - BOOST_CONTAINER_FORCEINLINE dtl::insert_copy_proxy priv_single_insert_proxy(const T &x) - { return dtl::insert_copy_proxy (x); } - - BOOST_CONTAINER_FORCEINLINE dtl::insert_move_proxy priv_single_insert_proxy(BOOST_RV_REF(T) x) - { return dtl::insert_move_proxy (x); } - template BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u) { @@ -2623,9 +2621,12 @@ private: ++this->m_holder.m_size; } else{ - this->priv_forward_range_insert_no_capacity - ( this->back_ptr(), 1 - , this->priv_single_insert_proxy(::boost::forward(u)), alloc_version()); + typedef typename dtl::if_c < boost::move_detail::is_rvalue_reference::value + , dtl::insert_move_proxy + , dtl::insert_copy_proxy + >::type proxy_t; + this->priv_insert_forward_range_no_capacity + ( this->back_ptr(), 1, proxy_t((reference)u), alloc_version()); } } @@ -2638,20 +2639,6 @@ private: BOOST_CONTAINER_FORCEINLINE dtl::insert_value_initialized_n_proxy priv_resize_proxy(value_init_t) { return dtl::insert_value_initialized_n_proxy(); } - template - void priv_resize(size_type new_size, const U& u) - { - const size_type sz = this->size(); - if (new_size < sz){ - //Destroy last elements - this->priv_destroy_last_n(sz - new_size); - } - else{ - const size_type n = new_size - this->size(); - this->priv_forward_range_insert_at_end(n, this->priv_resize_proxy(u), alloc_version()); - } - } - BOOST_CONTAINER_FORCEINLINE void priv_shrink_to_fit(version_0) BOOST_NOEXCEPT_OR_NOTHROW {} @@ -2667,17 +2654,7 @@ private: this->m_holder.m_capacity = 0; } else if(sz < cp){ - //Allocate a new buffer. - //Pass the hint so that allocators can take advantage of this. - pointer const p = this->m_holder.allocate(sz); - - //We will reuse insert code, so create a dummy input iterator - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_forward_range_insert_new_allocation - ( boost::movelib::to_raw_pointer(p), sz - , this->priv_raw_begin(), 0, this->priv_dummy_empty_proxy()); + this->priv_move_to_new_buffer(sz, alloc_version()); } } } @@ -2708,15 +2685,14 @@ private: } template - iterator priv_forward_range_insert_no_capacity - (const pointer &pos, const size_type, const InsertionProxy , version_0) + BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range_no_capacity + (const pointer &, const size_type, const InsertionProxy , version_0) { - alloc_holder_t::on_capacity_overflow(); - return iterator(pos); + return alloc_holder_t::on_capacity_overflow(), iterator(); } template - iterator priv_forward_range_insert_no_capacity + BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range_no_capacity (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_1) { //Check if we have enough memory or try to expand current memory @@ -2729,13 +2705,12 @@ private: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif - this->priv_forward_range_insert_new_allocation - ( new_buf, new_cap, raw_pos, n, insert_range_proxy); + this->priv_insert_forward_range_new_allocation(new_buf, new_cap, raw_pos, n, insert_range_proxy); return iterator(this->m_holder.start() + n_pos); } template - iterator priv_forward_range_insert_no_capacity + iterator priv_insert_forward_range_no_capacity (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_2) { //Check if we have enough memory or try to expand current memory @@ -2758,14 +2733,14 @@ private: #endif this->m_holder.capacity(real_cap); //Expand forward - this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + this->priv_insert_forward_range_expand_forward(raw_pos, n, insert_range_proxy); } //Backwards (and possibly forward) expansion else{ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_expand_bwd; #endif - this->priv_forward_range_insert_expand_backwards + this->priv_insert_forward_range_expand_backwards (boost::movelib::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy); } } @@ -2774,7 +2749,7 @@ private: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif - this->priv_forward_range_insert_new_allocation + this->priv_insert_forward_range_new_allocation ( boost::movelib::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy); } @@ -2782,46 +2757,52 @@ private: } template - iterator priv_forward_range_insert + BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy) { BOOST_ASSERT(this->m_holder.capacity() >= this->m_holder.m_size); //Check if we have enough memory or try to expand current memory - const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; - - bool same_buffer_start = n <= remaining; - if (!same_buffer_start){ - return priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); + if (BOOST_LIKELY(n <= (this->m_holder.capacity() - this->m_holder.m_size))){ + //Expand forward + this->priv_insert_forward_range_expand_forward(boost::movelib::to_raw_pointer(pos), n, insert_range_proxy); + return iterator(pos); } else{ - //Expand forward - T *const raw_pos = boost::movelib::to_raw_pointer(pos); - const size_type n_pos = raw_pos - this->priv_raw_begin(); - this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); - return iterator(this->m_holder.start() + n_pos); + return this->priv_insert_forward_range_no_capacity(pos, n, insert_range_proxy, alloc_version()); } } - template - iterator priv_forward_range_insert_at_end - (const size_type n, const InsertionProxy insert_range_proxy, version_0) + template + void priv_resize(const size_type new_size, const U &u, version_0) { - //Check if we have enough memory or try to expand current memory - const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; - - if (n > remaining){ + const size_type sz = this->m_holder.m_size; + if (new_size > this->capacity()){ //This will trigger an error alloc_holder_t::on_capacity_overflow(); } - this->priv_forward_range_insert_at_end_expand_forward(n, insert_range_proxy); - return this->end(); + else if (new_size < sz){ + //Destroy last elements + this->priv_destroy_last_n(sz - new_size); + } + else{ + T* const old_finish = this->priv_raw_end(); + this->priv_resize_proxy(u).uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, new_size - sz); + this->m_holder.set_stored_size(new_size); + } } - template - BOOST_CONTAINER_FORCEINLINE iterator priv_forward_range_insert_at_end - (const size_type n, const InsertionProxy insert_range_proxy, AllocVersion) + template + BOOST_CONTAINER_FORCEINLINE void priv_resize + (const size_type new_size, const U &u, AllocVersion) { - return this->priv_forward_range_insert(this->back_ptr(), n, insert_range_proxy); + const size_type sz = this->m_holder.m_size; + if (new_size < sz){ + //Destroy last elements + this->priv_destroy_last_n(sz - new_size); + } + else { + this->priv_insert_forward_range(this->back_ptr(), new_size - sz, this->priv_resize_proxy(u)); + } } //Takes the range pointed by [first_pos, last_pos) and shifts it to the right @@ -2918,86 +2899,89 @@ private: { return this->priv_raw_begin() + this->m_holder.m_size; } template - void priv_forward_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy) - { - T* const old_finish = this->priv_raw_end(); - insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n); - this->m_holder.m_size += n; - } - - template - void priv_forward_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy) + BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy) { //n can't be 0, because there is nothing to do in that case - if(BOOST_UNLIKELY(!n)) return; + bool const single_value_proxy = dtl::is_single_value_proxy::value; + //bool const single_value_proxy = false; + if(BOOST_UNLIKELY(!single_value_proxy && !n)) + return; + //There is enough memory T* const old_finish = this->priv_raw_end(); - const size_type elems_after = old_finish - pos; + const size_type elems_after = old_finish - raw_pos; + allocator_type & a = this->m_holder.alloc(); if (!elems_after){ - insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n); - this->m_holder.m_size += n; + insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, n); + this->m_holder.m_size += static_cast(n); } - else if (elems_after >= n){ + else if(single_value_proxy){ //New elements can be just copied. //Move to uninitialized memory last objects - ::boost::container::uninitialized_move_alloc - (this->m_holder.alloc(), old_finish - n, old_finish, old_finish); - this->m_holder.m_size += n; + allocator_traits_type::construct(a, old_finish, ::boost::move(*(old_finish-1))); + ++this->m_holder.m_size; //Copy previous to last objects to the initialized end - boost::container::move_backward(pos, old_finish - n, old_finish); - //Insert new objects in the pos - insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, n); + boost::container::move_backward(raw_pos, old_finish - 1, old_finish); + //Insert new objects in the raw_pos + insert_range_proxy.copy_n_and_update(a, raw_pos, 1); + } + else if(elems_after >= n){ + //New elements can be just copied. + //Move to uninitialized memory last objects + ::boost::container::uninitialized_move_alloc_n(a, old_finish - n, n, old_finish); + this->m_holder.m_size += static_cast(n); + //Copy previous to last objects to the initialized end + boost::container::move_backward(raw_pos, old_finish - n, old_finish); + //Insert new objects in the raw_pos + insert_range_proxy.copy_n_and_update(a, raw_pos, n); } else { - //The new elements don't fit in the [pos, end()) range. - - //Copy old [pos, end()) elements to the uninitialized memory (a gap is created) - ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), pos, old_finish, pos + n); - BOOST_TRY{ - //Copy first new elements in pos (gap is still there) - insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, elems_after); - //Copy to the beginning of the unallocated zone the last new elements (the gap is closed). - insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n - elems_after); - this->m_holder.m_size += n; - } - BOOST_CATCH(...){ - boost::container::destroy_alloc_n(this->get_stored_allocator(), pos + n, elems_after); - BOOST_RETHROW - } - BOOST_CATCH_END + //The new elements don't fit in the [raw_pos, end()) range. + //Copy old [raw_pos, end()) elements to the uninitialized memory (a gap is created) + ::boost::container::uninitialized_move_alloc(a, raw_pos, old_finish, raw_pos + n); + typename value_traits::ArrayDestructor on_exception(raw_pos + n, a, elems_after); + //Copy first new elements in raw_pos (gap is still there) + insert_range_proxy.copy_n_and_update(a, raw_pos, elems_after); + //Copy to the beginning of the unallocated zone the last new elements (the gap is closed). + insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, n - elems_after); + this->m_holder.m_size += static_cast(n); + on_exception.release(); } } template - void priv_forward_range_insert_new_allocation + void priv_insert_forward_range_new_allocation (T* const new_start, size_type new_cap, T* const pos, const size_type n, InsertionProxy insert_range_proxy) { //n can be zero, if we want to reallocate! T *new_finish = new_start; T *old_finish; + + allocator_type &a = this->m_holder.alloc(); + //Anti-exception rollbacks - typename value_traits::ArrayDeallocator new_buffer_deallocator(new_start, this->m_holder.alloc(), new_cap); - typename value_traits::ArrayDestructor new_values_destroyer(new_start, this->m_holder.alloc(), 0u); + typename value_traits::ArrayDeallocator new_buffer_deallocator(new_start, a, new_cap); + typename value_traits::ArrayDestructor new_values_destroyer(new_start, a, 0u); //Initialize with [begin(), pos) old buffer //the start of the new buffer T * const old_buffer = this->priv_raw_begin(); if(old_buffer){ new_finish = ::boost::container::uninitialized_move_alloc - (this->m_holder.alloc(), this->priv_raw_begin(), pos, old_finish = new_finish); + (a, this->priv_raw_begin(), pos, old_finish = new_finish); new_values_destroyer.increment_size(new_finish - old_finish); } //Initialize new objects, starting from previous point old_finish = new_finish; - insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n); + insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, n); new_finish += n; new_values_destroyer.increment_size(new_finish - old_finish); //Initialize from the rest of the old buffer, //starting from previous point if(old_buffer){ new_finish = ::boost::container::uninitialized_move_alloc - (this->m_holder.alloc(), pos, old_buffer + this->m_holder.m_size, new_finish); + (a, pos, old_buffer + this->m_holder.m_size, new_finish); //Destroy and deallocate old elements //If there is allocated memory, destroy and deallocate if(!value_traits::trivial_dctr_after_move) @@ -3005,7 +2989,7 @@ private: this->m_holder.deallocate(this->m_holder.start(), this->m_holder.capacity()); } this->m_holder.start(new_start); - this->m_holder.m_size = size_type(new_finish - new_start); + m_holder.set_stored_size(new_finish - new_start); this->m_holder.capacity(new_cap); //All construction successful, disable rollbacks new_values_destroyer.release(); @@ -3013,7 +2997,7 @@ private: } template - void priv_forward_range_insert_expand_backwards + void priv_insert_forward_range_expand_backwards (T* const new_start, const size_type new_capacity, T* const pos, const size_type n, InsertionProxy insert_range_proxy) { @@ -3022,27 +3006,30 @@ private: T* const old_start = this->priv_raw_begin(); const size_type old_size = this->m_holder.m_size; T* const old_finish = old_start + old_size; - - //We can have 8 possibilities: - const size_type elemsbefore = static_cast(pos - old_start); - const size_type s_before = static_cast(old_start - new_start); - const size_type before_plus_new = elemsbefore + n; + allocator_type &a = this->m_holder.alloc(); //Update the vector buffer information to a safe state this->m_holder.start(new_start); this->m_holder.capacity(new_capacity); this->m_holder.m_size = 0; + //We can have 8 possibilities: + const size_type elemsbefore = static_cast(pos - old_start); + const size_type s_before = static_cast(old_start - new_start); + const size_type before_plus_new = elemsbefore + n; + + typedef typename value_traits::ArrayDestructor array_destructor_t; + //If anything goes wrong, this object will destroy //all the old objects to fulfill previous vector state - typename value_traits::ArrayDestructor old_values_destroyer(old_start, this->m_holder.alloc(), old_size); + array_destructor_t old_values_destroyer(old_start, a, old_size); //Check if s_before is big enough to hold the beginning of old data + new data if(s_before >= before_plus_new){ //Copy first old values before pos, after that the new objects T *const new_elem_pos = - ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), old_start, pos, new_start); + ::boost::container::uninitialized_move_alloc(a, old_start, pos, new_start); this->m_holder.set_stored_size(elemsbefore); - insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_elem_pos, n); + insert_range_proxy.uninitialized_copy_n_and_update(a, new_elem_pos, n); this->m_holder.set_stored_size(before_plus_new); const size_type new_size = old_size + n; //Check if s_before is so big that even copying the old data + new data @@ -3060,15 +3047,14 @@ private: // //Now initialize the rest of memory with the last old values if(before_plus_new != new_size){ //Special case to avoid operations in back insertion - ::boost::container::uninitialized_move_alloc - (this->m_holder.alloc(), pos, old_finish, new_start + before_plus_new); + ::boost::container::uninitialized_move_alloc(a, pos, old_finish, new_start + before_plus_new); //All new elements correctly constructed, avoid new element destruction this->m_holder.set_stored_size(new_size); } //Old values destroyed automatically with "old_values_destroyer" //when "old_values_destroyer" goes out of scope unless the have trivial //destructor after move. - if(value_traits::trivial_dctr_after_move) + BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move) old_values_destroyer.release(); } //s_before is so big that divides old_end @@ -3086,11 +3072,10 @@ private: //Now initialize the rest of memory with the last old values //All new elements correctly constructed, avoid new element destruction const size_type raw_gap = s_before - before_plus_new; - if(!value_traits::trivial_dctr){ + BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr){ //Now initialize the rest of s_before memory with the //first of elements after new values - ::boost::container::uninitialized_move_alloc_n - (this->m_holder.alloc(), pos, raw_gap, new_start + before_plus_new); + ::boost::container::uninitialized_move_alloc_n(a, pos, raw_gap, new_start + before_plus_new); //Now we have a contiguous buffer so program trailing element destruction //and update size to the final size. old_values_destroyer.shrink_forward(new_size-s_before); @@ -3101,13 +3086,13 @@ private: ::boost::container::move(remaining_pos, old_finish, old_start); } //Once moved, avoid calling the destructors if trivial after move - if(value_traits::trivial_dctr_after_move){ + BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move){ old_values_destroyer.release(); } } else{ //If trivial destructor, we can uninitialized copy + copy in a single uninitialized copy ::boost::container::uninitialized_move_alloc_n - (this->m_holder.alloc(), pos, static_cast(old_finish - pos), new_start + before_plus_new); + (a, pos, static_cast(old_finish - pos), new_start + before_plus_new); this->m_holder.set_stored_size(new_size); old_values_destroyer.release(); } @@ -3162,8 +3147,7 @@ private: //|___________|_____|_________|_____________________| // //Copy the first part of old_begin to raw_mem - ::boost::container::uninitialized_move_alloc_n - (this->m_holder.alloc(), old_start, s_before, new_start); + ::boost::container::uninitialized_move_alloc_n(a, old_start, s_before, new_start); //The buffer is all constructed until old_end, //so program trailing destruction and assign final size //if !do_after, s_before+n otherwise. @@ -3175,8 +3159,9 @@ private: } else{ new_1st_range = n; - if(value_traits::trivial_dctr_after_move) + BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move){ old_values_destroyer.release(); + } else{ old_values_destroyer.shrink_forward(old_size - (s_before - n)); } @@ -3185,7 +3170,7 @@ private: //Now copy the second part of old_begin overwriting itself T *const next = ::boost::container::move(old_start + s_before, pos, old_start); //Now copy the new_beg elements - insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), next, new_1st_range); + insert_range_proxy.copy_n_and_update(a, next, new_1st_range); //If there is no after work and the last old part needs to be moved to front, do it if(!do_after && (n != s_before)){ @@ -3221,10 +3206,10 @@ private: // //First copy whole old_begin and part of new to raw_mem T * const new_pos = ::boost::container::uninitialized_move_alloc - (this->m_holder.alloc(), old_start, pos, new_start); + (a, old_start, pos, new_start); this->m_holder.set_stored_size(elemsbefore); const size_type mid_n = s_before - elemsbefore; - insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_pos, mid_n); + insert_range_proxy.uninitialized_copy_n_and_update(a, new_pos, mid_n); //The buffer is all constructed until old_end, //release destroyer this->m_holder.set_stored_size(old_size + s_before); @@ -3232,12 +3217,12 @@ private: if(do_after){ //Copy new_beg part - insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), old_start, elemsbefore); + insert_range_proxy.copy_n_and_update(a, old_start, elemsbefore); } else{ //Copy all new elements const size_type rest_new = n - mid_n; - insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), old_start, rest_new); + insert_range_proxy.copy_n_and_update(a, old_start, rest_new); T* const move_start = old_start + rest_new; //Displace old_end, but make sure data has to be moved T* const move_end = move_start != pos ? ::boost::container::move(pos, old_finish, move_start) @@ -3245,8 +3230,9 @@ private: //Destroy remaining moved elements from old_end except if they //have trivial destructor after being moved size_type n_destroy = s_before - n; - if(!value_traits::trivial_dctr_after_move) - boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); + BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr_after_move){ + boost::container::destroy_alloc_n(a, move_end, n_destroy); + } this->m_holder.set_stored_size(this->size() - n_destroy); } } @@ -3289,14 +3275,13 @@ private: // //First copy the part of old_end raw_mem T* finish_n = old_finish - n_after; - ::boost::container::uninitialized_move_alloc - (this->m_holder.alloc(), finish_n, old_finish, old_finish); + ::boost::container::uninitialized_move_alloc(a, finish_n, old_finish, old_finish); this->m_holder.set_stored_size(this->size() + n_after); //Displace the rest of old_end to the new position boost::container::move_backward(pos, finish_n, old_finish); //Now overwrite with new_end //The new_end part is [first + (n - n_after), last) - insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, n_after); + insert_range_proxy.copy_n_and_update(a, pos, n_after); } else { //The raw_mem from end will divide new_end part @@ -3310,22 +3295,19 @@ private: // _____________________________________________________________ //| old_begin + new_beg | new_end |old_end | raw_mem | //|__________________________|_______________|________|_________| - // - const size_type mid_last_dist = n_after - elemsafter; //First initialize data in raw memory + const size_type mid_last_dist = n_after - elemsafter; //Copy to the old_end part to the uninitialized zone leaving a gap. - ::boost::container::uninitialized_move_alloc - (this->m_holder.alloc(), pos, old_finish, old_finish + mid_last_dist); + ::boost::container::uninitialized_move_alloc(a, pos, old_finish, old_finish + mid_last_dist); - typename value_traits::ArrayDestructor old_end_destroyer - (old_finish + mid_last_dist, this->m_holder.alloc(), old_finish - pos); + array_destructor_t old_end_destroyer(old_finish + mid_last_dist, a, old_finish - pos); //Copy the first part to the already constructed old_end zone - insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, elemsafter); + insert_range_proxy.copy_n_and_update(a, pos, elemsafter); //Copy the rest to the uninitialized zone filling the gap - insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, mid_last_dist); + insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, mid_last_dist); this->m_holder.set_stored_size(this->size() + n_after); old_end_destroyer.release(); } From ebcd0222b470c2d7693deb8d93a40895d5f85c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 10 Aug 2020 00:16:58 +0200 Subject: [PATCH 49/61] Integrate and adapt "devector's", from Thaler Benedek's implementation. --- bench/bench_vectors.cpp | 283 ++ doc/container.qbk | 25 +- include/boost/container/container_fwd.hpp | 6 + include/boost/container/container_fwd.hpp.bak | 389 ++ include/boost/container/detail/flat_tree.hpp | 21 +- .../boost/container/detail/guards_dended.hpp | 198 + include/boost/container/devector.hpp | 2951 +++++++++++++ include/boost/container/options.hpp | 41 + include/boost/container/pmr/devector.hpp | 51 + proj/vc7ide/container.sln | 8 - test/devector_options_test.cpp | 121 + test/devector_test.cpp | 3932 +++++++++++++++++ test/explicit_inst_devector_test.cpp | 41 + test/flat_map_adaptor_test.cpp | 10 + test/flat_set_adaptor_test.cpp | 9 + test/hash_table_test.cppx | 0 test/input_iterator.hpp | 119 + test/pmr_devector_test.cpp | 26 + test/test_elem.hpp | 319 ++ test/test_util.hpp | 139 + 20 files changed, 8665 insertions(+), 24 deletions(-) create mode 100644 bench/bench_vectors.cpp create mode 100644 include/boost/container/container_fwd.hpp.bak create mode 100644 include/boost/container/detail/guards_dended.hpp create mode 100644 include/boost/container/devector.hpp create mode 100644 include/boost/container/pmr/devector.hpp create mode 100644 test/devector_options_test.cpp create mode 100644 test/devector_test.cpp create mode 100644 test/explicit_inst_devector_test.cpp delete mode 100644 test/hash_table_test.cppx create mode 100644 test/input_iterator.hpp create mode 100644 test/pmr_devector_test.cpp create mode 100644 test/test_elem.hpp create mode 100644 test/test_util.hpp diff --git a/bench/bench_vectors.cpp b/bench/bench_vectors.cpp new file mode 100644 index 0000000..e46c6c4 --- /dev/null +++ b/bench/bench_vectors.cpp @@ -0,0 +1,283 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning (disable : 4512) +#pragma warning (disable : 4267) +#pragma warning (disable : 4244) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include //std::allocator +#include //std::cout, std::endl +#include //std::strcmp +#include +#include + +//capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace test { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include + +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +namespace bc = boost::container; + +class MyInt +{ + int int_; + + public: + explicit MyInt(int i = 0) + : int_(i) + {} + + MyInt(const MyInt &other) + : int_(other.int_) + {} + + MyInt & operator=(const MyInt &other) + { + int_ = other.int_; + return *this; + } + + ~MyInt() + { + int_ = 0; + } +}; + +template::value> +struct capacity_wrapper +{ + static typename C::size_type get_capacity(const C &c) + { return c.capacity(); } + + static void set_reserve(C &c, typename C::size_type cp) + { c.reserve(cp); } +}; + +template +struct capacity_wrapper +{ + static typename C::size_type get_capacity(const C &) + { return 0u; } + + static void set_reserve(C &, typename C::size_type ) + { } +}; + +const std::size_t RangeSize = 5; + +struct insert_end_range +{ + std::size_t capacity_multiplier() const + { return RangeSize; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int) + { c.insert(c.end(), &a[0], &a[0]+RangeSize); } + + const char *name() const + { return "insert_end_range"; } + + MyInt a[RangeSize]; +}; + +struct insert_end_repeated +{ + std::size_t capacity_multiplier() const + { return RangeSize; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { c.insert(c.end(), RangeSize, MyInt(i)); } + + const char *name() const + { return "insert_end_repeated"; } + + MyInt a[RangeSize]; +}; + +struct push_back +{ + std::size_t capacity_multiplier() const + { return 1; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { c.push_back(MyInt(i)); } + + const char *name() const + { return "push_back"; } +}; + +struct emplace_back +{ + std::size_t capacity_multiplier() const + { return 1; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { c.emplace_back(MyInt(i)); } + + const char *name() const + { return "emplace_back"; } +}; + +struct insert_near_end_repeated +{ + + std::size_t capacity_multiplier() const + { return RangeSize; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), RangeSize, MyInt(i)); } + + const char *name() const + { return "insert_near_end_repeated"; } +}; + +struct insert_near_end_range +{ + std::size_t capacity_multiplier() const + { return RangeSize; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int) + { + c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), &a[0], &a[0]+RangeSize); + } + + const char *name() const + { return "insert_near_end_repeated"; } + + MyInt a[RangeSize]; +}; + +struct insert_near_end +{ + std::size_t capacity_multiplier() const + { return 1; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { + typedef typename C::iterator it_t; + it_t it (c.end()); + it -= static_cast(!c.empty()); + c.insert(it, MyInt(i)); + } + + const char *name() const + { return "insert_near_end"; } +}; + + +template +void vector_test_template(unsigned int num_iterations, unsigned int num_elements, const char *cont_name) +{ + cpu_timer timer; + timer.resume(); + + + unsigned int capacity = 0; + Operation op; + typedef capacity_wrapper cpw_t; + const typename Container::size_type multiplier = op.capacity_multiplier(); + + for(unsigned int r = 0; r != num_iterations; ++r){ + Container c; + cpw_t::set_reserve(c, num_elements); + + for(unsigned e = 0, max = num_elements/multiplier; e != max; ++e){ + op(c, static_cast(e)); + } + + capacity = static_cast(cpw_t::get_capacity(c)); + } + + timer.stop(); + + + nanosecond_type nseconds = timer.elapsed().wall; + + std::cout << cont_name << "->" << op.name() <<" ns: " + << float(nseconds)/(num_iterations*num_elements) + << '\t' + << "Capacity: " << (unsigned int)capacity + << "\n"; +} + +template +void test_vectors() +{ + //#define SINGLE_TEST + #define SIMPLE_IT + #ifdef SINGLE_TEST + #ifdef NDEBUG + std::size_t numit [] = { 100 }; + #else + std::size_t numit [] = { 20 }; + #endif + std::size_t numele [] = { 10000 }; + #elif defined SIMPLE_IT + std::size_t numit [] = { 100 }; + std::size_t numele [] = { 10000 }; + #else + #ifdef NDEBUG + unsigned int numit [] = { 1000, 10000, 100000, 1000000 }; + #else + unsigned int numit [] = { 100, 1000, 10000, 100000 }; + #endif + unsigned int numele [] = { 10000, 1000, 100, 10 }; + #endif + + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template< std::vector >, Operation >(numit[i], numele[i] , "std::vector "); + vector_test_template< bc::vector >, Operation >(numit[i], numele[i] , "vector "); + vector_test_template< bc::devector >, Operation >(numit[i], numele[i] , "devector "); + vector_test_template< bc::small_vector >, Operation >(numit[i], numele[i] , "small_vector "); + vector_test_template< std::deque >, Operation >(numit[i], numele[i] , "std::deque "); + vector_test_template< bc::deque >, Operation >(numit[i], numele[i] , "deque "); + } + + std::cout << "---------------------------------\n---------------------------------\n"; +} + +int main() +{ + //end + test_vectors(); + test_vectors(); + test_vectors(); + test_vectors(); + //near end + test_vectors(); + test_vectors(); + test_vectors(); + + return 0; +} diff --git a/doc/container.qbk b/doc/container.qbk index 64cc808..24f4314 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -47,12 +47,14 @@ In short, what does [*Boost.Container] offer? searches. * [classref boost::container::stable_vector stable_vector]: a std::list and std::vector hybrid container: vector-like random-access iterators and list-like iterator stability in insertions and erasures. - * [classref boost::container::static_vector static_vector ]: a vector-like container that internally embeds + * [classref boost::container::static_vector static_vector]: a vector-like container that internally embeds (statically allocates) all needed memory up to the maximum capacity. Maximum capacity can't be increased and it's specified at compile time. - * [classref boost::container::small_vector small_vector ]: a vector-like container that internally embeds + * [classref boost::container::small_vector small_vector]: a vector-like container that internally embeds (statically allocates) a minimum amount of memory, but dynamically allocates elements when capacity has to be increased. This minimum capacity is specified at compile time. + * [classref boost::container::devector devector]: is a hybrid of the standard vector and deque containers. + It offers cheap (amortized constant time) insertion at both the front and back ends. * [classref boost::container::slist slist]: the classic pre-standard singly linked list implementation offering constant-time `size()`. Note that C++11 `forward_list` has no `size()`. @@ -458,6 +460,21 @@ erasure times considerably. Flat associative containers have the following attri [endsect] +[section:devector ['devector]] + +`devector` is a hybrid of the standard vector and deque containers originally written by Thaler Benedek. +It offers cheap (amortized constant time) insertion at both the front and back ends, +while also providing the regular features of `vector`, in particular the contiguous underlying memory. + +Unlike `vector`, devector can have free capacity both before and after the elements. This enables efficient +implementation of methods that modify the devector at the front. In general, `devector`'s available methods +are a superset of those of `vector` with identical behaviour, barring a couple of iterator invalidation +guarantees that differ. + +The overhead for devector is one extra `size_t` per container: Usually sizeof(devector) == 4*sizeof(T*). + +[endsect] + [section:slist ['slist]] When the standard template library was designed, it contained a singly linked list called `slist`. @@ -1306,6 +1323,10 @@ use [*Boost.Container]? There are several reasons for that: * `static_vector` was based on Andrew Hundt's and Adam Wulkiewicz's high-performance `varray` class. Many performance improvements of `vector` were also inspired by their implementation. Thanks! +* `devector` is based on Thaler Benedek's high-performance `devector` implementation, then + adapted for [*Boost.Container]. Also inspired by similar implemenations by Orson Peters and Lars Hagen. + Thanks for such a great code and documentation! + * Howard Hinnant's help and advices were essential when implementing move semantics, improving allocator support or implementing small string optimization. Thanks Howard for your wonderful standard library implementations. diff --git a/include/boost/container/container_fwd.hpp b/include/boost/container/container_fwd.hpp index fb4d7bd..7855257 100644 --- a/include/boost/container/container_fwd.hpp +++ b/include/boost/container/container_fwd.hpp @@ -26,6 +26,7 @@ //! - boost::container::static_vector //! - boost::container::small_vector_base //! - boost::container::small_vector +//! - boost::container::devector //! - boost::container::slist //! - boost::container::list //! - boost::container::set @@ -122,6 +123,11 @@ template < class T , class Options = void > class small_vector; +template +class devector; + template diff --git a/include/boost/container/container_fwd.hpp.bak b/include/boost/container/container_fwd.hpp.bak new file mode 100644 index 0000000..9d419f7 --- /dev/null +++ b/include/boost/container/container_fwd.hpp.bak @@ -0,0 +1,389 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP +#define BOOST_CONTAINER_CONTAINER_FWD_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//! \file +//! This header file forward declares the following containers: +//! - boost::container::vector +//! - boost::container::stable_vector +//! - boost::container::static_vector +//! - boost::container::small_vector_base +//! - boost::container::small_vector +//! - boost::container::slist +//! - boost::container::list +//! - boost::container::set +//! - boost::container::multiset +//! - boost::container::map +//! - boost::container::multimap +//! - boost::container::flat_set +//! - boost::container::flat_multiset +//! - boost::container::flat_map +//! - boost::container::flat_multimap +//! - boost::container::basic_string +//! - boost::container::string +//! - boost::container::wstring +//! +//! Forward declares the following allocators: +//! - boost::container::allocator +//! - boost::container::node_allocator +//! - boost::container::adaptive_pool +//! +//! Forward declares the following polymorphic resource classes: +//! - boost::container::pmr::memory_resource +//! - boost::container::pmr::polymorphic_allocator +//! - boost::container::pmr::monotonic_buffer_resource +//! - boost::container::pmr::pool_options +//! - boost::container::pmr::unsynchronized_pool_resource +//! - boost::container::pmr::synchronized_pool_resource +//! +//! And finally it defines the following types + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//Std forward declarations +#ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP + #include +#endif + +namespace boost{ +namespace intrusive{ +namespace detail{ + //Create namespace to avoid compilation errors +}}} + +namespace boost{ namespace container{ namespace dtl{ + namespace bi = boost::intrusive; + namespace bid = boost::intrusive::detail; +}}} + +namespace boost{ namespace container{ namespace pmr{ + namespace bi = boost::intrusive; + namespace bid = boost::intrusive::detail; +}}} + +#include + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +////////////////////////////////////////////////////////////////////////////// +// Containers +////////////////////////////////////////////////////////////////////////////// + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +template +struct pair; + +template +class new_allocator; + +template +class vector; + +template +class stable_vector; + +template < class T + , std::size_t Capacity + , class Options = void> +class static_vector; + +template < class T + , class Allocator = void + , class Options = void > +class small_vector_base; + +template < class T + , std::size_t N + , class Allocator = void + , class Options = void > +class small_vector; + +template +class devector; + +template +class deque; + +template +class list; + +template +class slist; + +template + ,class Allocator = void + ,class Options = void> +class set; + +template + ,class Allocator = void + ,class Options = void > +class multiset; + +template + ,class Allocator = void + ,class Options = void > +class map; + +template + ,class Allocator = void + ,class Options = void > +class multimap; + +template + ,class Allocator = void > +class flat_set; + +template + ,class Allocator = void > +class flat_multiset; + +template + ,class Allocator = void > +class flat_map; + +template + ,class Allocator = void > +class flat_multimap; + +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + +//! Alias templates for small_flat_[multi]{set|map} using small_vector as container + +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +using small_flat_set = flat_set>; + +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +using small_flat_multiset = flat_multiset>; + +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +using small_flat_map = flat_map, N, SmallVectorAllocator, SmallVectorOptions>>; + +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +using small_flat_multimap = flat_multimap, N, SmallVectorAllocator, SmallVectorOptions>>; + +#endif // #ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + + +//! A portable metafunction to obtain a small_flat_set +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_set_of +{ + typedef flat_set > type; +}; + +//! A portable metafunction to obtain a small_flat_multiset +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_multiset_of +{ + typedef flat_multiset > type; +}; + +//! A portable metafunction to obtain a small_flat_map +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_map_of +{ + typedef flat_map, N, SmallVectorAllocator, SmallVectorOptions> > type; +}; + +//! A portable metafunction to obtain a small_flat_multimap +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_multimap_of +{ + typedef flat_multimap, N, SmallVectorAllocator, SmallVectorOptions> > type; +}; + +template + ,class Allocator = void > +class basic_string; + +typedef basic_string string; +typedef basic_string wstring; + +static const std::size_t ADP_nodes_per_block = 256u; +static const std::size_t ADP_max_free_blocks = 2u; +static const std::size_t ADP_overhead_percent = 1u; +static const std::size_t ADP_only_alignment = 0u; + +template < class T + , std::size_t NodesPerBlock = ADP_nodes_per_block + , std::size_t MaxFreeBlocks = ADP_max_free_blocks + , std::size_t OverheadPercent = ADP_overhead_percent + , unsigned Version = 2 + > +class adaptive_pool; + +template < class T + , unsigned Version = 2 + , unsigned int AllocationDisableMask = 0> +class allocator; + +static const std::size_t NodeAlloc_nodes_per_block = 256u; + +template + < class T + , std::size_t NodesPerBlock = NodeAlloc_nodes_per_block + , std::size_t Version = 2> +class node_allocator; + +namespace pmr { + +class memory_resource; + +template +class polymorphic_allocator; + +class monotonic_buffer_resource; + +struct pool_options; + +template +class resource_adaptor_imp; + +class unsynchronized_pool_resource; + +class synchronized_pool_resource; + +} //namespace pmr { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! Type used to tag that the input range is +//! guaranteed to be ordered +struct ordered_range_t +{}; + +//! Value used to tag that the input range is +//! guaranteed to be ordered +static const ordered_range_t ordered_range = ordered_range_t(); + +//! Type used to tag that the input range is +//! guaranteed to be ordered and unique +struct ordered_unique_range_t + : public ordered_range_t +{}; + +//! Value used to tag that the input range is +//! guaranteed to be ordered and unique +static const ordered_unique_range_t ordered_unique_range = ordered_unique_range_t(); + +//! Type used to tag that the inserted values +//! should be default initialized +struct default_init_t +{}; + +//! Value used to tag that the inserted values +//! should be default initialized +static const default_init_t default_init = default_init_t(); +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! Type used to tag that the inserted values +//! should be value initialized +struct value_init_t +{}; + +//! Value used to tag that the inserted values +//! should be value initialized +static const value_init_t value_init = value_init_t(); + +namespace container_detail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)ordered_range; + (void)ordered_unique_range; + (void)default_init; + } +}; + +} //detail_really_deep_namespace { + + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +}} //namespace boost { namespace container { + +#endif //#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index c346360..8e62a61 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -130,7 +130,8 @@ void flat_tree_container_inplace_merge //is_contiguous_container == true 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()); + boost::movelib::adaptive_merge + (braw, iraw, eraw, comp, eraw, back_free_capacity::get(dest)); } template @@ -152,7 +153,8 @@ void flat_tree_container_inplace_sort_ending //is_contiguous_container == 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()); + boost::movelib::adaptive_sort + (iraw, eraw, comp, eraw, back_free_capacity::get(dest)); } template @@ -984,10 +986,7 @@ class flat_tree ret.first = this->nth(data.position - this->cbegin()); } else{ - typedef typename emplace_functor_type::type func_t; - typedef emplace_iterator it_t; - func_t func(try_emplace_t(), ::boost::forward(key), ::boost::forward(args)...); - ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t()); + ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward(key), ::boost::forward(args)...); } return ret; } @@ -1053,10 +1052,7 @@ class flat_tree ret.first = this->nth(data.position - this->cbegin());\ }\ else{\ - typedef typename emplace_functor_type::type func_t;\ - typedef emplace_iterator it_t;\ - func_t func(try_emplace_t(), ::boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());\ + ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ }\ return ret;\ }\ @@ -1080,10 +1076,7 @@ class flat_tree ret.first->second = boost::forward(obj); } else{ - typedef typename emplace_functor_type::type func_t; - typedef emplace_iterator it_t; - func_t func(boost::forward(key), boost::forward(obj)); - ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t()); + ret.first = this->m_data.m_seq.emplace(data.position, boost::forward(key), boost::forward(obj)); } return ret; } diff --git a/include/boost/container/detail/guards_dended.hpp b/include/boost/container/detail/guards_dended.hpp new file mode 100644 index 0000000..db5e1d0 --- /dev/null +++ b/include/boost/container/detail/guards_dended.hpp @@ -0,0 +1,198 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Benedek Thaler 2015-2016 +// (C) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://erenon.hu/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_GUARDS_HPP +#define BOOST_CONTAINER_DETAIL_GUARDS_HPP + +#include +#include + +#include // BOOST_MOVABLE_BUT_NOT_COPYABLE + +// move/detail +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif + +#include + +namespace boost { +namespace container { +namespace detail { + +class null_construction_guard +{ +public: + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + template + null_construction_guard(Args&&...) {} + + #else + + #define NULL_CONSTRUCTION_GUARD_CODE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE null_construction_guard(BOOST_MOVE_UREFANON##N)\ + {}\ + // + BOOST_MOVE_ITERATE_0TO9(NULL_CONSTRUCTION_GUARD_CODE) + #undef NULL_CONSTRUCTION_GUARD_CODE + #endif + + void release() {} + void extend() {} +}; + +template +class construction_guard +{ + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(construction_guard) + +public: + construction_guard() + : _alloc_ptr() + , _elem_count() + , _allocator() + {} + + construction_guard(pointer alloc_ptr, Allocator& allocator) + :_alloc_ptr(alloc_ptr) + , _elem_count(0) + , _allocator(&allocator) + {} + + construction_guard(BOOST_RV_REF(construction_guard) rhs) + :_alloc_ptr(rhs._alloc_ptr) + , _elem_count(rhs._elem_count) + , _allocator(rhs._allocator) + { + rhs._elem_count = 0; + } + + ~construction_guard() + { + while (_elem_count) { + --_elem_count; + boost::container::allocator_traits::destroy(*_allocator, _alloc_ptr++); + } + } + + void release() + { + _elem_count = 0; + } + + void extend() + { + ++_elem_count; + } + +private: + pointer _alloc_ptr; + size_type _elem_count; + Allocator* _allocator; +}; + + +/** + * Has two ranges + * + * On success, destroys the first range (src), + * on failure, destroys the second range (dst). + * + * Can be used when copying/moving a range + */ +template +class nand_construction_guard +{ + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + + construction_guard _src; + construction_guard _dst; + bool _dst_released; + + public: + nand_construction_guard() + : _src() + , _dst() + , _dst_released(false) + {} + + nand_construction_guard( pointer src, Allocator& src_alloc + , pointer dst, Allocator& dst_alloc) + :_src(src, src_alloc), + _dst(dst, dst_alloc), + _dst_released(false) + {} + + void extend() + { + _src.extend(); + _dst.extend(); + } + + void release() // on success + { + _dst.release(); + _dst_released = true; + } + + ~nand_construction_guard() + { + if (! _dst_released) { _src.release(); } + } +}; + + +template +class allocation_guard +{ + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(allocation_guard) + +public: + allocation_guard(pointer alloc_ptr, size_type alloc_size, Allocator& allocator) + :_alloc_ptr(alloc_ptr), + _alloc_size(alloc_size), + _allocator(allocator) + {} + + ~allocation_guard() + { + if (_alloc_ptr) + { + boost::container::allocator_traits::deallocate(_allocator, _alloc_ptr, _alloc_size); + } + } + + void release() + { + _alloc_ptr = 0; + } + +private: + pointer _alloc_ptr; + size_type _alloc_size; + Allocator& _allocator; +}; + +}}} // namespace boost::container::detail + +#include + +#endif // BOOST_CONTAINER_DETAIL_GUARDS_HPP diff --git a/include/boost/container/devector.hpp b/include/boost/container/devector.hpp new file mode 100644 index 0000000..2b56829 --- /dev/null +++ b/include/boost/container/devector.hpp @@ -0,0 +1,2951 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Benedek Thaler 2015-2016 +// (C) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DEVECTOR_HPP +#define BOOST_CONTAINER_DEVECTOR_HPP + +#include +#include + +//#include +#include // memcpy + +#include +#include + +#include +#include //new_allocator +#include //allocator_traits +#include //equal() +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// move +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include + +//std +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +#include //for std::initializer_list +#endif + +namespace boost { +namespace container { + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +struct growth_factor_60; + +template +struct get_devector_opt +{ + typedef devector_opt< typename default_if_void::type + , typename default_if_void::type + > type; +}; + +template +struct get_devector_opt +{ + typedef vector_opt type; +}; + +#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +struct reserve_only_tag_t {}; +//struct unsafe_uninitialized_tag_t {}; + +/** + * A vector-like sequence container providing front and back operations + * (e.g: `push_front`/`pop_front`/`push_back`/`pop_back`) with amortized constant complexity + * and unsafe methods geared towards additional performance. + * + * Models the [SequenceContainer], [ReversibleContainer], and [AllocatorAwareContainer] concepts. + * + * **Requires**: + * - `T` shall be [MoveInsertable] into the devector. + * - `T` shall be [Erasable] from any `devector`. + * - `GrowthFactor`, and `Allocator` must model the concepts with the same names or be void. + * + * **Definition**: `T` is `NothrowConstructible` if it's either nothrow move constructible or + * nothrow copy constructible. + * + * **Definition**: `T` is `NothrowAssignable` if it's either nothrow move assignable or + * nothrow copy assignable. + * + * **Exceptions**: The exception specifications assume `T` is nothrow [Destructible]. + * + * Most methods providing the strong exception guarantee assume `T` either has a move + * constructor marked noexcept or is [CopyInsertable] into the devector. If it isn't true, + * and the move constructor throws, the guarantee is waived and the effects are unspecified. + * + * In addition to the exceptions specified in the **Throws** clause, the following operations + * of `T` can throw when any of the specified concept is required: + * - [DefaultInsertable][]: Default constructor + * - [MoveInsertable][]: Move constructor + * - [CopyInsertable][]: Copy constructor + * - [DefaultConstructible][]: Default constructor + * - [EmplaceConstructible][]: Constructor selected by the given arguments + * - [MoveAssignable][]: Move assignment operator + * - [CopyAssignable][]: Copy assignment operator + * + * Furthermore, not `noexcept` methods throws whatever the allocator throws + * if memory allocation fails. Such methods also throw `length_error` if the capacity + * exceeds `max_size()`. + * + * **Remark**: If a method invalidates some iterators, it also invalidates references + * and pointers to the elements pointed by the invalidated iterators. + * + * **Policies**: + * + * @ref devector_growth_policy models the `GrowthFactor` concept. + * + * [SequenceContainer]: http://en.cppreference.com/w/cpp/concept/SequenceContainer + * [ReversibleContainer]: http://en.cppreference.com/w/cpp/concept/ReversibleContainer + * [AllocatorAwareContainer]: http://en.cppreference.com/w/cpp/concept/AllocatorAwareContainer + * [DefaultInsertable]: http://en.cppreference.com/w/cpp/concept/DefaultInsertable + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [Erasable]: http://en.cppreference.com/w/cpp/concept/Erasable + * [DefaultConstructible]: http://en.cppreference.com/w/cpp/concept/DefaultConstructible + * [Destructible]: http://en.cppreference.com/w/cpp/concept/Destructible + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ +template < typename T, class A BOOST_CONTAINER_DOCONLY(= void), class Options BOOST_CONTAINER_DOCONLY(= void)> +class devector +{ + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef boost::container::allocator_traits + ::type> allocator_traits_type; + typedef typename allocator_traits_type::size_type alloc_size_type; + typedef typename get_devector_opt::type options_type; + typedef typename options_type::growth_factor_type growth_factor_type; + typedef typename options_type::stored_size_type stored_size_type; + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + // Standard Interface Types: + typedef T value_type; + typedef BOOST_CONTAINER_IMPDEF + (typename real_allocator::type) allocator_type; + typedef allocator_type stored_allocator_type; + typedef typename allocator_traits::pointer pointer; + typedef typename allocator_traits::const_pointer const_pointer; + typedef typename allocator_traits::reference reference; + typedef typename allocator_traits::const_reference const_reference; + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::difference_type difference_type; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef BOOST_CONTAINER_IMPDEF + (boost::container::reverse_iterator) reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF + (boost::container::reverse_iterator) const_reverse_iterator; + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + BOOST_COPYABLE_AND_MOVABLE(devector) + + // Guard to deallocate buffer on exception + typedef typename detail::allocation_guard allocation_guard; + + // Random access pseudo iterator always yielding to the same result + typedef constant_iterator cvalue_iterator; + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + // Standard Interface + public: + // construct/copy/destroy + + /** + * **Effects**: Constructs an empty devector. + * + * **Postcondition**: `empty() && front_free_capacity() == 0 + * && back_free_capacity() == 0`. + * + * **Complexity**: Constant. + */ + devector() BOOST_NOEXCEPT + : m_() + {} + + /** + * **Effects**: Constructs an empty devector, using the specified allocator. + * + * **Postcondition**: `empty() && front_free_capacity() == 0 + * && back_free_capacity() == 0`. + * + * **Complexity**: Constant. + */ + explicit devector(const allocator_type& allocator) BOOST_NOEXCEPT + : m_(allocator) + {} + + /** + * **Effects**: Constructs an empty devector, using the specified allocator + * and reserves `n` slots as if `reserve(n)` was called. + * + * **Postcondition**: `empty() && front_free_capacity() == 0 + * && back_free_capacity() >= n`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Constant. + */ + devector(size_type n, reserve_only_tag_t, const allocator_type& allocator = allocator_type()) + : m_(allocator, this->allocate(n), 0u, 0u, n) + {} + + /** + * **Effects**: Constructs an empty devector, using the specified allocator + * and reserves `front_cap + back_cap` slots as if `reserve_front(front_cap)` and + * `reserve_back(back_cap)` was called. + * + * **Postcondition**: `empty() && front_free_capacity() == front_cap + * && back_free_capacity() >= back_cap`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Constant. + */ + devector(size_type front_cap, size_type back_cap, reserve_only_tag_t, const allocator_type& allocator = allocator_type()) + : m_(allocator, this->allocate(front_cap + back_cap), front_cap, front_cap, front_cap + back_cap) + {} + + /** + * [DefaultInsertable]: http://en.cppreference.com/w/cpp/concept/DefaultInsertable + * + * **Effects**: Constructs a devector with `n` default-inserted elements using the specified allocator. + * + * **Requires**: `T` shall be [DefaultInsertable] into `*this`. + * + * **Postcondition**: `size() == n && front_free_capacity() == 0`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in `n`. + */ + explicit devector(size_type n, const allocator_type& allocator = allocator_type()) + : m_(allocator, n ? allocate(n): pointer(), 0u, n, n) + { + // Cannot use construct_from_range/constant_iterator and copy_range, + // because we are not allowed to default construct T + allocation_guard buffer_guard(m_.buffer, m_.capacity, get_allocator_ref()); + detail::construction_guard copy_guard(m_.buffer, get_allocator_ref()); + + for (size_type i = 0; i < n; ++i) + { + this->alloc_construct(m_.buffer + i); + copy_guard.extend(); + } + + copy_guard.release(); + buffer_guard.release(); + + BOOST_ASSERT(invariants_ok()); + } + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Constructs a devector with `n` copies of `value`, using the specified allocator. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Postcondition**: `size() == n && front_free_capacity() == 0`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in `n`. + */ + devector(size_type n, const T& value, const allocator_type& allocator = allocator_type()) + : m_(allocator, n ? allocate(n): pointer(), 0u, n, n) + { + construct_from_range(cvalue_iterator(value, n), cvalue_iterator()); + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: Constructs a devector equal to the range `[first,last)`, using the specified allocator. + * + * **Requires**: `T` shall be [EmplaceConstructible] into `*this` from `*first`. If the specified + * iterator does not meet the forward iterator requirements, `T` shall also be [MoveInsertable] + * into `*this`. + * + * **Postcondition**: `size() == boost::container::iterator_distance(first, last) + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Makes only `N` calls to the copy constructor of `T` (where `N` is the distance between `first` + * and `last`), at most one allocation and no reallocations if iterators first and last are of forward, + * bidirectional, or random access categories. It makes `O(N)` calls to the copy constructor of `T` + * and `O(log(N)) reallocations if they are just input iterators. + * + * **Remarks**: Each iterator in the range `[first,last)` shall be dereferenced exactly once, + * unless an exception is thrown. + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + */ + template + devector(InputIterator first, InputIterator last, const allocator_type& allocator = allocator_type() + //Input iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_not_input_iterator + >::type * = 0) + ) + : m_(allocator, pointer(), 0u, 0u, 0u) + { + while (first != last) { + this->emplace_back(*first++); + } + + BOOST_ASSERT(invariants_ok()); + } + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + devector(ForwardIterator first, ForwardIterator last, const allocator_type& allocator = allocator_type() + //Other iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_input_iterator + >::type * = 0) + ) + : m_(allocator, pointer(), 0u, 0u, 0u) + { + const size_type n = boost::container::iterator_distance(first, last); + m_.buffer = n ? allocate(n) : pointer(); + m_.front_idx = 0u; + m_.set_back_idx(n); + m_.set_capacity(n); + construct_from_range(first, last); + BOOST_ASSERT(invariants_ok()); + } + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Copy constructs a devector. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Postcondition**: `this->size() == x.size() && front_free_capacity() == 0`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `x`. + */ + devector(const devector& x) + : m_( allocator_traits_type::select_on_container_copy_construction(x.get_allocator_ref()) + , pointer(), 0u, 0u, 0u) + { + const size_type n = x.size(); + m_.buffer = n ? allocate(n) : pointer(); + m_.front_idx = 0u; + //this->allocate(n) will take care of overflows + m_.set_back_idx(n); + m_.set_capacity(n); + this->construct_from_range(x.begin(), x.end()); + BOOST_ASSERT(invariants_ok()); + } + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Copy constructs a devector, using the specified allocator. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Postcondition**: `this->size() == x.size() && front_free_capacity() == 0`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `x`. + */ + devector(const devector& x, const allocator_type& allocator) + : m_(allocator, pointer(), 0u, 0u, 0u) + { + const size_type n = x.size(); + m_.buffer = n ? this->allocate(n) : pointer(); + m_.front_idx = 0u; + //this->allocate(n) will take care of overflows + m_.set_back_idx(n); + m_.set_capacity(n); + this->construct_from_range(x.begin(), x.end()); + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: Moves `rhs`'s resources to `*this`. + * + * **Throws**: Nothing. + * + * **Postcondition**: `rhs` is left in an unspecified but valid state. + * + * **Exceptions**: Strong exception guarantee if not `noexcept`. + * + * **Complexity**: Constant. + */ + devector(BOOST_RV_REF(devector) rhs) BOOST_NOEXCEPT_OR_NOTHROW + : m_(::boost::move(rhs.get_allocator_ref()), rhs.m_.buffer, rhs.m_.front_idx, rhs.m_.back_idx, rhs.capacity()) + { + // buffer is already acquired, reset rhs + rhs.m_.capacity = 0u; + rhs.m_.buffer = pointer(); + rhs.m_.front_idx = 0; + rhs.m_.back_idx = 0; + BOOST_ASSERT( invariants_ok()); + BOOST_ASSERT(rhs.invariants_ok()); + } + + /** + * **Effects**: Moves `rhs`'s resources to `*this`, using the specified allocator. + * + * **Throws**: If allocation or T's move constructor throws. + * + * **Postcondition**: `rhs` is left in an unspecified but valid state. + * + * **Exceptions**: Strong exception guarantee if not `noexcept`. + * + * **Complexity**: Linear if allocator != rhs.get_allocator(), otherwise constant. + */ + devector(BOOST_RV_REF(devector) rhs, const allocator_type& allocator) + : m_(allocator, rhs.m_.buffer, rhs.m_.front_idx, rhs.m_.back_idx, rhs.capacity()) + { + // TODO should move elems-by-elems if the two allocators differ + // buffer is already acquired, reset rhs + rhs.m_.capacity = 0u; + rhs.m_.buffer = pointer(); + rhs.m_.front_idx = 0; + rhs.m_.back_idx = 0; + BOOST_ASSERT( invariants_ok()); + BOOST_ASSERT(rhs.invariants_ok()); + } + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** + * **Equivalent to**: `devector(il.begin(), il.end())` or `devector(il.begin(), il.end(), allocator)`. + */ + devector(const std::initializer_list& il, const allocator_type& allocator = allocator_type()) + : devector(il.begin(), il.end(), allocator) + {} + #endif + + /** + * **Effects**: Destroys the devector. All stored values are destroyed and + * used memory, if any, deallocated. + * + * **Complexity**: Linear in the size of `*this`. + */ + ~devector() BOOST_NOEXCEPT + { + destroy_elements(m_.buffer + m_.front_idx, m_.buffer + m_.back_idx); + deallocate_buffer(); + } + + /** + * **Effects**: Copies elements of `x` to `*this`. Previously + * held elements get copy assigned to or destroyed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Postcondition**: `this->size() == x.size()`, the elements of + * `*this` are copies of elements in `x` in the same order. + * + * **Returns**: `*this`. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and the allocator is allowed to be propagated + * ([propagate_on_container_copy_assignment] is true), + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `x` and `*this`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [propagate_on_container_copy_assignment]: http://en.cppreference.com/w/cpp/memory/allocator_traits + */ + + BOOST_CONTAINER_FORCEINLINE devector& operator=(BOOST_COPY_ASSIGN_REF(devector) rhs) + { + const devector &x = rhs; + if (this == &x) { return *this; } // skip self + + BOOST_IF_CONSTEXPR(allocator_traits_type::propagate_on_container_copy_assignment::value) + { + allocator_type &this_alloc = this->get_allocator_ref(); + const allocator_type &other_alloc = x.get_allocator_ref(); + if (this_alloc != other_alloc) + { + // new allocator cannot free existing storage + this->clear(); + this->deallocate_buffer(); + m_.capacity = 0u; + m_.buffer = pointer(); + } + + this_alloc = other_alloc; + } + + size_type n = x.size(); + if (capacity() >= n) + { + this->overwrite_buffer(x.begin(), x.end()); + } + else + { + this->allocate_and_copy_range(x.begin(), x.end()); + } + + BOOST_ASSERT(invariants_ok()); + + return *this; + } + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Moves elements of `x` to `*this`. Previously + * held elements get move/copy assigned to or destroyed. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Postcondition**: `x` is left in an unspecified but valid state. + * + * **Returns**: `*this`. + * + * **Exceptions**: Basic exception guarantee if not `noexcept`. + * + * **Complexity**: Constant if allocator_traits_type:: + * propagate_on_container_move_assignment is true or + * this->get>allocator() == x.get_allocator(). Linear otherwise. + */ + devector& operator=(BOOST_RV_REF(devector) x) + BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value) + { + BOOST_CONSTEXPR_OR_CONST bool copy_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; + + BOOST_IF_CONSTEXPR (copy_alloc || get_allocator_ref() == x.get_allocator_ref()) + { + this->clear(); + this->deallocate_buffer(); + + if (copy_alloc) + { + this->get_allocator_ref() = boost::move(x.get_allocator_ref()); + } + + m_.capacity = x.m_.capacity; + m_.buffer = x.m_.buffer; + m_.front_idx = x.m_.front_idx; + m_.back_idx = x.m_.back_idx; + + // leave x in valid state + x.m_.capacity = 0u; + x.m_.buffer = pointer(); + x.m_.back_idx = x.m_.front_idx = 0; + } + else + { + // if the allocator shouldn't be copied and they do not compare equal + // we can't steal memory. + + move_iterator xbegin = boost::make_move_iterator(x.begin()); + move_iterator xend = boost::make_move_iterator(x.end()); + + if (copy_alloc) + { + get_allocator_ref() = boost::move(x.get_allocator_ref()); + } + + if (capacity() >= x.size()) + { + overwrite_buffer(xbegin, xend); + } + else + { + allocate_and_copy_range(xbegin, xend); + } + } + + BOOST_ASSERT(invariants_ok()); + + return *this; + } + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** + * **Effects**: Copies elements of `il` to `*this`. Previously + * held elements get copy assigned to or destroyed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this` and [CopyAssignable]. + * + * **Postcondition**: `this->size() == il.size()`, the elements of + * `*this` are copies of elements in `il` in the same order. + * + * **Exceptions**: Strong exception guarantee if `T` is nothrow copy assignable + * from `T` and `NothrowConstructible`, Basic exception guarantee otherwise. + * + * **Returns**: `*this`. + * + * **Complexity**: Linear in the size of `il` and `*this`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + devector& operator=(std::initializer_list il) + { + assign(il.begin(), il.end()); + return *this; + } + #endif + + /** + * **Effects**: Replaces elements of `*this` with a copy of `[first,last)`. + * Previously held elements get copy assigned to or destroyed. + * + * **Requires**: `T` shall be [EmplaceConstructible] from `*first`. If the specified iterator + * does not meet the forward iterator requirements, `T` shall be also [MoveInsertable] into `*this`. + * + * **Precondition**: `first` and `last` are not iterators into `*this`. + * + * **Postcondition**: `size() == N`, where `N` is the distance between `first` and `last`. + * + * **Exceptions**: Strong exception guarantee if `T` is nothrow copy assignable + * from `*first` and `NothrowConstructible`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the distance between `first` and `last`. + * Makes a single reallocation at most if the iterators `first` and `last` + * are of forward, bidirectional, or random access categories. It makes + * `O(log(N))` reallocations if they are just input iterators. + * + * **Remarks**: Each iterator in the range `[first,last)` shall be dereferenced exactly once, + * unless an exception is thrown. + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + */ + template + void assign(InputIterator first, InputIterator last + //Input iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_not_input_iterator + >::type * = 0) + ) + { + first = overwrite_buffer_impl(first, last, dtl::false_()); + while (first != last) + { + this->emplace_back(*first++); + } + } + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + void assign(ForwardIterator first, ForwardIterator last + //Other iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_input_iterator + >::type * = 0) + ) + { + const size_type n = boost::container::iterator_distance(first, last); + + if (capacity() >= n) + { + overwrite_buffer(first, last); + } + else + { + allocate_and_copy_range(first, last); + } + + BOOST_ASSERT(invariants_ok()); + } + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + /** + * **Effects**: Replaces elements of `*this` with `n` copies of `u`. + * Previously held elements get copy assigned to or destroyed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this` and + * [CopyAssignable]. + * + * **Precondition**: `u` is not a reference into `*this`. + * + * **Postcondition**: `size() == n` and the elements of + * `*this` are copies of `u`. + * + * **Exceptions**: Strong exception guarantee if `T` is nothrow copy assignable + * from `u` and `NothrowConstructible`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in `n` and the size of `*this`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + void assign(size_type n, const T& u) + { + cvalue_iterator first(u, n); + cvalue_iterator last; + + assign(first, last); + } + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** **Equivalent to**: `assign(il.begin(), il.end())`. */ + void assign(std::initializer_list il) + { + assign(il.begin(), il.end()); + } + #endif + + /** + * **Returns**: A copy of the allocator associated with the container. + * + * **Complexity**: Constant. + */ + allocator_type get_allocator() const BOOST_NOEXCEPT + { + return static_cast(m_); + } + + const allocator_type &get_stored_allocator() const BOOST_NOEXCEPT + { + return static_cast(m_); + } + + allocator_type &get_stored_allocator() BOOST_NOEXCEPT + { + return static_cast(m_); + } + + // iterators + + /** + * **Returns**: A iterator pointing to the first element in the devector, + * or the past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + iterator begin() BOOST_NOEXCEPT + { + return m_.buffer + m_.front_idx; + } + + /** + * **Returns**: A constant iterator pointing to the first element in the devector, + * or the past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + const_iterator begin() const BOOST_NOEXCEPT + { + return m_.buffer + m_.front_idx; + } + + /** + * **Returns**: An iterator pointing past the last element of the container. + * + * **Complexity**: Constant. + */ + iterator end() BOOST_NOEXCEPT + { + return m_.buffer + m_.back_idx; + } + + /** + * **Returns**: A constant iterator pointing past the last element of the container. + * + * **Complexity**: Constant. + */ + const_iterator end() const BOOST_NOEXCEPT + { + return m_.buffer + m_.back_idx; + } + + /** + * **Returns**: A reverse iterator pointing to the first element in the reversed devector, + * or the reverse past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + reverse_iterator rbegin() BOOST_NOEXCEPT + { + return reverse_iterator(m_.buffer + m_.back_idx); + } + + /** + * **Returns**: A constant reverse iterator + * pointing to the first element in the reversed devector, + * or the reverse past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + const_reverse_iterator rbegin() const BOOST_NOEXCEPT + { + return const_reverse_iterator(m_.buffer + m_.back_idx); + } + + /** + * **Returns**: A reverse iterator pointing past the last element in the + * reversed container, or to the beginning of the reversed container if it's empty. + * + * **Complexity**: Constant. + */ + reverse_iterator rend() BOOST_NOEXCEPT + { + return reverse_iterator(m_.buffer + m_.front_idx); + } + + /** + * **Returns**: A constant reverse iterator pointing past the last element in the + * reversed container, or to the beginning of the reversed container if it's empty. + * + * **Complexity**: Constant. + */ + const_reverse_iterator rend() const BOOST_NOEXCEPT + { + return const_reverse_iterator(m_.buffer + m_.front_idx); + } + + /** + * **Returns**: A constant iterator pointing to the first element in the devector, + * or the past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + const_iterator cbegin() const BOOST_NOEXCEPT + { + return m_.buffer + m_.front_idx; + } + + /** + * **Returns**: A constant iterator pointing past the last element of the container. + * + * **Complexity**: Constant. + */ + const_iterator cend() const BOOST_NOEXCEPT + { + return m_.buffer + m_.back_idx; + } + + /** + * **Returns**: A constant reverse iterator + * pointing to the first element in the reversed devector, + * or the reverse past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + const_reverse_iterator crbegin() const BOOST_NOEXCEPT + { + return const_reverse_iterator(m_.buffer + m_.back_idx); + } + + /** + * **Returns**: A constant reverse iterator pointing past the last element in the + * reversed container, or to the beginning of the reversed container if it's empty. + * + * **Complexity**: Constant. + */ + const_reverse_iterator crend() const BOOST_NOEXCEPT + { + return const_reverse_iterator(m_.buffer + m_.front_idx); + } + + // capacity + + /** + * **Returns**: True, if `size() == 0`, false otherwise. + * + * **Complexity**: Constant. + */ + bool empty() const BOOST_NOEXCEPT + { + return m_.front_idx == m_.back_idx; + } + + /** + * **Returns**: The number of elements the devector contains. + * + * **Complexity**: Constant. + */ + size_type size() const BOOST_NOEXCEPT + { + return m_.back_idx - m_.front_idx; + } + + /** + * **Returns**: The maximum number of elements the devector could possibly hold. + * + * **Complexity**: Constant. + */ + size_type max_size() const BOOST_NOEXCEPT + { + size_type alloc_max = allocator_traits_type::max_size(get_allocator_ref()); + size_type size_type_max = (size_type)-1; + return (alloc_max <= size_type_max) ? size_type(alloc_max) : size_type_max; + } + + /** + * **Returns**: The total number of elements that the devector can hold without requiring reallocation. + * + * **Complexity**: Constant. + */ + size_type capacity() const BOOST_NOEXCEPT + { + return m_.capacity; + } + + /** + * **Returns**: The total number of elements that can be pushed to the front of the + * devector without requiring reallocation. + * + * **Complexity**: Constant. + */ + size_type front_free_capacity() const BOOST_NOEXCEPT + { + return m_.front_idx; + } + + /** + * **Returns**: The total number of elements that can be pushed to the back of the + * devector without requiring reallocation. + * + * **Complexity**: Constant. + */ + size_type back_free_capacity() const BOOST_NOEXCEPT + { + return m_.capacity - m_.back_idx; + } + + /** **Equivalent to**: `resize_back(sz)` */ + void resize(size_type sz) { resize_back(sz); } + + /** **Equivalent to**: `resize_back(sz, c)` */ + void resize(size_type sz, const T& c) { resize_back(sz, c); } + + /** + * **Effects**: If `sz` is greater than the size of `*this`, + * additional value-initialized elements are inserted + * to the front. Invalidates iterators if reallocation is needed. + * If `sz` is smaller than than the size of `*this`, + * elements are popped from the front. + * + * **Requires**: T shall be [MoveInsertable] into *this and [DefaultConstructible]. + * + * **Postcondition**: `sz == size()`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `*this` and `sz`. + * + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [DefaultConstructible]: http://en.cppreference.com/w/cpp/concept/DefaultConstructible + */ + void resize_front(size_type sz) + { + resize_front_impl(sz); + BOOST_ASSERT(invariants_ok()); + } + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: If `sz` is greater than the size of `*this`, + * copies of `c` are inserted to the front. + * Invalidates iterators if reallocation is needed. + * If `sz` is smaller than than the size of `*this`, + * elements are popped from the front. + * + * **Postcondition**: `sz == size()`. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `*this` and `sz`. + */ + void resize_front(size_type sz, const T& c) + { + resize_front_impl(sz, c); + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: If `sz` is greater than the size of `*this`, + * additional value-initialized elements are inserted + * to the back. Invalidates iterators if reallocation is needed. + * If `sz` is smaller than than the size of `*this`, + * elements are popped from the back. + * + * **Requires**: T shall be [MoveInsertable] into *this and [DefaultConstructible]. + * + * **Postcondition**: `sz == size()`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `*this` and `sz`. + * + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [DefaultConstructible]: http://en.cppreference.com/w/cpp/concept/DefaultConstructible + */ + void resize_back(size_type sz) + { + resize_back_impl(sz); + BOOST_ASSERT(invariants_ok()); + } + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: If `sz` is greater than the size of `*this`, + * copies of `c` are inserted to the back. + * If `sz` is smaller than than the size of `*this`, + * elements are popped from the back. + * + * **Postcondition**: `sz == size()`. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `*this` and `sz`. + */ + void resize_back(size_type sz, const T& c) + { + resize_back_impl(sz, c); + BOOST_ASSERT(invariants_ok()); + } + + // unsafe uninitialized resize methods + + /** + * **Unsafe method**, use with care. + * + * **Effects**: Changes the size of the devector without properly + * initializing the extra or destroying the superfluous elements. + * If `n < size()`, elements are removed from the front without + * getting destroyed; if `n > size()`, uninitialized elements are added + * before the first element at the front. + * Invalidates iterators if reallocation is needed. + * + * **Postcondition**: `size() == n`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in `size()` if `capacity() < n`, constant otherwise. + * + * **Remarks**: The devector does not keep track of initialization of the elements: + * Elements without a trivial destructor must be manually destroyed before shrinking, + * elements without a trivial constructor must be initialized after growing. + */ +/* + void unsafe_uninitialized_resize_front(size_type n) + { + if (n > size()) + { + unsafe_uninitialized_grow_front(n); + } + else + { + unsafe_uninitialized_shrink_front(n); + } + } +*/ + /** + * **Unsafe method**, use with care. + * + * **Effects**: Changes the size of the devector without properly + * initializing the extra or destroying the superfluous elements. + * If `n < size()`, elements are removed from the back without + * getting destroyed; if `n > size()`, uninitialized elements are added + * after the last element at the back. + * Invalidates iterators if reallocation is needed. + * + * **Postcondition**: `size() == n`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in `size()` if `capacity() < n`, constant otherwise. + * + * **Remarks**: The devector does not keep track of initialization of the elements: + * Elements without a trivial destructor must be manually destroyed before shrinking, + * elements without a trivial constructor must be initialized after growing. + */ +/* + void unsafe_uninitialized_resize_back(size_type n) + { + if (n > size()) + { + unsafe_uninitialized_grow_back(n); + } + else + { + unsafe_uninitialized_shrink_back(n); + } + } +*/ + // reserve promise: + // after reserve_[front,back](n), n - size() push_[front,back] will not allocate + + /** **Equivalent to**: `reserve_back(new_capacity)` */ + void reserve(size_type new_capacity) { reserve_back(new_capacity); } + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Ensures that `n` elements can be pushed to the front + * without requiring reallocation, where `n` is `new_capacity - size()`, + * if `n` is positive. Otherwise, there are no effects. + * Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Complexity**: Linear in the size of *this. + * + * **Exceptions**: Strong exception guarantee. + * + * **Throws**: `length_error` if `new_capacity > max_size()`. + */ + void reserve_front(size_type new_capacity) + { + if (front_capacity() >= new_capacity) { return; } + + reallocate_at(new_capacity + back_free_capacity(), new_capacity - size()); + + BOOST_ASSERT(invariants_ok()); + } + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Ensures that `n` elements can be pushed to the back + * without requiring reallocation, where `n` is `new_capacity - size()`, + * if `n` is positive. Otherwise, there are no effects. + * Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Complexity**: Linear in the size of *this. + * + * **Exceptions**: Strong exception guarantee. + * + * **Throws**: length_error if `new_capacity > max_size()`. + */ + void reserve_back(size_type new_capacity) + { + if (back_capacity() >= new_capacity) { return; } + + reallocate_at(new_capacity + front_free_capacity(), m_.front_idx); + + BOOST_ASSERT(invariants_ok()); + } + + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Reduces `capacity()` to `size()`. Invalidates iterators. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of *this. + */ + void shrink_to_fit() + { + if(this->front_capacity() || this->back_capacity()) + this->reallocate_at(size(), 0); + } + + // element access: + + /** + * **Returns**: A reference to the `n`th element in the devector. + * + * **Precondition**: `n < size()`. + * + * **Complexity**: Constant. + */ + reference operator[](size_type n) BOOST_NOEXCEPT + { + BOOST_ASSERT(n < size()); + + return *(begin() + n); + } + + /** + * **Returns**: A constant reference to the `n`th element in the devector. + * + * **Precondition**: `n < size()`. + * + * **Complexity**: Constant. + */ + const_reference operator[](size_type n) const BOOST_NOEXCEPT + { + BOOST_ASSERT(n < size()); + + return *(begin() + n); + } + + /** + * **Returns**: A reference to the `n`th element in the devector. + * + * **Throws**: `std::out_of_range`, if `n >= size()`. + * + * **Complexity**: Constant. + */ + reference at(size_type n) + { + if (size() <= n) + throw_out_of_range("devector::at out of range"); + return (*this)[n]; + } + + /** + * **Returns**: A constant reference to the `n`th element in the devector. + * + * **Throws**: `std::out_of_range`, if `n >= size()`. + * + * **Complexity**: Constant. + */ + const_reference at(size_type n) const + { + if (size() <= n) + throw_out_of_range("devector::at out of range"); + return (*this)[n]; + } + + /** + * **Returns**: A reference to the first element in the devector. + * + * **Precondition**: `!empty()`. + * + * **Complexity**: Constant. + */ + reference front() BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + + return *(m_.buffer + m_.front_idx); + } + + /** + * **Returns**: A constant reference to the first element in the devector. + * + * **Precondition**: `!empty()`. + * + * **Complexity**: Constant. + */ + const_reference front() const BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + + return *(m_.buffer + m_.front_idx); + } + + /** + * **Returns**: A reference to the last element in the devector. + * + * **Precondition**: `!empty()`. + * + * **Complexity**: Constant. + */ + reference back() BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + + return *(m_.buffer + m_.back_idx -1); + } + + /** + * **Returns**: A constant reference to the last element in the devector. + * + * **Precondition**: `!empty()`. + * + * **Complexity**: Constant. + */ + const_reference back() const BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + + return *(m_.buffer + m_.back_idx -1); + } + + /** + * **Returns**: A pointer to the underlying array serving as element storage. + * The range `[data(); data() + size())` is always valid. For a non-empty devector, + * `data() == &front()`. + * + * **Complexity**: Constant. + */ + T* data() BOOST_NOEXCEPT + { + return boost::movelib::to_raw_pointer(m_.buffer) + m_.front_idx; + } + + /** + * **Returns**: A constant pointer to the underlying array serving as element storage. + * The range `[data(); data() + size())` is always valid. For a non-empty devector, + * `data() == &front()`. + * + * **Complexity**: Constant. + */ + const T* data() const BOOST_NOEXCEPT + { + return boost::movelib::to_raw_pointer(m_.buffer) + m_.front_idx; + } + + // modifiers: + + /** + * **Effects**: Pushes a new element to the front of the devector. + * The element is constructed in-place, using the perfect forwarded `args` + * as constructor arguments. Invalidates iterators if reallocation is needed. + * (`front_free_capacity() == 0`) + * + * **Requires**: `T` shall be [EmplaceConstructible] from `args` and [MoveInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `front_free_capacity() > 0`) + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + */ + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + void emplace_front(Args&&... args) + { + if (front_free_capacity()) // fast path + { + this->alloc_construct(m_.buffer + m_.front_idx - 1, boost::forward(args)...); + --m_.front_idx; + } + else + { + this->emplace_reallocating_slow_path(true, 0, boost::forward(args)...); + } + + BOOST_ASSERT(invariants_ok()); + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_EMPLACE_FRONT(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE void emplace_front(BOOST_MOVE_UREF##N)\ + {\ + if (front_free_capacity())\ + {\ + this->alloc_construct(m_.buffer + m_.front_idx - 1 BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + --m_.front_idx;\ + }\ + else\ + {\ + this->emplace_reallocating_slow_path(true, 0 BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + \ + BOOST_ASSERT(invariants_ok());\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_EMPLACE_FRONT) + #undef BOOST_CONTAINER_DEVECTOR_EMPLACE_FRONT + + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Pushes the copy of `x` to the front of the devector. + * Invalidates iterators if reallocation is needed. + * (`front_free_capacity() == 0`) + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `front_free_capacity() > 0`) + */ + void push_front(const T& x); + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Move constructs a new element at the front of the devector using `x`. + * Invalidates iterators if reallocation is needed. + * (`front_free_capacity() == 0`) + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee, not regarding the state of `x`. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `front_free_capacity() > 0`) + */ + void push_front(T&& x); + + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) + #endif + + /** + * **Effects**: Removes the first element of `*this`. + * + * **Precondition**: `!empty()`. + * + * **Postcondition**: `front_free_capacity()` is incremented by 1. + * + * **Complexity**: Constant. + */ + void pop_front() BOOST_NOEXCEPT + { + BOOST_ASSERT(! empty()); + allocator_traits_type::destroy(get_allocator_ref(), m_.buffer + m_.front_idx); + ++m_.front_idx; + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: Pushes a new element to the back of the devector. + * The element is constructed in-place, using the perfect forwarded `args` + * as constructor arguments. Invalidates iterators if reallocation is needed. + * (`back_free_capacity() == 0`) + * + * **Requires**: `T` shall be [EmplaceConstructible] from `args` and [MoveInsertable] into `*this`, + * and [MoveAssignable]. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `back_free_capacity() > 0`) + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + */ + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + BOOST_CONTAINER_FORCEINLINE void emplace_back(Args&&... args) + { + if (this->back_free_capacity()){ + this->alloc_construct(m_.buffer + m_.back_idx, boost::forward(args)...); + ++m_.back_idx; + } + else { + this->emplace_reallocating_slow_path(false, size(), boost::forward(args)...); + } + BOOST_ASSERT(invariants_ok()); + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_EMPLACE_BACK(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE void emplace_back(BOOST_MOVE_UREF##N)\ + {\ + if (this->back_free_capacity()){\ + this->alloc_construct(m_.buffer + m_.back_idx BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ++m_.back_idx;\ + }\ + else {\ + this->emplace_reallocating_slow_path(false, size() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + BOOST_ASSERT(invariants_ok());\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_EMPLACE_BACK) + #undef BOOST_CONTAINER_DEVECTOR_EMPLACE_BACK + + #endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Pushes the copy of `x` to the back of the devector. + * Invalidates iterators if reallocation is needed. + * (`back_free_capacity() == 0`) + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `back_free_capacity() > 0`) + */ + void push_back(const T& x); + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Move constructs a new element at the back of the devector using `x`. + * Invalidates iterators if reallocation is needed. + * (`back_free_capacity() == 0`) + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee, not regarding the state of `x`. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `back_free_capacity() > 0`) + */ + void push_back(T&& x); + + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + #endif + + /** + * **Effects**: Removes the last element of `*this`. + * + * **Precondition**: `!empty()`. + * + * **Postcondition**: `back_free_capacity()` is incremented by 1. + * + * **Complexity**: Constant. + */ + void pop_back() BOOST_NOEXCEPT + { + BOOST_ASSERT(! empty()); + --m_.back_idx; + allocator_traits_type::destroy(get_allocator_ref(), m_.buffer + m_.back_idx); + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: Constructs a new element before the element pointed by `position`. + * The element is constructed in-place, using the perfect forwarded `args` + * as constructor arguments. Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [EmplaceConstructible], and [MoveInsertable] into `*this`, + * and [MoveAssignable]. + * + * **Returns**: Iterator pointing to the newly constructed element. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `*this`. + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + */ + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator emplace(const_iterator position, Args&&... args) + { + BOOST_ASSERT(position >= begin()); + BOOST_ASSERT(position <= end()); + + if (position == end() && back_free_capacity()) // fast path + { + this->alloc_construct(m_.buffer + m_.back_idx, boost::forward(args)...); + ++m_.back_idx; + return end() - 1; + } + else if (position == begin() && front_free_capacity()) // secondary fast path + { + this->alloc_construct(m_.buffer + (m_.front_idx - 1), boost::forward(args)...); + --m_.front_idx; + return begin(); + } + else + { + size_type new_elem_index = position - begin(); + return this->emplace_slow_path(new_elem_index, boost::forward(args)...); + } + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_EMPLACE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace(const_iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + BOOST_ASSERT(position >= begin());\ + BOOST_ASSERT(position <= end());\ + \ + if (position == end() && back_free_capacity()){\ + this->alloc_construct(m_.buffer + m_.back_idx BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ++m_.back_idx;\ + return end() - 1;\ + }\ + else if (position == begin() && front_free_capacity()){\ + this->alloc_construct(m_.buffer + m_.front_idx - 1 BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + --m_.front_idx;\ + return begin();\ + }\ + else{\ + size_type new_elem_index = position - begin();\ + return this->emplace_slow_path(new_elem_index BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_EMPLACE) + #undef BOOST_CONTAINER_DEVECTOR_EMPLACE + + #endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + /** + * **Effects**: Copy constructs a new element before the element pointed by `position`, + * using `x` as constructor argument. Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this` and and [CopyAssignable]. + * + * **Returns**: Iterator pointing to the newly constructed element. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `*this`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + iterator insert(const_iterator position, const T &x); + + /** + * **Effects**: Move constructs a new element before the element pointed by `position`, + * using `x` as constructor argument. Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this` and and [CopyAssignable]. + * + * **Returns**: Iterator pointing to the newly constructed element. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable` (not regarding the state of `x`), + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `*this`. + * + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + iterator insert(const_iterator position, T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator) + #endif + + /** + * **Effects**: Copy constructs `n` elements before the element pointed by `position`, + * using `x` as constructor argument. Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this` and and [CopyAssignable]. + * + * **Returns**: Iterator pointing to the first inserted element, or `position`, if `n` is zero. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `*this` and `n`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + iterator insert(const_iterator position, size_type n, const T& x) + { + cvalue_iterator first(x, n); + cvalue_iterator last = first + n; + return insert_range(position, first, last); + } + + /** + * **Effects**: Copy constructs elements before the element pointed by position + * using each element in the rage pointed by `first` and `last` as constructor arguments. + * Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [EmplaceConstructible] into `*this` from `*first`. If the specified iterator + * does not meet the forward iterator requirements, `T` shall also be [MoveInsertable] into `*this` + * and [MoveAssignable]. + * + * **Precondition**: `first` and `last` are not iterators into `*this`. + * + * **Returns**: Iterator pointing to the first inserted element, or `position`, if `first == last`. + * + * **Complexity**: Linear in the size of `*this` and `N` (where `N` is the distance between `first` and `last`). + * Makes only `N` calls to the constructor of `T` and no reallocations if iterators `first` and `last` + * are of forward, bidirectional, or random access categories. It makes 2N calls to the copy constructor of `T` + * and allocates memory twice at most if they are just input iterators. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable`, Basic exception guarantee otherwise. + * + * **Remarks**: Each iterator in the range `[first,last)` shall be dereferenced exactly once, + * unless an exception is thrown. + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + */ + template + iterator insert(const_iterator position, InputIterator first, InputIterator last + //Input iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_not_input_iterator + >::type * = 0) + ) + { + if (position == end()) + { + size_type insert_index = size(); + + for (; first != last; ++first) + { + this->emplace_back(*first); + } + + return begin() + insert_index; + } + else + { + const size_type insert_index = static_cast(position - this->cbegin()); + const size_type old_size = static_cast(this->size()); + + for (; first != last; ++first) { + this->emplace_back(*first); + } + iterator rit (this->begin() + insert_index); + boost::movelib::rotate_gcd(rit, this->begin() + old_size, this->begin() + this->size()); + return rit; + } + } + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + iterator insert(const_iterator position, ForwardIterator first, ForwardIterator last + //Other iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_input_iterator + >::type * = 0) + ) + { + return insert_range(position, first, last); + } + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** **Equivalent to**: `insert(position, il.begin(), il.end())` */ + iterator insert(const_iterator position, std::initializer_list il) + { + return insert_range(position, il.begin(), il.end()); + } + #endif + + /** + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + * + * **Effects**: Destroys the element pointed by `position` and removes it from the devector. + * Invalidates iterators. + * + * **Requires**: `T` shall be [MoveAssignable]. + * + * **Precondition**: `position` must be in the range of `[begin(), end())`. + * + * **Returns**: Iterator pointing to the element immediately following the erased element + * prior to its erasure. If no such element exists, `end()` is returned. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowAssignable`, + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in half the size of `*this`. + */ + iterator erase(const_iterator position) + { + return erase(position, position + 1); + } + + /** + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + * + * **Effects**: Destroys the range `[first,last)` and removes it from the devector. + * Invalidates iterators. + * + * **Requires**: `T` shall be [MoveAssignable]. + * + * **Precondition**: `[first,last)` must be in the range of `[begin(), end())`. + * + * **Returns**: Iterator pointing to the element pointed to by `last` prior to any elements + * being erased. If no such element exists, `end()` is returned. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowAssignable`, + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in half the size of `*this` + * plus the distance between `first` and `last`. + */ + iterator erase(const_iterator first, const_iterator last) + { + iterator nc_first = begin() + (first - begin()); + iterator nc_last = begin() + (last - begin()); + return erase(nc_first, nc_last); + } + + /** + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + * + * **Effects**: Destroys the range `[first,last)` and removes it from the devector. + * Invalidates iterators. + * + * **Requires**: `T` shall be [MoveAssignable]. + * + * **Precondition**: `[first,last)` must be in the range of `[begin(), end())`. + * + * **Returns**: Iterator pointing to the element pointed to by `last` prior to any elements + * being erased. If no such element exists, `end()` is returned. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowAssignable`, + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in half the size of `*this`. + */ + iterator erase(iterator first, iterator last) + { + size_type front_distance = last - begin(); + size_type back_distance = end() - first; + size_type n = boost::container::iterator_distance(first, last); + + if (front_distance < back_distance) + { + // move n to the right + boost::container::move_backward(begin(), first, last); + + for (iterator i = begin(); i != begin() + n; ++i) + { + allocator_traits_type::destroy(get_allocator_ref(), i); + } + //n is always less than max stored_size_type + m_.set_front_idx(m_.front_idx + n); + + BOOST_ASSERT(invariants_ok()); + return last; + } + else { + // move n to the left + boost::container::move(last, end(), first); + + for (iterator i = end() - n; i != end(); ++i) + { + allocator_traits_type::destroy(get_allocator_ref(), i); + } + //n is always less than max stored_size_type + m_.set_back_idx(m_.back_idx - n); + + BOOST_ASSERT(invariants_ok()); + return first; + } + } + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: exchanges the contents of `*this` and `b`. + * + * **Requires**: instances of `T` must be swappable by unqualified call of `swap` + * and `T` must be [MoveInsertable] into `*this`. + * + * **Precondition**: The allocators should allow propagation or should compare equal. + * + * **Exceptions**: Basic exceptions guarantee if not `noexcept`. + * + * **Complexity**: Constant. + */ + void swap(devector& b) + BOOST_NOEXCEPT_IF( allocator_traits_type::propagate_on_container_swap::value + || allocator_traits_type::is_always_equal::value) + { + BOOST_CONSTEXPR_OR_CONST bool propagate_alloc = allocator_traits_type::propagate_on_container_swap::value; + BOOST_ASSERT(propagate_alloc || get_allocator_ref() == b.get_allocator_ref()); // else it's undefined behavior + + swap_big_big(*this, b); + + // swap indices + boost::adl_move_swap(m_.front_idx, b.m_.front_idx); + boost::adl_move_swap(m_.back_idx, b.m_.back_idx); + + //And now swap the allocator + dtl::swap_alloc(this->get_allocator_ref(), b.get_allocator_ref(), dtl::bool_()); + + BOOST_ASSERT( invariants_ok()); + BOOST_ASSERT(b.invariants_ok()); + } + + /** + * **Effects**: Destroys all elements in the devector. + * Invalidates all references, pointers and iterators to the + * elements of the devector. + * + * **Postcondition**: `empty() && front_free_capacity() == 0 + * && back_free_capacity() == old capacity`. + * + * **Complexity**: Linear in the size of `*this`. + * + * **Remarks**: Does not free memory. + */ + void clear() BOOST_NOEXCEPT + { + destroy_elements(begin(), end()); + m_.front_idx = m_.back_idx = 0; + } + + BOOST_CONTAINER_FORCEINLINE friend bool operator==(const devector& x, const devector& y) + { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const devector& x, const devector& y) + { return !(x == y); } + + friend bool operator< (const devector& x, const devector& y) + { return boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator>(const devector& x, const devector& y) + { return y < x; } + + BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const devector& x, const devector& y) + { return !(y < x); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const devector& x, const devector& y) + { return !(x < y); } + + BOOST_CONTAINER_FORCEINLINE friend void swap(devector& x, devector& y) + { x.swap(y); } + + private: + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + T* raw_begin() BOOST_NOEXCEPT + { return boost::movelib::to_raw_pointer(m_.buffer) + m_.front_idx; } + + T* raw_end() BOOST_NOEXCEPT + { return boost::movelib::to_raw_pointer(m_.buffer) + m_.back_idx; } + + + template + BOOST_CONTAINER_FORCEINLINE void priv_push_front(BOOST_FWD_REF(U) u) + { + this->emplace_front(boost::forward(u)); + } + + template + BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u) + { + this->emplace_back(boost::forward(u)); + } + + template + BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator pos, BOOST_FWD_REF(U) u) + { + return this->emplace(pos, boost::forward(u)); + } + + // allocator_type wrappers + + BOOST_CONTAINER_FORCEINLINE allocator_type& get_allocator_ref() BOOST_NOEXCEPT + { + return static_cast(m_); + } + + BOOST_CONTAINER_FORCEINLINE const allocator_type& get_allocator_ref() const BOOST_NOEXCEPT + { + return static_cast(m_); + } + + pointer allocate(size_type capacity) + { + //First detect overflow on smaller stored_size_types + if (capacity > stored_size_type(-1)){ + boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); + } + //(clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + ++m_.capacity_alloc_count; + #endif // BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + return allocator_traits_type::allocate(get_allocator_ref(), capacity); + } + + void destroy_elements(pointer begin, pointer end) + { + for (; begin != end; ++begin) + { + allocator_traits_type::destroy(get_allocator_ref(), begin); + } + } + + void deallocate_buffer() + { + if (m_.buffer) + { + allocator_traits_type::deallocate(get_allocator_ref(), m_.buffer, m_.capacity); + } + } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + BOOST_CONTAINER_FORCEINLINE void alloc_construct(pointer dst, Args&&... args) + { + allocator_traits_type::construct( + get_allocator_ref(), + dst, + boost::forward(args)... + ); + } + + template + void construct_n(pointer buffer, size_type n, Args&&... args) + { + detail::construction_guard ctr_guard(buffer, get_allocator_ref()); + guarded_construct_n(buffer, n, ctr_guard, boost::forward(args)...); + ctr_guard.release(); + } + + template + void guarded_construct_n(pointer buffer, size_type n, detail::construction_guard& ctr_guard, Args&&... args) + { + for (size_type i = 0; i < n; ++i) { + this->alloc_construct(buffer + i, boost::forward(args)...); + ctr_guard.extend(); + } + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_ALLOC_CONSTRUCT(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE void alloc_construct(pointer dst BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + allocator_traits_type::construct(\ + get_allocator_ref(), dst BOOST_MOVE_I##N BOOST_MOVE_FWD##N );\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void construct_n(pointer buffer, size_type n BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + detail::construction_guard ctr_guard(buffer, get_allocator_ref());\ + guarded_construct_n(buffer, n, ctr_guard BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ctr_guard.release();\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void guarded_construct_n(pointer buffer, size_type n, detail::construction_guard& ctr_guard BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + for (size_type i = 0; i < n; ++i) {\ + this->alloc_construct(buffer + i BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ctr_guard.extend();\ + }\ + } + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_ALLOC_CONSTRUCT) + #undef BOOST_CONTAINER_DEVECTOR_ALLOC_CONSTRUCT + + #endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + size_type front_capacity() const + { + return m_.back_idx; + } + + size_type back_capacity() const + { + return m_.capacity - m_.front_idx; + } + + size_type calculate_new_capacity(size_type requested_capacity) + { + size_type max = allocator_traits_type::max_size(this->get_allocator_ref()); + (clamp_by_stored_size_type)(max, stored_size_type()); + const size_type remaining_additional_cap = max - size_type(m_.capacity); + const size_type min_additional_cap = requested_capacity - size_type(m_.capacity); + if ( remaining_additional_cap < min_additional_cap ) + boost::container::throw_length_error("devector: get_next_capacity, max size exceeded"); + + return growth_factor_type()( size_type(m_.capacity), min_additional_cap, max); + } + + void buffer_move_or_copy(pointer dst) + { + detail::construction_guard guard(dst, get_allocator_ref()); + + buffer_move_or_copy(dst, guard); + + guard.release(); + } + + void buffer_move_or_copy(pointer dst, detail::construction_guard& guard) + { + opt_move_or_copy(begin(), end(), dst, guard); + + destroy_elements(data(), data() + size()); + deallocate_buffer(); + } + + void opt_move_or_copy(pointer begin, pointer end, pointer dst) + { + typedef typename dtl::if_c + < boost::move_detail::is_nothrow_copy_constructible::value || boost::is_nothrow_move_constructible::value + , detail::null_construction_guard + , detail::construction_guard + >::type guard_t; + + guard_t guard(dst, get_allocator_ref()); + + opt_move_or_copy(begin, end, dst, guard); + + guard.release(); + } + + template + void opt_move_or_copy(pointer begin, pointer end, pointer dst, Guard& guard) + { + // if trivial copy and default allocator, memcpy + boost::container::uninitialized_move_alloc(get_allocator_ref(), begin, end, dst); + guard.extend(); + } + + template + void opt_copy(Iterator begin, Iterator end, pointer dst) + { + typedef typename dtl::if_c + < boost::move_detail::is_nothrow_copy_constructible::value + , detail::null_construction_guard + , detail::construction_guard + >::type guard_t; + + guard_t guard(dst, get_allocator_ref()); + + opt_copy(begin, end, dst, guard); + + guard.release(); + } + + template + void opt_copy(Iterator begin, Iterator end, pointer dst, Guard& guard) + { + while (begin != end) + { + this->alloc_construct(dst++, *begin++); + guard.extend(); + } + } + + template + void opt_copy(const_pointer begin, const_pointer end, pointer dst, Guard& guard) + { + // if trivial copy and default allocator, memcpy + boost::container::uninitialized_copy_alloc(get_allocator_ref(), begin, end, dst); + guard.extend(); + } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + template + void resize_front_impl(size_type sz , Args&&... args) + { + if (sz > size()) + { + const size_type n = sz - size(); + + if (sz <= front_capacity()) + { + construct_n(m_.buffer + m_.front_idx - n, n, boost::forward(args)...); + m_.set_front_idx(m_.front_idx - n); + } + else + { + resize_front_slow_path(sz, n, boost::forward(args)...); + } + } + else { + while (this->size() > sz) + { + this->pop_front(); + } + } + } + + template + void resize_front_slow_path(size_type sz, size_type n, Args&&... args) + { + const size_type new_capacity = calculate_new_capacity(sz + back_free_capacity()); + pointer new_buffer = allocate(new_capacity); + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + const size_type new_old_elem_index = new_capacity - size(); + const size_type new_elem_index = new_old_elem_index - n; + + detail::construction_guard guard(new_buffer + new_elem_index, get_allocator_ref()); + guarded_construct_n(new_buffer + new_elem_index, n, guard, boost::forward(args)...); + + buffer_move_or_copy(new_buffer + new_old_elem_index, guard); + + guard.release(); + new_buffer_guard.release(); + + m_.buffer = new_buffer; + m_.set_capacity(new_capacity); + m_.set_back_idx(new_old_elem_index + m_.back_idx - m_.front_idx); + m_.set_front_idx(new_elem_index); + } + + template + void resize_back_impl(size_type sz, Args&&... args) + { + if (sz > size()) + { + const size_type n = sz - size(); + + if (sz <= back_capacity()) + { + construct_n(m_.buffer + m_.back_idx, n, boost::forward(args)...); + m_.set_back_idx(m_.back_idx + n); + } + else + { + resize_back_slow_path(sz, n, boost::forward(args)...); + } + } + else + { + while (size() > sz) + { + pop_back(); + } + } + } + + template + void resize_back_slow_path(size_type sz, size_type n, Args&&... args) + { + const size_type new_capacity = calculate_new_capacity(sz + front_free_capacity()); + pointer new_buffer = allocate(new_capacity); + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + detail::construction_guard guard(new_buffer + m_.back_idx, get_allocator_ref()); + guarded_construct_n(new_buffer + m_.back_idx, n, guard, boost::forward(args)...); + + buffer_move_or_copy(new_buffer + m_.front_idx); + + guard.release(); + new_buffer_guard.release(); + + m_.buffer = new_buffer; + m_.set_capacity(new_capacity); + m_.set_back_idx(m_.back_idx + n); + } + + template + iterator emplace_slow_path(size_type new_elem_index, Args&&... args) + { + pointer position = begin() + new_elem_index; + + // prefer moving front to access memory forward if there are less elems to move + bool prefer_move_front = new_elem_index <= size()/2; + + if (front_free_capacity() && (!back_free_capacity() || prefer_move_front)) + { + BOOST_ASSERT(size() >= 1); + + // move things closer to the front a bit + + // avoid invalidating any reference in args later + T tmp(boost::forward(args)...); + + // construct at front - 1 from front (no guard) + this->alloc_construct(begin() - 1, boost::move(*begin())); + + // move front half left + boost::move(begin() + 1, position, begin()); + --m_.front_idx; + + // move assign new elem before pos + --position; + *position = boost::move(tmp); + + return position; + } + else if (back_free_capacity()) { + BOOST_ASSERT(size() >= 1); + + // move things closer to the end a bit + + // avoid invalidating any reference in args later + T tmp(boost::forward(args)...); + + // construct at back + 1 from back (no guard) + this->alloc_construct(end(), boost::move(back())); + + // move back half right + boost::container::move_backward(position, end() - 1, end()); + ++m_.back_idx; + + // move assign new elem to pos + *position = boost::move(tmp); + + return position; + } + else + { + return emplace_reallocating_slow_path(prefer_move_front, new_elem_index, boost::forward(args)...); + } + } + + template + pointer emplace_reallocating_slow_path(bool make_front_free, size_type new_elem_index, Args&&... args) + { + // reallocate + size_type new_capacity = calculate_new_capacity(capacity() + 1); + pointer new_buffer = allocate(new_capacity); + + // guard allocation + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + size_type new_front_index = (make_front_free) + ? new_capacity - back_free_capacity() - size() - 1 + : m_.front_idx; + + iterator new_begin = new_buffer + new_front_index; + iterator new_position = new_begin + new_elem_index; + iterator old_position = begin() + new_elem_index; + + // construct new element (and guard it) + this->alloc_construct(new_position, boost::forward(args)...); + + detail::construction_guard second_half_guard(new_position, get_allocator_ref()); + second_half_guard.extend(); + + // move front-pos (possibly guarded) + detail::construction_guard first_half_guard(new_begin, get_allocator_ref()); + opt_move_or_copy(begin(), old_position, new_begin, first_half_guard); + + // move pos+1-end (possibly guarded) + opt_move_or_copy(old_position, end(), new_position + 1, second_half_guard); + + // cleanup + destroy_elements(begin(), end()); + deallocate_buffer(); + + // release alloc and other guards + second_half_guard.release(); + first_half_guard.release(); + new_buffer_guard.release(); + + // rebind members + m_.set_capacity(new_capacity); + m_.buffer = new_buffer; + m_.set_back_idx(new_front_index + size() + 1); + m_.set_front_idx(new_front_index); + + return new_position; + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_SLOW_PATH(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void resize_front_impl(size_type sz BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + if (sz > size())\ + {\ + const size_type n = sz - size();\ + if (sz <= front_capacity()){\ + construct_n(m_.buffer + m_.front_idx - n, n BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + m_.set_front_idx(m_.front_idx - n);\ + }\ + else\ + {\ + resize_front_slow_path(sz, n BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + }\ + else {\ + while (this->size() > sz)\ + {\ + this->pop_front();\ + }\ + }\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void resize_front_slow_path(size_type sz, size_type n BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + const size_type new_capacity = calculate_new_capacity(sz + back_free_capacity());\ + pointer new_buffer = allocate(new_capacity);\ + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref());\ + \ + const size_type new_old_elem_index = new_capacity - size();\ + const size_type new_elem_index = new_old_elem_index - n;\ + \ + detail::construction_guard guard(new_buffer + new_elem_index, get_allocator_ref());\ + guarded_construct_n(new_buffer + new_elem_index, n, guard BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + \ + buffer_move_or_copy(new_buffer + new_old_elem_index, guard);\ + \ + guard.release();\ + new_buffer_guard.release();\ + m_.buffer = new_buffer;\ + m_.set_capacity(new_capacity);\ + m_.set_back_idx(new_old_elem_index + m_.back_idx - m_.front_idx);\ + m_.set_front_idx(new_elem_index);\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void resize_back_impl(size_type sz BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + if (sz > size())\ + {\ + const size_type n = sz - size();\ + \ + if (sz <= back_capacity())\ + {\ + construct_n(m_.buffer + m_.back_idx, n BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + m_.set_back_idx(m_.back_idx + n);\ + }\ + else\ + {\ + resize_back_slow_path(sz, n BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + }\ + else\ + {\ + while (size() > sz)\ + {\ + pop_back();\ + }\ + }\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void resize_back_slow_path(size_type sz, size_type n BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + const size_type new_capacity = calculate_new_capacity(sz + front_free_capacity());\ + pointer new_buffer = allocate(new_capacity);\ + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref());\ + \ + detail::construction_guard guard(new_buffer + m_.back_idx, get_allocator_ref());\ + guarded_construct_n(new_buffer + m_.back_idx, n, guard BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + \ + buffer_move_or_copy(new_buffer + m_.front_idx);\ + \ + guard.release();\ + new_buffer_guard.release();\ + \ + m_.buffer = new_buffer;\ + m_.set_capacity(new_capacity);\ + m_.set_back_idx(m_.back_idx + n);\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace_slow_path(size_type new_elem_index BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + pointer position = begin() + new_elem_index;\ + \ + bool prefer_move_front = new_elem_index <= size()/2;\ + \ + if (front_free_capacity() && (!back_free_capacity() || prefer_move_front))\ + {\ + BOOST_ASSERT(size() >= 1);\ + typename dtl::aligned_storage::value>::type v;\ + T *vp = reinterpret_cast(v.data);\ + allocator_traits_type::construct(get_stored_allocator(), vp BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + T &tmp = *vp;\ + dtl::value_destructor on_exit(get_stored_allocator(), tmp); (void)on_exit;\ + \ + this->alloc_construct(begin() - 1, boost::move(*begin()));\ + boost::move(begin() + 1, position, begin());\ + --m_.front_idx;\ + --position;\ + *position = boost::move(tmp);\ + return position;\ + }\ + else if (back_free_capacity()) {\ + BOOST_ASSERT(size() >= 1);\ + typename dtl::aligned_storage::value>::type v;\ + T *vp = reinterpret_cast(v.data);\ + allocator_traits_type::construct(get_stored_allocator(), vp BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + T &tmp = *vp;\ + dtl::value_destructor on_exit(get_stored_allocator(), tmp); (void)on_exit;\ + this->alloc_construct(end(), boost::move(back()));\ + boost::container::move_backward(position, end() - 1, end());\ + ++m_.back_idx;\ + *position = boost::move(tmp);\ + return position;\ + }\ + else {\ + return emplace_reallocating_slow_path(prefer_move_front, new_elem_index BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + pointer emplace_reallocating_slow_path(bool make_front_free, size_type new_elem_index BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + size_type new_capacity = calculate_new_capacity(capacity() + 1);\ + pointer new_buffer = allocate(new_capacity);\ + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref());\ + size_type new_front_index = (make_front_free)\ + ? new_capacity - back_free_capacity() - size() - 1\ + : m_.front_idx;\ + iterator new_begin = new_buffer + new_front_index;\ + iterator new_position = new_begin + new_elem_index;\ + iterator old_position = begin() + new_elem_index;\ + this->alloc_construct(new_position BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + detail::construction_guard second_half_guard(new_position, get_allocator_ref());\ + second_half_guard.extend();\ + detail::construction_guard first_half_guard(new_begin, get_allocator_ref());\ + opt_move_or_copy(begin(), old_position, new_begin, first_half_guard);\ + opt_move_or_copy(old_position, end(), new_position + 1, second_half_guard);\ + destroy_elements(begin(), end());\ + deallocate_buffer();\ + second_half_guard.release();\ + first_half_guard.release();\ + new_buffer_guard.release();\ + m_.set_capacity(new_capacity);\ + m_.buffer = new_buffer;\ + m_.set_back_idx(new_front_index + size() + 1);\ + m_.set_front_idx(new_front_index);\ + return new_position;\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_SLOW_PATH) + #undef BOOST_CONTAINER_DEVECTOR_SLOW_PATH + + #endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) +/* + void unsafe_uninitialized_grow_front(size_type n) + { + BOOST_ASSERT(n >= size()); + + size_type need = n - size(); + + if (need > front_free_capacity()) + { + reallocate_at(n + back_free_capacity(), need); + } + + m_.set_front_idx(m_.front_idx - need); + } + + void unsafe_uninitialized_shrink_front(size_type n) + { + BOOST_ASSERT(n <= size()); + + size_type doesnt_need = size() - n; + m_.set_front_idx(m_.front_idx + doesnt_need); + } + + void unsafe_uninitialized_grow_back(size_type n) + { + BOOST_ASSERT(n >= size()); + + size_type need = n - size(); + + if (need > back_free_capacity()) + { + reallocate_at(n + front_free_capacity(), front_free_capacity()); + } + + m_.set_back_idx(m_.back_idx + need); + } + + void unsafe_uninitialized_shrink_back(size_type n) + { + BOOST_ASSERT(n <= size()); + + size_type doesnt_need = size() - n; + m_.set_back_idx(m_.back_idx - doesnt_need); + } +*/ + + void reallocate_at(size_type new_capacity, size_type buffer_offset) + { + pointer new_buffer = allocate(new_capacity); + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + buffer_move_or_copy(new_buffer + buffer_offset); + + new_buffer_guard.release(); + + m_.buffer = new_buffer; + //Safe cast, allocate() will handle stored_size_type overflow + m_.set_capacity(new_capacity); + m_.set_back_idx(m_.back_idx - m_.front_idx + buffer_offset); + m_.set_front_idx(buffer_offset); + + BOOST_ASSERT(invariants_ok()); + } + + template + iterator insert_range(const_iterator position, ForwardIterator first, ForwardIterator last) + { + size_type n = boost::container::iterator_distance(first, last); + + if (position == end() && back_free_capacity() >= n) {// fast path + iterator r(this->end()); + boost::container::uninitialized_copy_alloc(get_allocator_ref(), first, last, this->raw_end()); + m_.set_back_idx(m_.back_idx + n); + return r; + } + else if (position == begin() && front_free_capacity() >= n) { // secondary fast path + boost::container::uninitialized_copy_alloc(get_allocator_ref(), first, last, this->raw_begin() - n); + m_.set_front_idx(m_.front_idx - n); + return begin(); + } + else { + return insert_range_slow_path(position, first, last); + } + } + + template + iterator insert_range_slow_path(const_iterator position, ForwardIterator first, ForwardIterator last) + { + size_type n = boost::container::iterator_distance(first, last); + size_type index = position - begin(); + + if (front_free_capacity() + back_free_capacity() >= n) { + // if we move enough, it can be done without reallocation + + iterator middle = begin() + index; + n -= insert_range_slow_path_near_front(middle, first, n); + + if (n) { + insert_range_slow_path_near_back(middle, first, n); + } + + BOOST_ASSERT(first == last); + return begin() + index; + } + else { + const bool prefer_move_front = 2 * index <= size(); + return insert_range_reallocating_slow_path(prefer_move_front, index, first, n); + } + } + + template + size_type insert_range_slow_path_near_front(iterator position, Iterator& first, size_type n) + { + size_type n_front = dtl::min_value(front_free_capacity(), n); + iterator new_begin = begin() - n_front; + iterator ctr_pos = new_begin; + detail::construction_guard ctr_guard(ctr_pos, get_allocator_ref()); + + while (ctr_pos != begin()) { + this->alloc_construct(ctr_pos++, *(first++)); + ctr_guard.extend(); + } + + boost::movelib::rotate_gcd(new_begin, ctr_pos, position); + m_.set_front_idx(m_.front_idx - n_front); + + ctr_guard.release(); + + BOOST_ASSERT(invariants_ok()); + + return n_front; + } + + template + size_type insert_range_slow_path_near_back(iterator position, Iterator& first, size_type n) + { + const size_type n_back = dtl::min_value(back_free_capacity(), n); + iterator ctr_pos = end(); + + detail::construction_guard ctr_guard(ctr_pos, get_allocator_ref()); + + for (size_type i = 0; i < n_back; ++i) { + this->alloc_construct(ctr_pos++, *first++); + ctr_guard.extend(); + } + + boost::movelib::rotate_gcd(position, end(), ctr_pos); + m_.set_back_idx(m_.back_idx + n_back); + + ctr_guard.release(); + + BOOST_ASSERT(invariants_ok()); + + return n_back; + } + + template + iterator insert_range_reallocating_slow_path + (bool make_front_free, size_type new_elem_index, Iterator elems, size_type n) + { + // reallocate + const size_type new_capacity = calculate_new_capacity(capacity() + n); + pointer new_buffer = allocate(new_capacity); + + // guard allocation + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + const size_type new_front_index = (make_front_free) + ? new_capacity - back_free_capacity() - size() - n + : m_.front_idx; + + const iterator new_begin = new_buffer + new_front_index; + const iterator new_position = new_begin + new_elem_index; + const iterator old_position = begin() + new_elem_index; + + // construct new element (and guard it) + iterator second_half_position = new_position; + detail::construction_guard second_half_guard(second_half_position, get_allocator_ref()); + + for (size_type i = 0; i < n; ++i) { + this->alloc_construct(second_half_position++, *(elems++)); + second_half_guard.extend(); + } + + // move front-pos (possibly guarded) + detail::construction_guard first_half_guard(new_begin, get_allocator_ref()); + opt_move_or_copy(begin(), old_position, new_begin, first_half_guard); + + // move pos+1-end (possibly guarded) + opt_move_or_copy(old_position, end(), second_half_position, second_half_guard); + + // cleanup + destroy_elements(begin(), end()); + deallocate_buffer(); + + // release alloc and other guards + second_half_guard.release(); + first_half_guard.release(); + new_buffer_guard.release(); + + // rebind members + m_.set_capacity(new_capacity); + m_.buffer = new_buffer; + m_.set_back_idx(new_front_index + size() + n); + m_.set_front_idx(new_front_index); + + return new_position; + } + + template + void construct_from_range(Iterator begin, Iterator end) + { + allocation_guard buffer_guard(m_.buffer, m_.capacity, get_allocator_ref()); + opt_copy(begin, end, m_.buffer); + + buffer_guard.release(); + } + + template + void allocate_and_copy_range(ForwardIterator first, ForwardIterator last) + { + size_type n = boost::container::iterator_distance(first, last); + + pointer new_buffer = n ? allocate(n) : pointer(); + allocation_guard new_buffer_guard(new_buffer, n, get_allocator_ref()); + + opt_copy(first, last, new_buffer); + + destroy_elements(begin(), end()); + deallocate_buffer(); + + m_.set_capacity(n); + m_.buffer = new_buffer; + m_.front_idx = 0; + m_.set_back_idx(n); + + new_buffer_guard.release(); + } + + static void swap_big_big(devector& a, devector& b) BOOST_NOEXCEPT + { + boost::adl_move_swap(a.m_.capacity, b.m_.capacity); + boost::adl_move_swap(a.m_.buffer, b.m_.buffer); + } + + template + void overwrite_buffer_impl(ForwardIterator first, ForwardIterator last, dtl::true_) + { + const size_type n = boost::container::iterator_distance(first, last); + + BOOST_ASSERT(capacity() >= n); + boost::container::uninitialized_copy_alloc_n + ( get_allocator_ref(), boost::movelib::iterator_to_raw_pointer(first) + , n, boost::movelib::iterator_to_raw_pointer(m_.buffer)); + m_.front_idx = 0; + m_.set_back_idx(n); + } + + template + InputIterator overwrite_buffer_impl(InputIterator first, InputIterator last, dtl::false_) + { + pointer pos = m_.buffer; + detail::construction_guard front_guard(pos, get_allocator_ref()); + + while (first != last && pos != begin()) { + this->alloc_construct(pos++, *first++); + front_guard.extend(); + } + + while (first != last && pos != end()) { + *pos++ = *first++; + } + + detail::construction_guard back_guard(pos, get_allocator_ref()); + + iterator capacity_end = m_.buffer + capacity(); + while (first != last && pos != capacity_end) { + this->alloc_construct(pos++, *first++); + back_guard.extend(); + } + + pointer destroy_after = dtl::min_value(dtl::max_value(begin(), pos), end()); + destroy_elements(destroy_after, end()); + + front_guard.release(); + back_guard.release(); + + m_.front_idx = 0; + m_.set_back_idx(pos - begin()); + return first; + } + + template + BOOST_CONTAINER_FORCEINLINE void overwrite_buffer(ForwardIterator first, ForwardIterator last) + { + this->overwrite_buffer_impl(first, last, + dtl::bool_::value>()); + } + + bool invariants_ok() + { + return (!m_.capacity || m_.buffer) + && m_.front_idx <= m_.back_idx + && m_.back_idx <= m_.capacity; + } + + struct impl : allocator_type + { + impl() + : allocator_type(), buffer(), front_idx(), back_idx(), capacity() + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + , capacity_alloc_count() + #endif + {} + + explicit impl(const allocator_type &a) + : allocator_type(a), buffer(), front_idx(), back_idx(), capacity() + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + , capacity_alloc_count() + #endif + {} + + impl(const allocator_type &a, pointer p, size_type f, size_type b, size_type c) + : allocator_type(a), buffer(p) + //static cast sizes, as the allocation function will take care of overflows + , front_idx(static_cast(f)) + , back_idx(static_cast(b)) + , capacity(static_cast(c)) + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + , capacity_alloc_count() + #endif + {} + + impl(BOOST_RV_REF(allocator_type) a, pointer p, size_type f, size_type b, size_type c) + : allocator_type(boost::move(a)), buffer(p) + //static cast sizes, as the allocation function will take care of overflows + , front_idx(static_cast(f)) + , back_idx(static_cast(b)) + , capacity(static_cast(c)) + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + , capacity_alloc_count() + #endif + {} + + void set_back_idx(size_type bi) + { back_idx = static_cast(bi);} + + void set_front_idx(size_type fi) + { front_idx = static_cast(fi);} + + void set_capacity(size_type c) + { capacity = static_cast(c);} + + pointer buffer; + stored_size_type front_idx; + stored_size_type back_idx; + stored_size_type capacity; + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + size_type capacity_alloc_count; + #endif + } m_; + + + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + public: + void reset_alloc_stats() + { + m_.capacity_alloc_count = 0; + } + + size_type get_alloc_count() const + { + return m_.capacity_alloc_count; + } + + #endif // ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +}; + +}} // namespace boost::container + +#include + +#endif // BOOST_CONTAINER_DEVECTOR_HPP diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index ce85668..893c0df 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -215,6 +215,13 @@ class default_next_capacity; typedef vector_opt vector_null_opt; +template +struct devector_opt + : vector_opt +{}; + +typedef devector_opt devector_null_opt; + #else //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //!This growth factor argument specifies that the container should increase it's @@ -442,6 +449,40 @@ using static_vector_options_t = typename boost::container::static_vector_options #endif +//! Helper metafunction to combine options into a single type to be used +//! by \c boost::container::devector. +//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size +#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct devector_options +{ + /// @cond + typedef typename ::boost::intrusive::pack_options + < devector_null_opt, + #if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + typedef devector_opt< typename packed_options::growth_factor_type + , typename packed_options::stored_size_type> implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +//! Helper alias metafunction to combine options into a single type to be used +//! by \c boost::container::devector. +//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size +template +using devector_options_t = typename boost::container::devector_options::type; + +#endif //////////////////////////////////////////////////////////////// // diff --git a/include/boost/container/pmr/devector.hpp b/include/boost/container/pmr/devector.hpp new file mode 100644 index 0000000..2ae9b0b --- /dev/null +++ b/include/boost/container/pmr/devector.hpp @@ -0,0 +1,51 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_PMR_VECTOR_HPP +#define BOOST_CONTAINER_PMR_VECTOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template < + typename T, + typename GrowthPolicy = growth_factor_60 +> +using devector = boost::container::devector >; + +#endif + +//! A portable metafunction to obtain a vector +//! that uses a polymorphic allocator +template < + typename T, + typename GrowthPolicy = growth_factor_60 +> +struct devector_of +{ + typedef boost::container::devector + < T, GrowthPolicy, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_VECTOR_HPP diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 7693348..5b97c4c 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -39,10 +39,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_set_test", "flat_set_t ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hash_table_test", "hash_table_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -383,10 +379,6 @@ Global {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 diff --git a/test/devector_options_test.cpp b/test/devector_options_test.cpp new file mode 100644 index 0000000..8c8e29f --- /dev/null +++ b/test/devector_options_test.cpp @@ -0,0 +1,121 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +using namespace boost::container; + +template +void test_stored_size_type_impl() +{ + DevectorType v; + typedef typename DevectorType::size_type size_type; + typedef typename DevectorType::value_type value_type; + size_type const max = Unsigned(-1); + v.resize(5); + v.resize(max); + BOOST_TEST_THROWS(v.resize(max+1), std::exception); + BOOST_TEST_THROWS(v.push_back(value_type(1)), std::exception); + BOOST_TEST_THROWS(v.insert(v.begin(), value_type(1)), std::exception); + BOOST_TEST_THROWS(v.emplace(v.begin(), value_type(1)),std::exception); + BOOST_TEST_THROWS(v.reserve(max+1), std::exception); + BOOST_TEST_THROWS(DevectorType v2(max+1), std::exception); +} + +template +void test_stored_size_type() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = devector_options_t< stored_size >; + #else + typedef typename devector_options + < stored_size >::type options_t; + #endif + + //Test first with a typical allocator + { + typedef devector, options_t> devector_t; + test_stored_size_type_impl(); + } + //Test with a V2 allocator + { + typedef devector, options_t> devector_t; + test_stored_size_type_impl(); + } +} + +void test_growth_factor_50() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = devector_options_t< growth_factor >; + #else + typedef devector_options + < growth_factor >::type options_t; + #endif + + devector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + old_capacity/2); +} + +void test_growth_factor_60() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = devector_options_t< growth_factor >; + #else + typedef devector_options + < growth_factor >::type options_t; + #endif + + devector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + 3*old_capacity/5); +} + +void test_growth_factor_100() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = devector_options_t< growth_factor >; + #else + typedef devector_options + < growth_factor >::type options_t; + #endif + + devector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == 2*old_capacity); +} + +int main() +{ + test_growth_factor_50(); + test_growth_factor_60(); + test_growth_factor_100(); + test_stored_size_type(); + test_stored_size_type(); + return ::boost::report_errors(); +} diff --git a/test/devector_test.cpp b/test/devector_test.cpp new file mode 100644 index 0000000..88ef964 --- /dev/null +++ b/test/devector_test.cpp @@ -0,0 +1,3932 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include // memcmp +#include +#include +#include +#include +#include +#include +#include +#include "dummy_test_allocator.hpp" +#include "propagate_allocator_test.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" + +#include + +#define BOOST_CONTAINER_DEVECTOR_ALLOC_STATS +#include +#undef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + +#include "test_util.hpp" +#include "test_elem.hpp" +#include "input_iterator.hpp" + +using namespace boost::container; + +struct boost_container_devector; + +#ifdef _MSC_VER + #pragma warning (push) + #pragma warning (disable : 4127) // conditional expression is constant +#endif + +namespace boost { +namespace container { +namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef devector type; + }; +}; + +}}} //namespace boost::container::test { + +struct different_growth_policy +{ + template + static SizeType new_capacity(SizeType capacity) + { + return (capacity) ? capacity * 4u : 32u; + } +}; + +// END HELPERS + +template void test_constructor_default() +{ + Devector a; + + BOOST_TEST(a.empty()); + BOOST_TEST(a.get_alloc_count() == 0u); + BOOST_TEST(a.capacity() == 0u); +} + +template void test_constructor_allocator() +{ + typename Devector::allocator_type alloc_template; + + Devector a(alloc_template); + + BOOST_TEST(a.empty()); + BOOST_TEST(a.get_alloc_count() == 0u); + BOOST_TEST(a.capacity() == 0u); +} + +template void test_constructor_reserve_only() +{ + { + Devector a(16, reserve_only_tag_t()); + BOOST_TEST(a.size() == 0u); + BOOST_TEST(a.capacity() >= 16u); + } + + { + Devector b(0, reserve_only_tag_t()); + BOOST_TEST(b.get_alloc_count() == 0u); + } +} + +template void test_constructor_reserve_only_front_back() +{ + { + Devector a(8, 8, reserve_only_tag_t()); + BOOST_TEST(a.size() == 0u); + BOOST_TEST(a.capacity() >= 16u); + + for (int i = 8; i; --i) + { + a.emplace_front(i); + } + + for (int i = 9; i < 17; ++i) + { + a.emplace_back(i); + } + + const int expected [] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() <= 1u); + } + + { + Devector b(0, 0, reserve_only_tag_t()); + BOOST_TEST(b.get_alloc_count() == 0u); + } +} + +template void test_constructor_n() +{ + typedef typename Devector::value_type T; + + { + Devector a(8); + const int expected [] = {0, 0, 0, 0, 0, 0, 0, 0}; + test_equal_range(a, expected); + } + + { + Devector b(0); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + BOOST_IF_CONSTEXPR (! boost::move_detail::is_nothrow_default_constructible::value) + { + test_elem_throw::on_ctor_after(4); + BOOST_TEST_THROWS(Devector(8), test_exception); + BOOST_TEST(test_elem_base::no_living_elem()); + test_elem_throw::do_not_throw(); + } +} + +template void test_constructor_n_copy_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + test_elem_throw::on_copy_after(4); + const T x(404); + BOOST_TEST_THROWS(Devector(8, x), test_exception); + test_elem_throw::do_not_throw(); +} + + +template void test_constructor_n_copy_throwing(dtl::false_) +{} + +template void test_constructor_n_copy() +{ + typedef typename Devector::value_type T; + { + const T x(9); + Devector a(8, x); + const int expected [] = {9, 9, 9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + } + + { + const T x(9); + Devector b(0, x); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + test_constructor_n_copy_throwing + (dtl::bool_::value>()); + + BOOST_TEST(test_elem_base::no_living_elem()); +} + +template void test_constructor_input_range() +{ + typedef typename Devector::value_type T; + { + devector expected; get_range >(16, expected); + devector input = expected; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a(input_begin, input_end); + BOOST_TEST(a == expected); + } + + { // empty range + devector input; + input_iterator input_begin = make_input_iterator(input, input.begin()); + + Devector b(input_begin, input_begin); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + BOOST_TEST(test_elem_base::no_living_elem()); +/* //if move_if_noexcept is implemented + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + devector input; get_range >(16, input); + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + test_elem_throw::on_copy_after(4); + + BOOST_TEST_THROWS(Devector c(input_begin, input_end), test_exception); + } + + BOOST_TEST(test_elem_base::no_living_elem()); +*/ +} + + +void test_constructor_forward_range_throwing(dtl::true_) +{} + +void test_constructor_forward_range_throwing(dtl::false_) +{} + +template void test_constructor_forward_range() +{ + typedef typename Devector::value_type T; + boost::container::list ncx; + ncx.emplace_back(1); + ncx.emplace_back(2); + ncx.emplace_back(3); + ncx.emplace_back(4); + ncx.emplace_back(5); + ncx.emplace_back(6); + ncx.emplace_back(7); + ncx.emplace_back(8); + const boost::container::list &x = ncx; + + { + Devector a(x.begin(), x.end()); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() <= 1u); + a.reset_alloc_stats(); + } + + { + Devector b(x.begin(), x.begin()); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + BOOST_IF_CONSTEXPR (! boost::move_detail::is_nothrow_copy_constructible::value) + { + test_elem_throw::on_copy_after(4); + BOOST_TEST_THROWS(Devector c(x.begin(), x.end()), test_exception); + test_elem_throw::do_not_throw(); + } +} + +template void test_constructor_pointer_range() +{ + typedef typename Devector::value_type T; + + boost::container::vector x; get_range >(8, x); + const T* xbeg = x.data(); + const T* xend = x.data() + x.size(); + + { + Devector a(xbeg, xend); + + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() <= 1u); + } + + { + Devector b(xbeg, xbeg); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + test_elem_throw::on_copy_after(4); + BOOST_TEST_THROWS(Devector c(xbeg, xend), test_exception); + test_elem_throw::do_not_throw(); + } +} + +template void test_copy_constructor() +{ + typedef typename Devector::value_type T; + + { + Devector a; + Devector b(a); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + { + Devector a; get_range(8, a); + Devector b(a); + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(b.get_alloc_count() <= 1u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + Devector a; get_range(8, a); + + test_elem_throw::on_copy_after(4); + BOOST_TEST_THROWS(Devector b(a), test_exception); + test_elem_throw::do_not_throw(); + } +} + +template void test_move_constructor() +{ + { // empty + Devector a; + Devector b(boost::move(a)); + + BOOST_TEST(a.empty()); + BOOST_TEST(b.empty()); + } + + { // maybe small + Devector a; get_range(1, 5, 5, 9, a); + Devector b(boost::move(a)); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + + // a is unspecified but valid state + a.clear(); + BOOST_TEST(a.empty()); + } + + { // big + Devector a; get_range(32, a); + Devector b(boost::move(a)); + + boost::container::vector expected; get_range >(32, expected); + test_equal_range(b, expected); + + // a is unspecified but valid state + a.clear(); + BOOST_TEST(a.empty()); + } +} + +template void test_destructor() +{ + Devector a; + + Devector b; get_range(3, b); +} + +template void test_assignment() +{ + typedef typename Devector::value_type T; + const typename Devector::size_type alloc_count = + boost::container::allocator_traits + < typename Devector::allocator_type >::propagate_on_container_copy_assignment::value; + + { // assign to empty (maybe small) + Devector a; + Devector c; get_range(6, c); + Devector &b = c; + + a = b; + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign from empty + Devector a; get_range(6, a); + const Devector b; + + a = b; + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + Devector c; get_range(6, c); + const Devector &b = c; + + a = b; + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + Devector c; get_range(6, c); + const Devector &b = c; + + a = b; + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == alloc_count); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + Devector c; get_range(6, c); + const Devector &b = c; + + a = b; + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == alloc_count); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + Devector c; get_range(12, c); + const Devector &b = c; + + a = b; + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == alloc_count); + } + + BOOST_IF_CONSTEXPR (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + Devector c; get_range(12, c); + const Devector &b = c; + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a = b, test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + + } +} + +template void test_move_assignment_throwing(dtl::true_) +// move should be used on the slow path +{ + Devector a; get_range(11, 15, 15, 19, a); + Devector b; get_range(6, b); + + test_elem_throw::on_copy_after(3); + a = boost::move(b); + test_elem_throw::do_not_throw(); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + + b.clear(); + test_equal_range(b); +} + +template void test_move_assignment_throwing(dtl::false_) +{} + +template void test_move_assignment() +{ + typedef typename Devector::value_type T; + + { // assign to empty (maybe small) + Devector a; + Devector b; get_range(6, b); + + a = boost::move(b); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + + // b is in unspecified but valid state + b.clear(); + test_equal_range(b); + } + + { // assign from empty + Devector a; get_range(6, a); + Devector b; + + a = boost::move(b); + + test_equal_range(a); + test_equal_range(b); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + Devector b; get_range(6, b); + + a = boost::move(b); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + + b.clear(); + test_equal_range(b); + } + + test_move_assignment_throwing + (boost::move_detail::bool_::value>()); +} + +template void test_il_assignment() +{ + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef typename Devector::value_type T; + + { // assign to empty (maybe small) + Devector a; + a = {1, 2, 3, 4, 5, 6 }; + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + + { // assign from empty + Devector a; get_range(6, a); + a = {}; + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a = {1, 2, 3, 4, 5, 6}; + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a = {1, 2, 3, 4, 5, 6}; + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a = {1, 2, 3, 4, 5, 6}; + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + + test_equal_range(a, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + + try + { + a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + BOOST_TEST(false); + } catch(const test_exception&) {} + test_elem_throw::do_not_throw(); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + #endif //#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +} + +template void test_assign_input_range() +{ + typedef typename Devector::value_type T; + + { // assign to empty, keep it small + devector expected; get_range(1, 13, 13, 25, expected); + devector input = expected; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; + a.reset_alloc_stats(); + a.assign(input_begin, input_end); + + BOOST_TEST(a == expected); + } + + { // assign to empty (maybe small) + devector input; get_range >(6, input); + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; + + a.assign(input_begin, input_end); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign from empty + devector input; get_range >(6, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + + Devector a; get_range(6, a); + a.assign(input_begin, input_begin); + + test_equal_range(a); + } + + { // assign to non-empty + devector input; get_range >(6, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(11, 15, 15, 19, a); + a.assign(input_begin, input_end); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign to free front + devector input; get_range >(6, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign(input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assignment overlaps contents + devector input; get_range >(6, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign(input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assignment exceeds contents + devector input; get_range >(12, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign(input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + test_equal_range(a, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + + devector input; get_range >(12, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign(input_begin, input_end), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } +} + +template void test_assign_forward_range_throwing(dtl::false_) +{} + +template void test_assign_forward_range() +{ + typedef typename Devector::value_type T; + typedef boost::container::list List; + + boost::container::list x; + typedef typename List::iterator list_iterator; + x.emplace_back(1); + x.emplace_back(2); + x.emplace_back(3); + x.emplace_back(4); + x.emplace_back(5); + x.emplace_back(6); + x.emplace_back(7); + x.emplace_back(8); + x.emplace_back(9); + x.emplace_back(10); + x.emplace_back(11); + x.emplace_back(12); + + list_iterator one = x.begin(); + list_iterator six = one; + list_iterator twelve = one; + + iterator_advance(six, 6); + iterator_advance(twelve, 12); + + { // assign to empty (maybe small) + Devector a; + + a.assign(one, six); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign from empty + Devector a; get_range(6, a); + + a.assign(one, one); + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a.assign(one, six); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign(one, six); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign(one, six); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign(one, twelve); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + BOOST_IF_CONSTEXPR(! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign(one, twelve), test_exception); + test_elem_throw::do_not_throw(); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } +} + +template void test_assign_pointer_range() +{ + typedef typename Devector::value_type T; + + boost::container::vector x; get_range >(12, x); + const T* one = x.data(); + const T* six = one + 6; + const T* twelve = one + 12; + + { // assign to empty (maybe small) + Devector a; + + a.assign(one, six); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign from empty + Devector a; get_range(6, a); + + a.assign(one, one); + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a.assign(one, six); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign(one, six); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign(one, six); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign(one, twelve); + + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign(one, twelve), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } +} + +template void test_assign_n() +{ + typedef typename Devector::value_type T; + + { // assign to empty (maybe small) + Devector a; + + a.assign(6, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + } + + { // assign from empty + Devector a; get_range(6, a); + + a.assign(0, T(404)); + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a.assign(6, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign(6, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign(6, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign(12, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign(32, T(9)), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } +} + +template void test_assign_il() +{ + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef typename Devector::value_type T; + + { // assign to empty (maybe small) + Devector a; + + a.assign({1, 2, 3, 4, 5, 6}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + + { // assign from empty + Devector a; get_range(6, a); + + a.assign({}); + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a.assign({1, 2, 3, 4, 5, 6}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign({1, 2, 3, 4, 5, 6}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign({1, 2, 3, 4, 5, 6}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + #endif //#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +} + +template void test_get_allocator() +{ + Devector a; + (void) a.get_allocator(); +} + +template void test_begin_end() +{ + boost::container::vector expected; get_range >(10, expected); + { + Devector actual; get_range(10, actual); + + BOOST_TEST(boost::algorithm::equal(expected.begin(), expected.end(), actual.begin(), actual.end())); + BOOST_TEST(boost::algorithm::equal(expected.rbegin(), expected.rend(), actual.rbegin(), actual.rend())); + BOOST_TEST(boost::algorithm::equal(expected.cbegin(), expected.cend(), actual.cbegin(), actual.cend())); + BOOST_TEST(boost::algorithm::equal(expected.crbegin(), expected.crend(), actual.crbegin(), actual.crend())); + } + + { + Devector cactual; get_range(10, cactual); + + BOOST_TEST(boost::algorithm::equal(expected.begin(), expected.end(), cactual.begin(), cactual.end())); + BOOST_TEST(boost::algorithm::equal(expected.rbegin(), expected.rend(), cactual.rbegin(), cactual.rend())); + } +} + +template void test_empty() +{ + typedef typename Devector::value_type T; + + Devector a; + BOOST_TEST(a.empty()); + + a.push_front(T(1)); + BOOST_TEST(! a.empty()); + + a.pop_back(); + BOOST_TEST(a.empty()); + + Devector b(16, reserve_only_tag_t()); + BOOST_TEST(b.empty()); + + Devector c; get_range(3, c); + BOOST_TEST(! c.empty()); +} + +//template +//using gp_devector = devector; + +void test_max_size() +{/* + gp_devector a; + BOOST_TEST(a.max_size() == (std::numeric_limits::max)()); + + gp_devector b; + BOOST_TEST(b.max_size() == (std::numeric_limits::max)()); + + gp_devector c; + BOOST_TEST(c.max_size() >= b.max_size()); + + gp_devector d; + BOOST_TEST(d.max_size() >= c.max_size()); +*/ +} + +void test_exceeding_max_size() +{/* + using Devector = gp_devector; + + Devector a((std::numeric_limits::max)()); + BOOST_TEST_THROWS(a.emplace_back(404), std::length_error); +*/ +} + +template void test_size() +{ + typedef typename Devector::value_type T; + + Devector a; + BOOST_TEST(a.size() == 0u); + + a.push_front(T(1)); + BOOST_TEST(a.size() == 1u); + + a.pop_back(); + BOOST_TEST(a.size() == 0u); + + Devector b(16, reserve_only_tag_t()); + BOOST_TEST(b.size() == 0u); + + Devector c; get_range(3, c); + BOOST_TEST(c.size() == 3u); +} + +template void test_capacity() +{ + Devector a; + BOOST_TEST(a.capacity() == 0u); + + Devector b(128, reserve_only_tag_t()); + BOOST_TEST(b.capacity() >= 128u); + + Devector c; get_range(10, c); + BOOST_TEST(c.capacity() >= 10u); +} + +template void test_resize_front_throwing(dtl::true_) +{ + typedef typename Devector::iterator iterator; + + Devector d; get_range(5, d); + boost::container::vector d_origi; get_range >(5, d_origi); + iterator origi_begin = d.begin(); + + test_elem_throw::on_ctor_after(3); + BOOST_TEST_THROWS(d.resize_front(256), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(d, d_origi); + BOOST_TEST(origi_begin == d.begin()); +} + +template void test_resize_front_throwing(dtl::false_) +{} + + +template void test_resize_front() +{ + typedef typename Devector::value_type T; + + // size < required, alloc needed + { + Devector a; get_range(5, a); + a.resize_front(8); + const int expected [] = {0, 0, 0, 1, 2, 3, 4, 5}; + test_equal_range(a, expected); + } + + // size < required, but capacity provided + { + Devector b; get_range(5, b); + b.reserve_front(16); + b.resize_front(8); + const int expected [] = {0, 0, 0, 1, 2, 3, 4, 5}; + test_equal_range(b, expected); + } + /* + // size < required, move would throw + if (! boost::is_nothrow_move_constructible::value && std::is_copy_constructible::value) + { + Devector c; get_range(5, c); + + test_elem_throw::on_move_after(3); + c.resize_front(8); // shouldn't use the throwing move + test_elem_throw::do_not_throw(); + + test_equal_range(c, {0, 0, 0, 1, 2, 3, 4, 5}); + } + */ + + test_resize_front_throwing + (dtl::bool_::value>()); + + // size >= required + { + Devector e; get_range(6, e); + e.resize_front(4); + const int expected [] = {3, 4, 5, 6}; + test_equal_range(e, expected); + } + + // size < required, does not fit front small buffer + { + boost::container::vector expected(128); + Devector g; + g.resize_front(128); + test_equal_range(g, expected); + } + + // size = required + { + Devector e; get_range(6, e); + e.resize_front(6); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(e, expected); + } +} + +template void test_resize_front_copy_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + // size < required, copy throws + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(c.resize_front(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + } + + // size < required, copy throws, but later + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + iterator origi_begin = c.begin(); + + test_elem_throw::on_copy_after(7); + BOOST_TEST_THROWS(c.resize_front(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + BOOST_TEST(origi_begin == c.begin()); + } +} + +template void test_resize_front_copy_throwing(dtl::false_) +{} + +template void test_resize_front_copy() +{ + typedef typename Devector::value_type T; + + // size < required, alloc needed + { + Devector a; get_range(5, a); + a.resize_front(8, T(9)); + const int expected [] = {9, 9, 9, 1, 2, 3, 4, 5}; + test_equal_range(a, expected); + } + + // size < required, but capacity provided + { + Devector b; get_range(5, b); + b.reserve_front(16); + b.resize_front(8, T(9)); + const int expected [] = {9, 9, 9, 1, 2, 3, 4, 5}; + test_equal_range(b, expected); + } + + test_resize_front_copy_throwing + (dtl::bool_::value>()); + + // size >= required + { + Devector e; get_range(6, e); + e.resize_front(4, T(404)); + const int expected[] = {3, 4, 5, 6}; + test_equal_range(e, expected); + } + + // size < required, does not fit front small buffer + { + boost::container::vector expected(128, 9); + Devector g; + g.resize_front(128, T(9)); + test_equal_range(g, expected); + } + + // size = required + { + Devector e; get_range(6, e); + e.resize_front(6, T(9)); + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(e, expected); + } + + // size < required, tmp is already inserted + { + Devector f; get_range(8, f); + const T& tmp = *(f.begin() + 1); + f.resize_front(16, tmp); + const int expected[] = {2,2,2,2,2,2,2,2,1,2,3,4,5,6,7,8}; + test_equal_range(f, expected); + } +} + +template void test_resize_back_throwing(dtl::true_) +// size < required, constructor throws +{ + typedef typename Devector::iterator iterator; + + Devector d; get_range(5, d); + boost::container::vector d_origi; get_range >(5, d_origi); + iterator origi_begin = d.begin(); + + test_elem_throw::on_ctor_after(3); + BOOST_TEST_THROWS(d.resize_back(256), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(d, d_origi); + BOOST_TEST(origi_begin == d.begin()); +} + +template void test_resize_back_throwing(dtl::false_) +{} + +template void test_resize_back() +{ + typedef typename Devector::value_type T; + + // size < required, alloc needed + { + Devector a; get_range(5, a); + a.resize_back(8); + const int expected [] = {1, 2, 3, 4, 5, 0, 0, 0}; + test_equal_range(a, expected); + } + + // size < required, but capacity provided + { + Devector b; get_range(5, b); + b.reserve_back(16); + b.resize_back(8); + const int expected [] = {1, 2, 3, 4, 5, 0, 0, 0}; + test_equal_range(b, expected); + } + /* + // size < required, move would throw + if (! boost::is_nothrow_move_constructible::value && std::is_copy_constructible::value) + { + Devector c; get_range(5, c); + + test_elem_throw::on_move_after(3); + c.resize_back(8); // shouldn't use the throwing move + test_elem_throw::do_not_throw(); + + test_equal_range(c, {1, 2, 3, 4, 5, 0, 0, 0}); + } + */ + + test_resize_back_throwing + (dtl::bool_::value>()); + + // size >= required + { + Devector e; get_range(6, e); + e.resize_back(4); + const int expected [] = {1, 2, 3, 4}; + test_equal_range(e, expected); + } + + // size < required, does not fit front small buffer + { + boost::container::vector expected(128); + Devector g; + g.resize_back(128); + test_equal_range(g, expected); + } + + // size = required + { + Devector e; get_range(6, e); + e.resize_back(6); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(e, expected); + } +} + +template void test_resize_back_copy_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + // size < required, copy throws + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(c.resize_back(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + } + + // size < required, copy throws, but later + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + iterator origi_begin = c.begin(); + + test_elem_throw::on_copy_after(7); + BOOST_TEST_THROWS(c.resize_back(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + BOOST_TEST(origi_begin == c.begin()); + } + + // size < required, copy throws + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + iterator origi_begin = c.begin(); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(c.resize_back(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + BOOST_TEST(origi_begin == c.begin()); + } +} + +template void test_resize_back_copy_throwing(dtl::false_) +{} + +template void test_resize_back_copy() +{ + typedef typename Devector::value_type T; + + // size < required, alloc needed + { + Devector a; get_range(5, a); + a.resize_back(8, T(9)); + const int expected [] = {1, 2, 3, 4, 5, 9, 9, 9}; + test_equal_range(a, expected); + } + + // size < required, but capacity provided + { + Devector b; get_range(5, b); + b.reserve_back(16); + b.resize_back(8, T(9)); + const int expected [] = {1, 2, 3, 4, 5, 9, 9, 9}; + test_equal_range(b, expected); + } + + test_resize_back_copy_throwing + (dtl::bool_::value>()); + + // size >= required + { + Devector e; get_range(6, e); + e.resize_back(4, T(404)); + const int expected [] = {1, 2, 3, 4}; + test_equal_range(e, expected); + } + + // size < required, does not fit front small buffer + { + boost::container::vector expected(128, 9); + Devector g; + g.resize_back(128, T(9)); + test_equal_range(g, expected); + } + + // size = required + { + Devector e; get_range(6, e); + e.resize_back(6, T(9)); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(e, expected); + } + + // size < required, tmp is already inserted + { + Devector f; get_range(8, f); + const T& tmp = *(f.begin() + 1); + f.resize_back(16, tmp); + const int expected [] = {1,2,3,4,5,6,7,8,2,2,2,2,2,2,2,2}; + test_equal_range(f, expected); + } +} + +/* +template void test_constructor_unsafe_uninitialized() +{ + typedef typename Devector::value_type T; + + { + Devector a(8, unsafe_uninitialized_tag_t()); + BOOST_TEST(a.size() == 8u); + + for (int i = 0; i < 8; ++i) + { + new (a.data() + i) T(i+1); + } + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(a, expected); + } + + { + Devector b(0, unsafe_uninitialized_tag_t()); + BOOST_TEST(b.get_alloc_count() == 0u); + } +} +*/ + +/* +template void test_unsafe_uninitialized_resize_front() +{ + typedef typename Devector::value_type T; + + { // noop + Devector a; get_range(8, a); + a.reset_alloc_stats(); + + a.unsafe_uninitialized_resize_front(a.size()); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // grow (maybe has enough capacity) + Devector b; get_range(0, 0, 5, 9, b); + + b.unsafe_uninitialized_resize_front(8); + + for (int i = 0; i < 4; ++i) + { + new (b.data() + i) T(i+1); + } + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + } + + { // shrink uninitialized + Devector c; get_range(8, c); + + c.unsafe_uninitialized_resize_front(16); + c.unsafe_uninitialized_resize_front(8); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(c, expected ); + } + + if (std::is_trivially_destructible::value) + { + // shrink + Devector d; get_range(8, d); + + d.unsafe_uninitialized_resize_front(4); + + test_equal_range(d, {5, 6, 7, 8}); + } +} + +template void test_unsafe_uninitialized_resize_back() +{ + typedef typename Devector::value_type T; + + { // noop + Devector a; get_range(8, a); + a.reset_alloc_stats(); + + a.unsafe_uninitialized_resize_back(a.size()); + + test_equal_range(a, {1, 2, 3, 4, 5, 6, 7, 8}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // grow (maybe has enough capacity) + Devector b; get_range(1, 5, 0, 0, b); + + b.unsafe_uninitialized_resize_back(8); + + for (int i = 0; i < 4; ++i) + { + new (b.data() + 4 + i) T(i+5); + } + + test_equal_range(b, {1, 2, 3, 4, 5, 6, 7, 8}); + } + + { // shrink uninitialized + Devector c; get_range(8, c); + + c.unsafe_uninitialized_resize_back(16); + c.unsafe_uninitialized_resize_back(8); + + test_equal_range(c, {1, 2, 3, 4, 5, 6, 7, 8}); + } + + if (std::is_trivially_destructible::value) + { + // shrink + Devector d; get_range(8, d); + + d.unsafe_uninitialized_resize_back(4); + + test_equal_range(d, {1, 2, 3, 4}); + } +} +*/ + +template void test_reserve_front() +{ + typedef typename Devector::value_type value_type; + Devector a; + + a.reserve_front(100); + for (unsigned i = 0; i < 100u; ++i) + { + a.push_front(value_type(i)); + } + + BOOST_TEST(a.get_alloc_count() == 1u); + + Devector b; + b.reserve_front(4); + b.reserve_front(6); + b.reserve_front(4); + b.reserve_front(8); + b.reserve_front(16); +} + +template void test_reserve_back() +{ + Devector a; + typedef typename Devector::value_type value_type; + a.reserve_back(100); + for (unsigned i = 0; i < 100; ++i) + { + a.push_back(value_type(i)); + } + + BOOST_TEST(a.get_alloc_count() == 1u); + + Devector b; + b.reserve_back(4); + b.reserve_back(6); + b.reserve_back(4); + b.reserve_back(8); + b.reserve_back(16); +} + +template +void test_shrink_to_fit_always() +{ + Devector a; + a.reserve(100); + + a.push_back(1); + a.push_back(2); + a.push_back(3); + + a.shrink_to_fit(); + + boost::container::vector expected; + expected.push_back(1); + expected.push_back(2); + expected.push_back(3); + test_equal_range(a, expected); + + std::size_t exp_capacity = 3u; + BOOST_TEST(a.capacity() == exp_capacity); +} + +template +void test_shrink_to_fit_never() +{ + Devector a; + a.reserve(100); + + a.push_back(1); + a.push_back(2); + a.push_back(3); + + a.shrink_to_fit(); + + boost::container::vector expected; + expected.emplace_back(1); + expected.emplace_back(2); + expected.emplace_back(3); + test_equal_range(a, expected); + BOOST_TEST(a.capacity() == 100u); +} + +void shrink_to_fit() +{ + typedef devector devector_u_shr; + typedef devector small_devector_u_shr; + test_shrink_to_fit_always(); + test_shrink_to_fit_always(); +} + +template void test_index_operator() +{ + typedef typename Devector::value_type T; + + { // non-const [] + Devector a; get_range(5, a); + + BOOST_TEST(a[0] == 1); + BOOST_TEST(a[4] == 5); + BOOST_TEST(&a[3] == &a[0] + 3); + + a[0] = T(100); + BOOST_TEST(a[0] == 100); + } + + { // const [] + Devector b; get_range(5, b); + const Devector &a = b; + + BOOST_TEST(a[0] == 1); + BOOST_TEST(a[4] == 5); + BOOST_TEST(&a[3] == &a[0] + 3); + } +} + +template void test_at() +{ + typedef typename Devector::value_type T; + + { // non-const at + Devector a; get_range(3, a); + + BOOST_TEST(a.at(0) == 1); + a.at(0) = T(100); + BOOST_TEST(a.at(0) == 100); + + BOOST_TEST_THROWS(a.at(3), std::out_of_range); + } + + { // const at + Devector b; get_range(3, b); + const Devector &a = b; + + BOOST_TEST(a.at(0) == 1); + + BOOST_TEST_THROWS(a.at(3), std::out_of_range); + } +} + +template void test_front() +{ + typedef typename Devector::value_type T; + + { // non-const front + Devector a; get_range(3, a); + BOOST_TEST(a.front() == 1); + a.front() = T(100); + BOOST_TEST(a.front() == 100); + } + + { // const front + Devector b; get_range(3, b); const Devector &a = b; + BOOST_TEST(a.front() == 1); + } +} + +template void test_back() +{ + typedef typename Devector::value_type T; + + { // non-const back + Devector a; get_range(3, a); + BOOST_TEST(a.back() == 3); + a.back() = T(100); + BOOST_TEST(a.back() == 100); + } + + { // const back + Devector b; get_range(3, b); const Devector &a = b; + BOOST_TEST(a.back() == 3); + } +} + +void test_data() +{ + unsigned c_array[] = {1, 2, 3, 4}; + + { // non-const data + devector a(c_array, c_array + 4); + BOOST_TEST(a.data() == &a.front()); + + BOOST_TEST(std::memcmp(c_array, a.data(), 4 * sizeof(unsigned)) == 0); + + *(a.data()) = 100; + BOOST_TEST(a.front() == 100u); + } + + { // const data + const devector a(c_array, c_array + 4); + BOOST_TEST(a.data() == &a.front()); + + BOOST_TEST(std::memcmp(c_array, a.data(), 4 * sizeof(unsigned)) == 0); + } +} + +template void test_emplace_front(dtl::true_) +{ + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + test_elem_throw::on_ctor_after(1); + BOOST_TEST_THROWS(b.emplace_front(404), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_emplace_front(dtl::false_) +{ +} + +template void test_emplace_front() +{ + typedef typename Devector::value_type T; + + { + Devector a; + + a.emplace_front(3); + a.emplace_front(2); + a.emplace_front(1); + + boost::container::vector expected; get_range >(3, expected); + + test_equal_range(a, expected); + } + + test_emplace_front + (dtl::bool_::value>()); +} + +template void test_push_front() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + { + boost::container::vector expected; get_range >(16, expected); + std::reverse(expected.begin(), expected.end()); + Devector a; + + for (int i = 1; i <= 16; ++i) + { + T elem(i); + a.push_front(elem); + } + + test_equal_range(a, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + const T elem(404); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(b.push_front(elem), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); + } + + // test when tmp is already inserted + { + Devector c; get_range(4, c); + const T& tmp = *(c.begin() + 1); + c.push_front(tmp); + const int expected[] = {2, 1, 2, 3, 4}; + test_equal_range(c, expected); + } +} + +template void test_push_front_rvalue_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + test_elem_throw::on_move_after(1); + BOOST_TEST_THROWS(b.push_front(T(404)), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_push_front_rvalue_throwing(dtl::false_) +{} + +template void test_push_front_rvalue() +{ + typedef typename Devector::value_type T; + + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + + for (int i = 16; i > 0; --i) + { + T elem(i); + a.push_front(boost::move(elem)); + } + + test_equal_range(a, expected); + } + + test_push_front_rvalue_throwing(dtl::bool_::value>()); +} + +template void test_pop_front() +{ + { + Devector a; + a.emplace_front(1); + a.pop_front(); + BOOST_TEST(a.empty()); + } + + { + Devector b; + + b.emplace_back(2); + b.pop_front(); + BOOST_TEST(b.empty()); + + b.emplace_front(3); + b.pop_front(); + BOOST_TEST(b.empty()); + } + + { + Devector c; get_range(20, c); + for (int i = 0; i < 20; ++i) + { + BOOST_TEST(!c.empty()); + c.pop_front(); + } + BOOST_TEST(c.empty()); + } +} + +template void test_emplace_back_throwing(dtl::true_) +{ + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + test_elem_throw::on_ctor_after(1); + BOOST_TEST_THROWS(b.emplace_back(404), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_emplace_back_throwing(dtl::false_) +{} + +template void test_emplace_back() +{ + typedef typename Devector::value_type T; + + { + Devector a; + + a.emplace_back(1); + a.emplace_back(2); + a.emplace_back(3); + + boost::container::vector expected; get_range >(3, expected); + + test_equal_range(a, expected); + } + + test_emplace_back_throwing + (dtl::bool_::value>()); +} + +template void test_push_back_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + const T elem(404); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(b.push_back(elem), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_push_back_throwing(dtl::false_) +{} + +template void test_push_back() +{ + typedef typename Devector::value_type T; + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + + for (int i = 1; i <= 16; ++i) + { + T elem(i); + a.push_back(elem); + } + + test_equal_range(a, expected); + } + + test_push_back_throwing(dtl::bool_::value>()); + + // test when tmp is already inserted + { + Devector c; get_range(4, c); + const T& tmp = *(c.begin() + 1); + c.push_back(tmp); + const int expected[] = {1, 2, 3, 4, 2}; + test_equal_range(c, expected); + } +} + +template void test_push_back_rvalue_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + test_elem_throw::on_move_after(1); + BOOST_TEST_THROWS(b.push_back(T(404)), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_push_back_rvalue_throwing(dtl::false_) +{} + +template void test_push_back_rvalue() +{ + typedef typename Devector::value_type T; + + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + + for (int i = 1; i <= 16; ++i) + { + T elem(i); + a.push_back(boost::move(elem)); + } + + test_equal_range(a, expected); + } + + test_push_back_rvalue_throwing(dtl::bool_::value>()); +} + +/* +template void test_unsafe_push_front() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + boost::container::vector expected; get_range >(16, expected); + std::reverse(expected.begin(), expected.end()); + Devector a; + a.reserve_front(16); + + for (std::size_t i = 1; i <= 16; ++i) + { + T elem(i); + a.unsafe_push_front(elem); + } + + test_equal_range(a, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + Devector b; get_range(4, b); + b.reserve_front(5); + iterator origi_begin = b.begin(); + + const T elem(404); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(b.unsafe_push_front(elem), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); + } +} + +template void test_unsafe_push_front_rvalue() +{ + typedef typename Devector::value_type T; + + { + boost::container::vector expected; get_range >(16, expected); + std::reverse(expected.begin(), expected.end()); + Devector a; + a.reserve_front(16); + + for (std::size_t i = 1; i <= 16; ++i) + { + T elem(i); + a.unsafe_push_front(boost::move(elem)); + } + + test_equal_range(a, expected); + } +} +*/ +/* +template void test_unsafe_push_back() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + a.reserve(16); + + for (std::size_t i = 1; i <= 16; ++i) + { + T elem(i); + a.unsafe_push_back(elem); + } + + test_equal_range(a, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + Devector b; get_range(4, b); + b.reserve(5); + iterator origi_begin = b.begin(); + + const T elem(404); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(b.unsafe_push_back(elem), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); + } +} + +template void test_unsafe_push_back_rvalue() +{ + typedef typename Devector::value_type T; + + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + a.reserve(16); + + for (std::size_t i = 1; i <= 16; ++i) + { + T elem(i); + a.unsafe_push_back(boost::move(elem)); + } + + test_equal_range(a, expected); + } +} +*/ +template void test_pop_back() +{ + { + Devector a; + a.emplace_back(1); + a.pop_back(); + BOOST_TEST(a.empty()); + } + + { + Devector b; + + b.emplace_front(2); + b.pop_back(); + BOOST_TEST(b.empty()); + + b.emplace_back(3); + b.pop_back(); + BOOST_TEST(b.empty()); + } + + { + Devector c; get_range(20, c); + for (int i = 0; i < 20; ++i) + { + BOOST_TEST(!c.empty()); + c.pop_back(); + } + BOOST_TEST(c.empty()); + } +} + +template void test_emplace_throwing(dtl::true_) +{ + typedef typename Devector::iterator iterator; + + Devector j; get_range(4, j); + iterator origi_begin = j.begin(); + + test_elem_throw::on_ctor_after(1); + BOOST_TEST_THROWS(j.emplace(j.begin() + 2, 404), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4}; + test_equal_range(j, expected); + BOOST_TEST(origi_begin == j.begin()); +} + +template void test_emplace_throwing(dtl::false_) +{} + + +template void test_emplace() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + Devector a; get_range(16, a); + typename Devector::iterator it = a.emplace(a.begin(), 123); + const int expected[] = {123, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(a, expected); + BOOST_TEST(*it == 123); + } + + { + Devector b; get_range(16, b); + typename Devector::iterator it = b.emplace(b.end(), 123); + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 123}; + test_equal_range(b, expected); + BOOST_TEST(*it == 123); + } + + { + Devector c; get_range(16, c); + c.pop_front(); + typename Devector::iterator it = c.emplace(c.begin(), 123); + const int expected [] = {123, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(c, expected); + BOOST_TEST(*it == 123); + } + + { + Devector d; get_range(16, d); + d.pop_back(); + typename Devector::iterator it = d.emplace(d.end(), 123); + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 123}; + test_equal_range(d, expected); + BOOST_TEST(*it == 123); + } + + { + Devector e; get_range(16, e); + typename Devector::iterator it = e.emplace(e.begin() + 5, 123); + const int expected [] = {1, 2, 3, 4, 5, 123, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(e, expected); + BOOST_TEST(*it == 123); + } + + { + Devector f; get_range(16, f); + f.pop_front(); + f.pop_back(); + iterator valid = f.begin() + 1; + typename Devector::iterator it = f.emplace(f.begin() + 1, 123); + const int expected [] = {2, 123, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(f, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 3); + } + + { + Devector g; get_range(16, g); + g.pop_front(); + g.pop_back(); + iterator valid = g.end() - 2; + typename Devector::iterator it = g.emplace(g.end() - 1, 123); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 123, 15}; + test_equal_range(g, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 14); + } + + { + Devector h; get_range(16, h); + h.pop_front(); + h.pop_back(); + iterator valid = h.begin() + 7; + typename Devector::iterator it = h.emplace(h.begin() + 7, 123); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 123, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(h, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 9); + } + + { + Devector i; + i.emplace(i.begin(), 1); + i.emplace(i.end(), 10); + for (int j = 2; j < 10; ++j) + { + i.emplace(i.begin() + (j-1), j); + } + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(i, expected); + } + + test_emplace_throwing + (dtl::bool_::value>()); +} + +template void test_insert_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + T test_elem(123); + + Devector j; get_range(4, j); + iterator origi_begin = j.begin(); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(j.insert(j.begin() + 2, test_elem), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4}; + test_equal_range(j, expected); + BOOST_TEST(origi_begin == j.begin()); +} + +template void test_insert_throwing(dtl::false_) +{} + +template void test_insert() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + T test_elem(123); + + { + Devector a; get_range(16, a); + typename Devector::iterator it = a.insert(a.begin(), test_elem); + const int expected[] = {123, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(a, expected); + BOOST_TEST(*it == 123); + } + + { + Devector b; get_range(16, b); + typename Devector::iterator it = b.insert(b.end(), test_elem); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 123}; + test_equal_range(b, expected); + BOOST_TEST(*it == 123); + } + + { + Devector c; get_range(16, c); + c.pop_front(); + typename Devector::iterator it = c.insert(c.begin(), test_elem); + const int expected[] = {123, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(c, expected); + BOOST_TEST(*it == 123); + } + + { + Devector d; get_range(16, d); + d.pop_back(); + typename Devector::iterator it = d.insert(d.end(), test_elem); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 123}; + test_equal_range(d, expected); + BOOST_TEST(*it == 123); + } + + { + Devector e; get_range(16, e); + typename Devector::iterator it = e.insert(e.begin() + 5, test_elem); + const int expected[] = {1, 2, 3, 4, 5, 123, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(e, expected); + BOOST_TEST(*it == 123); + } + + { + Devector f; get_range(16, f); + f.pop_front(); + f.pop_back(); + iterator valid = f.begin() + 1; + typename Devector::iterator it = f.insert(f.begin() + 1, test_elem); + const int expected[] = {2, 123, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(f, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 3); + } + + { + Devector g; get_range(16, g); + g.pop_front(); + g.pop_back(); + iterator valid = g.end() - 2; + typename Devector::iterator it = g.insert(g.end() - 1, test_elem); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 123, 15}; + test_equal_range(g, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 14); + } + + { + Devector h; get_range(16, h); + h.pop_front(); + h.pop_back(); + iterator valid = h.begin() + 7; + typename Devector::iterator it = h.insert(h.begin() + 7, test_elem); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 123, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(h, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 9); + } + + { + Devector i; + i.insert(i.begin(), T(1)); + i.insert(i.end(), T(10)); + for (int j = 2; j < 10; ++j) + { + i.insert(i.begin() + (j-1), T(j)); + } + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(i, expected); + } + + test_insert_throwing + (dtl::bool_::value>()); + + // test when tmp is already inserted and there's free capacity + { + Devector c; get_range(6, c); + c.pop_back(); + const T& tmp = *(c.begin() + 2); + c.insert(c.begin() + 1, tmp); + const int expected[] = {1, 3, 2, 3, 4, 5}; + test_equal_range(c, expected); + } + + // test when tmp is already inserted and maybe there's no free capacity + { + Devector c; get_range(6, c); + const T& tmp = *(c.begin() + 2); + c.insert(c.begin() + 1, tmp); + const int expected[] = {1, 3, 2, 3, 4, 5, 6}; + test_equal_range(c, expected); + } +} + +template void test_insert_rvalue_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + Devector j; get_range(4, j); + iterator origi_begin = j.begin(); + + test_elem_throw::on_ctor_after(1); + BOOST_TEST_THROWS(j.insert(j.begin() + 2, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4}; + test_equal_range(j, expected); + BOOST_TEST(origi_begin == j.begin()); +} + +template void test_insert_rvalue_throwing(dtl::false_) +{} + + +template void test_insert_rvalue() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + Devector a; get_range(16, a); + typename Devector::iterator it = a.insert(a.begin(), T(123)); + const int expected[] = {123, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(a, expected); + BOOST_TEST(*it == 123); + } + + { + Devector b; get_range(16, b); + typename Devector::iterator it = b.insert(b.end(), T(123)); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 123}; + test_equal_range(b, expected); + BOOST_TEST(*it == 123); + } + + { + Devector c; get_range(16, c); + c.pop_front(); + typename Devector::iterator it = c.insert(c.begin(), T(123)); + const int expected[] = {123, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(c, expected); + BOOST_TEST(*it == 123); + } + + { + Devector d; get_range(16, d); + d.pop_back(); + typename Devector::iterator it = d.insert(d.end(), T(123)); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 123}; + test_equal_range(d, expected); + BOOST_TEST(*it == 123); + } + + { + Devector e; get_range(16, e); + typename Devector::iterator it = e.insert(e.begin() + 5, T(123)); + const int expected[] = {1, 2, 3, 4, 5, 123, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(e, expected); + BOOST_TEST(*it == 123); + } + + { + Devector f; get_range(16, f); + f.pop_front(); + f.pop_back(); + iterator valid = f.begin() + 1; + typename Devector::iterator it = f.insert(f.begin() + 1, T(123)); + const int expected[] = {2, 123, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(f, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 3); + } + + { + Devector g; get_range(16, g); + g.pop_front(); + g.pop_back(); + iterator valid = g.end() - 2; + typename Devector::iterator it = g.insert(g.end() - 1, T(123)); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 123, 15}; + test_equal_range(g, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 14); + } + + { + Devector h; get_range(16, h); + h.pop_front(); + h.pop_back(); + iterator valid = h.begin() + 7; + typename Devector::iterator it = h.insert(h.begin() + 7, T(123)); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 123, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(h, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 9); + } + + { + Devector i; + i.insert(i.begin(), T(1)); + i.insert(i.end(), T(10)); + for (int j = 2; j < 10; ++j) + { + i.insert(i.begin() + (j-1), T(j)); + } + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(i, expected); + } + + test_insert_rvalue_throwing + (dtl::bool_::value>()); +} + +template void test_insert_n_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + // insert at begin + { + Devector j; get_range(4, j); + + const T x(404); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(j.insert(j.begin(), 4, x), test_exception); + test_elem_throw::do_not_throw(); + } + + // insert at end + { + Devector k; get_range(4, k); + + const T x(404); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(k.insert(k.end(), 4, x), test_exception); + test_elem_throw::do_not_throw(); + } +} + +template void test_insert_n_throwing(dtl::false_) +{} + +template void test_insert_n() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + Devector a; + const T x(123); + iterator ret = a.insert(a.end(), 5, x); + const int expected[] = {123, 123, 123, 123, 123}; + test_equal_range(a, expected); + BOOST_TEST(ret == a.begin()); + } + + { + Devector b; get_range(8, b); + const T x(9); + iterator ret = b.insert(b.begin(), 3, x); + const int expected[] = {9, 9, 9, 1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.begin()); + } + + { + Devector c; get_range(8, c); + const T x(9); + iterator ret = c.insert(c.end(), 3, x); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 8); + } + + { + Devector d; get_range(8, d); + + d.pop_front(); + d.pop_front(); + d.pop_front(); + + const T x(9); + iterator origi_end = d.end(); + iterator ret = d.insert(d.begin(), 3, x); + + const int expected[] = {9, 9, 9, 4, 5, 6, 7, 8}; + test_equal_range(d, expected); + BOOST_TEST(origi_end == d.end()); + BOOST_TEST(ret == d.begin()); + } + + { + Devector e; get_range(8, e); + + e.pop_back(); + e.pop_back(); + e.pop_back(); + + const T x(9); + iterator origi_begin = e.begin(); + iterator ret = e.insert(e.end(), 3, x); + + const int expected[] = {1, 2, 3, 4, 5, 9, 9, 9}; + test_equal_range(e, expected); + BOOST_TEST(origi_begin == e.begin()); + BOOST_TEST(ret == e.begin() + 5); + } + + { + Devector f; get_range(8, f); + f.reset_alloc_stats(); + + f.pop_front(); + f.pop_front(); + f.pop_back(); + f.pop_back(); + + const T x(9); + iterator ret = f.insert(f.begin() + 2, 4, x); + + const int expected[] = {3, 4, 9, 9, 9, 9, 5, 6}; + test_equal_range(f, expected); + BOOST_TEST(f.get_alloc_count() == 0u); + BOOST_TEST(ret == f.begin() + 2); + } + + { + Devector g; get_range(8, g); + g.reset_alloc_stats(); + + g.pop_front(); + g.pop_front(); + g.pop_back(); + g.pop_back(); + g.pop_back(); + + const T x(9); + iterator ret = g.insert(g.begin() + 2, 5, x); + + const int expected[] = {3, 4, 9, 9, 9, 9, 9, 5}; + test_equal_range(g, expected); + BOOST_TEST(g.get_alloc_count() == 0u); + BOOST_TEST(ret == g.begin() + 2); + } + + { + Devector g; get_range(8, g); + + const T x(9); + iterator ret = g.insert(g.begin() + 2, 5, x); + + const int expected[] = {1, 2, 9, 9, 9, 9, 9, 3, 4, 5, 6, 7, 8}; + test_equal_range(g, expected); + BOOST_TEST(ret == g.begin() + 2); + } + + { // n == 0 + Devector h; get_range(8, h); + h.reset_alloc_stats(); + + const T x(9); + + iterator ret = h.insert(h.begin(), 0, x); + BOOST_TEST(ret == h.begin()); + + ret = h.insert(h.begin() + 4, 0, x); + BOOST_TEST(ret == h.begin() + 4); + + ret = h.insert(h.end(), 0, x); + BOOST_TEST(ret == h.end()); + + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(h, expected); + BOOST_TEST(h.get_alloc_count() == 0u); + } + + { // test insert already inserted + Devector i; get_range(8, i); + i.reset_alloc_stats(); + + i.pop_front(); + i.pop_front(); + + iterator ret = i.insert(i.end() - 1, 2, *i.begin()); + + const int expected[] = {3, 4, 5, 6, 7, 3, 3, 8}; + test_equal_range(i, expected); + BOOST_TEST(i.get_alloc_count() == 0u); + BOOST_TEST(ret == i.begin() + 5); + } + + test_insert_n_throwing + (dtl::bool_::value>()); +} + +template void test_insert_input_range() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + devector x; + x.emplace_back(9); + x.emplace_back(9); + x.emplace_back(9); + x.emplace_back(9); + x.emplace_back(9); + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 5); + + Devector a; + iterator ret = a.insert(a.end(), input_begin, input_end); + const int expected[] = {9, 9, 9, 9, 9}; + test_equal_range(a, expected); + BOOST_TEST(ret == a.begin()); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 3); + + Devector b; get_range(8, b); + iterator ret = b.insert(b.begin(), input_begin, input_end); + const int expected[] = {9, 9, 9, 1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.begin()); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 3); + + Devector c; get_range(8, c); + iterator ret = c.insert(c.end(), input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 8); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 3); + + Devector d; get_range(8, d); + + d.pop_front(); + d.pop_front(); + d.pop_front(); + + iterator ret = d.insert(d.begin(), input_begin, input_end); + const int expected[] = {9, 9, 9, 4, 5, 6, 7, 8}; + test_equal_range(d, expected); + BOOST_TEST(ret == d.begin()); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 3); + + Devector e; get_range(8, e); + + e.pop_back(); + e.pop_back(); + e.pop_back(); + + iterator origi_begin = e.begin(); + iterator ret = e.insert(e.end(), input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 9, 9, 9}; + test_equal_range(e, expected); + BOOST_TEST(origi_begin == e.begin()); + BOOST_TEST(ret == e.begin() + 5); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 4); + + Devector f; get_range(8, f); + f.reset_alloc_stats(); + + f.pop_front(); + f.pop_front(); + f.pop_back(); + f.pop_back(); + + iterator ret = f.insert(f.begin() + 2, input_begin, input_end); + + const int expected[] = {3, 4, 9, 9, 9, 9, 5, 6}; + test_equal_range(f, expected); + BOOST_TEST(ret == f.begin() + 2); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 5); + + Devector g; get_range(8, g); + g.reset_alloc_stats(); + + g.pop_front(); + g.pop_front(); + g.pop_back(); + g.pop_back(); + g.pop_back(); + + iterator ret = g.insert(g.begin() + 2, input_begin, input_end); + + const int expected [] = {3, 4, 9, 9, 9, 9, 9, 5}; + test_equal_range(g, expected); + BOOST_TEST(ret == g.begin() + 2); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 5); + + Devector g; get_range(8, g); + + iterator ret = g.insert(g.begin() + 2, input_begin, input_end); + + const int expected [] = {1, 2, 9, 9, 9, 9, 9, 3, 4, 5, 6, 7, 8}; + test_equal_range(g, expected); + BOOST_TEST(ret == g.begin() + 2); + } + + { // n == 0 + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + + Devector h; get_range(8, h); + h.reset_alloc_stats(); + + iterator ret = h.insert(h.begin(), input_begin, input_begin); + BOOST_TEST(ret == h.begin()); + + ret = h.insert(h.begin() + 4, input_begin, input_begin); + BOOST_TEST(ret == h.begin() + 4); + + ret = h.insert(h.end(), input_begin, input_begin); + BOOST_TEST(ret == h.end()); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(h, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // insert at begin + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 4); + + Devector j; get_range(4, j); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(j.insert(j.begin(), input_begin, input_end), test_exception); + test_elem_throw::do_not_throw(); + } + + // insert at end + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 4); + + Devector k; get_range(4, k); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(k.insert(k.end(), input_begin, input_end), test_exception); + test_elem_throw::do_not_throw(); + } + } +} + +template void test_insert_range() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + typedef boost::container::vector Vector; + + Vector x; + x.emplace_back(9); + x.emplace_back(10); + x.emplace_back(11); + x.emplace_back(12); + x.emplace_back(13); + + typename Vector::iterator xb = x.begin(); + + { + Devector a; + iterator ret = a.insert(a.end(), xb, xb+5); + const int expected [] = {9, 10, 11, 12, 13}; + test_equal_range(a, expected); + BOOST_TEST(ret == a.begin()); + } + + { + Devector b; get_range(8, b); + iterator ret = b.insert(b.begin(), xb, xb+3); + const int expected [] = {9, 10, 11, 1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.begin()); + } + + { + Devector c; get_range(8, c); + iterator ret = c.insert(c.end(), xb, xb+3); + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 8); + } + + { + Devector d; get_range(8, d); + + d.pop_front(); + d.pop_front(); + d.pop_front(); + + iterator origi_end = d.end(); + iterator ret = d.insert(d.begin(), xb, xb+3); + + const int expected [] = {9, 10, 11, 4, 5, 6, 7, 8}; + test_equal_range(d, expected); + + BOOST_TEST(origi_end == d.end()); + BOOST_TEST(ret == d.begin()); + } + + { + Devector e; get_range(8, e); + + e.pop_back(); + e.pop_back(); + e.pop_back(); + + iterator origi_begin = e.begin(); + iterator ret = e.insert(e.end(), xb, xb+3); + + const int expected [] = {1, 2, 3, 4, 5, 9, 10, 11}; + test_equal_range(e, expected); + + BOOST_TEST(origi_begin == e.begin()); + BOOST_TEST(ret == e.begin() + 5); + } + + { + Devector f; get_range(8, f); + f.reset_alloc_stats(); + + f.pop_front(); + f.pop_front(); + f.pop_back(); + f.pop_back(); + + iterator ret = f.insert(f.begin() + 2, xb, xb+4); + + const int expected [] = {3, 4, 9, 10, 11, 12, 5, 6}; + test_equal_range(f, expected); + + BOOST_TEST(f.get_alloc_count() == 0u); + BOOST_TEST(ret == f.begin() + 2); + } + + { + Devector g; get_range(8, g); + g.reset_alloc_stats(); + + g.pop_front(); + g.pop_front(); + g.pop_back(); + g.pop_back(); + g.pop_back(); + + iterator ret = g.insert(g.begin() + 2, xb, xb+5); + + const int expected [] = {3, 4, 9, 10, 11, 12, 13, 5}; + test_equal_range(g, expected); + + BOOST_TEST(g.get_alloc_count() == 0u); + BOOST_TEST(ret == g.begin() + 2); + } + + { + Devector g; get_range(8, g); + + iterator ret = g.insert(g.begin() + 2, xb, xb+5); + + const int expected [] = {1, 2, 9, 10, 11, 12, 13, 3, 4, 5, 6, 7, 8}; + test_equal_range(g, expected); + + BOOST_TEST(ret == g.begin() + 2); + } + + { // n == 0 + Devector h; get_range(8, h); + h.reset_alloc_stats(); + + iterator ret = h.insert(h.begin(), xb, xb); + BOOST_TEST(ret == h.begin()); + + ret = h.insert(h.begin() + 4, xb, xb); + BOOST_TEST(ret == h.begin() + 4); + + ret = h.insert(h.end(), xb, xb); + BOOST_TEST(ret == h.end()); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(h, expected); + + BOOST_TEST(h.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // insert at begin + { + Devector j; get_range(4, j); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(j.insert(j.begin(), xb, xb+4), test_exception); + test_elem_throw::do_not_throw(); + } + + // insert at end + { + Devector k; get_range(4, k); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(k.insert(k.end(), xb, xb+4), test_exception); + test_elem_throw::do_not_throw(); + } + } +} + +template void test_insert_init_list() +{ + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + Devector a; + iterator ret = a.insert(a.end(), {T(123), T(124), T(125), T(126), T(127)}); + test_equal_range(a, {123, 124, 125, 126, 127}); + BOOST_TEST(ret == a.begin()); + } + + { + Devector b; get_range(8, b); + iterator ret = b.insert(b.begin(), {T(9), T(10), T(11)}); + test_equal_range(b, {9, 10, 11, 1, 2, 3, 4, 5, 6, 7, 8}); + BOOST_TEST(ret == b.begin()); + } + + { + Devector c; get_range(8, c); + iterator ret = c.insert(c.end(), {T(9), T(10), T(11)}); + test_equal_range(c, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}); + BOOST_TEST(ret == c.begin() + 8); + } + + { + Devector d; get_range(8, d); + + d.pop_front(); + d.pop_front(); + d.pop_front(); + + iterator origi_end = d.end(); + iterator ret = d.insert(d.begin(), {T(9), T(10), T(11)}); + + test_equal_range(d, {9, 10, 11, 4, 5, 6, 7, 8}); + BOOST_TEST(origi_end == d.end()); + BOOST_TEST(ret == d.begin()); + } + + { + Devector e; get_range(8, e); + + e.pop_back(); + e.pop_back(); + e.pop_back(); + + iterator origi_begin = e.begin(); + iterator ret = e.insert(e.end(), {T(9), T(10), T(11)}); + + test_equal_range(e, {1, 2, 3, 4, 5, 9, 10, 11}); + BOOST_TEST(origi_begin == e.begin()); + BOOST_TEST(ret == e.begin() + 5); + } + + { + Devector f; get_range(8, f); + f.reset_alloc_stats(); + + f.pop_front(); + f.pop_front(); + f.pop_back(); + f.pop_back(); + + iterator ret = f.insert(f.begin() + 2, {T(9), T(10), T(11), T(12)}); + + test_equal_range(f, {3, 4, 9, 10, 11, 12, 5, 6}); + BOOST_TEST(f.get_alloc_count() == 0u); + BOOST_TEST(ret == f.begin() + 2); + } + + { + Devector g; get_range(8, g); + g.reset_alloc_stats(); + + g.pop_front(); + g.pop_front(); + g.pop_back(); + g.pop_back(); + g.pop_back(); + + iterator ret = g.insert(g.begin() + 2, {T(9), T(10), T(11), T(12), T(13)}); + + test_equal_range(g, {3, 4, 9, 10, 11, 12, 13, 5}); + BOOST_TEST(g.get_alloc_count() == 0u); + BOOST_TEST(ret == g.begin() + 2); + } + + { + Devector g; get_range(8, g); + + iterator ret = g.insert(g.begin() + 2, {T(9), T(10), T(11), T(12), T(13)}); + + test_equal_range(g, {1, 2, 9, 10, 11, 12, 13, 3, 4, 5, 6, 7, 8}); + BOOST_TEST(ret == g.begin() + 2); + } + + BOOST_IF_CONSTEXPR (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // insert at begin + { + Devector j; get_range(4, j); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(j.insert(j.begin(), {T(9), T(9), T(9), T(9), T(9)}), test_exception); + test_elem_throw::do_not_throw(); + } + + // insert at end + { + Devector k; get_range(4, k); + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(k.insert(k.end(), {T(9), T(9), T(9), T(9), T(9)}), test_exception); + test_elem_throw::do_not_throw(); + } + } + #endif // #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +} + +template void test_erase() +{ + typedef typename Devector::iterator iterator; + { + Devector a; get_range(4, a); + iterator ret = a.erase(a.begin()); + const int expected[] = {2, 3, 4}; + test_equal_range(a, expected); + BOOST_TEST(ret == a.begin()); + } + + { + Devector b; get_range(4, b); + iterator ret = b.erase(b.end() - 1); + const int expected[] = {1, 2, 3}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.end()); + } + + { + Devector c; get_range(6, c); + iterator ret = c.erase(c.begin() + 2); + const int expected [] = {1, 2, 4, 5, 6}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 2); + BOOST_TEST(c.front_free_capacity() > 0u); + } + + { + Devector d; get_range(6, d); + iterator ret = d.erase(d.begin() + 4); + const int expected [] = {1, 2, 3, 4, 6}; + test_equal_range(d, expected); + BOOST_TEST(ret == d.begin() + 4); + BOOST_TEST(d.back_free_capacity() > 0u); + } +} + +template void test_erase_range() +{ + typedef typename Devector::iterator iterator; + { + Devector a; get_range(4, a); + a.erase(a.end(), a.end()); + a.erase(a.begin(), a.begin()); + } + + { + Devector b; get_range(8, b); + iterator ret = b.erase(b.begin(), b.begin() + 2); + const int expected [] = {3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.begin()); + BOOST_TEST(b.front_free_capacity() > 0u); + } + + { + Devector c; get_range(8, c); + iterator ret = c.erase(c.begin() + 1, c.begin() + 3); + const int expected [] = {1, 4, 5, 6, 7, 8}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 1); + BOOST_TEST(c.front_free_capacity() > 0u); + } + + { + Devector d; get_range(8, d); + iterator ret = d.erase(d.end() - 2, d.end()); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(d, expected); + BOOST_TEST(ret == d.end()); + BOOST_TEST(d.back_free_capacity() > 0u); + } + + { + Devector e; get_range(8, e); + iterator ret = e.erase(e.end() - 3, e.end() - 1); + const int expected [] = {1, 2, 3, 4, 5, 8}; + test_equal_range(e, expected); + BOOST_TEST(ret == e.end() - 1); + BOOST_TEST(e.back_free_capacity() > 0u); + } + + { + Devector f; get_range(8, f); + iterator ret = f.erase(f.begin(), f.end()); + test_equal_range(f); + BOOST_TEST(ret == f.end()); + } +} + +template void test_swap() +{ + using std::swap; // test if ADL works + + // empty-empty + { + Devector a; + Devector b; + + swap(a, b); + + BOOST_TEST(a.empty()); + BOOST_TEST(b.empty()); + } + + // empty-not empty + { + Devector a; + Devector b; get_range(4, b); + + swap(a, b); + + const int expected [] = {1, 2, 3, 4}; + { + BOOST_TEST(b.empty()); + test_equal_range(a, expected); + } + + swap(a, b); + { + BOOST_TEST(a.empty()); + test_equal_range(b, expected); + } + } + + // small-small / big-big + { + Devector a; get_range(1, 5, 5, 7, a); + Devector b; get_range(13, 15, 15, 19, b); + + swap(a, b); + + const int expected [] = {13, 14, 15, 16, 17, 18}; + test_equal_range(a, expected); + const int expected2 [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(b, expected2); + + swap(a, b); + + const int expected3 [] = {13, 14, 15, 16, 17, 18}; + test_equal_range(b, expected3); + const int expected4 [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected4); + } + + // big-small + small-big + { + Devector a; get_range(10, a); + Devector b; get_range(9, 11, 11, 17, b); + + swap(a, b); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(b, expected); + const int expected2 [] = {9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(a, expected2); + + swap(a, b); + + const int expected3 [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(a, expected3); + const int expected4 [] = {9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(b, expected4); + } + + // self swap + { + Devector a; get_range(10, a); + + swap(a, a); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(a, expected); + } + + // no overlap + { + Devector a; get_range(1, 9, 0, 0, a); + Devector b; get_range(0, 0, 11, 17, b); + + a.pop_back(); + a.pop_back(); + + b.pop_front(); + b.pop_front(); + + swap(a, b); + + const int expected [] = {13, 14, 15, 16}; + test_equal_range(a, expected); + const int expected2 [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(b, expected2); + } + + // big-big does not copy or move + { + Devector a; get_range(32, a); + Devector b; get_range(32, b); + boost::container::vector c; get_range >(32, c); + + test_elem_throw::on_copy_after(1); + test_elem_throw::on_move_after(1); + + swap(a, b); + + test_elem_throw::do_not_throw(); + + test_equal_range(a, c); + test_equal_range(b, c); + } +} + +template void test_clear() +{ + { + Devector a; + a.clear(); + BOOST_TEST(a.empty()); + } + + { + Devector a; get_range(8, a); + typename Devector::size_type cp = a.capacity(); + a.clear(); + BOOST_TEST(a.empty()); + BOOST_TEST(cp == a.capacity()); + } +} + +template void test_op_eq() +{ + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST(a == b); + } + + { // diff size + Devector a; get_range(8, a); + Devector b; get_range(9, b); + + BOOST_TEST(!(a == b)); + } + + { // diff content + Devector a; get_range(8, a); + Devector b; get_range(2,6,6,10, b); + + BOOST_TEST(!(a == b)); + } +} + +template void test_op_lt() +{ + { // little than + Devector a; get_range(7, a); + Devector b; get_range(8, b); + + BOOST_TEST((a < b)); + } + + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a < b)); + } + + { // greater than + Devector a; get_range(8, a); + Devector b; get_range(7, b); + + BOOST_TEST(!(a < b)); + } +} + +template void test_op_ne() +{ + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a != b)); + } + + { // diff size + Devector a; get_range(8, a); + Devector b; get_range(9, b); + + BOOST_TEST((a != b)); + } + + { // diff content + Devector a; get_range(8, a); + Devector b; get_range(2,6,6,10, b); + + BOOST_TEST((a != b)); + } +} + + +template void test_op_gt() +{ + { // little than + Devector a; get_range(7, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a > b)); + } + + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a > b)); + } + + { // greater than + Devector a; get_range(8, a); + Devector b; get_range(7, b); + + BOOST_TEST((a > b)); + } +} + +template void test_op_ge() +{ + { // little than + Devector a; get_range(7, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a >= b)); + } + + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST((a >= b)); + } + + { // greater than + Devector a; get_range(8, a); + Devector b; get_range(7, b); + + BOOST_TEST((a >= b)); + } +} + +template void test_op_le() +{ + { // little than + Devector a; get_range(7, a); + Devector b; get_range(8, b); + + BOOST_TEST((a <= b)); + } + + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST((a <= b)); + } + + { // greater than + Devector a; get_range(8, a); + Devector b; get_range(7, b); + + BOOST_TEST(!(a <= b)); + } +} + + +template +void test_devector_default_constructible(dtl::true_) +{ + test_constructor_n(); + test_resize_front(); + test_resize_back(); +} + +template +void test_devector_default_constructible(dtl::false_) +{} + +template +void test_devector_copy_constructible(dtl::false_) +{} + + +template +void test_devector_copy_constructible(dtl::true_) +{ + test_constructor_n_copy(); + test_constructor_input_range(); + test_constructor_forward_range(); + test_constructor_pointer_range(); + test_copy_constructor(); + test_assignment(); + test_assign_input_range(); + test_assign_pointer_range(); + test_assign_n(); + test_resize_front_copy(); + test_push_back(); + //test_unsafe_push_back(); + test_push_front(); + //test_unsafe_push_front(); + test_resize_back_copy(); + test_insert(); + test_insert_n(); + test_insert_input_range(); + test_insert_range(); + test_insert_init_list(); +} + +template +void test_devector() +{ + test_devector_default_constructible(dtl::bool_::value>()); + test_devector_copy_constructible(dtl::bool_::value>()); + + test_constructor_default(); + test_constructor_allocator(); + + test_constructor_reserve_only(); + test_constructor_reserve_only_front_back(); + //test_constructor_unsafe_uninitialized(); + + test_move_constructor(); + test_destructor(); + + test_move_assignment(); + test_get_allocator(); + test_begin_end(); + test_empty(); + test_size(); + test_capacity(); + + //test_unsafe_uninitialized_resize_front(); + //test_unsafe_uninitialized_resize_back(); + test_reserve_front(); + test_reserve_back(); + test_index_operator(); + test_at(); + test_front(); + test_back(); + test_emplace_front(); + test_push_front_rvalue(); + + //test_unsafe_push_front_rvalue(); + test_pop_front(); + test_emplace_back(); + test_push_back_rvalue(); + + //test_unsafe_push_back_rvalue(); + test_pop_back(); + test_emplace(); + test_insert_rvalue(); + + test_erase(); + test_erase_range(); + test_swap(); + test_clear(); + test_op_eq(); + test_op_lt(); + test_op_ne(); + test_op_gt(); + test_op_ge(); + test_op_le(); +} + +class recursive_devector +{ + public: + recursive_devector(const recursive_devector &x) + : devector_(x.devector_) + {} + + recursive_devector & operator=(const recursive_devector &x) + { this->devector_ = x.devector_; return *this; } + + int id_; + devector devector_; + devector::iterator it_; + devector::const_iterator cit_; + devector::reverse_iterator rit_; + devector::const_reverse_iterator crit_; +}; + +void test_recursive_devector()//Test for recursive types +{ + devector rdv; + BOOST_TEST(rdv.empty()); + BOOST_TEST(rdv.get_alloc_count() == 0u); + BOOST_TEST(rdv.capacity() == 0u); +} + +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef vector< ValueType + , typename allocator_traits + ::template portable_rebind_alloc::type + > type; + }; +}; + +#ifdef _MSC_VER + #pragma warning (pop) +#endif + + +void test_all() +{/* + test_recursive_devector(); + test_max_size(); + test_exceeding_max_size(); + shrink_to_fit(); + test_data(); + test_il_assignment< devector >(); + test_assign_forward_range< devector >(); + test_assign_il >(); +*/ + //test_devector< devector >(); + test_devector< devector >(); + test_devector< devector >(); + test_devector< devector >(); + test_devector< devector >(); + test_devector< devector >(); + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + (void)boost::container::test::test_propagate_allocator(); +} + + +boost::container::vector getom() +{ + typedef boost::container::vector V; + V v; + return BOOST_MOVE_RET(V, v); +} + + +boost::container::vector get() +{ + typedef boost::container::vector V; + V v; + return BOOST_MOVE_RET(V, v); +} + +int main() +{ +// boost::container::vectora(get()); + //boost::container::vector b(getom()); + //boost::container::vector c(get_range< boost::container::vector >(1, 5, 5, 9)); + test_all(); + return boost::report_errors(); +} diff --git a/test/explicit_inst_devector_test.cpp b/test/explicit_inst_devector_test.cpp new file mode 100644 index 0000000..ded7e24 --- /dev/null +++ b/test/explicit_inst_devector_test.cpp @@ -0,0 +1,41 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include "movable_int.hpp" + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::devector; + +namespace boost { +namespace container { + +//Test stored_size option +template class devector< test::movable_and_copyable_int + , new_allocator + , devector_options< stored_size >::type + >; + + +} //namespace container { +} //namespace boost { + +int main() +{ + ::boost::container::devector dummy; + (void)dummy; + return 0; +} diff --git a/test/flat_map_adaptor_test.cpp b/test/flat_map_adaptor_test.cpp index bc75949..2ffa02d 100644 --- a/test/flat_map_adaptor_test.cpp +++ b/test/flat_map_adaptor_test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -99,6 +100,15 @@ int main() std::cout << "Error in map_test > >" << std::endl; return 1; } + + if (0 != test::map_test + < GetMapContainer > >::apply::map_type + , MyStdMap + , GetMapContainer > >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test > >" << std::endl; + return 1; + } } { using namespace boost::container; diff --git a/test/flat_set_adaptor_test.cpp b/test/flat_set_adaptor_test.cpp index 6225bbf..cd5ef19 100644 --- a/test/flat_set_adaptor_test.cpp +++ b/test/flat_set_adaptor_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -96,6 +97,14 @@ int main() std::cout << "Error in set_test >" << std::endl; return 1; } + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } } { using namespace boost::container; diff --git a/test/hash_table_test.cppx b/test/hash_table_test.cppx deleted file mode 100644 index e69de29..0000000 diff --git a/test/input_iterator.hpp b/test/input_iterator.hpp new file mode 100644 index 0000000..1d576cf --- /dev/null +++ b/test/input_iterator.hpp @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://erenon.hu/double_ended for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +/** + * Emulates input iterator, validates algorithm + * does a single pass only, removes visited elements. + * + * Container::erase(front_iterator) must not invalidate other iterators. + * + * The hack around `_erase_on_destroy` is required to make `*it++` work. + */ +template +class input_iterator +{ + typedef typename Container::iterator iterator; + + public: + + typedef std::input_iterator_tag iterator_category; + typedef typename Container::value_type value_type; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; + typedef typename Container::difference_type difference_type; + + struct erase_on_destroy {}; + +public: + + input_iterator() + : _container() + , _it() + , _erase_on_destroy() + {} + + input_iterator(Container& c, iterator it) + :_container(&c) + , _it(it) + , _erase_on_destroy() + {} + + input_iterator(const input_iterator& rhs) + :_container(rhs._container), + _it(rhs._it), + _erase_on_destroy(rhs._erase_on_destroy) + { + rhs._erase_on_destroy = false; + } + + input_iterator & operator=(const input_iterator& rhs) + { + _container = rhs._container; + _it = rhs._it; + _erase_on_destroy = rhs._erase_on_destroy; + rhs._erase_on_destroy = false; + return *this; + } + + input_iterator(const input_iterator& rhs, erase_on_destroy) + :_container(rhs._container), + _it(rhs._it), + _erase_on_destroy(true) + {} + + ~input_iterator() + { + if (_erase_on_destroy) + { + _container->erase(_it); // must not invalidate other iterators + } + } + + const value_type& operator*() + { + return *_it; + } + + input_iterator operator++() + { + _container->erase(_it); + ++_it; + return *this; + } + + input_iterator operator++(int) + { + input_iterator old(*this, erase_on_destroy()); + ++_it; + return old; + } + + friend bool operator==(const input_iterator a, const input_iterator b) + { + return a._it == b._it; + } + + friend bool operator!=(const input_iterator a, const input_iterator b) + { + return !(a == b); + } + +private: + Container* _container; + iterator _it; + mutable bool _erase_on_destroy; +}; + +template +input_iterator make_input_iterator(Container& c, typename Container::iterator it) +{ + return input_iterator(c, it); +} diff --git a/test/pmr_devector_test.cpp b/test/pmr_devector_test.cpp new file mode 100644 index 0000000..b7001d0 --- /dev/null +++ b/test/pmr_devector_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef devector > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/test/test_elem.hpp b/test/test_elem.hpp new file mode 100644 index 0000000..b57a8dd --- /dev/null +++ b/test/test_elem.hpp @@ -0,0 +1,319 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://erenon.hu/double_ended for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_TEST_ELEM_HPP +#define BOOST_CONTAINER_TEST_TEST_ELEM_HPP + +#include + +namespace boost { +namespace container { + +struct test_exception {}; + +struct test_elem_throw +{ + private: + static int throw_on_ctor_after /*= -1*/; + static int throw_on_copy_after /*= -1*/; + static int throw_on_move_after /*= -1*/; + + public: + static void on_ctor_after(int x) { throw_on_ctor_after = x; } + static void on_copy_after(int x) { throw_on_copy_after = x; } + static void on_move_after(int x) { throw_on_move_after = x; } + + static void do_not_throw() + { + throw_on_ctor_after = -1; + throw_on_copy_after = -1; + throw_on_move_after = -1; + } + + static void in_constructor() { maybe_throw(throw_on_ctor_after); } + static void in_copy() { maybe_throw(throw_on_copy_after); } + static void in_move() { maybe_throw(throw_on_move_after); } + + private: + static void maybe_throw(int& counter) + { + if (counter > 0) + { + --counter; + if (counter == 0) + { + --counter; + throw test_exception(); + } + } + } +}; + +int test_elem_throw::throw_on_ctor_after = -1; +int test_elem_throw::throw_on_copy_after = -1; +int test_elem_throw::throw_on_move_after = -1; + +struct test_elem_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(test_elem_base) + + public: + test_elem_base() + { + test_elem_throw::in_constructor(); + _index = new int(0); + ++_live_count; + } + + test_elem_base(int index) + { + test_elem_throw::in_constructor(); + _index = new int(index); + ++_live_count; + } + + explicit test_elem_base(const test_elem_base& rhs) + { + test_elem_throw::in_copy(); + _index = new int(*rhs._index); + ++_live_count; + } + + test_elem_base(BOOST_RV_REF(test_elem_base) rhs) + { + test_elem_throw::in_move(); + _index = rhs._index; + rhs._index = 0; + ++_live_count; + } + + test_elem_base &operator=(BOOST_COPY_ASSIGN_REF(test_elem_base) rhs) + { + test_elem_throw::in_copy(); + if (_index) { delete _index; } + _index = new int(*rhs._index); + return *this; + } + + test_elem_base &operator=(BOOST_RV_REF(test_elem_base) rhs) + { + test_elem_throw::in_move(); + if (_index) { delete _index; } + _index = rhs._index; + rhs._index = 0; + return *this; + } + + ~test_elem_base() + { + if (_index) { delete _index; } + --_live_count; + } + + friend bool operator==(const test_elem_base& a, const test_elem_base& b) + { + return a._index && b._index && *(a._index) == *(b._index); + } + + friend bool operator==(int a, const test_elem_base& b) + { + return b._index != 0 && a == *(b._index); + } + + friend bool operator==(const test_elem_base& a, int b) + { + return a._index != 0 && *(a._index) == b; + } + + friend bool operator<(const test_elem_base& a, const test_elem_base& b) + { + return boost::less_pointees(a._index, b._index); + } + + friend std::ostream& operator<<(std::ostream& out, const test_elem_base& elem) + { + if (elem._index) { out << *elem._index; } + else { out << "null"; } + return out; + } + + template + void serialize(Archive& ar, unsigned /* version */) + { + ar & *_index; + } + + static bool no_living_elem() + { + return _live_count == 0; + } + + private: + int* _index; + + static int _live_count; +}; + +int test_elem_base::_live_count = 0; + +struct regular_elem : test_elem_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(regular_elem) + + public: + regular_elem() + {} + + regular_elem(int index) : test_elem_base(index) {} + + regular_elem(const regular_elem& rhs) + :test_elem_base(rhs) + {} + + regular_elem(BOOST_RV_REF(regular_elem) rhs) + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + regular_elem &operator=(BOOST_COPY_ASSIGN_REF(regular_elem) rhs) + { + static_cast(*this) = rhs; + return *this; + } + + regular_elem &operator=(BOOST_RV_REF(regular_elem) rhs) + { + regular_elem &r = rhs; + static_cast(*this) = boost::move(r); + return *this; + } +}; + +struct noex_move : test_elem_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(noex_move) + + public: + noex_move() + {} + + noex_move(int index) : test_elem_base(index) {} + + noex_move(const noex_move& rhs) + :test_elem_base(rhs) + {} + + noex_move(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + noex_move &operator=(BOOST_COPY_ASSIGN_REF(noex_move) rhs) + { + static_cast(*this) = rhs; + return *this; + } + + noex_move &operator=(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT + { + noex_move & r = rhs; + static_cast(*this) = boost::move(r); + return *this; + } +}; + +struct noex_copy : test_elem_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(noex_copy) + + public: + noex_copy(){} + + noex_copy(int index) : test_elem_base(index) {} + + noex_copy(const noex_copy& rhs) BOOST_NOEXCEPT + :test_elem_base(rhs) + {} + + noex_copy(BOOST_RV_REF(noex_copy) rhs) + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + noex_copy &operator=(BOOST_COPY_ASSIGN_REF(noex_copy) rhs) BOOST_NOEXCEPT + { + static_cast(*this) = rhs; + return *this; + } + + noex_copy &operator=(BOOST_RV_REF(noex_copy) rhs) + { + noex_copy &r = rhs; + static_cast(*this) = boost::move(r); + return *this; + } +}; + +struct only_movable : test_elem_base +{ + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(only_movable) + + public: + only_movable(){}; + + only_movable(int index) : test_elem_base(index) {} + + only_movable(BOOST_RV_REF(only_movable) rhs) + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + only_movable &operator=(BOOST_RV_REF(only_movable) rhs) + { + static_cast(*this) = boost::move(rhs); + return *this; + } +}; + +struct no_default_ctor : test_elem_base +{ + + private: + BOOST_COPYABLE_AND_MOVABLE(no_default_ctor) + + public: + no_default_ctor(int index) : test_elem_base(index) {} + + no_default_ctor(const no_default_ctor& rhs) + :test_elem_base(rhs) + {} + + no_default_ctor(BOOST_RV_REF(no_default_ctor) rhs) + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + no_default_ctor &operator=(BOOST_RV_REF(no_default_ctor) rhs) + { + static_cast(*this) = boost::move(rhs); + return *this; + } + + no_default_ctor &operator=(BOOST_COPY_ASSIGN_REF(no_default_ctor) rhs) + { + static_cast(*this) = rhs; + return *this; + } +}; + +}} + +#endif //BOOST_CONTAINER_TEST_TEST_ELEM_HPP diff --git a/test/test_util.hpp b/test/test_util.hpp new file mode 100644 index 0000000..f2db77b --- /dev/null +++ b/test/test_util.hpp @@ -0,0 +1,139 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://erenon.hu/double_ended for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_TEST_UTIL_HPP +#define BOOST_CONTAINER_TEST_TEST_UTIL_HPP + +#include "test_elem.hpp" + +// get_range + +template +void get_range(int fbeg, int fend, int bbeg, int bend, DeVector &c) +{ + c.clear(); + + for (int i = fend; i > fbeg ;) + { + c.emplace_front(--i); + } + + for (int i = bbeg; i < bend; ++i) + { + c.emplace_back(i); + } +} + +template +void get_range(int count, Container &c) +{ + c.clear(); + + for (int i = 1; i <= count; ++i) + { + c.emplace_back(i); + } +} + +template +void get_range(Container &c) +{ + get_range(1, 13, 13, 25, c); +} + +template +void test_equal_range(const C1& a) +{ + BOOST_TEST(a.empty()); +} + +template +void print_range(std::ostream& out, Iterator b, Iterator e) +{ + out << '['; + bool first = true; + + for (; b != e; ++b) + { + if (first) { first = false; } + else { out << ','; } + out << *b; + } + out << ']'; +} + +template +void print_range(std::ostream& out, const Range& range) +{ + print_range(out, range.cbegin(), range.cend()); +} + +template +void print_range(std::ostream& out, Array (&range)[N]) +{ + print_range(out, range, range + N); +} + +template +void test_equal_range(const C1& a, const C2 (&b)[N]) +{ + bool equals = boost::algorithm::equal + (a.begin(), a.end(), b, b+N); + + BOOST_TEST(equals); + + if (!equals) + { + print_range(std::cerr, a); + std::cerr << "\n"; + print_range(std::cerr, b); + std::cerr << "\n"; + } +} + + +template +void test_equal_range(const C1& a, const C2&b) +{ + bool equals = boost::algorithm::equal + (a.begin(), a.end(), b.begin(), b.end()); + + BOOST_TEST(equals); + + if (!equals) + { + print_range(std::cerr, a); + std::cerr << "\n"; + print_range(std::cerr, b); + std::cerr << "\n"; + } +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + +// support initializer_list +template +void test_equal_range(const C& a, std::initializer_list il) +{ + typedef typename C::value_type T; + boost::container::vector b; + + for (auto&& elem : il) + { + b.emplace_back(elem); + } + + test_equal_range(a, b); +} + +#endif //#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + +#endif //BOOST_CONTAINER_TEST_TEST_UTIL_HPP From fb881800012ebe9ed134de21003748a0c04e8bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 10 Aug 2020 11:18:36 +0200 Subject: [PATCH 50/61] - Change priv_insert_forward_range_expand_forward position to raw pointer to be more homogeneous with the rest of similar functions. - Remove some unused variable warnings due to BOOST_IF_CONSTEXPR additions. --- include/boost/container/vector.hpp | 92 ++++++++++++++---------------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index f8f264a..8722f62 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -386,6 +386,12 @@ struct vector_alloc_holder BOOST_CONTAINER_FORCEINLINE void set_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW { this->m_size = static_cast(s); } + BOOST_CONTAINER_FORCEINLINE void dec_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size -= static_cast(s); } + + BOOST_CONTAINER_FORCEINLINE void inc_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size += static_cast(s); } + BOOST_CONTAINER_FORCEINLINE void set_stored_capacity(size_type c) BOOST_NOEXCEPT_OR_NOTHROW { this->m_capacity = static_cast(c); } @@ -610,6 +616,12 @@ struct vector_alloc_holder BOOST_CONTAINER_FORCEINLINE void set_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW { this->m_size = static_cast(s); } + BOOST_CONTAINER_FORCEINLINE void dec_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size -= static_cast(s); } + + BOOST_CONTAINER_FORCEINLINE void inc_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size += static_cast(s); } + BOOST_CONTAINER_FORCEINLINE void priv_first_allocation(size_type cap) { if(cap > allocator_type::internal_capacity){ @@ -655,7 +667,7 @@ struct vector_alloc_holder BOOST_CONTAINER_FORCEINLINE pointer start() const BOOST_NOEXCEPT_OR_NOTHROW { return allocator_type::internal_storage(); } - BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW { return allocator_type::internal_capacity; } stored_size_type m_size; @@ -1754,9 +1766,9 @@ private: template BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_FWD_REF(Args)...args) { + T* const p = this->priv_raw_end(); if (BOOST_LIKELY(this->room_enough())){ //There is more memory, just construct a new object at the end - T* const p = this->priv_raw_end(); allocator_traits_type::construct(this->m_holder.alloc(), p, ::boost::forward(args)...); ++this->m_holder.m_size; return *p; @@ -1764,7 +1776,7 @@ private: else{ typedef dtl::insert_emplace_proxy proxy_t; return *this->priv_insert_forward_range_no_capacity - (this->back_ptr(), 1, proxy_t(::boost::forward(args)...), alloc_version()); + (p, 1, proxy_t(::boost::forward(args)...), alloc_version()); } } @@ -1814,8 +1826,8 @@ private: BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_MOVE_UREF##N)\ {\ + T* const p = this->priv_raw_end();\ if (BOOST_LIKELY(this->room_enough())){\ - T* const p = this->priv_raw_end();\ allocator_traits_type::construct (this->m_holder.alloc()\ , this->priv_raw_end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ ++this->m_holder.m_size;\ @@ -1824,7 +1836,7 @@ private: else{\ typedef dtl::insert_emplace_proxy_arg##N proxy_t;\ return *this->priv_insert_forward_range_no_capacity\ - ( this->back_ptr(), 1, proxy_t(BOOST_MOVE_FWD##N), alloc_version());\ + ( p, 1, proxy_t(BOOST_MOVE_FWD##N), alloc_version());\ }\ }\ \ @@ -2243,14 +2255,14 @@ private: else{ //Hole was just filled, disable exception rollback and change vector size past_hole_values_destroyer.release(); - this->m_holder.set_stored_size(this->size() + element_count); + this->m_holder.inc_stored_size(element_count); } } else{ if(old_hole_size){ //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size past_hole_values_destroyer.release(); - this->m_holder.set_stored_size(this->size() + element_count); + this->m_holder.inc_stored_size(element_count); } //Insert the new value in the already constructed range begin_ptr[pos + insertions_left - 1] = position_value.get_val(); @@ -2359,7 +2371,7 @@ private: } BOOST_CONTAINER_FORCEINLINE bool room_enough() const - { return this->m_holder.m_size < this->m_holder.capacity(); } + { return this->m_holder.m_size != this->m_holder.capacity(); } BOOST_CONTAINER_FORCEINLINE pointer back_ptr() const { return this->m_holder.start() + this->m_holder.m_size; } @@ -2581,7 +2593,7 @@ private: T* const destroy_pos = this->priv_raw_begin() + (this->m_holder.m_size-n); boost::container::destroy_alloc_n(this->get_stored_allocator(), destroy_pos, n); } - this->m_holder.set_stored_size(this->size() - n); + this->m_holder.dec_stored_size(n); } template @@ -2589,7 +2601,7 @@ private: { T* const old_end_pos = this->priv_raw_end(); T* const new_end_pos = boost::container::uninitialized_copy_alloc(this->m_holder.alloc(), first, last, old_end_pos); - this->m_holder.set_stored_size(this->size() + new_end_pos - old_end_pos); + this->m_holder.inc_stored_size(new_end_pos - old_end_pos); } void priv_destroy_all() BOOST_NOEXCEPT_OR_NOTHROW @@ -2602,32 +2614,13 @@ private: template BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) u) { - BOOST_ASSERT(this->priv_in_range_or_end(p)); - typedef typename dtl::if_c < boost::move_detail::is_rvalue_reference::value - , dtl::insert_move_proxy - , dtl::insert_copy_proxy - >::type proxy_t; - return this->priv_insert_forward_range - ( vector_iterator_get_ptr(p), 1, proxy_t((reference)u)); + return this->emplace(p, ::boost::forward(u)); } template BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u) { - if (BOOST_LIKELY(this->room_enough())){ - //There is more memory, just construct a new object at the end - allocator_traits_type::construct - ( this->m_holder.alloc(), this->priv_raw_end(), ::boost::forward(u) ); - ++this->m_holder.m_size; - } - else{ - typedef typename dtl::if_c < boost::move_detail::is_rvalue_reference::value - , dtl::insert_move_proxy - , dtl::insert_copy_proxy - >::type proxy_t; - this->priv_insert_forward_range_no_capacity - ( this->back_ptr(), 1, proxy_t((reference)u), alloc_version()); - } + this->emplace_back(::boost::forward(u)); } BOOST_CONTAINER_FORCEINLINE dtl::insert_n_copies_proxy priv_resize_proxy(const T &x) @@ -2686,18 +2679,17 @@ private: template BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range_no_capacity - (const pointer &, const size_type, const InsertionProxy , version_0) + (T * const, const size_type, const InsertionProxy , version_0) { return alloc_holder_t::on_capacity_overflow(), iterator(); } template - BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range_no_capacity - (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_1) + iterator priv_insert_forward_range_no_capacity + (T *const raw_pos, const size_type n, const InsertionProxy insert_range_proxy, version_1) { //Check if we have enough memory or try to expand current memory - const size_type n_pos = pos - this->m_holder.start(); - T *const raw_pos = boost::movelib::to_raw_pointer(pos); + const size_type n_pos = raw_pos - this->priv_raw_begin(); const size_type new_cap = this->m_holder.template next_capacity(n); //Pass the hint so that allocators can take advantage of this. @@ -2711,10 +2703,9 @@ private: template iterator priv_insert_forward_range_no_capacity - (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_2) + (T *const raw_pos, const size_type n, const InsertionProxy insert_range_proxy, version_2) { //Check if we have enough memory or try to expand current memory - T *const raw_pos = boost::movelib::to_raw_pointer(pos); const size_type n_pos = raw_pos - this->priv_raw_begin(); //There is not enough memory, allocate a new @@ -2757,18 +2748,19 @@ private: } template - BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range + iterator priv_insert_forward_range (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy) { BOOST_ASSERT(this->m_holder.capacity() >= this->m_holder.m_size); + T *const p = boost::movelib::to_raw_pointer(pos); //Check if we have enough memory or try to expand current memory if (BOOST_LIKELY(n <= (this->m_holder.capacity() - this->m_holder.m_size))){ //Expand forward - this->priv_insert_forward_range_expand_forward(boost::movelib::to_raw_pointer(pos), n, insert_range_proxy); + this->priv_insert_forward_range_expand_forward(p, n, insert_range_proxy); return iterator(pos); } else{ - return this->priv_insert_forward_range_no_capacity(pos, n, insert_range_proxy, alloc_version()); + return this->priv_insert_forward_range_no_capacity(p, n, insert_range_proxy, alloc_version()); } } @@ -2792,8 +2784,7 @@ private: } template - BOOST_CONTAINER_FORCEINLINE void priv_resize - (const size_type new_size, const U &u, AllocVersion) + void priv_resize(const size_type new_size, const U &u, AllocVersion) { const size_type sz = this->m_holder.m_size; if (new_size < sz){ @@ -2899,7 +2890,7 @@ private: { return this->priv_raw_begin() + this->m_holder.m_size; } template - BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy) + void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy) { //n can't be 0, because there is nothing to do in that case bool const single_value_proxy = dtl::is_single_value_proxy::value; @@ -3071,8 +3062,8 @@ private: // //Now initialize the rest of memory with the last old values //All new elements correctly constructed, avoid new element destruction - const size_type raw_gap = s_before - before_plus_new; BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr){ + const size_type raw_gap = s_before - before_plus_new; //Now initialize the rest of s_before memory with the //first of elements after new values ::boost::container::uninitialized_move_alloc_n(a, pos, raw_gap, new_start + before_plus_new); @@ -3223,17 +3214,20 @@ private: //Copy all new elements const size_type rest_new = n - mid_n; insert_range_proxy.copy_n_and_update(a, old_start, rest_new); + T* const move_start = old_start + rest_new; //Displace old_end, but make sure data has to be moved T* const move_end = move_start != pos ? ::boost::container::move(pos, old_finish, move_start) : old_finish; + (void)move_end; //To avoid warnings of unused initialization for move_end in case + //trivial_dctr_after_move is true //Destroy remaining moved elements from old_end except if they //have trivial destructor after being moved - size_type n_destroy = s_before - n; + const size_type n_destroy = s_before - n; BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr_after_move){ boost::container::destroy_alloc_n(a, move_end, n_destroy); } - this->m_holder.set_stored_size(this->size() - n_destroy); + this->m_holder.dec_stored_size(n_destroy); } } @@ -3276,7 +3270,7 @@ private: //First copy the part of old_end raw_mem T* finish_n = old_finish - n_after; ::boost::container::uninitialized_move_alloc(a, finish_n, old_finish, old_finish); - this->m_holder.set_stored_size(this->size() + n_after); + this->m_holder.inc_stored_size(n_after); //Displace the rest of old_end to the new position boost::container::move_backward(pos, finish_n, old_finish); //Now overwrite with new_end @@ -3308,7 +3302,7 @@ private: insert_range_proxy.copy_n_and_update(a, pos, elemsafter); //Copy the rest to the uninitialized zone filling the gap insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, mid_last_dist); - this->m_holder.set_stored_size(this->size() + n_after); + this->m_holder.inc_stored_size(n_after); old_end_destroyer.release(); } } From efd08d9a0eb774acbc414ac85f8b55341d56907a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 10 Aug 2020 11:19:01 +0200 Subject: [PATCH 51/61] Improve timing and add warm-up step --- bench/bench_vectors.cpp | 92 ++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 52 deletions(-) diff --git a/bench/bench_vectors.cpp b/bench/bench_vectors.cpp index e46c6c4..8e3665d 100644 --- a/bench/bench_vectors.cpp +++ b/bench/bench_vectors.cpp @@ -8,12 +8,6 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER -#pragma warning (disable : 4512) -#pragma warning (disable : 4267) -#pragma warning (disable : 4244) -#endif - #include #include #include @@ -47,21 +41,21 @@ class MyInt int int_; public: - explicit MyInt(int i = 0) + BOOST_CONTAINER_FORCEINLINE explicit MyInt(int i = 0) : int_(i) {} - MyInt(const MyInt &other) + BOOST_CONTAINER_FORCEINLINE MyInt(const MyInt &other) : int_(other.int_) {} - MyInt & operator=(const MyInt &other) + BOOST_CONTAINER_FORCEINLINE MyInt & operator=(const MyInt &other) { int_ = other.int_; return *this; } - ~MyInt() + BOOST_CONTAINER_FORCEINLINE ~MyInt() { int_ = 0; } @@ -71,20 +65,20 @@ template::value> struct capacity_wrapper { - static typename C::size_type get_capacity(const C &c) + BOOST_CONTAINER_FORCEINLINE static typename C::size_type get_capacity(const C &c) { return c.capacity(); } - static void set_reserve(C &c, typename C::size_type cp) + BOOST_CONTAINER_FORCEINLINE static void set_reserve(C &c, typename C::size_type cp) { c.reserve(cp); } }; template struct capacity_wrapper { - static typename C::size_type get_capacity(const C &) + BOOST_CONTAINER_FORCEINLINE static typename C::size_type get_capacity(const C &) { return 0u; } - static void set_reserve(C &, typename C::size_type ) + BOOST_CONTAINER_FORCEINLINE static void set_reserve(C &, typename C::size_type ) { } }; @@ -92,7 +86,7 @@ const std::size_t RangeSize = 5; struct insert_end_range { - std::size_t capacity_multiplier() const + BOOST_CONTAINER_FORCEINLINE std::size_t capacity_multiplier() const { return RangeSize; } template @@ -107,14 +101,14 @@ struct insert_end_range struct insert_end_repeated { - std::size_t capacity_multiplier() const + BOOST_CONTAINER_FORCEINLINE std::size_t capacity_multiplier() const { return RangeSize; } template BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) { c.insert(c.end(), RangeSize, MyInt(i)); } - const char *name() const + BOOST_CONTAINER_FORCEINLINE const char *name() const { return "insert_end_repeated"; } MyInt a[RangeSize]; @@ -122,47 +116,33 @@ struct insert_end_repeated struct push_back { - std::size_t capacity_multiplier() const + BOOST_CONTAINER_FORCEINLINE std::size_t capacity_multiplier() const { return 1; } template BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) { c.push_back(MyInt(i)); } - const char *name() const + BOOST_CONTAINER_FORCEINLINE const char *name() const { return "push_back"; } }; -struct emplace_back -{ - std::size_t capacity_multiplier() const - { return 1; } - - template - BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) - { c.emplace_back(MyInt(i)); } - - const char *name() const - { return "emplace_back"; } -}; - struct insert_near_end_repeated { - - std::size_t capacity_multiplier() const + BOOST_CONTAINER_FORCEINLINE std::size_t capacity_multiplier() const { return RangeSize; } template BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) { c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), RangeSize, MyInt(i)); } - const char *name() const + BOOST_CONTAINER_FORCEINLINE const char *name() const { return "insert_near_end_repeated"; } }; struct insert_near_end_range { - std::size_t capacity_multiplier() const + BOOST_CONTAINER_FORCEINLINE std::size_t capacity_multiplier() const { return RangeSize; } template @@ -171,7 +151,7 @@ struct insert_near_end_range c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), &a[0], &a[0]+RangeSize); } - const char *name() const + BOOST_CONTAINER_FORCEINLINE const char *name() const { return "insert_near_end_repeated"; } MyInt a[RangeSize]; @@ -179,7 +159,7 @@ struct insert_near_end_range struct insert_near_end { - std::size_t capacity_multiplier() const + BOOST_CONTAINER_FORCEINLINE std::size_t capacity_multiplier() const { return 1; } template @@ -191,36 +171,45 @@ struct insert_near_end c.insert(it, MyInt(i)); } - const char *name() const + BOOST_CONTAINER_FORCEINLINE const char *name() const { return "insert_near_end"; } }; template -void vector_test_template(unsigned int num_iterations, unsigned int num_elements, const char *cont_name) +void vector_test_template(std::size_t num_iterations, std::size_t num_elements, const char *cont_name) { - cpu_timer timer; - timer.resume(); - - - unsigned int capacity = 0; - Operation op; typedef capacity_wrapper cpw_t; + + Container c; + cpw_t::set_reserve(c, num_elements); + + Operation op; const typename Container::size_type multiplier = op.capacity_multiplier(); - for(unsigned int r = 0; r != num_iterations; ++r){ - Container c; - cpw_t::set_reserve(c, num_elements); + //Warm-up operations + for(std::size_t e = 0, max = num_elements/multiplier; e != max; ++e){ + op(c, static_cast(e)); + } + c.clear(); - for(unsigned e = 0, max = num_elements/multiplier; e != max; ++e){ + cpu_timer timer; + timer.start(); + + for(std::size_t r = 0; r != num_iterations; ++r){ + + for(std::size_t e = 0, max = num_elements/multiplier; e != max; ++e){ op(c, static_cast(e)); } - capacity = static_cast(cpw_t::get_capacity(c)); + timer.stop(); + c.clear(); + timer.resume(); } timer.stop(); + std::size_t capacity = cpw_t::get_capacity(c); nanosecond_type nseconds = timer.elapsed().wall; @@ -271,7 +260,6 @@ int main() { //end test_vectors(); - test_vectors(); test_vectors(); test_vectors(); //near end From 2e78cb524c599a8392ca3eb2bcde0e7d7f1528a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 11 Aug 2020 23:49:13 +0200 Subject: [PATCH 52/61] Unroll operation loop to avoid measuring loop overhead and other modifications to exercise more paths of the insertion functions. --- bench/bench_vectors.cpp | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/bench/bench_vectors.cpp b/bench/bench_vectors.cpp index 8e3665d..1fae391 100644 --- a/bench/bench_vectors.cpp +++ b/bench/bench_vectors.cpp @@ -134,7 +134,7 @@ struct insert_near_end_repeated template BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) - { c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), RangeSize, MyInt(i)); } + { c.insert(c.size() >= 2*RangeSize ? c.end()-2*RangeSize : c.begin(), RangeSize, MyInt(i)); } BOOST_CONTAINER_FORCEINLINE const char *name() const { return "insert_near_end_repeated"; } @@ -148,11 +148,11 @@ struct insert_near_end_range template BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int) { - c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), &a[0], &a[0]+RangeSize); + c.insert(c.size() >= 2*RangeSize ? c.end()-2*RangeSize : c.begin(), &a[0], &a[0]+RangeSize); } BOOST_CONTAINER_FORCEINLINE const char *name() const - { return "insert_near_end_repeated"; } + { return "insert_near_end_range"; } MyInt a[RangeSize]; }; @@ -167,7 +167,7 @@ struct insert_near_end { typedef typename C::iterator it_t; it_t it (c.end()); - it -= static_cast(!c.empty()); + it -= static_cast(c.size() >= 2)*2; c.insert(it, MyInt(i)); } @@ -187,24 +187,41 @@ void vector_test_template(std::size_t num_iterations, std::size_t num_elements, Operation op; const typename Container::size_type multiplier = op.capacity_multiplier(); - //Warm-up operations + //Warm-up operation for(std::size_t e = 0, max = num_elements/multiplier; e != max; ++e){ op(c, static_cast(e)); } c.clear(); cpu_timer timer; - timer.start(); + const std::size_t max = num_elements/multiplier; for(std::size_t r = 0; r != num_iterations; ++r){ - for(std::size_t e = 0, max = num_elements/multiplier; e != max; ++e){ - op(c, static_cast(e)); + //Unrolll the loop to avoid noise from loop code + int i = 0; + timer.resume(); + for(std::size_t e = 0; e < max/16; ++e){ + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); + op(c, static_cast(i++)); } timer.stop(); c.clear(); - timer.resume(); } timer.stop(); @@ -216,7 +233,7 @@ void vector_test_template(std::size_t num_iterations, std::size_t num_elements, std::cout << cont_name << "->" << op.name() <<" ns: " << float(nseconds)/(num_iterations*num_elements) << '\t' - << "Capacity: " << (unsigned int)capacity + << "Capacity: " << capacity << "\n"; } From c2a4ed70d9e3577fe6c91a0f05ef7496502722ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 11 Aug 2020 23:49:48 +0200 Subject: [PATCH 53/61] Avoid unsigned underflow, legal but flagged as suspicious by several tools. --- .../container/detail/advanced_insert_int.hpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index b130993..dcc8c9f 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -107,8 +107,10 @@ struct insert_n_copies_proxy BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, size_type n) const { - for (; 0 < n; --n, ++p){ + while (n){ + --n; *p = v_; + ++p; } } @@ -121,18 +123,21 @@ struct insert_value_initialized_n_proxy typedef ::boost::container::allocator_traits alloc_traits; typedef typename allocator_traits::size_type size_type; typedef typename allocator_traits::value_type value_type; + typedef typename dtl::aligned_storage::value>::type storage_t; BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { boost::container::uninitialized_value_init_alloc_n(a, n, p); } void copy_n_and_update(Allocator &a, Iterator p, size_type n) const { - for (; 0 < n; --n, ++p){ - typename dtl::aligned_storage::value>::type v; + while (n){ + --n; + storage_t v; value_type *vp = reinterpret_cast(v.data); alloc_traits::construct(a, vp); value_destructor on_exit(a, *vp); (void)on_exit; *p = ::boost::move(*vp); + ++p; } } }; @@ -143,6 +148,7 @@ struct insert_default_initialized_n_proxy typedef ::boost::container::allocator_traits alloc_traits; typedef typename allocator_traits::size_type size_type; typedef typename allocator_traits::value_type value_type; + typedef typename dtl::aligned_storage::value>::type storage_t; BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { boost::container::uninitialized_default_init_alloc_n(a, n, p); } @@ -150,12 +156,14 @@ struct insert_default_initialized_n_proxy void copy_n_and_update(Allocator &a, Iterator p, size_type n) const { if(!is_pod::value){ - for (; 0 < n; --n, ++p){ + while (n){ + --n; typename dtl::aligned_storage::value>::type v; value_type *vp = reinterpret_cast(v.data); alloc_traits::construct(a, vp, default_init); value_destructor on_exit(a, *vp); (void)on_exit; *p = ::boost::move(*vp); + ++p; } } } From 5d100cb45f26445608a42f5ab6909de04d254742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 11 Aug 2020 23:50:08 +0200 Subject: [PATCH 54/61] Add BOOST_CONTAINER_FORCEINLINE to trivial functions --- .../boost/container/detail/copy_move_algo.hpp | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/include/boost/container/detail/copy_move_algo.hpp b/include/boost/container/detail/copy_move_algo.hpp index cb21cc1..2212281 100644 --- a/include/boost/container/detail/copy_move_algo.hpp +++ b/include/boost/container/detail/copy_move_algo.hpp @@ -171,7 +171,7 @@ struct disable_if_memtransfer_copy_assignable template // F models ForwardIterator -inline F memmove(I f, I l, F r) BOOST_NOEXCEPT_OR_NOTHROW +BOOST_CONTAINER_FORCEINLINE F memmove(I f, I l, F r) BOOST_NOEXCEPT_OR_NOTHROW { typedef typename boost::container::iterator_traits::value_type value_type; value_type *const dest_raw = boost::movelib::iterator_to_raw_pointer(r); @@ -189,7 +189,7 @@ template // F models ForwardIterator -F memmove_n(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW +BOOST_CONTAINER_FORCEINLINE F memmove_n(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW { typedef typename boost::container::iterator_traits::value_type value_type; if(BOOST_LIKELY(n)){ @@ -204,7 +204,7 @@ template // F models ForwardIterator -I memmove_n_source(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW +BOOST_CONTAINER_FORCEINLINE I memmove_n_source(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW { if(BOOST_LIKELY(n)){ typedef typename boost::container::iterator_traits::value_type value_type; @@ -218,7 +218,7 @@ template // F models ForwardIterator -I memmove_n_source_dest(I f, U n, F &r) BOOST_NOEXCEPT_OR_NOTHROW +BOOST_CONTAINER_FORCEINLINE I memmove_n_source_dest(I f, U n, F &r) BOOST_NOEXCEPT_OR_NOTHROW { typedef typename boost::container::iterator_traits::value_type value_type; if(BOOST_LIKELY(n)){ @@ -315,7 +315,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_constructible::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_constructible::type uninitialized_move_alloc(Allocator &, I f, I l, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove(f, l, r); } @@ -361,7 +361,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_constructible::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_constructible::type uninitialized_move_alloc_n(Allocator &, I f, typename boost::container::allocator_traits::size_type n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n(f, n, r); } @@ -407,7 +407,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_constructible::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_constructible::type uninitialized_move_alloc_n_source(Allocator &, I f, typename boost::container::allocator_traits::size_type n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n_source(f, n, r); } @@ -452,7 +452,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_constructible::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_constructible::type uninitialized_copy_alloc(Allocator &, I f, I l, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove(f, l, r); } @@ -498,7 +498,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_constructible::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_constructible::type uninitialized_copy_alloc_n(Allocator &, I f, typename boost::container::allocator_traits::size_type n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n(f, n, r); } @@ -543,7 +543,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_constructible::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_constructible::type uninitialized_copy_alloc_n_source(Allocator &, I f, typename boost::container::allocator_traits::size_type n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n_source(f, n, r); } @@ -587,7 +587,7 @@ inline typename dtl::disable_if_memzero_initializable::type template // F models ForwardIterator -inline typename dtl::enable_if_memzero_initializable::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memzero_initializable::type uninitialized_value_init_alloc_n(Allocator &, typename boost::container::allocator_traits::size_type n, F r) { typedef typename boost::container::iterator_traits::value_type value_type; @@ -758,7 +758,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_assignable::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_assignable::type copy_n(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n(f, n, r); } @@ -787,7 +787,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_assignable::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_assignable::type copy_n_source(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n_source(f, n, r); } @@ -816,7 +816,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_assignable::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_assignable::type copy_n_source_dest(I f, U n, F &r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n_source_dest(f, n, r); } @@ -871,7 +871,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_assignable::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_assignable::type move_n(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n(f, n, r); } @@ -898,7 +898,7 @@ inline typename dtl::disable_if_memtransfer_copy_assignable::type template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_assignable::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_assignable::type move_backward(I f, I l, F r) BOOST_NOEXCEPT_OR_NOTHROW { typedef typename boost::container::iterator_traits::value_type value_type; @@ -935,7 +935,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_assignable::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_assignable::type move_n_source_dest(I f, U n, F &r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n_source_dest(f, n, r); } @@ -964,7 +964,7 @@ template // F models ForwardIterator -inline typename dtl::enable_if_memtransfer_copy_assignable::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_assignable::type move_n_source(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n_source(f, n, r); } @@ -992,7 +992,7 @@ template // U models unsigned integral constant -inline typename dtl::enable_if_trivially_destructible::type +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_trivially_destructible::type destroy_alloc_n(Allocator &, I, U) {} From 5a52472cd00994bf1752e92c1c178a5a822a36cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 11 Aug 2020 23:50:47 +0200 Subject: [PATCH 55/61] Make a different version for single value proxies in priv_insert_forward_range_expand_forward and force-inline only that version --- include/boost/container/vector.hpp | 100 +++++++++++++++++------------ 1 file changed, 59 insertions(+), 41 deletions(-) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 8722f62..3268683 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -2685,7 +2685,7 @@ private: } template - iterator priv_insert_forward_range_no_capacity + BOOST_CONTAINER_NOINLINE iterator priv_insert_forward_range_no_capacity (T *const raw_pos, const size_type n, const InsertionProxy insert_range_proxy, version_1) { //Check if we have enough memory or try to expand current memory @@ -2702,7 +2702,7 @@ private: } template - iterator priv_insert_forward_range_no_capacity + BOOST_CONTAINER_NOINLINE iterator priv_insert_forward_range_no_capacity (T *const raw_pos, const size_type n, const InsertionProxy insert_range_proxy, version_2) { //Check if we have enough memory or try to expand current memory @@ -2724,7 +2724,8 @@ private: #endif this->m_holder.capacity(real_cap); //Expand forward - this->priv_insert_forward_range_expand_forward(raw_pos, n, insert_range_proxy); + this->priv_insert_forward_range_expand_forward + (raw_pos, n, insert_range_proxy, dtl::bool_::value>()); } //Backwards (and possibly forward) expansion else{ @@ -2748,7 +2749,7 @@ private: } template - iterator priv_insert_forward_range + BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy) { BOOST_ASSERT(this->m_holder.capacity() >= this->m_holder.m_size); @@ -2756,7 +2757,8 @@ private: //Check if we have enough memory or try to expand current memory if (BOOST_LIKELY(n <= (this->m_holder.capacity() - this->m_holder.m_size))){ //Expand forward - this->priv_insert_forward_range_expand_forward(p, n, insert_range_proxy); + this->priv_insert_forward_range_expand_forward + (p, n, insert_range_proxy, dtl::bool_::value>()); return iterator(pos); } else{ @@ -2889,55 +2891,71 @@ private: BOOST_CONTAINER_FORCEINLINE T* priv_raw_end() const { return this->priv_raw_begin() + this->m_holder.m_size; } - template - void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy) + template //inline single-element version as it is significantly smaller + BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward + (T* const raw_pos, const size_type, InsertionProxy insert_range_proxy, dtl::true_type) { - //n can't be 0, because there is nothing to do in that case - bool const single_value_proxy = dtl::is_single_value_proxy::value; - //bool const single_value_proxy = false; - if(BOOST_UNLIKELY(!single_value_proxy && !n)) - return; - + BOOST_ASSERT(this->room_enough()); //There is enough memory T* const old_finish = this->priv_raw_end(); - const size_type elems_after = old_finish - raw_pos; - allocator_type & a = this->m_holder.alloc(); - if (!elems_after){ - insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, n); - this->m_holder.m_size += static_cast(n); + if (old_finish == raw_pos){ + insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, 1); + ++this->m_holder.m_size; } - else if(single_value_proxy){ + else{ //New elements can be just copied. //Move to uninitialized memory last objects - allocator_traits_type::construct(a, old_finish, ::boost::move(*(old_finish-1))); + T * const before_old_finish = old_finish-1; + allocator_type & a = this->m_holder.alloc(); + allocator_traits_type::construct(a, old_finish, ::boost::move(*before_old_finish)); ++this->m_holder.m_size; //Copy previous to last objects to the initialized end - boost::container::move_backward(raw_pos, old_finish - 1, old_finish); + boost::container::move_backward(raw_pos, before_old_finish, old_finish); //Insert new objects in the raw_pos insert_range_proxy.copy_n_and_update(a, raw_pos, 1); } - else if(elems_after >= n){ - //New elements can be just copied. - //Move to uninitialized memory last objects - ::boost::container::uninitialized_move_alloc_n(a, old_finish - n, n, old_finish); - this->m_holder.m_size += static_cast(n); - //Copy previous to last objects to the initialized end - boost::container::move_backward(raw_pos, old_finish - n, old_finish); - //Insert new objects in the raw_pos - insert_range_proxy.copy_n_and_update(a, raw_pos, n); + } + + template + void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy, dtl::false_type) + { + //In case n is 0 there is nothing to do + if(BOOST_UNLIKELY(!n)) + return; + + //There is enough memory + T* const raw_old_finish = this->priv_raw_end(); + + if (raw_old_finish == raw_pos){ + insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), raw_old_finish, n); + this->m_holder.inc_stored_size(n); } - else { - //The new elements don't fit in the [raw_pos, end()) range. - //Copy old [raw_pos, end()) elements to the uninitialized memory (a gap is created) - ::boost::container::uninitialized_move_alloc(a, raw_pos, old_finish, raw_pos + n); - typename value_traits::ArrayDestructor on_exception(raw_pos + n, a, elems_after); - //Copy first new elements in raw_pos (gap is still there) - insert_range_proxy.copy_n_and_update(a, raw_pos, elems_after); - //Copy to the beginning of the unallocated zone the last new elements (the gap is closed). - insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, n - elems_after); - this->m_holder.m_size += static_cast(n); - on_exception.release(); + else{ + const size_type elems_after = raw_old_finish - raw_pos; + allocator_type & a = this->m_holder.alloc(); + if(elems_after >= n){ + //New elements can be just copied. + //Move to uninitialized memory last objects + ::boost::container::uninitialized_move_alloc_n(a, raw_old_finish - n, n, raw_old_finish); + this->m_holder.inc_stored_size(n); + //Copy previous to last objects to the initialized end + boost::container::move_backward(raw_pos, raw_old_finish - n, raw_old_finish); + //Insert new objects in the raw_pos + insert_range_proxy.copy_n_and_update(a, raw_pos, n); + } + else { + //The new elements don't fit in the [raw_pos, end()) range. + //Copy old [raw_pos, end()) elements to the uninitialized memory (a gap is created) + ::boost::container::uninitialized_move_alloc(a, raw_pos, raw_old_finish, raw_pos + n); + typename value_traits::ArrayDestructor on_exception(raw_pos + n, a, elems_after); + //Copy first new elements in raw_pos (gap is still there) + insert_range_proxy.copy_n_and_update(a, raw_pos, elems_after); + //Copy to the beginning of the unallocated zone the last new elements (the gap is closed). + insert_range_proxy.uninitialized_copy_n_and_update(a, raw_old_finish, n - elems_after); + this->m_holder.inc_stored_size(n); + on_exception.release(); + } } } From 2f9f3831efa19ba3035e17699eeb9faa115b36d9 Mon Sep 17 00:00:00 2001 From: Lucas Camolezi Date: Tue, 25 Aug 2020 15:15:59 -0300 Subject: [PATCH 56/61] Add missing include Allow this header file to be built standalone, in a clang C++ modules context. --- include/boost/container/detail/compare_functors.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/container/detail/compare_functors.hpp b/include/boost/container/detail/compare_functors.hpp index 21f222b..6478418 100644 --- a/include/boost/container/detail/compare_functors.hpp +++ b/include/boost/container/detail/compare_functors.hpp @@ -20,6 +20,7 @@ #endif #include +#include namespace boost { namespace container { From 438813726b0b92133241d7a5a426cc881c032931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 31 Aug 2020 13:36:46 +0200 Subject: [PATCH 57/61] Add BOOST_CONTAINER_FORCEINLINE to trivial operations. --- include/boost/container/detail/flat_tree.hpp | 38 ++++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 8e62a61..a8bcfd8 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -123,7 +123,7 @@ BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(stored_allocator_type) // /////////////////////////////////////// template -void flat_tree_container_inplace_merge //is_contiguous_container == true +BOOST_CONTAINER_FORCEINLINE 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; @@ -135,7 +135,7 @@ void flat_tree_container_inplace_merge //is_contiguous_container == true } template -void flat_tree_container_inplace_merge //is_contiguous_container == false +BOOST_CONTAINER_FORCEINLINE 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); @@ -147,7 +147,7 @@ void flat_tree_container_inplace_merge //is_contiguous_container == false // /////////////////////////////////////// template -void flat_tree_container_inplace_sort_ending //is_contiguous_container == true +BOOST_CONTAINER_FORCEINLINE 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; @@ -158,7 +158,7 @@ void flat_tree_container_inplace_sort_ending //is_contiguous_container == true } template -void flat_tree_container_inplace_sort_ending //is_contiguous_container == false +BOOST_CONTAINER_FORCEINLINE 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); @@ -314,7 +314,7 @@ void flat_tree_sort_contiguous_to_adopt // is_contiguous_container == true } template -void flat_tree_adopt_sequence_equal // is_contiguous_container == true +BOOST_CONTAINER_FORCEINLINE void flat_tree_adopt_sequence_equal // is_contiguous_container == true (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_) { flat_tree_sort_contiguous_to_adopt(tseq, boost::move(seq), comp); @@ -322,7 +322,7 @@ void flat_tree_adopt_sequence_equal // is_contiguous_container == true } template -void flat_tree_adopt_sequence_equal // is_contiguous_container == false +BOOST_CONTAINER_FORCEINLINE void flat_tree_adopt_sequence_equal // is_contiguous_container == false (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::false_) { boost::movelib::adaptive_sort(seq.begin(), seq.end(), comp); @@ -408,24 +408,24 @@ class flat_tree_value_compare typedef Value second_argument_type; typedef bool return_type; public: - flat_tree_value_compare() + BOOST_CONTAINER_FORCEINLINE flat_tree_value_compare() : Compare() {} - flat_tree_value_compare(const Compare &pred) + BOOST_CONTAINER_FORCEINLINE flat_tree_value_compare(const Compare &pred) : Compare(pred) {} - bool operator()(const Value& lhs, const Value& rhs) const + BOOST_CONTAINER_FORCEINLINE bool operator()(const Value& lhs, const Value& rhs) const { KeyOfValue key_extract; return Compare::operator()(key_extract(lhs), key_extract(rhs)); } - const Compare &get_comp() const + BOOST_CONTAINER_FORCEINLINE const Compare &get_comp() const { return *this; } - Compare &get_comp() + BOOST_CONTAINER_FORCEINLINE Compare &get_comp() { return *this; } }; @@ -479,35 +479,35 @@ class flat_tree BOOST_COPYABLE_AND_MOVABLE(Data) public: - Data() + BOOST_CONTAINER_FORCEINLINE Data() : value_compare(), m_seq() {} - explicit Data(const allocator_t &alloc) + BOOST_CONTAINER_FORCEINLINE explicit Data(const allocator_t &alloc) : value_compare(), m_seq(alloc) {} - explicit Data(const Compare &comp) + BOOST_CONTAINER_FORCEINLINE explicit Data(const Compare &comp) : value_compare(comp), m_seq() {} - Data(const Compare &comp, const allocator_t &alloc) + BOOST_CONTAINER_FORCEINLINE Data(const Compare &comp, const allocator_t &alloc) : value_compare(comp), m_seq(alloc) {} - explicit Data(const Data &d) + BOOST_CONTAINER_FORCEINLINE explicit Data(const Data &d) : value_compare(static_cast(d)), m_seq(d.m_seq) {} - Data(BOOST_RV_REF(Data) d) + BOOST_CONTAINER_FORCEINLINE Data(BOOST_RV_REF(Data) d) : value_compare(boost::move(static_cast(d))), m_seq(boost::move(d.m_seq)) {} - Data(const Data &d, const allocator_t &a) + BOOST_CONTAINER_FORCEINLINE Data(const Data &d, const allocator_t &a) : value_compare(static_cast(d)), m_seq(d.m_seq, a) {} - Data(BOOST_RV_REF(Data) d, const allocator_t &a) + BOOST_CONTAINER_FORCEINLINE Data(BOOST_RV_REF(Data) d, const allocator_t &a) : value_compare(boost::move(static_cast(d))), m_seq(boost::move(d.m_seq), a) {} From 0b297019ec43483f523a3270b632fecbc3ce5e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 31 Aug 2020 13:37:11 +0200 Subject: [PATCH 58/61] Fixes #161: ("polymorphic_allocator(memory_resource*) non-standard extension causes headache") --- doc/container.qbk | 8 ++++++++ include/boost/container/pmr/polymorphic_allocator.hpp | 5 ++--- test/polymorphic_allocator_test.cpp | 3 --- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 24f4314..ed389d1 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1338,6 +1338,14 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_75_00 Boost 1.75 Release] + +* New [classref boost::container::devector devector] container. +* Fixed bugs/issues: + * [@https://github.com/boostorg/container/issues/157 GitHub #157: ['"Add missing include"]]. + +[endsect] + [section:release_notes_boost_1_74_00 Boost 1.74 Release] * Fixed bugs/issues: diff --git a/include/boost/container/pmr/polymorphic_allocator.hpp b/include/boost/container/pmr/polymorphic_allocator.hpp index 8c04653..b3a1eb3 100644 --- a/include/boost/container/pmr/polymorphic_allocator.hpp +++ b/include/boost/container/pmr/polymorphic_allocator.hpp @@ -53,10 +53,9 @@ class polymorphic_allocator //! Throws: Nothing //! //! Notes: This constructor provides an implicit conversion from memory_resource*. - //! Non-standard extension: if r is null m_resource is set to get_default_resource(). polymorphic_allocator(memory_resource* r) - : m_resource(r ? r : ::boost::container::pmr::get_default_resource()) - {} + : m_resource(r) + { BOOST_ASSERT(r != 0); } //! Effects: Sets m_resource to //! other.resource(). diff --git a/test/polymorphic_allocator_test.cpp b/test/polymorphic_allocator_test.cpp index 10899ca..36f99c8 100644 --- a/test/polymorphic_allocator_test.cpp +++ b/test/polymorphic_allocator_test.cpp @@ -25,9 +25,6 @@ void test_default_constructor() void test_resource_constructor() { - polymorphic_allocator a(0); - BOOST_TEST(a.resource() == get_default_resource()); - derived_from_memory_resource d; polymorphic_allocator b(&d); BOOST_TEST(&d == b.resource()); From 1ac7339ff4a54e2be848f81ba18aeec8368a0a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 31 Aug 2020 22:21:02 +0200 Subject: [PATCH 59/61] Add test to erase the last element --- test/vector_test.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 016da1a..e290c6a 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -338,6 +338,10 @@ int vector_test() stdvector.erase(stdvector.begin()); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + boostvector.erase(boostvector.end()-1); + stdvector.erase(stdvector.end()-1); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + { //Initialize values IntType aux_vect[50]; From cdd6d9ad8af0e057f5b3507757e754017ee4b114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 31 Aug 2020 22:21:41 +0200 Subject: [PATCH 60/61] Fixes #160 ("Usage of uses_allocator needs a remove_cvref_t") --- doc/container.qbk | 4 +++- .../container/detail/dispatch_uses_allocator.hpp | 12 ++++++------ include/boost/container/detail/type_traits.hpp | 1 + test/uses_allocator_test.cpp | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index ed389d1..be59adc 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1342,7 +1342,9 @@ use [*Boost.Container]? There are several reasons for that: * New [classref boost::container::devector devector] container. * Fixed bugs/issues: - * [@https://github.com/boostorg/container/issues/157 GitHub #157: ['"Add missing include"]]. + * [@https://github.com/boostorg/container/pull/157 GitHub #157: ['"Add missing include"]]. + * [@https://github.com/boostorg/container/issues/160 GitHub #160: ['"Usage of uses_allocator needs a remove_cvref_t"]]. + * [@https://github.com/boostorg/container/issues/161 GitHub #161: ['"polymorphic_allocator(memory_resource*) non-standard extension causes headache"]]. [endsect] diff --git a/include/boost/container/detail/dispatch_uses_allocator.hpp b/include/boost/container/detail/dispatch_uses_allocator.hpp index e4ed7ab..f9e761b 100644 --- a/include/boost/container/detail/dispatch_uses_allocator.hpp +++ b/include/boost/container/detail/dispatch_uses_allocator.hpp @@ -113,7 +113,7 @@ template < typename ConstructAlloc BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and < void , dtl::is_not_pair - , dtl::not_< uses_allocator > + , dtl::not_< uses_allocator::type > > >::type dispatch_uses_allocator ( ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args)...args) { @@ -130,7 +130,7 @@ template < typename ConstructAlloc BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and < void , dtl::is_not_pair - , uses_allocator + , uses_allocator::type> , is_constructible_with_allocator_prefix >::type dispatch_uses_allocator ( ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args) ...args) @@ -149,7 +149,7 @@ template < typename ConstructAlloc BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and < void , dtl::is_not_pair - , uses_allocator + , uses_allocator::type> , dtl::not_ > >::type dispatch_uses_allocator ( ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args)...args) @@ -165,7 +165,7 @@ BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and\ < void\ , dtl::is_not_pair\ - , dtl::not_ >\ + , dtl::not_::type> >\ >::type\ dispatch_uses_allocator\ (ConstructAlloc &construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ @@ -182,7 +182,7 @@ BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and\ < void\ , dtl::is_not_pair\ - , uses_allocator\ + , uses_allocator::type>\ , is_constructible_with_allocator_prefix\ >::type\ dispatch_uses_allocator\ @@ -200,7 +200,7 @@ BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and\ < void\ , dtl::is_not_pair\ - , uses_allocator\ + , uses_allocator::type>\ , dtl::not_ >\ >::type\ dispatch_uses_allocator\ diff --git a/include/boost/container/detail/type_traits.hpp b/include/boost/container/detail/type_traits.hpp index 5e90154..b5250d6 100644 --- a/include/boost/container/detail/type_traits.hpp +++ b/include/boost/container/detail/type_traits.hpp @@ -40,6 +40,7 @@ using ::boost::move_detail::add_const; using ::boost::move_detail::add_const_reference; using ::boost::move_detail::remove_const; using ::boost::move_detail::remove_reference; +using ::boost::move_detail::remove_cvref; using ::boost::move_detail::make_unsigned; using ::boost::move_detail::is_floating_point; using ::boost::move_detail::is_integral; diff --git a/test/uses_allocator_test.cpp b/test/uses_allocator_test.cpp index cb88a2b..16ab4cd 100644 --- a/test/uses_allocator_test.cpp +++ b/test/uses_allocator_test.cpp @@ -21,7 +21,7 @@ struct uses_allocator_and_not_convertible_to_int struct uses_allocator_and_convertible_to_int { - typedef char allocator_type; + typedef long allocator_type; }; struct uses_erased_type_allocator From 3da7877dc005d158b90a72fff697bf2905763ee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 31 Aug 2020 22:23:25 +0200 Subject: [PATCH 61/61] Fixes #158 (".bak file in git") --- include/boost/container/container_fwd.hpp.bak | 389 ------------------ 1 file changed, 389 deletions(-) delete mode 100644 include/boost/container/container_fwd.hpp.bak diff --git a/include/boost/container/container_fwd.hpp.bak b/include/boost/container/container_fwd.hpp.bak deleted file mode 100644 index 9d419f7..0000000 --- a/include/boost/container/container_fwd.hpp.bak +++ /dev/null @@ -1,389 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2005-2014. Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/container for documentation. -// -////////////////////////////////////////////////////////////////////////////// - -#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP -#define BOOST_CONTAINER_CONTAINER_FWD_HPP - -#ifndef BOOST_CONFIG_HPP -# include -#endif - -#if defined(BOOST_HAS_PRAGMA_ONCE) -# pragma once -#endif - -//! \file -//! This header file forward declares the following containers: -//! - boost::container::vector -//! - boost::container::stable_vector -//! - boost::container::static_vector -//! - boost::container::small_vector_base -//! - boost::container::small_vector -//! - boost::container::slist -//! - boost::container::list -//! - boost::container::set -//! - boost::container::multiset -//! - boost::container::map -//! - boost::container::multimap -//! - boost::container::flat_set -//! - boost::container::flat_multiset -//! - boost::container::flat_map -//! - boost::container::flat_multimap -//! - boost::container::basic_string -//! - boost::container::string -//! - boost::container::wstring -//! -//! Forward declares the following allocators: -//! - boost::container::allocator -//! - boost::container::node_allocator -//! - boost::container::adaptive_pool -//! -//! Forward declares the following polymorphic resource classes: -//! - boost::container::pmr::memory_resource -//! - boost::container::pmr::polymorphic_allocator -//! - boost::container::pmr::monotonic_buffer_resource -//! - boost::container::pmr::pool_options -//! - boost::container::pmr::unsynchronized_pool_resource -//! - boost::container::pmr::synchronized_pool_resource -//! -//! And finally it defines the following types - -#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -//Std forward declarations -#ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP - #include -#endif - -namespace boost{ -namespace intrusive{ -namespace detail{ - //Create namespace to avoid compilation errors -}}} - -namespace boost{ namespace container{ namespace dtl{ - namespace bi = boost::intrusive; - namespace bid = boost::intrusive::detail; -}}} - -namespace boost{ namespace container{ namespace pmr{ - namespace bi = boost::intrusive; - namespace bid = boost::intrusive::detail; -}}} - -#include - -#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -////////////////////////////////////////////////////////////////////////////// -// Containers -////////////////////////////////////////////////////////////////////////////// - -namespace boost { -namespace container { - -#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -template -struct pair; - -template -class new_allocator; - -template -class vector; - -template -class stable_vector; - -template < class T - , std::size_t Capacity - , class Options = void> -class static_vector; - -template < class T - , class Allocator = void - , class Options = void > -class small_vector_base; - -template < class T - , std::size_t N - , class Allocator = void - , class Options = void > -class small_vector; - -template -class devector; - -template -class deque; - -template -class list; - -template -class slist; - -template - ,class Allocator = void - ,class Options = void> -class set; - -template - ,class Allocator = void - ,class Options = void > -class multiset; - -template - ,class Allocator = void - ,class Options = void > -class map; - -template - ,class Allocator = void - ,class Options = void > -class multimap; - -template - ,class Allocator = void > -class flat_set; - -template - ,class Allocator = void > -class flat_multiset; - -template - ,class Allocator = void > -class flat_map; - -template - ,class Allocator = void > -class flat_multimap; - -#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES - -//! Alias templates for small_flat_[multi]{set|map} using small_vector as container - -template < class Key - , std::size_t N - , class Compare = std::less - , class SmallVectorAllocator = void - , class SmallVectorOptions = void > -using small_flat_set = flat_set>; - -template < class Key - , std::size_t N - , class Compare = std::less - , class SmallVectorAllocator = void - , class SmallVectorOptions = void > -using small_flat_multiset = flat_multiset>; - -template < class Key - , class T - , std::size_t N - , class Compare = std::less - , class SmallVectorAllocator = void - , class SmallVectorOptions = void > -using small_flat_map = flat_map, N, SmallVectorAllocator, SmallVectorOptions>>; - -template < class Key - , class T - , std::size_t N - , class Compare = std::less - , class SmallVectorAllocator = void - , class SmallVectorOptions = void > -using small_flat_multimap = flat_multimap, N, SmallVectorAllocator, SmallVectorOptions>>; - -#endif // #ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES - - -//! A portable metafunction to obtain a small_flat_set -template < class Key - , std::size_t N - , class Compare = std::less - , class SmallVectorAllocator = void - , class SmallVectorOptions = void > -struct small_flat_set_of -{ - typedef flat_set > type; -}; - -//! A portable metafunction to obtain a small_flat_multiset -template < class Key - , std::size_t N - , class Compare = std::less - , class SmallVectorAllocator = void - , class SmallVectorOptions = void > -struct small_flat_multiset_of -{ - typedef flat_multiset > type; -}; - -//! A portable metafunction to obtain a small_flat_map -template < class Key - , class T - , std::size_t N - , class Compare = std::less - , class SmallVectorAllocator = void - , class SmallVectorOptions = void > -struct small_flat_map_of -{ - typedef flat_map, N, SmallVectorAllocator, SmallVectorOptions> > type; -}; - -//! A portable metafunction to obtain a small_flat_multimap -template < class Key - , class T - , std::size_t N - , class Compare = std::less - , class SmallVectorAllocator = void - , class SmallVectorOptions = void > -struct small_flat_multimap_of -{ - typedef flat_multimap, N, SmallVectorAllocator, SmallVectorOptions> > type; -}; - -template - ,class Allocator = void > -class basic_string; - -typedef basic_string string; -typedef basic_string wstring; - -static const std::size_t ADP_nodes_per_block = 256u; -static const std::size_t ADP_max_free_blocks = 2u; -static const std::size_t ADP_overhead_percent = 1u; -static const std::size_t ADP_only_alignment = 0u; - -template < class T - , std::size_t NodesPerBlock = ADP_nodes_per_block - , std::size_t MaxFreeBlocks = ADP_max_free_blocks - , std::size_t OverheadPercent = ADP_overhead_percent - , unsigned Version = 2 - > -class adaptive_pool; - -template < class T - , unsigned Version = 2 - , unsigned int AllocationDisableMask = 0> -class allocator; - -static const std::size_t NodeAlloc_nodes_per_block = 256u; - -template - < class T - , std::size_t NodesPerBlock = NodeAlloc_nodes_per_block - , std::size_t Version = 2> -class node_allocator; - -namespace pmr { - -class memory_resource; - -template -class polymorphic_allocator; - -class monotonic_buffer_resource; - -struct pool_options; - -template -class resource_adaptor_imp; - -class unsynchronized_pool_resource; - -class synchronized_pool_resource; - -} //namespace pmr { - -#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -//! Type used to tag that the input range is -//! guaranteed to be ordered -struct ordered_range_t -{}; - -//! Value used to tag that the input range is -//! guaranteed to be ordered -static const ordered_range_t ordered_range = ordered_range_t(); - -//! Type used to tag that the input range is -//! guaranteed to be ordered and unique -struct ordered_unique_range_t - : public ordered_range_t -{}; - -//! Value used to tag that the input range is -//! guaranteed to be ordered and unique -static const ordered_unique_range_t ordered_unique_range = ordered_unique_range_t(); - -//! Type used to tag that the inserted values -//! should be default initialized -struct default_init_t -{}; - -//! Value used to tag that the inserted values -//! should be default initialized -static const default_init_t default_init = default_init_t(); -#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -//! Type used to tag that the inserted values -//! should be value initialized -struct value_init_t -{}; - -//! Value used to tag that the inserted values -//! should be value initialized -static const value_init_t value_init = value_init_t(); - -namespace container_detail_really_deep_namespace { - -//Otherwise, gcc issues a warning of previously defined -//anonymous_instance and unique_instance -struct dummy -{ - dummy() - { - (void)ordered_range; - (void)ordered_unique_range; - (void)default_init; - } -}; - -} //detail_really_deep_namespace { - - -#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -}} //namespace boost { namespace container { - -#endif //#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP