Add C++23 transparent extract() method to set/multiset/map/multimap

This commit is contained in:
Ion Gaztañaga
2025-11-05 22:31:54 +01:00
parent d179658a08
commit 21725febaa
5 changed files with 104 additions and 0 deletions

View File

@@ -1190,6 +1190,21 @@ class tree
return node_type();
}
template<class K>
inline typename dtl::enable_if_c<
dtl::is_transparent<key_compare>::value && //transparent
!dtl::is_convertible<K, iterator>::value && //not convertible to iterator
!dtl::is_convertible<K, const_iterator>::value //not convertible to const_iterator
, node_type>::type
extract(BOOST_FWD_REF(K) k)
{
iterator const it = this->find(k);
if(this->end() != it){
return this->extract(it);
}
return node_type();
}
node_type extract(const_iterator position)
{
BOOST_ASSERT(position != this->cend() && (priv_is_linked)(position));

View File

@@ -1069,6 +1069,29 @@ class map
return BOOST_MOVE_RET(node_type, nh);
}
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Removes the first element in the container with key equivalent to k.
//!
//! <b>Returns</b>: A node_type owning the element if found, otherwise an empty node_type.
//!
//! <b>Complexity</b>: log(size()).
template<class K>
inline BOOST_CONTAINER_DOC1ST
(node_type
, typename dtl::enable_if_c<
dtl::is_transparent<key_compare>::value && //transparent
!dtl::is_convertible<K BOOST_MOVE_I iterator>::value && //not convertible to iterator
!dtl::is_convertible<K BOOST_MOVE_I const_iterator>::value //not convertible to const_iterator
BOOST_MOVE_I node_type>::type)
extract(BOOST_FWD_REF(K) k)
{
typename base_t::node_type base_nh(this->base_t::extract(k));
node_type nh(boost::move(base_nh));
return BOOST_MOVE_RET(node_type, nh);
}
//! <b>Effects</b>: Removes the element pointed to by "position".
//!
//! <b>Returns</b>: A node_type owning the element, otherwise an empty node_type.
@@ -2043,6 +2066,22 @@ class multimap
return node_type(boost::move(base_nh));
}
//! @copydoc ::boost::container::map::extract(K&&)
template<class K>
inline BOOST_CONTAINER_DOC1ST
(node_type
, typename dtl::enable_if_c<
dtl::is_transparent<key_compare>::value && //transparent
!dtl::is_convertible<K BOOST_MOVE_I iterator>::value && //not convertible to iterator
!dtl::is_convertible<K BOOST_MOVE_I const_iterator>::value //not convertible to const_iterator
BOOST_MOVE_I node_type>::type)
extract(BOOST_FWD_REF(K) k)
{
typename base_t::node_type base_nh(this->base_t::extract(k));
node_type nh(boost::move(base_nh));
return BOOST_MOVE_RET(node_type, nh);
}
//! @copydoc ::boost::container::map::extract(const_iterator)
node_type extract(const_iterator position)
{

View File

@@ -722,6 +722,10 @@ class set
//! @copydoc ::boost::container::map::extract(const key_type&)
node_type extract(const key_type& x);
//! @copydoc ::boost::container::map::extract(K&&)
template <class K>
node_type extract(BOOST_FWD_REF(K) x);
//! <b>Effects</b>: Swaps the contents of *this and x.
//!
//! <b>Throws</b>: Nothing.
@@ -1508,6 +1512,10 @@ class multiset
//! @copydoc ::boost::container::multimap::extract(const key_type&)
node_type extract(const key_type& x);
//! @copydoc ::boost::container::multimap::extract(K&&)
template <class K>
node_type extract(BOOST_FWD_REF(K) x);
//! @copydoc ::boost::container::set::swap
void swap(multiset& x)
BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value

View File

@@ -371,6 +371,27 @@ bool test_heterogeneous_lookups()
return false;
if (mmap1.erase(find_me) != 0)
return false;
//extract
map1.clear();
map1.insert(value_type(1, 'a'));
mmap1.clear();
mmap1.insert(value_type(1, 'a'));
mmap1.insert(value_type(1, 'b'));
const test::non_copymovable_int extract_me(1);
if (!map1.extract(extract_me))
return false;
if (map1.extract(extract_me))
return false;
if (!mmap1.extract(extract_me))
return false;
if (!mmap1.extract(extract_me))
return false;
if (mmap1.extract(extract_me))
return false;
}
{
typedef map<test::movable_int, char, less_transparent> map_t;

View File

@@ -447,6 +447,27 @@ bool test_heterogeneous_lookups()
if (mset1.erase(find_me) != 0)
return false;
//extract
set1.clear();
set1.insert(1);
mset1.clear();
mset1.insert(1);
mset1.insert(1);
const test::non_copymovable_int extract_me(1);
if (!set1.extract(extract_me))
return false;
if (set1.extract(extract_me))
return false;
if (!mset1.extract(extract_me))
return false;
if (!mset1.extract(extract_me))
return false;
if (mset1.extract(extract_me))
return false;
return true;
}