diff options
5 files changed, 130 insertions, 8 deletions
diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index cc87f11..658d586 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -154,6 +154,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef __gnu_cxx::__alloc_traits<_Pair_alloc_type> _Alloc_traits; +#if __cplusplus >= 201703L + template<typename _Up, typename _Vp = remove_reference_t<_Up>> + static constexpr bool __usable_key + = __or_v<is_same<const _Vp, const _Key>, + __and_<is_scalar<_Vp>, is_scalar<_Key>>>; +#endif + public: // many of these are specified differently in ISO, but the following are // "functionally equivalent" @@ -574,7 +581,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template<typename... _Args> std::pair<iterator, bool> emplace(_Args&&... __args) - { return _M_t._M_emplace_unique(std::forward<_Args>(__args)...); } + { +#if __cplusplus >= 201703L + if constexpr (sizeof...(_Args) == 2) + if constexpr (is_same_v<allocator_type, allocator<value_type>>) + { + auto&& [__a, __v] = pair<_Args&...>(__args...); + if constexpr (__usable_key<decltype(__a)>) + { + const key_type& __k = __a; + iterator __i = lower_bound(__k); + if (__i == end() || key_comp()(__k, (*__i).first)) + { + __i = emplace_hint(__i, std::forward<_Args>(__args)...); + return {__i, true}; + } + return {__i, false}; + } + } +#endif + return _M_t._M_emplace_unique(std::forward<_Args>(__args)...); + } /** * @brief Attempts to build and insert a std::pair into the %map. @@ -814,7 +841,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __enable_if_t<is_constructible<value_type, _Pair>::value, pair<iterator, bool>> insert(_Pair&& __x) - { return _M_t._M_emplace_unique(std::forward<_Pair>(__x)); } + { +#if __cplusplus >= 201703L + using _P2 = remove_reference_t<_Pair>; + if constexpr (__is_pair<_P2>) + if constexpr (is_same_v<allocator_type, allocator<value_type>>) + if constexpr (__usable_key<typename _P2::first_type>) + { + const key_type& __k = __x.first; + iterator __i = lower_bound(__k); + if (__i == end() || key_comp()(__k, (*__i).first)) + { + __i = emplace_hint(__i, std::forward<_Pair>(__x)); + return {__i, true}; + } + return {__i, false}; + } +#endif + return _M_t._M_emplace_unique(std::forward<_Pair>(__x)); + } #endif /// @} diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 6081e0c..5f7b6093 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -777,6 +777,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp1, typename _Tp2> inline constexpr size_t tuple_size_v<const pair<_Tp1, _Tp2>> = 2; + + template<typename _Tp> + inline constexpr bool __is_pair = false; + + template<typename _Tp, typename _Up> + inline constexpr bool __is_pair<pair<_Tp, _Up>> = true; + + template<typename _Tp, typename _Up> + inline constexpr bool __is_pair<const pair<_Tp, _Up>> = true; #endif /// @cond undocumented diff --git a/libstdc++-v3/include/bits/uses_allocator_args.h b/libstdc++-v3/include/bits/uses_allocator_args.h index 8b548ff..e1fd7e7 100644 --- a/libstdc++-v3/include/bits/uses_allocator_args.h +++ b/libstdc++-v3/include/bits/uses_allocator_args.h @@ -56,12 +56,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template<typename _Tp> - inline constexpr bool __is_pair = false; - template<typename _Tp, typename _Up> - inline constexpr bool __is_pair<pair<_Tp, _Up>> = true; - template<typename _Tp, typename _Up> - inline constexpr bool __is_pair<const pair<_Tp, _Up>> = true; template<typename _Tp> concept _Std_pair = __is_pair<_Tp>; diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc new file mode 100644 index 0000000..937b4d9 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc @@ -0,0 +1,36 @@ +// { dg-do run { target c++17 } } + +#include <map> +#include <cstdlib> + +bool oom = false; + +void* operator new(std::size_t n) +{ + if (oom) + throw std::bad_alloc(); + return std::malloc(n); +} + +void operator delete(void* p) +{ + std::free(p); +} + +void operator delete(void* p, std::size_t) +{ + std::free(p); +} + +int main() +{ + std::map<int, int> m; + int i = 0; + (void) m[i]; + oom = true; + m.emplace(i, 1); + m.emplace(i, 2L); + const int c = 3; + m.emplace(i, c); + m.emplace((long)i, 4); +} diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc new file mode 100644 index 0000000..80abdaf --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc @@ -0,0 +1,38 @@ +// { dg-do run { target c++17 } } + +#include <map> +#include <cstdlib> + +bool oom = false; + +void* operator new(std::size_t n) +{ + if (oom) + throw std::bad_alloc(); + return std::malloc(n); +} + +void operator delete(void* p) +{ + std::free(p); +} + +void operator delete(void* p, std::size_t) +{ + std::free(p); +} + +int main() +{ + using std::pair; + std::map<int, int> m; + int i = 0; + (void) m[i]; + oom = true; + m.insert({i, 1}); // insert(value_type&&) + m.insert(pair<int, int>(i, 2)); // insert(Pair&&) + m.insert(pair<int&, int>(i, 3)); // insert(Pair&&) + m.insert(pair<int, long>(i, 4L)); // insert(Pair&&) + m.insert(pair<const int, long>(i, 5L)); // insert(Pair&&) + m.insert(pair<const int&, long>(i, 6L)); // insert(Pair&&) +} |