Implement C++26 heterogeneous operator[], refactor operator[] implementation.

This commit is contained in:
Ion Gaztañaga
2025-11-07 22:24:37 +01:00
parent 92d46cc151
commit 9f08eccc05
3 changed files with 95 additions and 42 deletions

View File

@@ -773,26 +773,43 @@ class flat_map
//
//////////////////////////////////////////////
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! Effects: If there is no key equivalent to x in the flat_map, inserts
//! value_type(x, T()) into the flat_map.
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || (defined(BOOST_CXX_VERSION) &&(BOOST_CXX_VERSION >= 201103L))
//! Effects: If there is no key equivalent to k in the flat_map, inserts
//! value_type(k, T()) into the flat_map.
//!
//! Returns: A reference to the mapped_type corresponding to x in *this.
//! Returns: A reference to the mapped_type corresponding to k in *this.
//!
//! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present.
mapped_type &operator[](const key_type& k);
mapped_type &operator[](const key_type& k)
{ return this->priv_subscript(k); }
//! Effects: If there is no key equivalent to x in the flat_map, inserts
//! value_type(move(x), T()) into the flat_map (the key is move-constructed)
//! Effects: If there is no key equivalent to k in the flat_map, inserts
//! value_type(move(k), T()) into the flat_map (the key is move-constructed)
//!
//! Returns: A reference to the mapped_type corresponding to x in *this.
//! Returns: A reference to the mapped_type corresponding to k in *this.
//!
//! 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
inline mapped_type& operator[](const key_type &k) { return this->priv_subscript(k); }
inline mapped_type& operator[](BOOST_RV_REF(key_type) k) { return this->priv_subscript(::boost::move(k)); }
mapped_type &operator[](key_type &&k)
{ return this->priv_subscript(boost::move(k)); }
//! <b>Precondition</b>: This overload is available only if key_compare::is_transparent exists.
//!
//! <b>Effects</b>: If there is no key equivalent to x in the map, inserts
//! value_type(boost::forward<K>(k), T()) into the map
//!
//! <b>Returns</b>: A reference to the mapped_type corresponding to k in *this.
//!
//! <b>Complexity</b>: Logarithmic search time plus linear insertion time in case no equivalent key is present
template <class K>
inline BOOST_CONTAINER_DOC1ST
( mapped_type&
, typename dtl::enable_if_transparent< key_compare
BOOST_MOVE_I K
BOOST_MOVE_I mapped_type&
>::type) //transparent
operator[](K &&k)
{ return this->priv_subscript(boost::forward<K>(k)); }
#else
BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript)
#endif
@@ -1807,29 +1824,26 @@ class flat_map
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private:
mapped_type &priv_subscript(const key_type& k)
template<class K>
inline mapped_type& priv_subscript(BOOST_FWD_REF(K) key)
{
const typename dtl::remove_cvref<K>::type & k = key; //Support emulated rvalue references
iterator i = this->lower_bound(k);
// i->first is greater than or equivalent to k.
if (i == end() || key_comp()(k, (*i).first)){
dtl::value_init<mapped_type> m;
impl_value_type v(k, ::boost::move(m.m_t));
i = dtl::force_copy<iterator>(this->m_flat_tree.insert_equal(::boost::move(v)));
}
return (*i).second;
}
mapped_type &priv_subscript(BOOST_RV_REF(key_type) mk)
{
key_type &k = mk;
iterator i = this->lower_bound(k);
// i->first is greater than or equivalent to k.
if (i == end() || key_comp()(k, (*i).first)) {
dtl::value_init<mapped_type> m;
impl_value_type v(::boost::move(k), ::boost::move(m.m_t));
i = dtl::force_copy<iterator>(this->m_flat_tree.insert_equal(::boost::move(v)));
typename dtl::aligned_storage<sizeof(impl_value_type), dtl::alignment_of<impl_value_type>::value>::type v;
impl_value_type *vp = move_detail::launder_cast<impl_value_type *>(&v);
impl_get_stored_allocator_noconst_return_t r = m_flat_tree.get_stored_allocator();
boost::container::allocator_traits<impl_stored_allocator_type>::construct
(r, vp, try_emplace_t(), ::boost::forward<K>(key));
i = dtl::force_copy<iterator> (this->m_flat_tree.insert_equal
(dtl::force_copy<impl_iterator>(i), ::boost::move(*vp)));
vp->~impl_value_type();
}
return (*i).second;
}
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
};

View File

@@ -555,26 +555,41 @@ class map
#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || (defined(BOOST_CXX_VERSION) &&(BOOST_CXX_VERSION >= 201103L))
//! <b>Effects</b>: If there is no key equivalent to x in the map, inserts
//! value_type(x, T()) into the map.
//! value_type(k, T()) into the map.
//!
//! <b>Returns</b>: A reference to the mapped_type corresponding to x in *this.
//! <b>Returns</b>: A reference to the mapped_type corresponding to k in *this.
//!
//! <b>Complexity</b>: Logarithmic.
mapped_type& operator[](const key_type &k);
mapped_type& operator[](const key_type& k)
{ return this->priv_subscript(k); }
//! <b>Effects</b>: If there is no key equivalent to x in the map, inserts
//! value_type(boost::move(x), T()) into the map (the key is move-constructed)
//! value_type(boost::move(k), T()) into the map (the key is move-constructed)
//!
//! <b>Returns</b>: A reference to the mapped_type corresponding to x in *this.
//! <b>Returns</b>: A reference to the mapped_type corresponding to k in *this.
//!
//! <b>Complexity</b>: Logarithmic.
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
inline mapped_type& operator[](const key_type &k) { return this->priv_subscript(k); }
inline mapped_type& operator[](BOOST_RV_REF(key_type) k) { return this->priv_subscript(::boost::move(k)); }
mapped_type& operator[](key_type&& k)
{ return this->priv_subscript(boost::move(k)); }
//! <b>Precondition</b>: This overload is available only if key_compare::is_transparent exists.
//!
//! <b>Effects</b>: If there is no key equivalent to x in the map, inserts
//! value_type(boost::forward<K>(k), T()) into the map
//!
//! <b>Returns</b>: A reference to the mapped_type corresponding to k in *this.
//!
//! <b>Complexity</b>: Logarithmic.
template <class K>
inline BOOST_CONTAINER_DOC1ST
( mapped_type&
, typename dtl::enable_if_transparent<key_compare BOOST_MOVE_I K BOOST_MOVE_I mapped_type&>::type
)
operator[](K&& k)
{ return this->priv_subscript(boost::forward<K>(k)); }
#else
BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript)
#endif
@@ -948,7 +963,7 @@ class map
//! forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...).
//!
//! <b>Effects</b>: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise
//! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)),
//! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(forward<K>(k)),
//! forward_as_tuple(forward<Args>(args)...).
//!
//! <b>Returns</b>: The bool component of the returned pair is true if and only if the

View File

@@ -1697,6 +1697,30 @@ bool test_heterogeneous_insert()
return false;
if (cmap1.find(2)->second != 'c')
return false;
//operator[]
typename map_t::mapped_type const *pm = &map1.find(2)->second;
typename map_t::mapped_type &m = map1[2];
if(m != 'c')
return false;
if(&m != pm)
return false;
map1[2] = 'd';
if (cmap1.find(2)->second != 'd')
return false;
if(&m != &map1[2])
return false;
map1[3] = 'e';
if (cmap1.find(3)->second != 'e')
return false;
if(map1[3] != map1[3])
return false;
if (map1[4] != 0)
return false;
}
return true;
}