refactored proxy_erase to reduce template instantiations and strengthen misuse avoidance

This commit is contained in:
joaquintides
2023-06-17 11:17:15 +02:00
committed by Christian Mazakas
parent 2b6cfe4f3c
commit 2eebe157fd
5 changed files with 53 additions and 31 deletions

View File

@ -123,6 +123,7 @@ public:
private: private:
template<typename,typename,bool> friend class table_iterator; template<typename,typename,bool> friend class table_iterator;
template<typename> friend class table_erase_return_type;
template<typename,typename,typename,typename> friend class table; template<typename,typename,typename,typename> friend class table;
table_iterator(Group* pg,std::size_t n,const table_element_type* p_): table_iterator(Group* pg,std::size_t n,const table_element_type* p_):
@ -198,6 +199,45 @@ private:
table_element_type *p=nullptr; table_element_type *p=nullptr;
}; };
/* Returned by table::erase([const_]iterator) to avoid iterator increment
* if discarded.
*/
template<typename Iterator>
class table_erase_return_type;
template<typename TypePolicy,typename Group,bool Const>
class table_erase_return_type<table_iterator<TypePolicy,Group,Const>>
{
using iterator=table_iterator<TypePolicy,Group,Const>;
using const_iterator=table_iterator<TypePolicy,Group,true>;
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<!Const||dependent_value>::type* =nullptr
>
operator const_iterator()const noexcept{return this->operator iterator();}
private:
template<typename,typename,typename,typename> 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 /* foa::table interface departs in a number of ways from that of C++ unordered
* associative containers because it's not for end-user consumption * associative containers because it's not for end-user consumption
* (boost::unordered_(flat|node)_(map|set) wrappers complete it as * (boost::unordered_(flat|node)_(map|set) wrappers complete it as
@ -271,6 +311,7 @@ public:
has_mutable_iterator, has_mutable_iterator,
table_iterator<type_policy,group_type,false>, table_iterator<type_policy,group_type,false>,
const_iterator>::type; const_iterator>::type;
using erase_return_type=table_erase_return_type<iterator>;
table( table(
std::size_t n=default_bucket_count,const Hash& h_=Hash(), std::size_t n=default_bucket_count,const Hash& h_=Hash(),
@ -348,40 +389,19 @@ public:
>::type >::type
insert(element_type&& x){return emplace_impl(std::move(x));} 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< template<
bool dependent_value=false, bool dependent_value=false,
typename std::enable_if< typename std::enable_if<
has_mutable_iterator||dependent_value>::type* =nullptr has_mutable_iterator||dependent_value>::type* =nullptr
> >
operator const_iterator()const noexcept erase_return_type erase(iterator pos)noexcept
{ {return erase(const_iterator(pos));}
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));}
BOOST_FORCEINLINE BOOST_FORCEINLINE
proxy_erase erase(const_iterator pos)noexcept erase_return_type erase(const_iterator pos)noexcept
{ {
super::erase(pos.pc,pos.p); super::erase(pos.pc,pos.p);
return proxy_erase{pos}; return {pos};
} }
template<typename Key> template<typename Key>

View File

@ -381,12 +381,13 @@ namespace boost {
.first; .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); return table_.erase(pos);
} }
BOOST_FORCEINLINE typename table_type::proxy_erase erase( BOOST_FORCEINLINE typename table_type::erase_return_type erase(
const_iterator pos) const_iterator pos)
{ {
return table_.erase(pos); return table_.erase(pos);

View File

@ -282,7 +282,7 @@ namespace boost {
return table_.emplace(std::forward<Args>(args)...).first; return table_.emplace(std::forward<Args>(args)...).first;
} }
BOOST_FORCEINLINE typename table_type::proxy_erase erase( BOOST_FORCEINLINE typename table_type::erase_return_type erase(
const_iterator pos) const_iterator pos)
{ {
return table_.erase(pos); return table_.erase(pos);

View File

@ -458,12 +458,13 @@ namespace boost {
.first; .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); return table_.erase(pos);
} }
BOOST_FORCEINLINE typename table_type::proxy_erase erase( BOOST_FORCEINLINE typename table_type::erase_return_type erase(
const_iterator pos) const_iterator pos)
{ {
return table_.erase(pos); return table_.erase(pos);

View File

@ -352,7 +352,7 @@ namespace boost {
return table_.emplace(std::forward<Args>(args)...).first; return table_.emplace(std::forward<Args>(args)...).first;
} }
BOOST_FORCEINLINE typename table_type::proxy_erase erase( BOOST_FORCEINLINE typename table_type::erase_return_type erase(
const_iterator pos) const_iterator pos)
{ {
return table_.erase(pos); return table_.erase(pos);