[patch] No allocation for empty unordered containers

Jonathan Wakely jwakely@redhat.com
Mon Aug 4 11:49:00 GMT 2014


On 25/07/14 22:53 +0200, François Dumont wrote:
>Hi
>
>    I think I never get feedback regarding this patch proposal. Note 

I've been trying to weigh up the pros and cons and am unsure what's
best, but I think my preference is to have a noexcept default
constructor. Unless you hear any objections in the next 48 hours
please go ahead and commit this to trunk, thanks

>that if accepted the doc will have to be updated regarding the default 
>hint value.

Good point.

>Thanks
>
>
>On 03/06/2014 22:44, François Dumont wrote:
>>Hi
>>
>>    Thanks to the single bucket introduced to make move semantic 
>>noexcept we can also avoid some over allocations. Here is a patch to 
>>avoid any allocation on default instantiation, on range constructor 
>>when range is empty and on construction from an initialization list 
>>when this list is empty too. I had to make all default hint value to 
>>0 so that if this value is used the rehash policy next bucket 
>>returns 1 bucket.
>>
>>    I don't know if you had in mind to noexcept qualify the default 
>>constructor but it would mean to have a real default constructor and 
>>another to deal with the hint which wouldn't match the Standard so 
>>no noexcept qualification at the moment.
>>
>>Tested under Linux x86_64.normal debug and profile modes.
>>
>>
>>2014-06-03  François Dumont <fdumont@gcc.gnu.org>
>>
>>    * include/bits/hashtable.h: Make use of the internal single bucket to
>>    limit allocation as long as container remains empty.
>>    * include/bits/unordered_map.h: Set default bucket hint to 0 in
>>    constructors to avoid allocation.
>>    * include/bits/unordered_set.h: Likewise.
>>    * include/debug/unordered_map: Likewise.
>>    * include/debug/unordered_set: Likewise.
>>    * include/profile/unordered_map: Likewise.
>>    * include/profile/unordered_set: Likewise.
>>    * src/c++11/hashtable_c++0x.cc (_Prime_rehash_policy::_M_next_bkt):
>>    Returns 1 for hint 0.
>>    * testsuite/23_containers/unordered_map/allocator/
>>    empty_instantiation.cc:    New.
>>    * testsuite/23_containers/unordered_multimap/allocator/
>>    empty_instantiation.cc:    New.
>>    * testsuite/23_containers/unordered_set/allocator/
>>    empty_instantiation.cc: New.
>>    * testsuite/23_containers/unordered_multiset/allocator/
>>    empty_instantiation.cc: New.
>>
>>Ok to commit ?
>>
>>François
>>
>>
>

