From e4f42d03cb978bc1a76573525de6be9237cb4442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 7 Nov 2025 23:09:05 +0100 Subject: [PATCH] Implement heterogeneous "at()" operation for map/flat_map --- include/boost/container/flat_map.hpp | 48 ++++++++++++++++++++++++++ include/boost/container/map.hpp | 50 +++++++++++++++++++++++++++- test/map_test.hpp | 32 ++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index e09f5e7..0fff739 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -982,12 +982,60 @@ class flat_map BOOST_CONTAINER_ATTRIBUTE_NODISCARD const T& at(const key_type& k) const { const_iterator i = this->find(k); + if(i == this->cend()){ + throw_out_of_range("flat_map::at key not found"); + } + return i->second; + } + + //! Precondition: This overload is available only if key_compare::is_transparent exists. + //! + //! Returns: A reference to the element whose key is equivalent to x. + //! + //! Throws: An exception object of type out_of_range if no such element is present. + //! + //! Complexity: logarithmic. + template + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + BOOST_CONTAINER_DOC1ST + ( T& + , typename dtl::enable_if_transparent< key_compare + BOOST_MOVE_I K + BOOST_MOVE_I T& + >::type) //transparent + at(const K& k) + { + iterator i = this->find(k); if(i == this->end()){ throw_out_of_range("flat_map::at key not found"); } return i->second; } + //! Precondition: This overload is available only if key_compare::is_transparent exists. + //! + //! Returns: A reference to the element whose key is equivalent to x. + //! + //! Throws: An exception object of type out_of_range if no such element is present. + //! + //! Complexity: logarithmic. + template + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + BOOST_CONTAINER_DOC1ST + ( const T& + , typename dtl::enable_if_transparent< key_compare + BOOST_MOVE_I K + BOOST_MOVE_I const T& + >::type) //transparent + at(const K& k) const + { + const_iterator i = this->find(k); + if(i == this->cend()){ + throw_out_of_range("flat_map::at key not found"); + } + return i->second; + } + ////////////////////////////////////////////// // // modifiers diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index e7991d6..a295dd9 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -713,7 +713,7 @@ class map //! Returns: A reference to the element whose key is equivalent to x. //! Throws: An exception object of type out_of_range if no such element is present. //! Complexity: logarithmic. - T& at(const key_type& k) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD T& at(const key_type& k) { iterator i = this->find(k); if(i == this->end()){ @@ -728,12 +728,60 @@ class map BOOST_CONTAINER_ATTRIBUTE_NODISCARD const T& at(const key_type& k) const { const_iterator i = this->find(k); + if(i == this->cend()){ + throw_out_of_range("map::at key not found"); + } + return i->second; + } + + //! Precondition: This overload is available only if key_compare::is_transparent exists. + //! + //! Returns: A reference to the element whose key is equivalent to x. + //! + //! Throws: An exception object of type out_of_range if no such element is present. + //! + //! Complexity: logarithmic. + template + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + BOOST_CONTAINER_DOC1ST + ( T& + , typename dtl::enable_if_transparent< key_compare + BOOST_MOVE_I K + BOOST_MOVE_I T& + >::type) //transparent + at(const K& k) + { + iterator i = this->find(k); if(i == this->end()){ throw_out_of_range("map::at key not found"); } return i->second; } + //! Precondition: This overload is available only if key_compare::is_transparent exists. + //! + //! Returns: A reference to the element whose key is equivalent to x. + //! + //! Throws: An exception object of type out_of_range if no such element is present. + //! + //! Complexity: logarithmic. + template + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + BOOST_CONTAINER_DOC1ST + ( const T& + , typename dtl::enable_if_transparent< key_compare + BOOST_MOVE_I K + BOOST_MOVE_I const T& + >::type) //transparent + at(const K& k) const + { + const_iterator i = this->find(k); + if(i == this->cend()){ + throw_out_of_range("map::at key not found"); + } + return i->second; + } + ////////////////////////////////////////////// // // modifiers diff --git a/test/map_test.hpp b/test/map_test.hpp index 15466d7..ada42b0 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -1575,6 +1575,7 @@ bool test_heterogeneous_lookup() mmap1.insert(value_type(3, 'e')); const test::non_copymovable_int find_me(2); + const test::non_copymovable_int not_present(5); //find if(map1.find(find_me)->second != 'd') @@ -1585,6 +1586,15 @@ bool test_heterogeneous_lookup() return false; if(cmmap1.find(find_me)->second != 'c') return false; + if(map1.find(not_present) != map1.end()) + return false; + if(cmap1.find(not_present) != cmap1.end()) + return false; + if(mmap1.find(not_present) != mmap1.end()) + return false; + if(cmmap1.find(not_present) != mmap1.cend()) + return false; + //count if(map1.count(find_me) != 1) @@ -1595,6 +1605,14 @@ bool test_heterogeneous_lookup() return false; if(cmmap1.count(find_me) != 2) return false; + if(map1.count(not_present) != 0) + return false; + if(cmap1.count(not_present) != 0) + return false; + if(mmap1.count(not_present) != 0) + return false; + if(cmmap1.count(not_present) != 0) + return false; //contains if(!map1.contains(find_me)) @@ -1605,6 +1623,20 @@ bool test_heterogeneous_lookup() return false; if(!cmmap1.contains(find_me)) return false; + if(map1.contains(not_present)) + return false; + if(cmap1.contains(not_present)) + return false; + if(mmap1.contains(not_present)) + return false; + if(cmmap1.contains(not_present)) + return false; + + //at + if(map1.at(find_me) != 'd') + return false; + if(cmap1.at(find_me) != 'd') + return false; //lower_bound if(map1.lower_bound(find_me)->second != 'd')