From: Jonathan Wakely Date: Fri, 12 Oct 2018 12:51:40 +0000 (+0100) Subject: PR libstdc++/78595 implement insertion into maps in terms of emplace X-Git-Tag: releases/gcc-7.4.0~113 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=894a59843b4a2efae1a09eef1f69be50b7c3095b;p=thirdparty%2Fgcc.git PR libstdc++/78595 implement insertion into maps in terms of emplace C++14 simplified the specification of the generic insert function templates to be equivalent to calling emplace (or emplace_hint). Defining them in terms of emplace takes care of the problems described in PR 78595, ensuring a single conversion to value_type is done at the right time. Backport from mainline 2018-09-03 Jonathan Wakely PR libstdc++/78595 * include/bits/stl_map.h (map::insert(_Pair&&)) (map::insert(const_iterator, _Pair&&)): Do emplace instead of insert. * include/bits/stl_multimap.h (multimap::insert(_Pair&&)) (multimap::insert(const_iterator, _Pair&&)): Likewise. * include/bits/unordered_map.h (unordered_map::insert(_Pair&&)) (unordered_map::insert(const_iterator, _Pair&&)) (unordered_multimap::insert(_Pair&&)) (unordered_multimap::insert(const_iterator, _Pair&&)): Likewise. * include/std/type_traits (__enable_if_t): Define for C++11. * testsuite/23_containers/map/modifiers/insert/78595.cc: New test. * testsuite/23_containers/multimap/modifiers/insert/78595.cc: New test. * testsuite/23_containers/unordered_map/modifiers/78595.cc: New test. * testsuite/23_containers/unordered_multimap/modifiers/78595.cc: New test. From-SVN: r265095 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index baa299050691..51336b60632d 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,24 @@ +2018-10-12 Jonathan Wakely + + Backport from mainline + 2018-09-03 Jonathan Wakely + + PR libstdc++/78595 + * include/bits/stl_map.h (map::insert(_Pair&&)) + (map::insert(const_iterator, _Pair&&)): Do emplace instead of insert. + * include/bits/stl_multimap.h (multimap::insert(_Pair&&)) + (multimap::insert(const_iterator, _Pair&&)): Likewise. + * include/bits/unordered_map.h (unordered_map::insert(_Pair&&)) + (unordered_map::insert(const_iterator, _Pair&&)) + (unordered_multimap::insert(_Pair&&)) + (unordered_multimap::insert(const_iterator, _Pair&&)): Likewise. + * include/std/type_traits (__enable_if_t): Define for C++11. + * testsuite/23_containers/map/modifiers/insert/78595.cc: New test. + * testsuite/23_containers/multimap/modifiers/insert/78595.cc: New test. + * testsuite/23_containers/unordered_map/modifiers/78595.cc: New test. + * testsuite/23_containers/unordered_multimap/modifiers/78595.cc: New + test. + 2018-10-12 Jonathan Wakely Backport from mainline diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index ea0e3277738a..6ec885ac3be3 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -802,12 +802,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(value_type&& __x) { return _M_t._M_insert_unique(std::move(__x)); } - template::value>::type> - std::pair + template + __enable_if_t::value, + pair> insert(_Pair&& __x) - { return _M_t._M_insert_unique(std::forward<_Pair>(__x)); } + { return _M_t._M_emplace_unique(std::forward<_Pair>(__x)); } #endif // @} @@ -863,13 +862,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(const_iterator __position, value_type&& __x) { return _M_t._M_insert_unique_(__position, std::move(__x)); } - template::value>::type> - iterator + template + __enable_if_t::value, iterator> insert(const_iterator __position, _Pair&& __x) - { return _M_t._M_insert_unique_(__position, - std::forward<_Pair>(__x)); } + { + return _M_t._M_emplace_hint_unique(__position, + std::forward<_Pair>(__x)); + } #endif // @} diff --git a/libstdc++-v3/include/bits/stl_multimap.h b/libstdc++-v3/include/bits/stl_multimap.h index 68ffea3adba6..63f0055cdd62 100644 --- a/libstdc++-v3/include/bits/stl_multimap.h +++ b/libstdc++-v3/include/bits/stl_multimap.h @@ -538,12 +538,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(value_type&& __x) { return _M_t._M_insert_equal(std::move(__x)); } - template::value>::type> - iterator + template + __enable_if_t::value, iterator> insert(_Pair&& __x) - { return _M_t._M_insert_equal(std::forward<_Pair>(__x)); } + { return _M_t._M_emplace_equal(std::forward<_Pair>(__x)); } #endif // @} @@ -583,13 +581,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(const_iterator __position, value_type&& __x) { return _M_t._M_insert_equal_(__position, std::move(__x)); } - template::value>::type> - iterator + template + __enable_if_t::value, iterator> insert(const_iterator __position, _Pair&& __x) - { return _M_t._M_insert_equal_(__position, - std::forward<_Pair>(__x)); } + { + return _M_t._M_emplace_hint_equal(__position, + std::forward<_Pair>(__x)); + } #endif // @} diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h index dd881d462138..4ff54d0ef2ec 100644 --- a/libstdc++-v3/include/bits/unordered_map.h +++ b/libstdc++-v3/include/bits/unordered_map.h @@ -584,12 +584,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(value_type&& __x) { return _M_h.insert(std::move(__x)); } - template::value>::type> - std::pair + template + __enable_if_t::value, + pair> insert(_Pair&& __x) - { return _M_h.insert(std::forward<_Pair>(__x)); } + { return _M_h.emplace(std::forward<_Pair>(__x)); } //@} //@{ @@ -624,12 +623,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(const_iterator __hint, value_type&& __x) { return _M_h.insert(__hint, std::move(__x)); } - template::value>::type> - iterator + template + __enable_if_t::value, iterator> insert(const_iterator __hint, _Pair&& __x) - { return _M_h.insert(__hint, std::forward<_Pair>(__x)); } + { return _M_h.emplace_hint(__hint, std::forward<_Pair>(__x)); } //@} /** @@ -1483,12 +1480,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(value_type&& __x) { return _M_h.insert(std::move(__x)); } - template::value>::type> - iterator + template + __enable_if_t::value, iterator> insert(_Pair&& __x) - { return _M_h.insert(std::forward<_Pair>(__x)); } + { return _M_h.emplace(std::forward<_Pair>(__x)); } //@} //@{ @@ -1521,12 +1516,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(const_iterator __hint, value_type&& __x) { return _M_h.insert(__hint, std::move(__x)); } - template::value>::type> - iterator + template + __enable_if_t::value, iterator> insert(const_iterator __hint, _Pair&& __x) - { return _M_h.insert(__hint, std::forward<_Pair>(__x)); } + { return _M_h.emplace_hint(__hint, std::forward<_Pair>(__x)); } //@} /** diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 834bef745c4b..80344a8bc583 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2458,7 +2458,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public __invoke_result<_Functor, _ArgTypes...> { }; -#if __cplusplus > 201103L +#if __cplusplus >= 201402L /// Alias template for aligned_storage template::__type)> @@ -2490,11 +2490,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Alias template for result_of template using result_of_t = typename result_of<_Tp>::type; -#endif +#endif // C++14 + // __enable_if_t (std::enable_if_t for C++11) + template + using __enable_if_t = typename enable_if<_Cond, _Tp>::type; + + // __void_t (std::void_t for C++11) template using __void_t = void; -#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 +#if __cplusplus >= 201703L || !defined(__STRICT_ANSI__) // c++17 or gnu++11 #define __cpp_lib_void_t 201411 /// A metafunction that always yields void, used for detecting valid types. template using void_t = void; diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/78595.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/78595.cc new file mode 100644 index 000000000000..187d165b0834 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/78595.cc @@ -0,0 +1,115 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do run { target c++11 } } + +#include +#include + +void +test01() +{ + struct X { + mutable int conversions = 0; + + operator std::pair() const { + if (++conversions > 1) + throw 1; + return {}; + } + }; + + std::map m; + m.insert(X()); + VERIFY( m.size() == 1 ); + m.insert(m.begin(), X()); + VERIFY( m.size() == 1 ); + +} +void +test02() +{ + struct Y { + int conversions = 0; + + operator std::pair() && { + if (++conversions > 1) + throw 1; + return {}; + } + }; + + std::map m; + m.insert(Y()); + VERIFY( m.size() == 1 ); + m.insert(m.begin(), Y()); + VERIFY( m.size() == 1 ); +} + +struct Key { + int key; + bool operator<(const Key& r) const { return key < r.key; } +}; + +struct Z { + operator std::pair() const { return { { z }, 0 }; } + int z; +}; + +template +struct Alloc +{ + Alloc() = default; + + template + Alloc(const Alloc&) { } + + using value_type = T; + + T* allocate(std::size_t n) { return std::allocator().allocate(n); } + + void deallocate(T* p, std::size_t n) { std::allocator().deallocate(p, n); } + + template + void construct(U* p, const Z& z) { ::new (p) U{ { z.z+1 }, 0}; } + + template + bool operator==(const Alloc&) { return true; } + + template + bool operator!=(const Alloc&) { return false; } +}; + +void +test03() +{ + std::map, Alloc>> m; + m.insert(Z{}); + m.insert(Z{}); + VERIFY( m.size() == 1 ); + m.insert(Z{}); + m.insert(Z{1}); + VERIFY( m.size() == 2 ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/23_containers/multimap/modifiers/insert/78595.cc b/libstdc++-v3/testsuite/23_containers/multimap/modifiers/insert/78595.cc new file mode 100644 index 000000000000..2f357fcae95b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/multimap/modifiers/insert/78595.cc @@ -0,0 +1,115 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do run { target c++11 } } + +#include +#include + +void +test01() +{ + struct X { + mutable int conversions = 0; + + operator std::pair() const { + if (++conversions > 1) + throw 1; + return {}; + } + }; + + std::multimap m; + m.insert(X()); + VERIFY( m.size() == 1 ); + m.insert(m.begin(), X()); + VERIFY( m.size() == 2 ); + +} +void +test02() +{ + struct Y { + int conversions = 0; + + operator std::pair() && { + if (++conversions > 1) + throw 1; + return {}; + } + }; + + std::multimap m; + m.insert(Y()); + VERIFY( m.size() == 1 ); + m.insert(m.begin(), Y()); + VERIFY( m.size() == 2 ); +} + +struct Key { + int key; + bool operator<(const Key& r) const { return key < r.key; } +}; + +struct Z { + operator std::pair() const { return { { z }, 0 }; } + int z; +}; + +template +struct Alloc +{ + Alloc() = default; + + template + Alloc(const Alloc&) { } + + using value_type = T; + + T* allocate(std::size_t n) { return std::allocator().allocate(n); } + + void deallocate(T* p, std::size_t n) { std::allocator().deallocate(p, n); } + + template + void construct(U* p, const Z& z) { ::new (p) U{ { z.z+1 }, 0}; } + + template + bool operator==(const Alloc&) { return true; } + + template + bool operator!=(const Alloc&) { return false; } +}; + +void +test03() +{ + std::multimap, Alloc>> m; + m.insert(Z{}); + m.insert(Z{}); + VERIFY( m.size() == 2 ); + m.insert(Z{}); + m.insert(Z{1}); + VERIFY( m.size() == 4 ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/78595.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/78595.cc new file mode 100644 index 000000000000..47cd67b86d84 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/78595.cc @@ -0,0 +1,122 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do run { target c++11 } } + +#include +#include + +void +test01() +{ + struct X { + mutable int conversions = 0; + + operator std::pair() const { + if (++conversions > 1) + throw 1; + return {}; + } + }; + + std::unordered_map m; + m.insert(X()); + VERIFY( m.size() == 1 ); + m.insert(m.begin(), X()); + VERIFY( m.size() == 1 ); + +} +void +test02() +{ + struct Y { + int conversions = 0; + + operator std::pair() && { + if (++conversions > 1) + throw 1; + return {}; + } + }; + + std::unordered_map m; + m.insert(Y()); + VERIFY( m.size() == 1 ); + m.insert(m.begin(), Y()); + VERIFY( m.size() == 1 ); +} + +struct Key { + int key; + bool operator==(const Key& r) const { return key == r.key; } +}; + +namespace std { + template<> struct hash { + size_t operator()(const Key& k) const { return std::hash()(k.key); } + }; +} + +struct Z { + operator std::pair() const { return { { z }, 0 }; } + int z; +}; + +template +struct Alloc +{ + Alloc() = default; + + template + Alloc(const Alloc&) { } + + using value_type = T; + + T* allocate(std::size_t n) { return std::allocator().allocate(n); } + + void deallocate(T* p, std::size_t n) { std::allocator().deallocate(p, n); } + + template + void construct(U* p, const Z& z) { ::new (p) U{ { z.z+1 }, 0}; } + + template + bool operator==(const Alloc&) { return true; } + + template + bool operator!=(const Alloc&) { return false; } +}; + +void +test03() +{ + std::unordered_map, std::equal_to, + Alloc>> m; + m.insert(Z{}); + m.insert(Z{}); + VERIFY( m.size() == 1 ); + m.insert(Z{}); + m.insert(Z{1}); + VERIFY( m.size() == 2 ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/78595.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/78595.cc new file mode 100644 index 000000000000..e47c20cad81f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/78595.cc @@ -0,0 +1,122 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do run { target c++11 } } + +#include +#include + +void +test01() +{ + struct X { + mutable int conversions = 0; + + operator std::pair() const { + if (++conversions > 1) + throw 1; + return {}; + } + }; + + std::unordered_multimap m; + m.insert(X()); + VERIFY( m.size() == 1 ); + m.insert(m.begin(), X()); + VERIFY( m.size() == 2 ); + +} +void +test02() +{ + struct Y { + int conversions = 0; + + operator std::pair() && { + if (++conversions > 1) + throw 1; + return {}; + } + }; + + std::unordered_multimap m; + m.insert(Y()); + VERIFY( m.size() == 1 ); + m.insert(m.begin(), Y()); + VERIFY( m.size() == 2 ); +} + +struct Key { + int key; + bool operator==(const Key& r) const { return key == r.key; } +}; + +namespace std { + template<> struct hash { + size_t operator()(const Key& k) const { return std::hash()(k.key); } + }; +} + +struct Z { + operator std::pair() const { return { { z }, 0 }; } + int z; +}; + +template +struct Alloc +{ + Alloc() = default; + + template + Alloc(const Alloc&) { } + + using value_type = T; + + T* allocate(std::size_t n) { return std::allocator().allocate(n); } + + void deallocate(T* p, std::size_t n) { std::allocator().deallocate(p, n); } + + template + void construct(U* p, const Z& z) { ::new (p) U{ { z.z+1 }, 0}; } + + template + bool operator==(const Alloc&) { return true; } + + template + bool operator!=(const Alloc&) { return false; } +}; + +void +test03() +{ + std::unordered_multimap, std::equal_to, + Alloc>> m; + m.insert(Z{}); + m.insert(Z{}); + VERIFY( m.size() == 2 ); + m.insert(Z{}); + m.insert(Z{1}); + VERIFY( m.size() == 4 ); +} + +int +main() +{ + test01(); + test02(); + test03(); +}