From cb1e6af53d48aeb32c3c41314763e781e9859599 Mon Sep 17 00:00:00 2001 From: "Pavel A. Lebedev" Date: Wed, 30 Dec 2020 08:28:06 +0300 Subject: [PATCH] Add conditional noexcept forwarding from free to member swap functions. This allows std::is_nothrow_swappable{,_with} to work properly. This only touches user-facing classes, with the following exceptions: - map,set: only doc changes (with a drive-by missing semicolon fix), detail::tree which they derive from already forwards noexcept for swap. - flat_set: only doc changes for flat_set and a change for detail::flat_tree, which it derives from to get swap. - static_vector: while this adds the forwarding, member static_vector::swap is currently never noexcept, although it could be for noexcept-swappable and noexcept-move-constructible elements. - small_vector: there is no free swap, and member swap is never noexcept, although it could be for noexcept-swappable and noexcept-move- constructible elements. Swapping small_vectors of exact same type goes through std::swap, which seems to get noexcept right, and small_vectors of different sizes use swap for boost::container::vector, which fails to detect when such swap could be noexcept. This patch doesn't touch small_vector. - scoped_allocator: neither member nor free swap are noexcept, although they should be, and all other constructions/assignments/comparisons too, as they only forward these operations to underlying allocators, which are required to not throw exceptions for them. Only static_vector's static_storage_allocator might throw for these and it shouldn't appear in scoped_allocator. Unsure of the scope of changes needed or whether it is even worth it, this patch doesn't touch scoped_allocator. --- include/boost/container/deque.hpp | 1 + include/boost/container/detail/flat_tree.hpp | 1 + include/boost/container/devector.hpp | 2 ++ include/boost/container/flat_map.hpp | 2 ++ include/boost/container/flat_set.hpp | 8 ++++++-- include/boost/container/list.hpp | 1 + include/boost/container/map.hpp | 10 +++++++--- include/boost/container/set.hpp | 8 ++++++-- include/boost/container/slist.hpp | 1 + include/boost/container/stable_vector.hpp | 1 + include/boost/container/static_vector.hpp | 5 ++++- include/boost/container/string.hpp | 1 + include/boost/container/vector.hpp | 1 + 13 files changed, 34 insertions(+), 8 deletions(-) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index e94ea7b..d95314e 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -1910,6 +1910,7 @@ class deque : protected deque_base::type, //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE friend void swap(deque& x, deque& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 8debd6f..2dc4230 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -1448,6 +1448,7 @@ class flat_tree { return !(x < y); } BOOST_CONTAINER_FORCEINLINE friend void swap(flat_tree& x, flat_tree& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } private: diff --git a/include/boost/container/devector.hpp b/include/boost/container/devector.hpp index 84d48e4..e16a79d 100644 --- a/include/boost/container/devector.hpp +++ b/include/boost/container/devector.hpp @@ -2000,6 +2000,8 @@ class devector { return !(x < y); } BOOST_CONTAINER_FORCEINLINE friend void swap(devector& x, devector& y) + BOOST_NOEXCEPT_IF( allocator_traits_type::propagate_on_container_swap::value + || allocator_traits_type::is_always_equal::value) { x.swap(y); } private: diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 4cf41af..5cb35d5 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -1602,6 +1602,7 @@ class flat_map //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE friend void swap(flat_map& x, flat_map& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -2959,6 +2960,7 @@ class flat_multimap //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE friend void swap(flat_multimap& x, flat_multimap& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } }; diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 7af8395..fe44fe5 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -1084,7 +1084,9 @@ class flat_set //! Effects: x.swap(y) //! //! Complexity: Constant. - friend void swap(flat_set& x, flat_set& y); + friend void swap(flat_set& x, flat_set& y) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable::value ); //! Effects: Extracts the internal sequence container. //! @@ -1817,7 +1819,9 @@ class flat_multiset //! Effects: x.swap(y) //! //! Complexity: Constant. - friend void swap(flat_multiset& x, flat_multiset& y); + friend void swap(flat_multiset& x, flat_multiset& y) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable::value ); //! Effects: Extracts the internal sequence container. //! diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 33270cf..67ee962 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -1439,6 +1439,7 @@ class list //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE friend void swap(list& x, list& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 84270e9..03d761e 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -1062,7 +1062,7 @@ class map //! Complexity: Constant. void swap(map& x) BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::dtl::is_nothrow_swappable::value ) + && boost::container::dtl::is_nothrow_swappable::value ); //! Effects: erase(begin(),end()). //! @@ -1283,7 +1283,9 @@ class map //! Effects: x.swap(y) //! //! Complexity: Constant. - friend void swap(map& x, map& y); + friend void swap(map& x, map& y) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable::value ); #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -2218,7 +2220,9 @@ class multimap //! Effects: x.swap(y) //! //! Complexity: Constant. - friend void swap(multimap& x, multimap& y); + friend void swap(multimap& x, multimap& y) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable::value ); #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) }; diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index 14b5b6b..0a39f2e 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -945,7 +945,9 @@ class set //! Effects: x.swap(y) //! //! Complexity: Constant. - friend void swap(set& x, set& y); + friend void swap(set& x, set& y) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable::value ); #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1608,7 +1610,9 @@ class multiset //! Effects: x.swap(y) //! //! Complexity: Constant. - friend void swap(multiset& x, multiset& y); + friend void swap(multiset& x, multiset& y) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable::value ); #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index d142744..f08c4b8 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -1629,6 +1629,7 @@ class slist //! //! Complexity: Constant. friend void swap(slist& x, slist& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index b5906bd..4a26ee5 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -1840,6 +1840,7 @@ class stable_vector //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE friend void swap(stable_vector& x, stable_vector& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index 6408c22..3678947 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -1169,6 +1169,7 @@ public: #else BOOST_CONTAINER_FORCEINLINE friend void swap(static_vector &x, static_vector &y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } @@ -1275,13 +1276,15 @@ bool operator>= (static_vector const& x, static_vector con //! @par Complexity //! Linear O(N). template -inline void swap(static_vector & x, static_vector & y); +inline void swap(static_vector & x, static_vector & y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))); #else template inline void swap(static_vector & x, static_vector & y , typename dtl::enable_if_c< C1 != C2>::type * = 0) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index bd1381b..b6c0aaf 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -3399,6 +3399,7 @@ operator>=( const basic_string& x, BasicStringView inline void swap(basic_string& x, basic_string& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 83b2aeb..0d7f837 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -2197,6 +2197,7 @@ private: //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE friend void swap(vector& x, vector& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED