From 2eebe157fd4524f8c8020d1ab63ee7ccb610f59a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 17 Jun 2023 11:17:15 +0200 Subject: [PATCH] refactored proxy_erase to reduce template instantiations and strengthen misuse avoidance --- include/boost/unordered/detail/foa/table.hpp | 70 ++++++++++++------- .../boost/unordered/unordered_flat_map.hpp | 5 +- .../boost/unordered/unordered_flat_set.hpp | 2 +- .../boost/unordered/unordered_node_map.hpp | 5 +- .../boost/unordered/unordered_node_set.hpp | 2 +- 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/include/boost/unordered/detail/foa/table.hpp b/include/boost/unordered/detail/foa/table.hpp index e42e08e4..85145cb6 100644 --- a/include/boost/unordered/detail/foa/table.hpp +++ b/include/boost/unordered/detail/foa/table.hpp @@ -123,6 +123,7 @@ public: private: template friend class table_iterator; + template friend class table_erase_return_type; template friend class table; table_iterator(Group* pg,std::size_t n,const table_element_type* p_): @@ -198,6 +199,45 @@ private: table_element_type *p=nullptr; }; +/* Returned by table::erase([const_]iterator) to avoid iterator increment + * if discarded. + */ + +template +class table_erase_return_type; + +template +class table_erase_return_type> +{ + using iterator=table_iterator; + using const_iterator=table_iterator; + +public: + /* can't delete it because VS in pre-C++17 mode needs to see it for RVO */ + table_erase_return_type(const table_erase_return_type&); + + operator iterator()const noexcept + { + auto it=pos; + it.increment(); /* valid even if *it was erased */ + return iterator(const_iterator_cast_tag{},it); + } + + template< + bool dependent_value=false, + typename std::enable_if::type* =nullptr + > + operator const_iterator()const noexcept{return this->operator iterator();} + +private: + template friend class table; + + table_erase_return_type(const_iterator pos_):pos{pos_}{} + table_erase_return_type& operator=(const table_erase_return_type&)=delete; + + const_iterator pos; +}; + /* foa::table interface departs in a number of ways from that of C++ unordered * associative containers because it's not for end-user consumption * (boost::unordered_(flat|node)_(map|set) wrappers complete it as @@ -271,6 +311,7 @@ public: has_mutable_iterator, table_iterator, const_iterator>::type; + using erase_return_type=table_erase_return_type; table( std::size_t n=default_bucket_count,const Hash& h_=Hash(), @@ -348,40 +389,19 @@ public: >::type insert(element_type&& x){return emplace_impl(std::move(x));} - struct proxy_erase { - const_iterator pos; - operator iterator()const noexcept - { - auto it=pos; - it.increment(); - return iterator(const_iterator_cast_tag{},it); - } - - template< - bool dependent_value=false, - typename std::enable_if< - has_mutable_iterator||dependent_value>::type* =nullptr - > - operator const_iterator()const noexcept - { - auto it=pos; - it.increment(); - return it; - } - }; - template< bool dependent_value=false, typename std::enable_if< has_mutable_iterator||dependent_value>::type* =nullptr > - proxy_erase erase(iterator pos)noexcept{return erase(const_iterator(pos));} + erase_return_type erase(iterator pos)noexcept + {return erase(const_iterator(pos));} BOOST_FORCEINLINE - proxy_erase erase(const_iterator pos)noexcept + erase_return_type erase(const_iterator pos)noexcept { super::erase(pos.pc,pos.p); - return proxy_erase{pos}; + return {pos}; } template diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index ad3f6fec..d74de55a 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -381,12 +381,13 @@ namespace boost { .first; } - BOOST_FORCEINLINE typename table_type::proxy_erase erase(iterator pos) + BOOST_FORCEINLINE typename table_type::erase_return_type erase( + iterator pos) { return table_.erase(pos); } - BOOST_FORCEINLINE typename table_type::proxy_erase erase( + BOOST_FORCEINLINE typename table_type::erase_return_type erase( const_iterator pos) { return table_.erase(pos); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 4be909b7..a3c7748e 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -282,7 +282,7 @@ namespace boost { return table_.emplace(std::forward(args)...).first; } - BOOST_FORCEINLINE typename table_type::proxy_erase erase( + BOOST_FORCEINLINE typename table_type::erase_return_type erase( const_iterator pos) { return table_.erase(pos); diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index a5cecba7..32bd5989 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -458,12 +458,13 @@ namespace boost { .first; } - BOOST_FORCEINLINE typename table_type::proxy_erase erase(iterator pos) + BOOST_FORCEINLINE typename table_type::erase_return_type erase( + iterator pos) { return table_.erase(pos); } - BOOST_FORCEINLINE typename table_type::proxy_erase erase( + BOOST_FORCEINLINE typename table_type::erase_return_type erase( const_iterator pos) { return table_.erase(pos); diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index 57a7405c..06833a8b 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -352,7 +352,7 @@ namespace boost { return table_.emplace(std::forward(args)...).first; } - BOOST_FORCEINLINE typename table_type::proxy_erase erase( + BOOST_FORCEINLINE typename table_type::erase_return_type erase( const_iterator pos) { return table_.erase(pos);