Skip to content

Commit 9f08ecc

Browse files
committed
Implement C++26 heterogeneous operator[], refactor operator[] implementation.
1 parent 92d46cc commit 9f08ecc

File tree

3 files changed

+95
-42
lines changed

3 files changed

+95
-42
lines changed

include/boost/container/flat_map.hpp

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -773,26 +773,43 @@ class flat_map
773773
//
774774
//////////////////////////////////////////////
775775

776-
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
777-
//! Effects: If there is no key equivalent to x in the flat_map, inserts
778-
//! value_type(x, T()) into the flat_map.
776+
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || (defined(BOOST_CXX_VERSION) &&(BOOST_CXX_VERSION >= 201103L))
777+
//! Effects: If there is no key equivalent to k in the flat_map, inserts
778+
//! value_type(k, T()) into the flat_map.
779779
//!
780-
//! Returns: A reference to the mapped_type corresponding to x in *this.
780+
//! Returns: A reference to the mapped_type corresponding to k in *this.
781781
//!
782782
//! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present.
783-
mapped_type &operator[](const key_type& k);
783+
mapped_type &operator[](const key_type& k)
784+
{ return this->priv_subscript(k); }
784785

785-
//! Effects: If there is no key equivalent to x in the flat_map, inserts
786-
//! value_type(move(x), T()) into the flat_map (the key is move-constructed)
786+
//! Effects: If there is no key equivalent to k in the flat_map, inserts
787+
//! value_type(move(k), T()) into the flat_map (the key is move-constructed)
787788
//!
788-
//! Returns: A reference to the mapped_type corresponding to x in *this.
789+
//! Returns: A reference to the mapped_type corresponding to k in *this.
789790
//!
790791
//! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present.
791-
mapped_type &operator[](key_type &&k);
792-
#elif defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN)
793-
//in compilers like GCC 3.4, we can't catch temporaries
794-
inline mapped_type& operator[](const key_type &k) { return this->priv_subscript(k); }
795-
inline mapped_type& operator[](BOOST_RV_REF(key_type) k) { return this->priv_subscript(::boost::move(k)); }
792+
mapped_type &operator[](key_type &&k)
793+
{ return this->priv_subscript(boost::move(k)); }
794+
795+
//! <b>Precondition</b>: This overload is available only if key_compare::is_transparent exists.
796+
//!
797+
//! <b>Effects</b>: If there is no key equivalent to x in the map, inserts
798+
//! value_type(boost::forward<K>(k), T()) into the map
799+
//!
800+
//! <b>Returns</b>: A reference to the mapped_type corresponding to k in *this.
801+
//!
802+
//! <b>Complexity</b>: Logarithmic search time plus linear insertion time in case no equivalent key is present
803+
template <class K>
804+
inline BOOST_CONTAINER_DOC1ST
805+
( mapped_type&
806+
, typename dtl::enable_if_transparent< key_compare
807+
BOOST_MOVE_I K
808+
BOOST_MOVE_I mapped_type&
809+
>::type) //transparent
810+
operator[](K &&k)
811+
{ return this->priv_subscript(boost::forward<K>(k)); }
812+
796813
#else
797814
BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript)
798815
#endif
@@ -1807,29 +1824,26 @@ class flat_map
18071824

18081825
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
18091826
private:
1810-
mapped_type &priv_subscript(const key_type& k)
1811-
{
1812-
iterator i = this->lower_bound(k);
1813-
// i->first is greater than or equivalent to k.
1814-
if (i == end() || key_comp()(k, (*i).first)){
1815-
dtl::value_init<mapped_type> m;
1816-
impl_value_type v(k, ::boost::move(m.m_t));
1817-
i = dtl::force_copy<iterator>(this->m_flat_tree.insert_equal(::boost::move(v)));
1818-
}
1819-
return (*i).second;
1820-
}
1821-
mapped_type &priv_subscript(BOOST_RV_REF(key_type) mk)
1827+
template<class K>
1828+
inline mapped_type& priv_subscript(BOOST_FWD_REF(K) key)
18221829
{
1823-
key_type &k = mk;
1830+
const typename dtl::remove_cvref<K>::type & k = key; //Support emulated rvalue references
18241831
iterator i = this->lower_bound(k);
1825-
// i->first is greater than or equivalent to k.
1832+
18261833
if (i == end() || key_comp()(k, (*i).first)) {
1827-
dtl::value_init<mapped_type> m;
1828-
impl_value_type v(::boost::move(k), ::boost::move(m.m_t));
1829-
i = dtl::force_copy<iterator>(this->m_flat_tree.insert_equal(::boost::move(v)));
1834+
typename dtl::aligned_storage<sizeof(impl_value_type), dtl::alignment_of<impl_value_type>::value>::type v;
1835+
impl_value_type *vp = move_detail::launder_cast<impl_value_type *>(&v);
1836+
1837+
impl_get_stored_allocator_noconst_return_t r = m_flat_tree.get_stored_allocator();
1838+
boost::container::allocator_traits<impl_stored_allocator_type>::construct
1839+
(r, vp, try_emplace_t(), ::boost::forward<K>(key));
1840+
i = dtl::force_copy<iterator> (this->m_flat_tree.insert_equal
1841+
(dtl::force_copy<impl_iterator>(i), ::boost::move(*vp)));
1842+
vp->~impl_value_type();
18301843
}
18311844
return (*i).second;
18321845
}
1846+
18331847
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
18341848
};
18351849