>Index: include/bits/hashtable.h
>===================================================================
>--- include/bits/hashtable.h	(revision 211144)
>+++ include/bits/hashtable.h	(working copy)
>@@ -407,12 +407,12 @@
>       // Use delegating constructors.
>       explicit
>       _Hashtable(const allocator_type& __a)
>-      : _Hashtable(10, _H1(), _H2(), _Hash(), key_equal(),
>+      : _Hashtable(0, _H1(), _H2(), _Hash(), key_equal(),
> 		   __key_extract(), __a)
>       { }
> 
>       explicit
>-      _Hashtable(size_type __n = 10,
>+      _Hashtable(size_type __n = 0,
> 		 const _H1& __hf = _H1(),
> 		 const key_equal& __eql = key_equal(),
> 		 const allocator_type& __a = allocator_type())
>@@ -792,14 +792,18 @@
> 	       const _Equal& __eq, const _ExtractKey& __exk,
> 	       const allocator_type& __a)
>     : __hashtable_base(__exk, __h1, __h2, __h, __eq),
>-      __map_base(),
>-      __rehash_base(),
>       __hashtable_alloc(__node_alloc_type(__a)),
>+      _M_buckets(&_M_single_bucket),
>+      _M_bucket_count(1),
>       _M_element_count(0),
>-      _M_rehash_policy()
>+      _M_single_bucket(nullptr)
>     {
>-      _M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint);
>-      _M_buckets = _M_allocate_buckets(_M_bucket_count);
>+      auto __bkt_count = _M_rehash_policy._M_next_bkt(__bucket_hint);
>+      if (_M_bucket_count != __bkt_count)
>+	{
>+	  _M_bucket_count = __bkt_count;
>+	  _M_buckets = _M_allocate_buckets(_M_bucket_count);
>+	}
>     }
> 
>   template<typename _Key, typename _Value,
>@@ -815,19 +819,24 @@
> 		 const _Equal& __eq, const _ExtractKey& __exk,
> 		 const allocator_type& __a)
>       : __hashtable_base(__exk, __h1, __h2, __h, __eq),
>-	__map_base(),
>-	__rehash_base(),
> 	__hashtable_alloc(__node_alloc_type(__a)),
>+	_M_buckets(&_M_single_bucket),
>+	_M_bucket_count(1),
> 	_M_element_count(0),
>-	_M_rehash_policy()
>+	_M_single_bucket(nullptr)
>       {
> 	auto __nb_elems = __detail::__distance_fw(__f, __l);
>-	_M_bucket_count =
>+	auto __bkt_count =
> 	  _M_rehash_policy._M_next_bkt(
> 	    std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems),
> 		     __bucket_hint));
>+ 
>+	if (_M_bucket_count != __bkt_count)
>+	  {
>+	    _M_bucket_count = __bkt_count;
>+	    _M_buckets = _M_allocate_buckets(_M_bucket_count);
>+	  }
> 
>-	_M_buckets = _M_allocate_buckets(_M_bucket_count);
> 	__try
> 	  {
> 	    for (; __f != __l; ++__f)
>@@ -864,14 +873,15 @@
> 	      {
> 		// Replacement allocator cannot free existing storage.
> 		this->_M_deallocate_nodes(_M_begin());
>-		_M_before_begin._M_nxt = nullptr;
> 		_M_deallocate_buckets();
>-		_M_buckets = nullptr;
>+		__hashtable_base::operator=(__ht);
> 		std::__alloc_on_copy(__this_alloc, __that_alloc);
>-		__hashtable_base::operator=(__ht);
>-		_M_bucket_count = __ht._M_bucket_count;
>+		_M_buckets = &_M_single_bucket;
>+		_M_bucket_count = 1;
>+		_M_before_begin._M_nxt = nullptr;
> 		_M_element_count = __ht._M_element_count;
> 		_M_rehash_policy = __ht._M_rehash_policy;
>+		_M_single_bucket = nullptr;
> 		__try
> 		  {
> 		    _M_assign(__ht,
>@@ -946,8 +956,14 @@
>       _M_assign(const _Hashtable& __ht, const _NodeGenerator& __node_gen)
>       {
> 	__bucket_type* __buckets = nullptr;
>-	if (!_M_buckets)
>-	  _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count);
>+	if (_M_bucket_count != __ht._M_bucket_count)
>+	  {
>+	    // Bucket deallocation useless because per design _M_buckets
>+	    // can only be pointing to _M_single_bucket.
>+	    //_M_deallocate_buckets();
>+	    _M_bucket_count = __ht._M_bucket_count;
>+	    _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count);
>+	  }
> 
> 	__try
> 	  {
>@@ -1101,10 +1117,11 @@
>       __rehash_base(__ht),
>       __hashtable_alloc(
> 	__node_alloc_traits::_S_select_on_copy(__ht._M_node_allocator())),
>-      _M_buckets(),
>-      _M_bucket_count(__ht._M_bucket_count),
>+      _M_buckets(&_M_single_bucket),
>+      _M_bucket_count(1),
>       _M_element_count(__ht._M_element_count),
>-      _M_rehash_policy(__ht._M_rehash_policy)
>+      _M_rehash_policy(__ht._M_rehash_policy),
>+      _M_single_bucket(nullptr)
>     {
>       _M_assign(__ht,
> 		[this](const __node_type* __n)
>@@ -1126,14 +1143,12 @@
>       _M_bucket_count(__ht._M_bucket_count),
>       _M_before_begin(__ht._M_before_begin._M_nxt),
>       _M_element_count(__ht._M_element_count),
>-      _M_rehash_policy(__ht._M_rehash_policy)
>+      _M_rehash_policy(__ht._M_rehash_policy),
>+      _M_single_bucket(__ht._M_single_bucket)
>     {
>       // Update, if necessary, buckets if __ht is using its single bucket.
>       if (__ht._M_uses_single_bucket())
>-	{
>-	  _M_buckets = &_M_single_bucket;
>-	  _M_single_bucket = __ht._M_single_bucket;
>-	}
>+	_M_buckets = &_M_single_bucket;
> 
>       // Update, if necessary, bucket pointing to before begin that hasn't
>       // moved.
>@@ -1154,10 +1169,11 @@
>       __map_base(__ht),
>       __rehash_base(__ht),
>       __hashtable_alloc(__node_alloc_type(__a)),
>-      _M_buckets(),
>-      _M_bucket_count(__ht._M_bucket_count),
>+      _M_buckets(&_M_single_bucket),
>+      _M_bucket_count(1),
>       _M_element_count(__ht._M_element_count),
>-      _M_rehash_policy(__ht._M_rehash_policy)
>+      _M_rehash_policy(__ht._M_rehash_policy),
>+      _M_single_bucket(nullptr)
>     {
>       _M_assign(__ht,
> 		[this](const __node_type* __n)
>@@ -1175,18 +1191,17 @@
>       __map_base(__ht),
>       __rehash_base(__ht),
>       __hashtable_alloc(__node_alloc_type(__a)),
>-      _M_buckets(),
>-      _M_bucket_count(__ht._M_bucket_count),
>+      _M_buckets(&_M_single_bucket),
>+      _M_bucket_count(1),
>       _M_element_count(__ht._M_element_count),
>-      _M_rehash_policy(__ht._M_rehash_policy)
>+      _M_rehash_policy(__ht._M_rehash_policy),
>+      _M_single_bucket(nullptr)
>     {
>       if (__ht._M_node_allocator() == this->_M_node_allocator())
> 	{
>+	  _M_bucket_count = __ht._M_bucket_count;
> 	  if (__ht._M_uses_single_bucket())
>-	    {
>-	      _M_buckets = &_M_single_bucket;
>-	      _M_single_bucket = __ht._M_single_bucket;
>-	    }
>+	    _M_single_bucket = __ht._M_single_bucket;
> 	  else
> 	    _M_buckets = __ht._M_buckets;
> 
>@@ -1195,6 +1210,7 @@
> 	  // moved.
> 	  if (_M_begin())
> 	    _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
>+
> 	  __ht._M_reset();
> 	}
>       else
>@@ -1218,8 +1234,7 @@
>     ~_Hashtable() noexcept
>     {
>       clear();
>-      if (_M_buckets)
>-	_M_deallocate_buckets();
>+      _M_deallocate_buckets();
>     }
> 
>   template<typename _Key, typename _Value,
>Index: include/bits/unordered_map.h
>===================================================================
>--- include/bits/unordered_map.h	(revision 211144)
>+++ include/bits/unordered_map.h	(working copy)
>@@ -136,7 +136,7 @@
>        *  @param __a  An allocator object.
>        */
>       explicit
>-      unordered_map(size_type __n = 10,
>+      unordered_map(size_type __n = 0,
> 		    const hasher& __hf = hasher(),
> 		    const key_equal& __eql = key_equal(),
> 		    const allocator_type& __a = allocator_type())
>@@ -848,7 +848,7 @@
>        *  @param __a  An allocator object.
>        */
>       explicit
>-      unordered_multimap(size_type __n = 10,
>+      unordered_multimap(size_type __n = 0,
> 			 const hasher& __hf = hasher(),
> 			 const key_equal& __eql = key_equal(),
> 			 const allocator_type& __a = allocator_type())
>Index: include/bits/unordered_set.h
>===================================================================
>--- include/bits/unordered_set.h	(revision 211144)
>+++ include/bits/unordered_set.h	(working copy)
>@@ -129,7 +129,7 @@
>        *  @param __a  An allocator object.
>        */
>       explicit
>-      unordered_set(size_type __n = 10,
>+      unordered_set(size_type __n = 0,
> 		    const hasher& __hf = hasher(),
> 		    const key_equal& __eql = key_equal(),
> 		    const allocator_type& __a = allocator_type())
>@@ -764,7 +764,7 @@
>        *  @param __a  An allocator object.
>        */
>       explicit
>-      unordered_multiset(size_type __n = 10,
>+      unordered_multiset(size_type __n = 0,
> 			 const hasher& __hf = hasher(),
> 			 const key_equal& __eql = key_equal(),
> 			 const allocator_type& __a = allocator_type())
>Index: include/debug/unordered_map
>===================================================================
>--- include/debug/unordered_map	(revision 211144)
>+++ include/debug/unordered_map	(working copy)
>@@ -83,7 +83,7 @@
> 	_Base_const_local_iterator, unordered_map>	const_local_iterator;
> 
>       explicit
>-      unordered_map(size_type __n = 10,
>+      unordered_map(size_type __n = 0,
> 		    const hasher& __hf = hasher(),
> 		    const key_equal& __eql = key_equal(),
> 		    const allocator_type& __a = allocator_type())
>@@ -496,7 +496,7 @@
> 	_Base_const_local_iterator, unordered_multimap> const_local_iterator;
> 
>       explicit
>-      unordered_multimap(size_type __n = 10,
>+      unordered_multimap(size_type __n = 0,
> 			 const hasher& __hf = hasher(),
> 			 const key_equal& __eql = key_equal(),
> 			 const allocator_type& __a = allocator_type())
>Index: include/debug/unordered_set
>===================================================================
>--- include/debug/unordered_set	(revision 211144)
>+++ include/debug/unordered_set	(working copy)
>@@ -83,7 +83,7 @@
> 	_Base_const_local_iterator, unordered_set>	const_local_iterator;
> 
>       explicit
>-      unordered_set(size_type __n = 10,
>+      unordered_set(size_type __n = 0,
> 		    const hasher& __hf = hasher(),
> 		    const key_equal& __eql = key_equal(),
> 		    const allocator_type& __a = allocator_type())
>@@ -492,7 +492,7 @@
> 	_Base_const_local_iterator, unordered_multiset> const_local_iterator;
> 
>       explicit
>-      unordered_multiset(size_type __n = 10,
>+      unordered_multiset(size_type __n = 0,
> 			 const hasher& __hf = hasher(),
> 			 const key_equal& __eql = key_equal(),
> 			 const allocator_type& __a = allocator_type())
>Index: include/profile/unordered_map
>===================================================================
>--- include/profile/unordered_map	(revision 211144)
>+++ include/profile/unordered_map	(working copy)
>@@ -77,7 +77,7 @@
>       typedef typename _Base::const_iterator	const_iterator;
> 
>       explicit
>-      unordered_map(size_type __n = 10,
>+      unordered_map(size_type __n = 0,
> 		    const hasher& __hf = hasher(),
> 		    const key_equal& __eql = key_equal(),
> 		    const allocator_type& __a = allocator_type())
>@@ -322,7 +322,7 @@
>       typedef typename _Base::const_iterator	const_iterator;
> 
>       explicit
>-      unordered_multimap(size_type __n = 10,
>+      unordered_multimap(size_type __n = 0,
> 			 const hasher& __hf = hasher(),
> 			 const key_equal& __eql = key_equal(),
> 			 const allocator_type& __a = allocator_type())
>Index: include/profile/unordered_set
>===================================================================
>--- include/profile/unordered_set	(revision 211144)
>+++ include/profile/unordered_set	(working copy)
>@@ -76,7 +76,7 @@
>       typedef typename _Base::const_iterator	const_iterator;
> 
>       explicit
>-      unordered_set(size_type __n = 10,
>+      unordered_set(size_type __n = 0,
> 		    const hasher& __hf = hasher(),
> 		    const key_equal& __eql = key_equal(),
> 		    const allocator_type& __a = allocator_type())
>@@ -300,7 +300,7 @@
>       typedef typename _Base::const_iterator const_iterator;
> 
>       explicit
>-      unordered_multiset(size_type __n = 10,
>+      unordered_multiset(size_type __n = 0,
> 			 const hasher& __hf = hasher(),
> 			 const key_equal& __eql = key_equal(),
> 			 const allocator_type& __a = allocator_type())
>Index: src/c++11/hashtable_c++0x.cc
>===================================================================
>--- src/c++11/hashtable_c++0x.cc	(revision 211144)
>+++ src/c++11/hashtable_c++0x.cc	(working copy)
>@@ -47,7 +47,7 @@
>     // Optimize lookups involving the first elements of __prime_list.
>     // (useful to speed-up, eg, constructors)
>     static const unsigned char __fast_bkt[12]
>-      = { 2, 2, 2, 3, 5, 5, 7, 7, 11, 11, 11, 11 };
>+      = { 1, 2, 2, 3, 5, 5, 7, 7, 11, 11, 11, 11 };
> 
>     if (__n <= 11)
>       {
>Index: testsuite/23_containers/unordered_map/allocator/empty_instantiation.cc
>===================================================================
>--- testsuite/23_containers/unordered_map/allocator/empty_instantiation.cc	(revision 0)
>+++ testsuite/23_containers/unordered_map/allocator/empty_instantiation.cc	(working copy)
>@@ -0,0 +1,98 @@
>+// Copyright (C) 2013-2014 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/>.
>+
>+// { dg-options "-std=gnu++11" }
>+
>+#include <unordered_map>
>+#include <testsuite_allocator.h>
>+#include <testsuite_hooks.h>
>+
>+using namespace __gnu_test;
>+typedef tracker_allocator<std::pair<const int, int>> alloc_type;
>+typedef std::unordered_map<int, int, std::hash<int>, std::equal_to<int>,
>+			   alloc_type> test_type;
>+
>+void test01()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    // Default constructor, in fact constructor with hint using default value.
>+    test_type u;
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    test_type u(1);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+void test02()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    std::pair<int, int> ints[] {};
>+    // Range constructor.
>+    test_type u(ints + 0, ints + 0);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    std::pair<int, int> ints[] { { 1, 1 } };
>+    // Range constructor.
>+    test_type u(ints + 0, ints + 1);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+void test03()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    // Initializer list constructor.
>+    test_type u({});
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    test_type u({ { 1, 1 } });
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+int
>+main()
>+{
>+  test01();
>+  test02();
>+  test03();
>+}
>Index: testsuite/23_containers/unordered_multimap/allocator/empty_instantiation.cc
>===================================================================
>--- testsuite/23_containers/unordered_multimap/allocator/empty_instantiation.cc	(revision 0)
>+++ testsuite/23_containers/unordered_multimap/allocator/empty_instantiation.cc	(working copy)
>@@ -0,0 +1,98 @@
>+// Copyright (C) 2013-2014 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/>.
>+
>+// { dg-options "-std=gnu++11" }
>+
>+#include <unordered_map>
>+#include <testsuite_allocator.h>
>+#include <testsuite_hooks.h>
>+
>+using namespace __gnu_test;
>+typedef tracker_allocator<std::pair<const int, int>> alloc_type;
>+typedef std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>,
>+				alloc_type> test_type;
>+
>+void test01()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    // Default constructor, in fact constructor with hint using default value.
>+    test_type u;
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    test_type u(1);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+void test02()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    std::pair<int, int> ints[] {};
>+    // Range constructor.
>+    test_type u(ints + 0, ints + 0);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    std::pair<int, int> ints[] { { 1, 1 } };
>+    // Range constructor.
>+    test_type u(ints + 0, ints + 1);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+void test03()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    // Initializer list constructor.
>+    test_type u({});
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    test_type u({ { 1, 1 } });
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+int
>+main()
>+{
>+  test01();
>+  test02();
>+  test03();
>+}
>Index: testsuite/23_containers/unordered_multiset/allocator/empty_instantiation.cc
>===================================================================
>--- testsuite/23_containers/unordered_multiset/allocator/empty_instantiation.cc	(revision 0)
>+++ testsuite/23_containers/unordered_multiset/allocator/empty_instantiation.cc	(working copy)
>@@ -0,0 +1,99 @@
>+// Copyright (C) 2013-2014 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/>.
>+
>+// { dg-options "-std=gnu++11" }
>+
>+#include <unordered_set>
>+#include <testsuite_allocator.h>
>+#include <testsuite_hooks.h>
>+
>+using namespace __gnu_test;
>+typedef tracker_allocator<int> alloc_type;
>+typedef std::unordered_multiset<int, std::hash<int>, std::equal_to<int>,
>+				alloc_type> test_type;
>+
>+
>+void test01()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    // Default constructor, in fact constructor with hint using default value.
>+    test_type u;
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    test_type u(1);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+void test02()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    int ints[] {};
>+    // Range constructor.
>+    test_type u(ints + 0, ints + 0);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    int ints[] { 1 };
>+    // Range constructor.
>+    test_type u(ints + 0, ints + 1);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+void test03()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    // Initializer list constructor.
>+    test_type u({});
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    test_type u({ 1 });
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+int
>+main()
>+{
>+  test01();
>+  test02();
>+  test03();
>+}
>Index: testsuite/23_containers/unordered_set/allocator/empty_instantiation.cc
>===================================================================
>--- testsuite/23_containers/unordered_set/allocator/empty_instantiation.cc	(revision 0)
>+++ testsuite/23_containers/unordered_set/allocator/empty_instantiation.cc	(working copy)
>@@ -0,0 +1,98 @@
>+// Copyright (C) 2013-2014 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/>.
>+
>+// { dg-options "-std=gnu++11" }
>+
>+#include <unordered_set>
>+#include <testsuite_allocator.h>
>+#include <testsuite_hooks.h>
>+
>+using namespace __gnu_test;
>+typedef tracker_allocator<int> alloc_type;
>+typedef std::unordered_set<int, std::hash<int>, std::equal_to<int>,
>+			   alloc_type> test_type;
>+
>+void test01()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    // Default constructor, in fact constructor with hint using default value.
>+    test_type u;
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    test_type u(1);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+void test02()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    int ints[] {};
>+    // Range constructor.
>+    test_type u(ints + 0, ints + 0);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    int ints[] { 1 };
>+    // Range constructor.
>+    test_type u(ints + 0, ints + 1);
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+void test03()
>+{
>+  bool test __attribute__((unused)) = true;
>+
>+  tracker_allocator_counter::reset();
>+
>+  {
>+    // Initializer list constructor.
>+    test_type u({});
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() == 0 );
>+
>+  {
>+    test_type u({ 1 });
>+  }
>+
>+  VERIFY( tracker_allocator_counter::get_allocation_count() != 0 );
>+}
>+
>+int
>+main()
>+{
>+  test01();
>+  test02();
>+  test03();
>+}



More information about the Libstdc++ mailing list