+2018-01-09 François Dumont <fdumont@gcc.gnu.org>
+
+ PR libstdc++/83709
+ * include/bits/hashtable_policy.h
+ (__distance_fwd(_Iterator, _Iterator, input_iterator_tag)): Return 1 if
+ __first != __last.
+ (_Insert_base::_M_insert_range(_Ite, _Ite, _NodeGetter, true_type)): New.
+ (_Insert_base::_M_insert_range(_Ite, _Ite, _NodeGetter, false_type)):
+ Add false_type parameter.
+ (_Insert_base::insert): Adapt.
+ * include/bits/hashtable.h (_Hashtable::operator=(initializzr_list<>)):
+ Adapt.
+ (_Hashtable::_M_insert(_Arg&&, const _NodeGen&, true_type, size_t)):
+ Add __n_elt parameter, defaulted to 1.
+ (_Hashtable::_M_insert_unique_node): Likewise. Use it to call rehash
+ policy _M_need_rehash.
+ (_Hashtable::_M_merge_unique): Pass target number of elements to add to
+ produce only 1 rehash if necessary.
+ * testsuite/23_containers/unordered_map/insert/83709.cc: New.
+ * testsuite/23_containers/unordered_set/insert/83709.cc: New.
+
2018-01-09 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/59253 (partial)
__reuse_or_alloc_node_type __roan(_M_begin(), *this);
_M_before_begin._M_nxt = nullptr;
clear();
- this->_M_insert_range(__l.begin(), __l.end(), __roan);
+ this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys());
return *this;
}
// deallocate it on exception.
iterator
_M_insert_unique_node(size_type __bkt, __hash_code __code,
- __node_type* __n);
+ __node_type* __n, size_type __n_elt = 1);
// Insert node with hash code __code. Take ownership of the node,
// deallocate it on exception.
template<typename _Arg, typename _NodeGenerator>
std::pair<iterator, bool>
- _M_insert(_Arg&&, const _NodeGenerator&, std::true_type);
+ _M_insert(_Arg&&, const _NodeGenerator&, true_type, size_type = 1);
template<typename _Arg, typename _NodeGenerator>
iterator
_M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen,
- std::false_type __uk)
+ false_type __uk)
{
return _M_insert(cend(), std::forward<_Arg>(__arg), __node_gen,
__uk);
template<typename _Arg, typename _NodeGenerator>
iterator
_M_insert(const_iterator, _Arg&& __arg,
- const _NodeGenerator& __node_gen, std::true_type __uk)
+ const _NodeGenerator& __node_gen, true_type __uk)
{
return
_M_insert(std::forward<_Arg>(__arg), __node_gen, __uk).first;
template<typename _Arg, typename _NodeGenerator>
iterator
_M_insert(const_iterator, _Arg&&,
- const _NodeGenerator&, std::false_type);
+ const _NodeGenerator&, false_type);
size_type
_M_erase(std::true_type, const key_type&);
node_type>, "Node types are compatible");
__glibcxx_assert(get_allocator() == __src.get_allocator());
+ auto __n_elt = __src.size();
for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
{
auto __pos = __i++;
if (_M_find_node(__bkt, __k, __code) == nullptr)
{
auto __nh = __src.extract(__pos);
- _M_insert_unique_node(__bkt, __code, __nh._M_ptr);
+ _M_insert_unique_node(__bkt, __code, __nh._M_ptr, __n_elt);
__nh._M_ptr = nullptr;
+ __n_elt = 1;
}
+ else if (__n_elt != 1)
+ --__n_elt;
}
}
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
_M_insert_unique_node(size_type __bkt, __hash_code __code,
- __node_type* __node)
+ __node_type* __node, size_type __n_elt)
-> iterator
{
const __rehash_state& __saved_state = _M_rehash_policy._M_state();
std::pair<bool, std::size_t> __do_rehash
- = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1);
+ = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count,
+ __n_elt);
__try
{
auto
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
- _M_insert(_Arg&& __v, const _NodeGenerator& __node_gen, std::true_type)
+ _M_insert(_Arg&& __v, const _NodeGenerator& __node_gen, true_type,
+ size_type __n_elt)
-> pair<iterator, bool>
{
const key_type& __k = this->_M_extract()(__v);
return std::make_pair(iterator(__n), false);
__n = __node_gen(std::forward<_Arg>(__v));
- return std::make_pair(_M_insert_unique_node(__bkt, __code, __n), true);
+ return { _M_insert_unique_node(__bkt, __code, __n, __n_elt), true };
}
// Insert v unconditionally.
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
_M_insert(const_iterator __hint, _Arg&& __v,
- const _NodeGenerator& __node_gen, std::false_type)
+ const _NodeGenerator& __node_gen, false_type)
-> iterator
{
// First compute the hash code so that we don't do anything if it
struct _Hashtable_base;
// Helper function: return distance(first, last) for forward
- // iterators, or 0 for input iterators.
+ // iterators, or 0/1 for input iterators.
template<class _Iterator>
inline typename std::iterator_traits<_Iterator>::difference_type
__distance_fw(_Iterator __first, _Iterator __last,
std::input_iterator_tag)
- { return 0; }
+ { return __first != __last ? 1 : 0; }
template<class _Iterator>
inline typename std::iterator_traits<_Iterator>::difference_type
template<class _Iterator>
inline typename std::iterator_traits<_Iterator>::difference_type
__distance_fw(_Iterator __first, _Iterator __last)
- {
- typedef typename std::iterator_traits<_Iterator>::iterator_category _Tag;
- return __distance_fw(__first, __last, _Tag());
- }
+ { return __distance_fw(__first, __last,
+ std::__iterator_category(__first)); }
struct _Identity
{
template<typename _InputIterator, typename _NodeGetter>
void
_M_insert_range(_InputIterator __first, _InputIterator __last,
- const _NodeGetter&);
+ const _NodeGetter&, true_type);
+
+ template<typename _InputIterator, typename _NodeGetter>
+ void
+ _M_insert_range(_InputIterator __first, _InputIterator __last,
+ const _NodeGetter&, false_type);
public:
__ireturn_type
{
__hashtable& __h = _M_conjure_hashtable();
__node_gen_type __node_gen(__h);
- return _M_insert_range(__first, __last, __node_gen);
+ return _M_insert_range(__first, __last, __node_gen, __unique_keys());
}
};
_Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash,
_RehashPolicy, _Traits>::
_M_insert_range(_InputIterator __first, _InputIterator __last,
- const _NodeGetter& __node_gen)
+ const _NodeGetter& __node_gen, true_type)
+ {
+ size_type __n_elt = __detail::__distance_fw(__first, __last);
+ if (__n_elt == 0)
+ return;
+
+ __hashtable& __h = _M_conjure_hashtable();
+ for (; __first != __last; ++__first)
+ {
+ if (__h._M_insert(*__first, __node_gen, __unique_keys(),
+ __n_elt).second)
+ __n_elt = 1;
+ else if (__n_elt != 1)
+ --__n_elt;
+ }
+ }
+
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash,
+ typename _RehashPolicy, typename _Traits>
+ template<typename _InputIterator, typename _NodeGetter>
+ void
+ _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits>::
+ _M_insert_range(_InputIterator __first, _InputIterator __last,
+ const _NodeGetter& __node_gen, false_type)
{
using __rehash_type = typename __hashtable::__rehash_type;
using __rehash_state = typename __hashtable::__rehash_state;
using pair_type = std::pair<bool, std::size_t>;
size_type __n_elt = __detail::__distance_fw(__first, __last);
+ if (__n_elt == 0)
+ return;
__hashtable& __h = _M_conjure_hashtable();
__rehash_type& __rehash = __h._M_rehash_policy;
--- /dev/null
+// { dg-do run { target c++11 } }
+//
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_map>
+#include <string>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::unordered_map<std::string, std::string> m
+ { {"E", "E" }, { "T", "T" } };
+
+ VERIFY( m.size() == 2 );
+
+ auto bcount = m.bucket_count();
+
+ m.insert({ {"E", "E" }, { "T", "T" } });
+
+ VERIFY( m.size() == 2 );
+ VERIFY( m.bucket_count() == bcount );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
--- /dev/null
+// { dg-do run { target c++11 } }
+//
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_set>
+#include <string>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::unordered_set<std::string> s { "E", "T" };
+
+ VERIFY( s.size() == 2 );
+
+ auto bcount = s.bucket_count();
+
+ s.insert({"E", "T" });
+
+ VERIFY( s.size() == 2 );
+ VERIFY( s.bucket_count() == bcount );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}