include/boost/container/map.hpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -555,26 +555,41 @@ class map
555555

556556
#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
557557

558-
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
558+
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || (defined(BOOST_CXX_VERSION) &&(BOOST_CXX_VERSION >= 201103L))
559+
//! <b>Effects</b>: If there is no key equivalent to x in the map, inserts
560+
//! value_type(k, T()) into the map.
561+
//!
562+
//! <b>Returns</b>: A reference to the mapped_type corresponding to k in *this.
563+
//!
564+
//! <b>Complexity</b>: Logarithmic.
565+
mapped_type& operator[](const key_type& k)
566+
{ return this->priv_subscript(k); }
567+
559568
//! <b>Effects</b>: If there is no key equivalent to x in the map, inserts
560-
//! value_type(x, T()) into the map.
569+
//! value_type(boost::move(k), T()) into the map (the key is move-constructed)
561570
//!
562-
//! <b>Returns</b>: A reference to the mapped_type corresponding to x in *this.
571+
//! <b>Returns</b>: A reference to the mapped_type corresponding to k in *this.
563572
//!
564573
//! <b>Complexity</b>: Logarithmic.
565-
mapped_type& operator[](const key_type &k);
574+
mapped_type& operator[](key_type&& k)
575+
{ return this->priv_subscript(boost::move(k)); }
566576

577+
//! <b>Precondition</b>: This overload is available only if key_compare::is_transparent exists.
578+
//!
567579
//! <b>Effects</b>: If there is no key equivalent to x in the map, inserts
568-
//! value_type(boost::move(x), T()) into the map (the key is move-constructed)
580+
//! value_type(boost::forward<K>(k), T()) into the map
569581
//!
570-
//! <b>Returns</b>: A reference to the mapped_type corresponding to x in *this.
582+
//! <b>Returns</b>: A reference to the mapped_type corresponding to k in *this.
571583
//!
572584
//! <b>Complexity</b>: Logarithmic.
573-
mapped_type& operator[](key_type &&k);
574-
#elif defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN)
575-
//in compilers like GCC 3.4, we can't catch temporaries
576-
inline mapped_type& operator[](const key_type &k) { return this->priv_subscript(k); }
577-
inline mapped_type& operator[](BOOST_RV_REF(key_type) k) { return this->priv_subscript(::boost::move(k)); }
585+
template <class K>
586+
inline BOOST_CONTAINER_DOC1ST
587+
( mapped_type&
588+
, typename dtl::enable_if_transparent<key_compare BOOST_MOVE_I K BOOST_MOVE_I mapped_type&>::type
589+
)
590+
operator[](K&& k)
591+
{ return this->priv_subscript(boost::forward<K>(k)); }
592+
578593
#else
579594
BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript)
580595
#endif
@@ -948,7 +963,7 @@ class map
948963
//! forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...).
949964
//!
950965
//! <b>Effects</b>: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise
951-
//! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)),
966+
//! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(forward<K>(k)),
952967
//! forward_as_tuple(forward<Args>(args)...).
953968
//!
954969
//! <b>Returns</b>: The bool component of the returned pair is true if and only if the

test/map_test.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,30 @@ bool test_heterogeneous_insert()
16971697
return false;
16981698
if (cmap1.find(2)->second != 'c')
16991699
return false;
1700+
1701+
//operator[]
1702+
typename map_t::mapped_type const *pm = &map1.find(2)->second;
1703+
typename map_t::mapped_type &m = map1[2];
1704+
if(m != 'c')
1705+
return false;
1706+
if(&m != pm)
1707+
return false;
1708+
1709+
map1[2] = 'd';
1710+
if (cmap1.find(2)->second != 'd')
1711+
return false;
1712+
if(&m != &map1[2])
1713+
return false;
1714+
1715+
map1[3] = 'e';
1716+
if (cmap1.find(3)->second != 'e')
1717+
return false;
1718+
if(map1[3] != map1[3])
1719+
return false;
1720+
1721+
if (map1[4] != 0)
1722+
return false;
1723+
17001724
}
17011725
return true;
17021726
}

0 commit comments

Comments
 (0)