public inbox for libstdc++-cvs@sourceware.org help / color / mirror / Atom feed
From: "Franथईois Dumont" <fdumont@gcc.gnu.org> To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-1114] libstdc++: [_Hashtable] Insert range of types convertible to value_type PR 105717 Date: Wed, 15 Jun 2022 18:23:31 +0000 (GMT) [thread overview] Message-ID: <20220615182331.C41543856267@sourceware.org> (raw) https://gcc.gnu.org/g:dc9b92facf87a6f2d8b0e5d5fc404f30c3b15a74 commit r13-1114-gdc9b92facf87a6f2d8b0e5d5fc404f30c3b15a74 Author: François Dumont <fdumont@gcc.gnu.org> Date: Tue Feb 15 09:47:52 2022 +0100 libstdc++: [_Hashtable] Insert range of types convertible to value_type PR 105717 Fix insertion of range of instances convertible to value_type. libstdc++-v3/ChangeLog: PR libstdc++/105717 * include/bits/hashtable_policy.h (_ConvertToValueType): New. * include/bits/hashtable.h (_Hashtable<>::_M_insert_unique_aux): New. (_Hashtable<>::_M_insert(_Arg&&, const _NodeGenerator&, true_type)): Use latters. (_Hashtable<>::_M_insert(_Arg&&, const _NodeGenerator&, false_type)): Likewise. (_Hashtable(_InputIterator, _InputIterator, size_type, const _Hash&, const _Equal&, const allocator_type&, true_type)): Use this.insert range. (_Hashtable(_InputIterator, _InputIterator, size_type, const _Hash&, const _Equal&, const allocator_type&, false_type)): Use _M_insert. * testsuite/23_containers/unordered_map/cons/56112.cc: Check how many times conversion is done. * testsuite/23_containers/unordered_map/insert/105717.cc: New test. * testsuite/23_containers/unordered_set/insert/105717.cc: New test. Diff: --- libstdc++-v3/include/bits/hashtable.h | 30 ++++++--- libstdc++-v3/include/bits/hashtable_policy.h | 34 ++++++++++ .../23_containers/unordered_map/cons/56112.cc | 33 ++++++++-- .../23_containers/unordered_map/insert/105717.cc | 73 ++++++++++++++++++++++ .../23_containers/unordered_set/insert/105717.cc | 73 ++++++++++++++++++++++ 5 files changed, 227 insertions(+), 16 deletions(-) diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 29ec1192f32..1b21b795f89 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -899,21 +899,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Arg, typename _NodeGenerator> std::pair<iterator, bool> - _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen, - true_type /* __uks */) + _M_insert_unique_aux(_Arg&& __arg, const _NodeGenerator& __node_gen) { return _M_insert_unique( _S_forward_key(_ExtractKey{}(std::forward<_Arg>(__arg))), std::forward<_Arg>(__arg), __node_gen); } + template<typename _Arg, typename _NodeGenerator> + std::pair<iterator, bool> + _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen, + true_type /* __uks */) + { + using __to_value + = __detail::_ConvertToValueType<_ExtractKey, value_type>; + return _M_insert_unique_aux( + __to_value{}(std::forward<_Arg>(__arg)), __node_gen); + } + template<typename _Arg, typename _NodeGenerator> iterator _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen, false_type __uks) { - return _M_insert(cend(), std::forward<_Arg>(__arg), __node_gen, - __uks); + using __to_value + = __detail::_ConvertToValueType<_ExtractKey, value_type>; + return _M_insert(cend(), + __to_value{}(std::forward<_Arg>(__arg)), __node_gen, __uks); } // Insert with hint, not used when keys are unique. @@ -1185,10 +1197,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const _Hash& __h, const _Equal& __eq, const allocator_type& __a, true_type /* __uks */) : _Hashtable(__bkt_count_hint, __h, __eq, __a) - { - for (; __f != __l; ++__f) - this->insert(*__f); - } + { this->insert(__f, __l); } template<typename _Key, typename _Value, typename _Alloc, typename _ExtractKey, typename _Equal, @@ -1200,7 +1209,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Hashtable(_InputIterator __f, _InputIterator __l, size_type __bkt_count_hint, const _Hash& __h, const _Equal& __eq, - const allocator_type& __a, false_type /* __uks */) + const allocator_type& __a, false_type __uks) : _Hashtable(__h, __eq, __a) { auto __nb_elems = __detail::__distance_fw(__f, __l); @@ -1215,8 +1224,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_bucket_count = __bkt_count; } + __alloc_node_gen_t __node_gen(*this); for (; __f != __l; ++__f) - this->insert(*__f); + _M_insert(*__f, __node_gen, __uks); } template<typename _Key, typename _Value, typename _Alloc, diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h index 1a259702f98..f2696ae9b07 100644 --- a/libstdc++-v3/include/bits/hashtable_policy.h +++ b/libstdc++-v3/include/bits/hashtable_policy.h @@ -113,6 +113,40 @@ namespace __detail { return std::forward<_Tp>(__x).first; } }; + template<typename _ExKey, typename _Value> + struct _ConvertToValueType; + + template<typename _Value> + struct _ConvertToValueType<_Identity, _Value> + { + template<typename _Kt> + constexpr _Kt&& + operator()(_Kt&& __k) const noexcept + { return std::forward<_Kt>(__k); } + }; + + template<typename _Value> + struct _ConvertToValueType<_Select1st, _Value> + { + constexpr _Value&& + operator()(_Value&& __x) const noexcept + { return std::move(__x); } + + constexpr const _Value& + operator()(const _Value& __x) const noexcept + { return __x; } + + template<typename _Kt, typename _Val> + constexpr std::pair<_Kt, _Val>&& + operator()(std::pair<_Kt, _Val>&& __x) const noexcept + { return std::move(__x); } + + template<typename _Kt, typename _Val> + constexpr const std::pair<_Kt, _Val>& + operator()(const std::pair<_Kt, _Val>& __x) const noexcept + { return __x; } + }; + template<typename _ExKey> struct _NodeBuilder; diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/56112.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/56112.cc index c4cdeee234c..b0eda30b4cb 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/56112.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/56112.cc @@ -20,30 +20,51 @@ #include <unordered_map> #include <utility> +#include <testsuite_hooks.h> + struct Key { explicit Key(const int* p) : value(p) { } ~Key() { value = nullptr; } - bool operator==(const Key& k) const { return *value == *k.value; } + bool operator==(const Key& k) const + { return *value == *k.value; } const int* value; }; struct hash { - std::size_t operator()(const Key& k) const noexcept { return *k.value; } + std::size_t operator()(const Key& k) const noexcept + { return *k.value; } }; struct S { + static int _count; + int value; - operator std::pair<const Key, int>() const { return {Key(&value), value}; } + operator std::pair<const Key, int>() const + { + ++_count; + return { Key(&value), value }; + } }; -int main() +int S::_count = 0; + +void test01() { S s[1] = { {2} }; - std::unordered_map<Key, int, hash> m(s, s+1); - std::unordered_multimap<Key, int, hash> mm(s, s+1); + std::unordered_map<Key, int, hash> m(s, s + 1); + VERIFY( S::_count == 1 ); + + std::unordered_multimap<Key, int, hash> mm(s, s + 1); + VERIFY( S::_count == 2 ); +} + +int main() +{ + test01(); + return 0; } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/insert/105717.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/insert/105717.cc new file mode 100644 index 00000000000..202baa9818b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/insert/105717.cc @@ -0,0 +1,73 @@ +// { dg-do run { target c++11 } } + +// Copyright (C) 2022 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 +// <http://www.gnu.org/licenses/>. + +#include <unordered_map> +#include <utility> + +#include <testsuite_hooks.h> + +struct Key +{ + explicit Key(const int* p) : value(p) { } + ~Key() { value = nullptr; } + + bool operator==(const Key& k) const + { return *value == *k.value; } + + const int* value; +}; + +struct hash +{ + std::size_t operator()(const Key& k) const noexcept + { return *k.value; } +}; + +struct S +{ + static int _count; + + int value; + operator std::pair<const Key, int>() const + { + ++_count; + return { Key(&value), value }; + } +}; + +int S::_count = 0; + +void test01() +{ + S s[1] = { {2} }; + std::unordered_map<Key, int, hash> m; + std::unordered_multimap<Key, int, hash> mm; + + m.insert(s, s + 1); + VERIFY( S::_count == 1 ); + + mm.insert(s, s + 1); + VERIFY( S::_count == 2 ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/insert/105717.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/insert/105717.cc new file mode 100644 index 00000000000..ab229c5baa1 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/insert/105717.cc @@ -0,0 +1,73 @@ +// { dg-do run { target c++11 } } + +// Copyright (C) 2022 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 +// <http://www.gnu.org/licenses/>. + +#include <unordered_set> +#include <utility> + +#include <testsuite_hooks.h> + +struct Key +{ + explicit Key(const int* p) : value(p) { } + ~Key() { value = nullptr; } + + bool operator==(const Key& k) const + { return *value == *k.value; } + + const int* value; +}; + +struct hash +{ + std::size_t operator()(const Key& k) const noexcept + { return *k.value; } +}; + +struct S +{ + static int _count; + + int value; + operator Key() const + { + ++_count; + return Key(&value); + } +}; + +int S::_count = 0; + +void test01() +{ + S a[1] = { {2} }; + std::unordered_set<Key, hash> s; + std::unordered_multiset<Key, hash> ms; + + s.insert(a, a + 1); + VERIFY( S::_count == 1 ); + + ms.insert(a, a + 1); + VERIFY( S::_count == 2 ); +} + +int main() +{ + test01(); + return 0; +}
reply other threads:[~2022-06-15 18:23 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220615182331.C41543856267@sourceware.org \ --to=fdumont@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ --cc=libstdc++-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).