google_hash 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. data/README +61 -27
  2. data/Rakefile +4 -1
  3. data/TODO +5 -0
  4. data/VERSION +1 -1
  5. data/changelog +3 -0
  6. data/ext/extconf.rb +10 -5
  7. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/AUTHORS +0 -0
  8. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/COPYING +0 -0
  9. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/ChangeLog +47 -0
  10. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/INSTALL +0 -0
  11. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/Makefile.am +29 -14
  12. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/Makefile.in +77 -42
  13. data/ext/sparsehash-1.8.1/NEWS +71 -0
  14. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/README +0 -0
  15. data/ext/{sparsehash-1.5.2/README.windows → sparsehash-1.8.1/README_windows.txt} +25 -25
  16. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/TODO +0 -0
  17. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/aclocal.m4 +0 -0
  18. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/compile +0 -0
  19. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/config.guess +0 -0
  20. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/config.sub +0 -0
  21. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/configure +3690 -4560
  22. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/configure.ac +1 -1
  23. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/depcomp +0 -0
  24. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/dense_hash_map.html +65 -5
  25. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/dense_hash_set.html +65 -5
  26. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/designstyle.css +0 -0
  27. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/implementation.html +11 -5
  28. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/index.html +0 -0
  29. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/performance.html +0 -0
  30. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparse_hash_map.html +65 -5
  31. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparse_hash_set.html +65 -5
  32. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparsetable.html +0 -0
  33. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/Makefile +0 -0
  34. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/README +0 -0
  35. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/example.c +0 -0
  36. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/libchash.c +0 -0
  37. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/libchash.h +0 -0
  38. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/google-sparsehash.sln +17 -1
  39. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/install-sh +0 -0
  40. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/acx_pthread.m4 +0 -0
  41. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/google_namespace.m4 +0 -0
  42. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/namespaces.m4 +0 -0
  43. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_hash.m4 +0 -0
  44. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_hash_fun.m4 +0 -0
  45. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_namespace.m4 +0 -0
  46. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/missing +0 -0
  47. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/mkinstalldirs +0 -0
  48. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb.sh +0 -0
  49. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/README +0 -0
  50. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/changelog +24 -0
  51. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/compat +0 -0
  52. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/control +1 -1
  53. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/copyright +0 -0
  54. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/docs +0 -0
  55. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/rules +0 -0
  56. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/sparsehash.dirs +0 -0
  57. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/sparsehash.install +0 -0
  58. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/rpm.sh +0 -0
  59. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/rpm/rpm.spec +1 -1
  60. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/config.h.in +3 -0
  61. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/config.h.include +0 -0
  62. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/dense_hash_map +43 -27
  63. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/dense_hash_set +40 -19
  64. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparse_hash_map +32 -23
  65. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparse_hash_set +31 -21
  66. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsehash/densehashtable.h +481 -298
  67. data/ext/sparsehash-1.8.1/src/google/sparsehash/hashtable-common.h +178 -0
  68. data/ext/sparsehash-1.8.1/src/google/sparsehash/libc_allocator_with_realloc.h +121 -0
  69. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsehash/sparsehashtable.h +404 -233
  70. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsetable +173 -83
  71. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/type_traits.h +3 -29
  72. data/ext/sparsehash-1.8.1/src/hash_test_interface.h +1011 -0
  73. data/ext/sparsehash-1.8.1/src/hashtable_test.cc +1733 -0
  74. data/ext/sparsehash-1.8.1/src/libc_allocator_with_realloc_test.cc +129 -0
  75. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/simple_test.cc +1 -1
  76. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/sparsetable_unittest.cc +202 -6
  77. data/ext/sparsehash-1.8.1/src/testutil.h +251 -0
  78. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/time_hash_map.cc +128 -54
  79. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/type_traits_unittest.cc +30 -20
  80. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/config.h +0 -0
  81. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/google/sparsehash/sparseconfig.h +0 -0
  82. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/port.cc +0 -0
  83. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/port.h +0 -0
  84. data/ext/sparsehash-1.8.1/vsprojects/hashtable_test/hashtable_test.vcproj +197 -0
  85. data/ext/{sparsehash-1.5.2/vsprojects/hashtable_unittest/hashtable_unittest.vcproj → sparsehash-1.8.1/vsprojects/simple_test/simple_test.vcproj} +9 -8
  86. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +0 -2
  87. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/time_hash_map/time_hash_map.vcproj +3 -2
  88. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +0 -2
  89. data/ext/template/google_hash.cpp.erb +2 -1
  90. data/ext/template/main.cpp.erb +1 -1
  91. data/results.txt +6 -22
  92. data/spec/benchmark.rb +57 -0
  93. data/spec/spec.google_hash.rb +1 -8
  94. metadata +140 -130
  95. data/ext/benchmark.rb +0 -47
  96. data/ext/sparsehash-1.5.2/NEWS +0 -0
  97. data/ext/sparsehash-1.5.2/src/hashtable_unittest.cc +0 -1375
  98. data/ext/sparsehash-1.5.2/src/words +0 -8944
  99. data/types.txt +0 -18
@@ -0,0 +1,1733 @@
1
+ // Copyright (c) 2010, Google Inc.
2
+ // All rights reserved.
3
+ //
4
+ // Redistribution and use in source and binary forms, with or without
5
+ // modification, are permitted provided that the following conditions are
6
+ // met:
7
+ //
8
+ // * Redistributions of source code must retain the above copyright
9
+ // notice, this list of conditions and the following disclaimer.
10
+ // * Redistributions in binary form must reproduce the above
11
+ // copyright notice, this list of conditions and the following disclaimer
12
+ // in the documentation and/or other materials provided with the
13
+ // distribution.
14
+ // * Neither the name of Google Inc. nor the names of its
15
+ // contributors may be used to endorse or promote products derived from
16
+ // this software without specific prior written permission.
17
+ //
18
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ // ----
31
+ // Author: Craig Silverstein
32
+ //
33
+ // This tests common/densehashtable.h
34
+ // This tests common/dense_hash_set.h
35
+ // This tests common/dense_hash_map.h
36
+ // This tests common/sparsehashtable.h
37
+ // This tests common/sparse_hash_set.h
38
+ // This tests common/sparse_hash_map.h
39
+ //
40
+ // This test replacess hashtable_unittest.cc, which was becoming
41
+ // unreadable.
42
+ //
43
+ // Note that since all these classes are templatized, it's important
44
+ // to call every public method on the class: not just to make sure
45
+ // they work, but to make sure they even compile.
46
+
47
+ #ifdef _MSC_VER
48
+ // Below, we purposefully test having a very small allocator size.
49
+ // This causes some "type conversion too small" errors when using this
50
+ // allocator with sparsetable buckets. We're testing to make sure we
51
+ // handle that situation ok, so we don't need the compiler warnings.
52
+ #pragma warning(disable:4244)
53
+ #endif
54
+
55
+ #include "config.h"
56
+ #include <math.h>
57
+ #include <stdlib.h>
58
+ #include <string.h>
59
+ #include <iostream>
60
+ #include <set>
61
+ #include <vector>
62
+ #include <google/type_traits.h>
63
+ #include <google/sparsetable>
64
+ #include "hash_test_interface.h"
65
+ #include "testutil.h"
66
+
67
+ using GOOGLE_NAMESPACE::sparsetable;
68
+ using GOOGLE_NAMESPACE::sparse_hash_map;
69
+ using GOOGLE_NAMESPACE::sparse_hash_set;
70
+ using GOOGLE_NAMESPACE::dense_hash_map;
71
+ using GOOGLE_NAMESPACE::dense_hash_set;
72
+ using GOOGLE_NAMESPACE::HashtableInterface_SparseHashMap;
73
+ using GOOGLE_NAMESPACE::HashtableInterface_SparseHashSet;
74
+ using GOOGLE_NAMESPACE::HashtableInterface_SparseHashtable;
75
+ using GOOGLE_NAMESPACE::HashtableInterface_DenseHashMap;
76
+ using GOOGLE_NAMESPACE::HashtableInterface_DenseHashSet;
77
+ using GOOGLE_NAMESPACE::HashtableInterface_DenseHashtable;
78
+ namespace testing = GOOGLE_NAMESPACE::testing;
79
+ using STL_NAMESPACE::cout;
80
+ using STL_NAMESPACE::pair;
81
+ using STL_NAMESPACE::set;
82
+ using STL_NAMESPACE::string;
83
+ using STL_NAMESPACE::vector;
84
+
85
+ namespace {
86
+
87
+ #ifndef _MSC_VER // windows defines its own version
88
+ static string TmpFile(const char* basename) {
89
+ return string("/tmp/") + basename;
90
+ }
91
+ #endif
92
+
93
+ typedef unsigned char uint8;
94
+
95
+ // Used as a value in some of the hashtable tests. It's just some
96
+ // arbitrary user-defined type with non-trivial memory management.
97
+ struct ValueType {
98
+ public:
99
+ ValueType() : s_(kDefault) { }
100
+ ValueType(const char* init_s) : s_(kDefault) { set_s(init_s); }
101
+ ~ValueType() { set_s(NULL); }
102
+ ValueType(const ValueType& that) : s_(kDefault) { operator=(that); }
103
+ void operator=(const ValueType& that) { set_s(that.s_); }
104
+ bool operator==(const ValueType& that) const {
105
+ return strcmp(this->s(), that.s()) == 0;
106
+ }
107
+ void set_s(const char* new_s) {
108
+ if (s_ != kDefault)
109
+ free(const_cast<char*>(s_));
110
+ s_ = (new_s == NULL ? kDefault : reinterpret_cast<char*>(strdup(new_s)));
111
+ }
112
+ const char* s() const { return s_; }
113
+ private:
114
+ const char* s_;
115
+ static const char* const kDefault;
116
+ };
117
+ const char* const ValueType::kDefault = "hi";
118
+
119
+ // This is used by the low-level sparse/dense_hashtable classes,
120
+ // which support the most general relationship between keys and
121
+ // values: the key is derived from the value through some arbitrary
122
+ // function. (For classes like sparse_hash_map, the 'value' is a
123
+ // key/data pair, and the function to derive the key is
124
+ // FirstElementOfPair.) KeyToValue is the inverse of this function,
125
+ // so GetKey(KeyToValue(key)) == key. To keep the tests a bit
126
+ // simpler, we've chosen to make the key and value actually be the
127
+ // same type, which is why we need only one template argument for the
128
+ // types, rather than two (one for the key and one for the value).
129
+ template<class KeyAndValueT, class KeyToValue>
130
+ struct SetKey {
131
+ void operator()(KeyAndValueT* value, const KeyAndValueT& new_key) const {
132
+ *value = KeyToValue()(new_key);
133
+ }
134
+ };
135
+
136
+ // A hash function that keeps track of how often it's called. We use
137
+ // a simple djb-hash so we don't depend on how STL hashes. We use
138
+ // this same method to do the key-comparison, so we can keep track
139
+ // of comparison-counts too.
140
+ struct Hasher {
141
+ explicit Hasher(int i=0) : id_(i), num_hashes_(0), num_compares_(0) { }
142
+ int id() const { return id_; }
143
+ int num_hashes() const { return num_hashes_; }
144
+ int num_compares() const { return num_compares_; }
145
+
146
+ size_t operator()(int a) const {
147
+ num_hashes_++;
148
+ return static_cast<size_t>(a);
149
+ }
150
+ size_t operator()(const char* a) const {
151
+ num_hashes_++;
152
+ size_t hash = 0;
153
+ for (size_t i = 0; a[i]; i++ )
154
+ hash = 33 * hash + a[i];
155
+ return hash;
156
+ }
157
+ size_t operator()(const string& a) const {
158
+ num_hashes_++;
159
+ size_t hash = 0;
160
+ for (size_t i = 0; i < a.length(); i++ )
161
+ hash = 33 * hash + a[i];
162
+ return hash;
163
+ }
164
+ bool operator()(int a, int b) const {
165
+ num_compares_++;
166
+ return a == b;
167
+ }
168
+ bool operator()(const string& a, const string& b) const {
169
+ num_compares_++;
170
+ return a == b;
171
+ }
172
+ bool operator()(const char* a, const char* b) const {
173
+ num_compares_++;
174
+ // The 'a == b' test is necessary, in case a and b are both NULL.
175
+ return (a == b || (a && b && strcmp(a, b) == 0));
176
+ }
177
+
178
+ private:
179
+ mutable int id_;
180
+ mutable int num_hashes_;
181
+ mutable int num_compares_;
182
+ };
183
+
184
+ // Allocator that allows controlling its size in various ways, to test
185
+ // allocator overflow. Because we use this allocator in a vector, we
186
+ // need to define != and swap for gcc.
187
+ template<typename T,
188
+ typename SizeT = size_t, SizeT MAX_SIZE = static_cast<SizeT>(~0)>
189
+ struct Alloc {
190
+ typedef T value_type;
191
+ typedef SizeT size_type;
192
+ typedef ptrdiff_t difference_type;
193
+ typedef T* pointer;
194
+ typedef const T* const_pointer;
195
+ typedef T& reference;
196
+ typedef const T& const_reference;
197
+
198
+ explicit Alloc(int i=0, int* count=NULL) : id_(i), count_(count) {}
199
+ ~Alloc() {}
200
+ pointer address(reference r) const { return &r; }
201
+ const_pointer address(const_reference r) const { return &r; }
202
+ pointer allocate(size_type n, const_pointer = 0) {
203
+ if (count_) ++(*count_);
204
+ return static_cast<pointer>(malloc(n * sizeof(value_type)));
205
+ }
206
+ void deallocate(pointer p, size_type) {
207
+ free(p);
208
+ }
209
+ pointer reallocate(pointer p, size_type n) {
210
+ if (count_) ++(*count_);
211
+ return static_cast<pointer>(realloc(p, n * sizeof(value_type)));
212
+ }
213
+ size_type max_size() const {
214
+ return static_cast<size_type>(MAX_SIZE);
215
+ }
216
+ void construct(pointer p, const value_type& val) {
217
+ new(p) value_type(val);
218
+ }
219
+ void destroy(pointer p) { p->~value_type(); }
220
+
221
+ bool is_custom_alloc() const { return true; }
222
+
223
+ template <class U>
224
+ Alloc(const Alloc<U, SizeT, MAX_SIZE>& that)
225
+ : id_(that.id_), count_(that.count_) {
226
+ }
227
+
228
+ template <class U>
229
+ struct rebind {
230
+ typedef Alloc<U, SizeT, MAX_SIZE> other;
231
+ };
232
+
233
+ bool operator==(const Alloc<T,SizeT,MAX_SIZE>& that) {
234
+ return this->id_ == that.id_ && this->count_ == that.count_;
235
+ }
236
+ bool operator!=(const Alloc<T,SizeT,MAX_SIZE>& that) {
237
+ return !this->operator==(that);
238
+ }
239
+
240
+ int id() const { return id_; }
241
+
242
+ // I have to make these public so the constructor used for rebinding
243
+ // can see them. Normally, I'd just make them private and say:
244
+ // template<typename U, typename U_SizeT, U_SizeT U_MAX_SIZE> friend struct Alloc;
245
+ // but MSVC 7.1 barfs on that. So public it is. But no peeking!
246
+ public:
247
+ int id_;
248
+ int* count_;
249
+ };
250
+
251
+
252
+ // Below are a few fun routines that convert a value into a key, used
253
+ // for dense_hashtable and sparse_hashtable. It's our responsibility
254
+ // to make sure, when we insert values into these objects, that the
255
+ // values match the keys we insert them under. To allow us to use
256
+ // these routines for SetKey as well, we require all these functions
257
+ // be their own inverse: f(f(x)) == x.
258
+ template<class Value>
259
+ struct Negation {
260
+ Value operator()(Value& v) { return -v; }
261
+ const Value operator()(const Value& v) const { return -v; }
262
+ };
263
+
264
+ struct Capital {
265
+ string operator()(string& s) {
266
+ return string(1, s[0] ^ 32) + s.substr(1);
267
+ }
268
+ const string operator()(const string& s) const {
269
+ return string(1, s[0] ^ 32) + s.substr(1);
270
+ }
271
+ };
272
+
273
+ struct Identity { // lame, I know, but an important case to test.
274
+ const char* operator()(const char* s) const {
275
+ return s;
276
+ }
277
+ };
278
+
279
+ // This is just to avoid memory leaks -- it's a global pointer to
280
+ // all the memory allocated by UniqueObjectHelper. We'll use it
281
+ // to semi-test sparsetable as well. :-)
282
+ sparsetable<char*> g_unique_charstar_objects(16);
283
+
284
+ // This is an object-generator: pass in an index, and it will return a
285
+ // unique object of type ItemType. We provide specializations for the
286
+ // types we actually support.
287
+ template <typename ItemType> ItemType UniqueObjectHelper(int index);
288
+ template<> int UniqueObjectHelper(int index) {
289
+ return index;
290
+ }
291
+ template<> string UniqueObjectHelper(int index) {
292
+ char buffer[64];
293
+ snprintf(buffer, sizeof(buffer), "%d", index);
294
+ return buffer;
295
+ }
296
+ template<> char* UniqueObjectHelper(int index) {
297
+ // First grow the table if need be.
298
+ sparsetable<char*>::size_type table_size = g_unique_charstar_objects.size();
299
+ while (index >= static_cast<int>(table_size)) {
300
+ assert(table_size * 2 > table_size); // avoid overflow problems
301
+ table_size *= 2;
302
+ }
303
+ if (table_size > g_unique_charstar_objects.size())
304
+ g_unique_charstar_objects.resize(table_size);
305
+
306
+ if (!g_unique_charstar_objects.test(index)) {
307
+ char buffer[64];
308
+ snprintf(buffer, sizeof(buffer), "%d", index);
309
+ g_unique_charstar_objects[index] = strdup(buffer);
310
+ }
311
+ return g_unique_charstar_objects.get(index);
312
+ }
313
+ template<> const char* UniqueObjectHelper(int index) {
314
+ return UniqueObjectHelper<char*>(index);
315
+ }
316
+ template<> ValueType UniqueObjectHelper(int index) {
317
+ return ValueType(UniqueObjectHelper<string>(index).c_str());
318
+ }
319
+ template<> pair<const int, int> UniqueObjectHelper(int index) {
320
+ return pair<const int,int>(index, index + 1);
321
+ }
322
+ template<> pair<const string, string> UniqueObjectHelper(int index) {
323
+ return pair<const string,string>(
324
+ UniqueObjectHelper<string>(index), UniqueObjectHelper<string>(index + 1));
325
+ }
326
+ template<> pair<const char* const,ValueType> UniqueObjectHelper(int index) {
327
+ return pair<const char* const,ValueType>(
328
+ UniqueObjectHelper<char*>(index), UniqueObjectHelper<ValueType>(index+1));
329
+ }
330
+
331
+ template <typename HashtableType>
332
+ class HashtableTest {
333
+ public:
334
+ HashtableTest() : ht_() { }
335
+ // Give syntactically-prettier access to UniqueObjectHelper.
336
+ typename HashtableType::value_type UniqueObject(int index) {
337
+ return UniqueObjectHelper<typename HashtableType::value_type>(index);
338
+ }
339
+ typename HashtableType::key_type UniqueKey(int index) {
340
+ return this->ht_.get_key(this->UniqueObject(index));
341
+ }
342
+ protected:
343
+ HashtableType ht_;
344
+ };
345
+
346
+ }
347
+
348
+ // These are used to specify the empty key and deleted key in some
349
+ // contexts. They can't be in the unnamed namespace, or static,
350
+ // because the template code requires external linkage.
351
+ extern const string kEmptyString("--empty string--");
352
+ extern const string kDeletedString("--deleted string--");
353
+ extern const int kEmptyInt = 0;
354
+ extern const int kDeletedInt = -1234676543; // an unlikely-to-pick int
355
+ extern const char* const kEmptyCharStar = "--empty char*--";
356
+ extern const char* const kDeletedCharStar = "--deleted char*--";
357
+
358
+ namespace {
359
+
360
+ #define INT_HASHTABLES \
361
+ HashtableInterface_SparseHashMap<int, int, Hasher, Hasher, \
362
+ Alloc<int> >, \
363
+ HashtableInterface_SparseHashSet<int, Hasher, Hasher, \
364
+ Alloc<int> >, \
365
+ /* This is a table where the key associated with a value is -value */ \
366
+ HashtableInterface_SparseHashtable<int, int, Hasher, Negation<int>, \
367
+ SetKey<int, Negation<int> >, \
368
+ Hasher, Alloc<int> >, \
369
+ HashtableInterface_DenseHashMap<int, int, kEmptyInt, Hasher, Hasher, \
370
+ Alloc<int> >, \
371
+ HashtableInterface_DenseHashSet<int, kEmptyInt, Hasher, Hasher, \
372
+ Alloc<int> >, \
373
+ HashtableInterface_DenseHashtable<int, int, kEmptyInt, \
374
+ Hasher, Negation<int>, \
375
+ SetKey<int, Negation<int> >, \
376
+ Hasher, Alloc<int> >
377
+
378
+ #define STRING_HASHTABLES \
379
+ HashtableInterface_SparseHashMap<string, string, Hasher, Hasher, \
380
+ Alloc<string> >, \
381
+ HashtableInterface_SparseHashSet<string, Hasher, Hasher, \
382
+ Alloc<string> >, \
383
+ /* This is a table where the key associated with a value is Cap(value) */ \
384
+ HashtableInterface_SparseHashtable<string, string, Hasher, Capital, \
385
+ SetKey<string, Capital>, \
386
+ Hasher, Alloc<string> >, \
387
+ HashtableInterface_DenseHashMap<string, string, kEmptyString, \
388
+ Hasher, Hasher, Alloc<string> >, \
389
+ HashtableInterface_DenseHashSet<string, kEmptyString, Hasher, Hasher, \
390
+ Alloc<string> >, \
391
+ HashtableInterface_DenseHashtable<string, string, kEmptyString, \
392
+ Hasher, Capital, \
393
+ SetKey<string, Capital>, \
394
+ Hasher, Alloc<string> >
395
+
396
+ // I'd like to use ValueType keys for SparseHashtable<> and
397
+ // DenseHashtable<> but I can't due to memory-management woes (nobody
398
+ // really owns the char* involved). So instead I do something simpler.
399
+ #define CHARSTAR_HASHTABLES \
400
+ HashtableInterface_SparseHashMap<const char*, ValueType, \
401
+ Hasher, Hasher, Alloc<const char*> >, \
402
+ HashtableInterface_SparseHashSet<const char*, Hasher, Hasher, \
403
+ Alloc<const char*> >, \
404
+ /* This is a table where each value is its own key. */ \
405
+ HashtableInterface_SparseHashtable<const char*, const char*, \
406
+ Hasher, Identity, \
407
+ SetKey<const char*, Identity>, \
408
+ Hasher, Alloc<const char*> >, \
409
+ HashtableInterface_DenseHashMap<const char*, ValueType, kEmptyCharStar, \
410
+ Hasher, Hasher, Alloc<const char*> >, \
411
+ HashtableInterface_DenseHashSet<const char*, kEmptyCharStar, \
412
+ Hasher, Hasher, Alloc<const char*> >, \
413
+ HashtableInterface_DenseHashtable<const char*, const char*, kEmptyCharStar, \
414
+ Hasher, Identity, \
415
+ SetKey<const char*, Identity>, \
416
+ Hasher, Alloc<ValueType> >
417
+
418
+ // This is the list of types we run each test against.
419
+ // We need to define the same class 4 times due to limitations in the
420
+ // testing framework. Basically, we associate each class below with
421
+ // the set of types we want to run tests on it with.
422
+ typedef testing::TypeList6<INT_HASHTABLES> IntHashtables;
423
+ template <typename HashtableType> class HashtableIntTest
424
+ : public HashtableTest<HashtableType> { };
425
+ TYPED_TEST_CASE_6(HashtableIntTest, IntHashtables);
426
+
427
+ typedef testing::TypeList6<STRING_HASHTABLES> StringHashtables;
428
+ template <typename HashtableType> class HashtableStringTest
429
+ : public HashtableTest<HashtableType> { };
430
+ TYPED_TEST_CASE_6(HashtableStringTest, StringHashtables);
431
+
432
+ typedef testing::TypeList6<CHARSTAR_HASHTABLES> CharStarHashtables;
433
+ template <typename HashtableType> class HashtableCharStarTest
434
+ : public HashtableTest<HashtableType> { };
435
+ TYPED_TEST_CASE_6(HashtableCharStarTest, CharStarHashtables);
436
+
437
+ typedef testing::TypeList18<INT_HASHTABLES, STRING_HASHTABLES,
438
+ CHARSTAR_HASHTABLES> AllHashtables;
439
+ template <typename HashtableType> class HashtableAllTest
440
+ : public HashtableTest<HashtableType> { };
441
+ TYPED_TEST_CASE_18(HashtableAllTest, AllHashtables);
442
+
443
+ // ------------------------------------------------------------------------
444
+ // If the first arg to TYPED_TEST is HashtableIntTest, it will run
445
+ // this test on all the hashtable types, with key=int and value=int.
446
+ // Likewise, HashtableStringTest will have string key/values, and
447
+ // HashtableCharStarTest will have char* keys and -- just to mix it up
448
+ // a little -- ValueType values. HashtableAllTest will run all three
449
+ // key/value types on all 6 hashtables types, for 18 test-runs total
450
+ // per test.
451
+ //
452
+ // In addition, TYPED_TEST makes available the magic keyword
453
+ // TypeParam, which is the type being used for the current test.
454
+
455
+ // This first set of tests just tests the public API, going through
456
+ // the public typedefs and methods in turn. It goes approximately
457
+ // in the definition-order in sparse_hash_map.h.
458
+
459
+ TYPED_TEST(HashtableIntTest, Typedefs) {
460
+ // Make sure all the standard STL-y typedefs are defined. The exact
461
+ // key/value types don't matter here, so we only bother testing on
462
+ // the int tables. This is just a compile-time "test"; nothing here
463
+ // can fail at runtime.
464
+ this->ht_.set_deleted_key(-2); // just so deleted_key succeeds
465
+ typename TypeParam::key_type kt;
466
+ typename TypeParam::value_type vt;
467
+ typename TypeParam::hasher h;
468
+ typename TypeParam::key_equal ke;
469
+ typename TypeParam::allocator_type at;
470
+
471
+ typename TypeParam::size_type st;
472
+ typename TypeParam::difference_type dt;
473
+ typename TypeParam::pointer p;
474
+ typename TypeParam::const_pointer cp;
475
+ // I can't declare variables of reference-type, since I have nothing
476
+ // to point them to, so I just make sure that these types exist.
477
+ typedef typename TypeParam::reference r;
478
+ typedef typename TypeParam::const_reference cf;
479
+
480
+ typename TypeParam::iterator i;
481
+ typename TypeParam::const_iterator ci;
482
+ typename TypeParam::local_iterator li;
483
+ typename TypeParam::const_local_iterator cli;
484
+
485
+ // Now make sure the variables are used, so the compiler doesn't
486
+ // complain. Where possible, I "use" the variable by calling the
487
+ // method that's supposed to return the unique instance of the
488
+ // relevant type (eg. get_allocator()). Otherwise, I try to call a
489
+ // different, arbitrary function that returns the type. Sometimes
490
+ // the type isn't used at all, and there's no good way to use the
491
+ // variable.
492
+ kt = this->ht_.deleted_key();
493
+ (void)vt; // value_type may not be copyable. Easiest not to try.
494
+ h = this->ht_.hash_funct();
495
+ ke = this->ht_.key_eq();
496
+ at = this->ht_.get_allocator();
497
+ st = this->ht_.size();
498
+ (void)dt;
499
+ (void)p;
500
+ (void)cp;
501
+ i = this->ht_.begin();
502
+ ci = this->ht_.begin();
503
+ li = this->ht_.begin(0);
504
+ cli = this->ht_.begin(0);
505
+ }
506
+
507
+ TYPED_TEST(HashtableAllTest, NormalIterators) {
508
+ EXPECT_TRUE(this->ht_.begin() == this->ht_.end());
509
+ this->ht_.insert(this->UniqueObject(1));
510
+ {
511
+ typename TypeParam::iterator it = this->ht_.begin();
512
+ EXPECT_TRUE(it != this->ht_.end());
513
+ ++it;
514
+ EXPECT_TRUE(it == this->ht_.end());
515
+ }
516
+ }
517
+
518
+ TEST(HashtableTest, ModifyViaIterator) {
519
+ // This only works for hash-maps, since only they have non-const values.
520
+ {
521
+ sparse_hash_map<int, int> ht;
522
+ ht[1] = 2;
523
+ sparse_hash_map<int, int>::iterator it = ht.find(1);
524
+ EXPECT_TRUE(it != ht.end());
525
+ EXPECT_EQ(1, it->first);
526
+ EXPECT_EQ(2, it->second);
527
+ it->second = 5;
528
+ it = ht.find(1);
529
+ EXPECT_TRUE(it != ht.end());
530
+ EXPECT_EQ(5, it->second);
531
+ }
532
+ {
533
+ dense_hash_map<int, int> ht;
534
+ ht.set_empty_key(0);
535
+ ht[1] = 2;
536
+ dense_hash_map<int, int>::iterator it = ht.find(1);
537
+ EXPECT_TRUE(it != ht.end());
538
+ EXPECT_EQ(1, it->first);
539
+ EXPECT_EQ(2, it->second);
540
+ it->second = 5;
541
+ it = ht.find(1);
542
+ EXPECT_TRUE(it != ht.end());
543
+ EXPECT_EQ(5, it->second);
544
+ }
545
+ }
546
+
547
+ TYPED_TEST(HashtableAllTest, ConstIterators) {
548
+ this->ht_.insert(this->UniqueObject(1));
549
+ typename TypeParam::const_iterator it = this->ht_.begin();
550
+ EXPECT_TRUE(it != this->ht_.end());
551
+ ++it;
552
+ EXPECT_TRUE(it == this->ht_.end());
553
+ }
554
+
555
+ TYPED_TEST(HashtableAllTest, LocalIterators) {
556
+ // Now, tr1 begin/end (the local iterator that takes a bucket-number).
557
+ // ht::bucket() returns the bucket that this key would be inserted in.
558
+ this->ht_.insert(this->UniqueObject(1));
559
+ const typename TypeParam::size_type bucknum =
560
+ this->ht_.bucket(this->UniqueKey(1));
561
+ typename TypeParam::local_iterator b = this->ht_.begin(bucknum);
562
+ typename TypeParam::local_iterator e = this->ht_.end(bucknum);
563
+ EXPECT_TRUE(b != e);
564
+ b++;
565
+ EXPECT_TRUE(b == e);
566
+
567
+ // Check an empty bucket. We can just xor the bottom bit and be sure
568
+ // of getting a legal bucket, since #buckets is always a power of 2.
569
+ EXPECT_TRUE(this->ht_.begin(bucknum ^ 1) == this->ht_.end(bucknum ^ 1));
570
+ // Another test, this time making sure we're using the right types.
571
+ typename TypeParam::local_iterator b2 = this->ht_.begin(bucknum ^ 1);
572
+ typename TypeParam::local_iterator e2 = this->ht_.end(bucknum ^ 1);
573
+ EXPECT_TRUE(b2 == e2);
574
+ }
575
+
576
+ TYPED_TEST(HashtableAllTest, ConstLocalIterators) {
577
+ this->ht_.insert(this->UniqueObject(1));
578
+ const typename TypeParam::size_type bucknum =
579
+ this->ht_.bucket(this->UniqueKey(1));
580
+ typename TypeParam::const_local_iterator b = this->ht_.begin(bucknum);
581
+ typename TypeParam::const_local_iterator e = this->ht_.end(bucknum);
582
+ EXPECT_TRUE(b != e);
583
+ b++;
584
+ EXPECT_TRUE(b == e);
585
+ typename TypeParam::const_local_iterator b2 = this->ht_.begin(bucknum ^ 1);
586
+ typename TypeParam::const_local_iterator e2 = this->ht_.end(bucknum ^ 1);
587
+ EXPECT_TRUE(b2 == e2);
588
+ }
589
+
590
+ TYPED_TEST(HashtableAllTest, Iterating) {
591
+ // Test a bit more iterating than just one ++.
592
+ this->ht_.insert(this->UniqueObject(1));
593
+ this->ht_.insert(this->UniqueObject(11));
594
+ this->ht_.insert(this->UniqueObject(111));
595
+ this->ht_.insert(this->UniqueObject(1111));
596
+ this->ht_.insert(this->UniqueObject(11111));
597
+ this->ht_.insert(this->UniqueObject(111111));
598
+ this->ht_.insert(this->UniqueObject(1111111));
599
+ this->ht_.insert(this->UniqueObject(11111111));
600
+ this->ht_.insert(this->UniqueObject(111111111));
601
+ typename TypeParam::iterator it = this->ht_.begin();
602
+ for (int i = 1; i <= 9; i++) { // start at 1 so i is never 0
603
+ // && here makes it easier to tell what loop iteration the test failed on.
604
+ EXPECT_TRUE(i && (it++ != this->ht_.end()));
605
+ }
606
+ EXPECT_TRUE(it == this->ht_.end());
607
+ }
608
+
609
+ TYPED_TEST(HashtableIntTest, Constructors) {
610
+ // The key/value types don't matter here, so I just test on one set
611
+ // of tables, the ones with int keys, which can easily handle the
612
+ // placement-news we have to do below.
613
+ Hasher hasher(1); // 1 is a unique id
614
+ int alloc_count = 0;
615
+ Alloc<typename TypeParam::key_type> alloc(2, &alloc_count);
616
+
617
+ TypeParam ht_noarg;
618
+ TypeParam ht_onearg(100);
619
+ TypeParam ht_twoarg(100, hasher);
620
+ TypeParam ht_threearg(100, hasher, hasher); // hasher serves as key_equal too
621
+ TypeParam ht_fourarg(100, hasher, hasher, alloc);
622
+
623
+ // The allocator should have been called at most once, for the last ht.
624
+ EXPECT_LE(1, alloc_count);
625
+ int old_alloc_count = alloc_count;
626
+
627
+ vector<typename TypeParam::value_type> input(4);
628
+ // We have to use placement-new because value_type may be const.
629
+ new(&input[0]) typename TypeParam::value_type(this->UniqueObject(1));
630
+ new(&input[1]) typename TypeParam::value_type(this->UniqueObject(2));
631
+ new(&input[2]) typename TypeParam::value_type(this->UniqueObject(4));
632
+ new(&input[3]) typename TypeParam::value_type(this->UniqueObject(8));
633
+ TypeParam ht_iter_noarg(input.begin(), input.end());
634
+ TypeParam ht_iter_onearg(input.begin(), input.end(), 100);
635
+ TypeParam ht_iter_twoarg(input.begin(), input.end(), 100, hasher);
636
+ TypeParam ht_iter_threearg(input.begin(), input.end(), 100, hasher, hasher);
637
+ TypeParam ht_iter_fourarg(input.begin(), input.end(), 100, hasher, hasher,
638
+ alloc);
639
+ // Now the allocator should have been called more.
640
+ EXPECT_GT(alloc_count, old_alloc_count);
641
+ old_alloc_count = alloc_count;
642
+
643
+ // Let's do a lot more inserting and make sure the alloc-count goes up
644
+ for (int i = 2; i < 2000; i++)
645
+ ht_fourarg.insert(this->UniqueObject(i));
646
+ EXPECT_GT(alloc_count, old_alloc_count);
647
+
648
+ EXPECT_LT(ht_noarg.bucket_count(), 100u);
649
+ EXPECT_GE(ht_onearg.bucket_count(), 100u);
650
+ EXPECT_GE(ht_twoarg.bucket_count(), 100u);
651
+ EXPECT_GE(ht_threearg.bucket_count(), 100u);
652
+ EXPECT_GE(ht_fourarg.bucket_count(), 100u);
653
+ EXPECT_GE(ht_iter_onearg.bucket_count(), 100u);
654
+
655
+ // When we pass in a hasher -- it can serve both as the hash-function
656
+ // and the key-equal function -- its id should be 1. Where we don't
657
+ // pass it in and use the default Hasher object, the id should be 0.
658
+ EXPECT_EQ(0, ht_noarg.hash_funct().id());
659
+ EXPECT_EQ(0, ht_noarg.key_eq().id());
660
+ EXPECT_EQ(0, ht_onearg.hash_funct().id());
661
+ EXPECT_EQ(0, ht_onearg.key_eq().id());
662
+ EXPECT_EQ(1, ht_twoarg.hash_funct().id());
663
+ EXPECT_EQ(0, ht_twoarg.key_eq().id());
664
+ EXPECT_EQ(1, ht_threearg.hash_funct().id());
665
+ EXPECT_EQ(1, ht_threearg.key_eq().id());
666
+
667
+ EXPECT_EQ(0, ht_iter_noarg.hash_funct().id());
668
+ EXPECT_EQ(0, ht_iter_noarg.key_eq().id());
669
+ EXPECT_EQ(0, ht_iter_onearg.hash_funct().id());
670
+ EXPECT_EQ(0, ht_iter_onearg.key_eq().id());
671
+ EXPECT_EQ(1, ht_iter_twoarg.hash_funct().id());
672
+ EXPECT_EQ(0, ht_iter_twoarg.key_eq().id());
673
+ EXPECT_EQ(1, ht_iter_threearg.hash_funct().id());
674
+ EXPECT_EQ(1, ht_iter_threearg.key_eq().id());
675
+
676
+ // Likewise for the allocator
677
+ EXPECT_EQ(0, ht_threearg.get_allocator().id());
678
+ EXPECT_EQ(0, ht_iter_threearg.get_allocator().id());
679
+ EXPECT_EQ(2, ht_fourarg.get_allocator().id());
680
+ EXPECT_EQ(2, ht_iter_fourarg.get_allocator().id());
681
+ }
682
+
683
+ TYPED_TEST(HashtableAllTest, OperatorEquals) {
684
+ {
685
+ TypeParam ht1, ht2;
686
+ ht1.set_deleted_key(this->UniqueKey(1));
687
+ ht2.set_deleted_key(this->UniqueKey(2));
688
+
689
+ ht1.insert(this->UniqueObject(10));
690
+ ht2.insert(this->UniqueObject(20));
691
+ EXPECT_FALSE(ht1 == ht2);
692
+ ht1 = ht2;
693
+ EXPECT_TRUE(ht1 == ht2);
694
+ }
695
+ {
696
+ TypeParam ht1, ht2;
697
+ ht1.insert(this->UniqueObject(30));
698
+ ht1 = ht2;
699
+ EXPECT_EQ(0u, ht1.size());
700
+ }
701
+ {
702
+ TypeParam ht1, ht2;
703
+ ht1.set_deleted_key(this->UniqueKey(1));
704
+ ht2.insert(this->UniqueObject(1)); // has same key as ht1.delkey
705
+ ht1 = ht2; // should reset deleted-key to 'unset'
706
+ EXPECT_EQ(1u, ht1.size());
707
+ EXPECT_EQ(1u, ht1.count(this->UniqueKey(1)));
708
+ }
709
+ }
710
+
711
+ TYPED_TEST(HashtableAllTest, Clear) {
712
+ for (int i = 1; i < 200; i++) {
713
+ this->ht_.insert(this->UniqueObject(i));
714
+ }
715
+ this->ht_.clear();
716
+ EXPECT_EQ(0u, this->ht_.size());
717
+ // TODO(csilvers): do we want to enforce that the hashtable has or
718
+ // has not shrunk? It does for dense_* but not sparse_*.
719
+ }
720
+
721
+ TYPED_TEST(HashtableAllTest, ClearNoResize) {
722
+ if (!this->ht_.supports_clear_no_resize())
723
+ return;
724
+ typename TypeParam::size_type empty_bucket_count = this->ht_.bucket_count();
725
+ int last_element = 1;
726
+ while (this->ht_.bucket_count() == empty_bucket_count) {
727
+ this->ht_.insert(this->UniqueObject(last_element));
728
+ ++last_element;
729
+ }
730
+ typename TypeParam::size_type last_bucket_count = this->ht_.bucket_count();
731
+ this->ht_.clear_no_resize();
732
+ EXPECT_EQ(last_bucket_count, this->ht_.bucket_count());
733
+ EXPECT_TRUE(this->ht_.empty());
734
+
735
+ // When inserting the same number of elements again, no resize
736
+ // should be necessary.
737
+ for (int i = 1; i < last_element; ++i) {
738
+ this->ht_.insert(this->UniqueObject(last_element + i));
739
+ EXPECT_EQ(last_bucket_count, this->ht_.bucket_count());
740
+ }
741
+ }
742
+
743
+ TYPED_TEST(HashtableAllTest, Swap) {
744
+ // Let's make a second hashtable with its own hasher, key_equal, etc.
745
+ Hasher hasher(1); // 1 is a unique id
746
+ TypeParam other_ht(200, hasher, hasher);
747
+
748
+ this->ht_.set_deleted_key(this->UniqueKey(1));
749
+ other_ht.set_deleted_key(this->UniqueKey(2));
750
+
751
+ for (int i = 3; i < 2000; i++) {
752
+ this->ht_.insert(this->UniqueObject(i));
753
+ }
754
+ this->ht_.erase(this->UniqueKey(1000));
755
+ other_ht.insert(this->UniqueObject(2001));
756
+ typename TypeParam::size_type expected_buckets = other_ht.bucket_count();
757
+
758
+ this->ht_.swap(other_ht);
759
+
760
+ EXPECT_EQ(this->UniqueKey(2), this->ht_.deleted_key());
761
+ EXPECT_EQ(this->UniqueKey(1), other_ht.deleted_key());
762
+
763
+ EXPECT_EQ(1, this->ht_.hash_funct().id());
764
+ EXPECT_EQ(0, other_ht.hash_funct().id());
765
+
766
+ EXPECT_EQ(1, this->ht_.key_eq().id());
767
+ EXPECT_EQ(0, other_ht.key_eq().id());
768
+
769
+ EXPECT_EQ(expected_buckets, this->ht_.bucket_count());
770
+ EXPECT_GT(other_ht.bucket_count(), 200u);
771
+
772
+ EXPECT_EQ(1u, this->ht_.size());
773
+ EXPECT_EQ(1996u, other_ht.size()); // because we erased 1000
774
+
775
+ EXPECT_EQ(0u, this->ht_.count(this->UniqueKey(111)));
776
+ EXPECT_EQ(1u, other_ht.count(this->UniqueKey(111)));
777
+ EXPECT_EQ(1u, this->ht_.count(this->UniqueKey(2001)));
778
+ EXPECT_EQ(0u, other_ht.count(this->UniqueKey(2001)));
779
+ EXPECT_EQ(0u, this->ht_.count(this->UniqueKey(1000)));
780
+ EXPECT_EQ(0u, other_ht.count(this->UniqueKey(1000)));
781
+
782
+ // We purposefully don't swap allocs -- they're not necessarily swappable.
783
+
784
+ // Now swap back, using the free-function swap.
785
+ // NOTE: MSVC seems to have trouble with this free swap, not quite
786
+ // sure why. I've given up trying to fix it though.
787
+ #ifdef _MSC_VER
788
+ other_ht.swap(this->ht_);
789
+ #else
790
+ swap(this->ht_, other_ht);
791
+ #endif
792
+
793
+ EXPECT_EQ(this->UniqueKey(1), this->ht_.deleted_key());
794
+ EXPECT_EQ(this->UniqueKey(2), other_ht.deleted_key());
795
+ EXPECT_EQ(0, this->ht_.hash_funct().id());
796
+ EXPECT_EQ(1, other_ht.hash_funct().id());
797
+ EXPECT_EQ(1996u, this->ht_.size());
798
+ EXPECT_EQ(1u, other_ht.size());
799
+ EXPECT_EQ(1u, this->ht_.count(this->UniqueKey(111)));
800
+ EXPECT_EQ(0u, other_ht.count(this->UniqueKey(111)));
801
+ }
802
+
803
+ TYPED_TEST(HashtableAllTest, Size) {
804
+ EXPECT_EQ(0u, this->ht_.size());
805
+ for (int i = 1; i < 1000; i++) { // go through some resizes
806
+ this->ht_.insert(this->UniqueObject(i));
807
+ EXPECT_EQ(static_cast<typename TypeParam::size_type>(i), this->ht_.size());
808
+ }
809
+ this->ht_.clear();
810
+ EXPECT_EQ(0u, this->ht_.size());
811
+
812
+ this->ht_.set_deleted_key(this->UniqueKey(1));
813
+ EXPECT_EQ(0u, this->ht_.size()); // deleted key doesn't count
814
+ for (int i = 2; i < 1000; i++) { // go through some resizes
815
+ this->ht_.insert(this->UniqueObject(i));
816
+ this->ht_.erase(this->UniqueKey(i));
817
+ EXPECT_EQ(0u, this->ht_.size());
818
+ }
819
+ }
820
+
821
+ TEST(HashtableTest, MaxSizeAndMaxBucketCount) {
822
+ // The max size depends on the allocator. So we can't use the
823
+ // built-in allocator type; instead, we make our own types.
824
+ sparse_hash_set<int, Hasher, Hasher, Alloc<int> > ht_default;
825
+ sparse_hash_set<int, Hasher, Hasher, Alloc<int, unsigned char> > ht_char;
826
+ sparse_hash_set<int, Hasher, Hasher, Alloc<int, unsigned char, 104> > ht_104;
827
+
828
+ EXPECT_GE(ht_default.max_size(), 256u);
829
+ EXPECT_EQ(255u, ht_char.max_size());
830
+ EXPECT_EQ(104u, ht_104.max_size());
831
+
832
+ // In our implementations, MaxBucketCount == MaxSize.
833
+ EXPECT_EQ(ht_default.max_size(), ht_default.max_bucket_count());
834
+ EXPECT_EQ(ht_char.max_size(), ht_char.max_bucket_count());
835
+ EXPECT_EQ(ht_104.max_size(), ht_104.max_bucket_count());
836
+ }
837
+
838
+ TYPED_TEST(HashtableAllTest, Empty) {
839
+ EXPECT_TRUE(this->ht_.empty());
840
+
841
+ this->ht_.insert(this->UniqueObject(1));
842
+ EXPECT_FALSE(this->ht_.empty());
843
+
844
+ this->ht_.clear();
845
+ EXPECT_TRUE(this->ht_.empty());
846
+
847
+ TypeParam empty_ht;
848
+ this->ht_.insert(this->UniqueObject(1));
849
+ this->ht_.swap(empty_ht);
850
+ EXPECT_TRUE(this->ht_.empty());
851
+ }
852
+
853
+ TYPED_TEST(HashtableAllTest, BucketCount) {
854
+ TypeParam ht(100);
855
+ // constructor arg is number of *items* to be inserted, not the
856
+ // number of buckets, so we expect more buckets.
857
+ EXPECT_GT(ht.bucket_count(), 100u);
858
+ for (int i = 1; i < 200; i++) {
859
+ ht.insert(this->UniqueObject(i));
860
+ }
861
+ EXPECT_GT(ht.bucket_count(), 200u);
862
+ }
863
+
864
+ TYPED_TEST(HashtableAllTest, BucketAndBucketSize) {
865
+ const typename TypeParam::size_type expected_bucknum = this->ht_.bucket(
866
+ this->UniqueKey(1));
867
+ EXPECT_EQ(0u, this->ht_.bucket_size(expected_bucknum));
868
+
869
+ this->ht_.insert(this->UniqueObject(1));
870
+ EXPECT_EQ(expected_bucknum, this->ht_.bucket(this->UniqueKey(1)));
871
+ EXPECT_EQ(1u, this->ht_.bucket_size(expected_bucknum));
872
+
873
+ // Check that a bucket we didn't insert into, has a 0 size. Since
874
+ // we have an even number of buckets, bucknum^1 is guaranteed in range.
875
+ EXPECT_EQ(0u, this->ht_.bucket_size(expected_bucknum ^ 1));
876
+ }
877
+
878
+ TYPED_TEST(HashtableAllTest, LoadFactor) {
879
+ const typename TypeParam::size_type kSize = 16536;
880
+ // Check growing past various thresholds and then shrinking below
881
+ // them.
882
+ for (float grow_threshold = 0.2f;
883
+ grow_threshold <= 0.8f;
884
+ grow_threshold += 0.2f) {
885
+ TypeParam ht;
886
+ ht.set_deleted_key(this->UniqueKey(1));
887
+ ht.max_load_factor(grow_threshold);
888
+ ht.min_load_factor(0.0);
889
+ EXPECT_EQ(grow_threshold, ht.max_load_factor());
890
+ EXPECT_EQ(0.0, ht.min_load_factor());
891
+
892
+ ht.resize(kSize);
893
+ size_t bucket_count = ht.bucket_count();
894
+ // Erase and insert an element to set consider_shrink = true,
895
+ // which should not cause a shrink because the threshold is 0.0.
896
+ ht.insert(this->UniqueObject(2));
897
+ ht.erase(this->UniqueKey(2));
898
+ for (int i = 2;; ++i) {
899
+ ht.insert(this->UniqueObject(i));
900
+ if (static_cast<float>(ht.size())/bucket_count < grow_threshold) {
901
+ EXPECT_EQ(bucket_count, ht.bucket_count());
902
+ } else {
903
+ EXPECT_GT(ht.bucket_count(), bucket_count);
904
+ break;
905
+ }
906
+ }
907
+ // Now set a shrink threshold 1% below the current size and remove
908
+ // items until the size falls below that.
909
+ const float shrink_threshold = static_cast<float>(ht.size()) /
910
+ ht.bucket_count() - 0.01f;
911
+
912
+ // This time around, check the old set_resizing_parameters interface.
913
+ ht.set_resizing_parameters(shrink_threshold, 1.0);
914
+ EXPECT_EQ(1.0, ht.max_load_factor());
915
+ EXPECT_EQ(shrink_threshold, ht.min_load_factor());
916
+
917
+ bucket_count = ht.bucket_count();
918
+ for (int i = 2;; ++i) {
919
+ ht.erase(this->UniqueKey(i));
920
+ // A resize is only triggered by an insert, so add and remove a
921
+ // value every iteration to trigger the shrink as soon as the
922
+ // threshold is passed.
923
+ ht.erase(this->UniqueKey(i+1));
924
+ ht.insert(this->UniqueObject(i+1));
925
+ if (static_cast<float>(ht.size())/bucket_count > shrink_threshold) {
926
+ EXPECT_EQ(bucket_count, ht.bucket_count());
927
+ } else {
928
+ EXPECT_LT(ht.bucket_count(), bucket_count);
929
+ break;
930
+ }
931
+ }
932
+ }
933
+ }
934
+
935
+ TYPED_TEST(HashtableAllTest, ResizeAndRehash) {
936
+ // resize() and rehash() are synonyms. rehash() is the tr1 name.
937
+ TypeParam ht(10000);
938
+ ht.max_load_factor(0.8f); // for consistency's sake
939
+
940
+ for (int i = 1; i < 100; ++i)
941
+ ht.insert(this->UniqueObject(i));
942
+ ht.resize(0);
943
+ // Now ht should be as small as possible.
944
+ EXPECT_LT(ht.bucket_count(), 300u);
945
+
946
+ ht.rehash(9000); // use the 'rehash' version of the name.
947
+ // Bucket count should be next power of 2, after considering max_load_factor.
948
+ EXPECT_EQ(16384u, ht.bucket_count());
949
+ for (int i = 101; i < 200; ++i)
950
+ ht.insert(this->UniqueObject(i));
951
+ // Adding a few hundred buckets shouldn't have caused a resize yet.
952
+ EXPECT_EQ(ht.bucket_count(), 16384u);
953
+ }
954
+
955
+ TYPED_TEST(HashtableAllTest, FindAndCountAndEqualRange) {
956
+ pair<typename TypeParam::iterator, typename TypeParam::iterator> eq_pair;
957
+ pair<typename TypeParam::const_iterator,
958
+ typename TypeParam::const_iterator> const_eq_pair;
959
+
960
+ EXPECT_TRUE(this->ht_.empty());
961
+ EXPECT_TRUE(this->ht_.find(this->UniqueKey(1)) == this->ht_.end());
962
+ EXPECT_EQ(0u, this->ht_.count(this->UniqueKey(1)));
963
+ eq_pair = this->ht_.equal_range(this->UniqueKey(1));
964
+ EXPECT_TRUE(eq_pair.first == eq_pair.second);
965
+
966
+ this->ht_.insert(this->UniqueObject(1));
967
+ EXPECT_FALSE(this->ht_.empty());
968
+ this->ht_.insert(this->UniqueObject(11));
969
+ this->ht_.insert(this->UniqueObject(111));
970
+ this->ht_.insert(this->UniqueObject(1111));
971
+ this->ht_.insert(this->UniqueObject(11111));
972
+ this->ht_.insert(this->UniqueObject(111111));
973
+ this->ht_.insert(this->UniqueObject(1111111));
974
+ this->ht_.insert(this->UniqueObject(11111111));
975
+ this->ht_.insert(this->UniqueObject(111111111));
976
+ EXPECT_EQ(9u, this->ht_.size());
977
+ typename TypeParam::const_iterator it = this->ht_.find(this->UniqueKey(1));
978
+ EXPECT_EQ(it.key(), this->UniqueKey(1));
979
+
980
+ // Allow testing the const version of the methods as well.
981
+ const TypeParam ht = this->ht_;
982
+
983
+ // Some successful lookups (via find, count, and equal_range).
984
+ EXPECT_TRUE(this->ht_.find(this->UniqueKey(1)) != this->ht_.end());
985
+ EXPECT_EQ(1u, this->ht_.count(this->UniqueKey(1)));
986
+ eq_pair = this->ht_.equal_range(this->UniqueKey(1));
987
+ EXPECT_TRUE(eq_pair.first != eq_pair.second);
988
+ EXPECT_EQ(eq_pair.first.key(), this->UniqueKey(1));
989
+ ++eq_pair.first;
990
+ EXPECT_TRUE(eq_pair.first == eq_pair.second);
991
+
992
+ EXPECT_TRUE(ht.find(this->UniqueKey(1)) != ht.end());
993
+ EXPECT_EQ(1u, ht.count(this->UniqueKey(1)));
994
+ const_eq_pair = ht.equal_range(this->UniqueKey(1));
995
+ EXPECT_TRUE(const_eq_pair.first != const_eq_pair.second);
996
+ EXPECT_EQ(const_eq_pair.first.key(), this->UniqueKey(1));
997
+ ++const_eq_pair.first;
998
+ EXPECT_TRUE(const_eq_pair.first == const_eq_pair.second);
999
+
1000
+ EXPECT_TRUE(this->ht_.find(this->UniqueKey(11111)) != this->ht_.end());
1001
+ EXPECT_EQ(1u, this->ht_.count(this->UniqueKey(11111)));
1002
+ eq_pair = this->ht_.equal_range(this->UniqueKey(11111));
1003
+ EXPECT_TRUE(eq_pair.first != eq_pair.second);
1004
+ EXPECT_EQ(eq_pair.first.key(), this->UniqueKey(11111));
1005
+ ++eq_pair.first;
1006
+ EXPECT_TRUE(eq_pair.first == eq_pair.second);
1007
+
1008
+ EXPECT_TRUE(ht.find(this->UniqueKey(11111)) != ht.end());
1009
+ EXPECT_EQ(1u, ht.count(this->UniqueKey(11111)));
1010
+ const_eq_pair = ht.equal_range(this->UniqueKey(11111));
1011
+ EXPECT_TRUE(const_eq_pair.first != const_eq_pair.second);
1012
+ EXPECT_EQ(const_eq_pair.first.key(), this->UniqueKey(11111));
1013
+ ++const_eq_pair.first;
1014
+ EXPECT_TRUE(const_eq_pair.first == const_eq_pair.second);
1015
+
1016
+ // Some unsuccessful lookups (via find, count, and equal_range).
1017
+ EXPECT_TRUE(this->ht_.find(this->UniqueKey(11112)) == this->ht_.end());
1018
+ EXPECT_EQ(0u, this->ht_.count(this->UniqueKey(11112)));
1019
+ eq_pair = this->ht_.equal_range(this->UniqueKey(11112));
1020
+ EXPECT_TRUE(eq_pair.first == eq_pair.second);
1021
+
1022
+ EXPECT_TRUE(ht.find(this->UniqueKey(11112)) == ht.end());
1023
+ EXPECT_EQ(0u, ht.count(this->UniqueKey(11112)));
1024
+ const_eq_pair = ht.equal_range(this->UniqueKey(11112));
1025
+ EXPECT_TRUE(const_eq_pair.first == const_eq_pair.second);
1026
+
1027
+ EXPECT_TRUE(this->ht_.find(this->UniqueKey(11110)) == this->ht_.end());
1028
+ EXPECT_EQ(0u, this->ht_.count(this->UniqueKey(11110)));
1029
+ eq_pair = this->ht_.equal_range(this->UniqueKey(11110));
1030
+ EXPECT_TRUE(eq_pair.first == eq_pair.second);
1031
+
1032
+ EXPECT_TRUE(ht.find(this->UniqueKey(11110)) == ht.end());
1033
+ EXPECT_EQ(0u, ht.count(this->UniqueKey(11110)));
1034
+ const_eq_pair = ht.equal_range(this->UniqueKey(11110));
1035
+ EXPECT_TRUE(const_eq_pair.first == const_eq_pair.second);
1036
+ }
1037
+
1038
+ TYPED_TEST(HashtableAllTest, BracketInsert) {
1039
+ // tests operator[], for those types that support it.
1040
+ if (!this->ht_.supports_brackets())
1041
+ return;
1042
+
1043
+ // bracket_equal is equivalent to ht_[a] == b. It should insert a if
1044
+ // it doesn't already exist.
1045
+ EXPECT_TRUE(this->ht_.bracket_equal(this->UniqueKey(1),
1046
+ this->ht_.default_data()));
1047
+ EXPECT_TRUE(this->ht_.find(this->UniqueKey(1)) != this->ht_.end());
1048
+
1049
+ // bracket_assign is equivalent to ht_[a] = b.
1050
+ this->ht_.bracket_assign(this->UniqueKey(2),
1051
+ this->ht_.get_data(this->UniqueObject(4)));
1052
+ EXPECT_TRUE(this->ht_.find(this->UniqueKey(2)) != this->ht_.end());
1053
+ EXPECT_TRUE(this->ht_.bracket_equal(
1054
+ this->UniqueKey(2), this->ht_.get_data(this->UniqueObject(4))));
1055
+
1056
+ this->ht_.bracket_assign(
1057
+ this->UniqueKey(2), this->ht_.get_data(this->UniqueObject(6)));
1058
+ EXPECT_TRUE(this->ht_.bracket_equal(
1059
+ this->UniqueKey(2), this->ht_.get_data(this->UniqueObject(6))));
1060
+ // bracket_equal shouldn't have modified the value.
1061
+ EXPECT_TRUE(this->ht_.bracket_equal(
1062
+ this->UniqueKey(2), this->ht_.get_data(this->UniqueObject(6))));
1063
+
1064
+ // Verify that an operator[] that doesn't cause a resize, also
1065
+ // doesn't require an extra rehash.
1066
+ TypeParam ht(100);
1067
+ EXPECT_EQ(0, ht.hash_funct().num_hashes());
1068
+ ht.bracket_assign(this->UniqueKey(2), ht.get_data(this->UniqueObject(2)));
1069
+ EXPECT_EQ(1, ht.hash_funct().num_hashes());
1070
+
1071
+ // And overwriting, likewise, should only cause one extra hash.
1072
+ ht.bracket_assign(this->UniqueKey(2), ht.get_data(this->UniqueObject(2)));
1073
+ EXPECT_EQ(2, ht.hash_funct().num_hashes());
1074
+ }
1075
+
1076
+ TYPED_TEST(HashtableAllTest, InsertValue) {
1077
+ // First, try some straightforward insertions.
1078
+ EXPECT_TRUE(this->ht_.empty());
1079
+ this->ht_.insert(this->UniqueObject(1));
1080
+ EXPECT_FALSE(this->ht_.empty());
1081
+ this->ht_.insert(this->UniqueObject(11));
1082
+ this->ht_.insert(this->UniqueObject(111));
1083
+ this->ht_.insert(this->UniqueObject(1111));
1084
+ this->ht_.insert(this->UniqueObject(11111));
1085
+ this->ht_.insert(this->UniqueObject(111111));
1086
+ this->ht_.insert(this->UniqueObject(1111111));
1087
+ this->ht_.insert(this->UniqueObject(11111111));
1088
+ this->ht_.insert(this->UniqueObject(111111111));
1089
+ EXPECT_EQ(9u, this->ht_.size());
1090
+ EXPECT_EQ(1u, this->ht_.count(this->UniqueKey(1)));
1091
+ EXPECT_EQ(1u, this->ht_.count(this->UniqueKey(1111)));
1092
+
1093
+ // Check the return type.
1094
+ pair<typename TypeParam::iterator, bool> insert_it;
1095
+ insert_it = this->ht_.insert(this->UniqueObject(1));
1096
+ EXPECT_EQ(false, insert_it.second); // false: already present
1097
+ EXPECT_TRUE(*insert_it.first == this->UniqueObject(1));
1098
+
1099
+ insert_it = this->ht_.insert(this->UniqueObject(2));
1100
+ EXPECT_EQ(true, insert_it.second); // true: not already present
1101
+ EXPECT_TRUE(*insert_it.first == this->UniqueObject(2));
1102
+ }
1103
+
1104
+ TYPED_TEST(HashtableIntTest, InsertRange) {
1105
+ // We just test the ints here, to make the placement-new easier.
1106
+ TypeParam ht_source;
1107
+ ht_source.insert(this->UniqueObject(10));
1108
+ ht_source.insert(this->UniqueObject(100));
1109
+ ht_source.insert(this->UniqueObject(1000));
1110
+ ht_source.insert(this->UniqueObject(10000));
1111
+ ht_source.insert(this->UniqueObject(100000));
1112
+ ht_source.insert(this->UniqueObject(1000000));
1113
+
1114
+ vector<typename TypeParam::value_type> input(4);
1115
+ // We have to use placement-new because value_type may be const.
1116
+ // This is a copy of the first element in ht_source.
1117
+ new(&input[0]) typename TypeParam::value_type(*ht_source.begin());
1118
+ new(&input[1]) typename TypeParam::value_type(this->UniqueObject(2));
1119
+ new(&input[2]) typename TypeParam::value_type(this->UniqueObject(4));
1120
+ new(&input[3]) typename TypeParam::value_type(this->UniqueObject(8));
1121
+
1122
+ set<typename TypeParam::value_type> set_input;
1123
+ set_input.insert(this->UniqueObject(1111111));
1124
+ set_input.insert(this->UniqueObject(111111));
1125
+ set_input.insert(this->UniqueObject(11111));
1126
+ set_input.insert(this->UniqueObject(1111));
1127
+ set_input.insert(this->UniqueObject(111));
1128
+ set_input.insert(this->UniqueObject(11));
1129
+
1130
+ // Insert from ht_source, an iterator of the same type as us.
1131
+ typename TypeParam::const_iterator begin = ht_source.begin();
1132
+ typename TypeParam::const_iterator end = begin;
1133
+ std::advance(end, 3);
1134
+ this->ht_.insert(begin, end); // insert 3 elements from ht_source
1135
+ EXPECT_EQ(3u, this->ht_.size());
1136
+ EXPECT_TRUE(*this->ht_.begin() == this->UniqueObject(10) ||
1137
+ *this->ht_.begin() == this->UniqueObject(100) ||
1138
+ *this->ht_.begin() == this->UniqueObject(1000) ||
1139
+ *this->ht_.begin() == this->UniqueObject(10000) ||
1140
+ *this->ht_.begin() == this->UniqueObject(100000) ||
1141
+ *this->ht_.begin() == this->UniqueObject(1000000));
1142
+
1143
+ // And insert from set_input, a separate, non-random-access iterator.
1144
+ typename set<typename TypeParam::value_type>::const_iterator set_begin;
1145
+ typename set<typename TypeParam::value_type>::const_iterator set_end;
1146
+ set_begin = set_input.begin();
1147
+ set_end = set_begin;
1148
+ std::advance(set_end, 3);
1149
+ this->ht_.insert(set_begin, set_end);
1150
+ EXPECT_EQ(6u, this->ht_.size());
1151
+
1152
+ // Insert from input as well, a separate, random-access iterator.
1153
+ // The first element of input overlaps with an existing element
1154
+ // of ht_, so this should only up the size by 2.
1155
+ this->ht_.insert(input.begin(), input.begin() + 3);
1156
+ EXPECT_EQ(8u, this->ht_.size());
1157
+ }
1158
+
1159
+ TEST(HashtableTest, InsertValueToMap) {
1160
+ // For the maps in particular, ensure that inserting doesn't change
1161
+ // the value.
1162
+ sparse_hash_map<int, int> shm;
1163
+ pair<sparse_hash_map<int,int>::iterator, bool> shm_it;
1164
+ shm[1] = 2; // test a different method of inserting
1165
+ shm_it = shm.insert(pair<int, int>(1, 3));
1166
+ EXPECT_EQ(false, shm_it.second);
1167
+ EXPECT_EQ(1, shm_it.first->first);
1168
+ EXPECT_EQ(2, shm_it.first->second);
1169
+ shm_it.first->second = 20;
1170
+ EXPECT_EQ(20, shm[1]);
1171
+
1172
+ shm_it = shm.insert(pair<int, int>(2, 4));
1173
+ EXPECT_EQ(true, shm_it.second);
1174
+ EXPECT_EQ(2, shm_it.first->first);
1175
+ EXPECT_EQ(4, shm_it.first->second);
1176
+ EXPECT_EQ(4, shm[2]);
1177
+
1178
+ // Do it all again, with dense_hash_map.
1179
+ dense_hash_map<int, int> dhm;
1180
+ dhm.set_empty_key(0);
1181
+ pair<dense_hash_map<int,int>::iterator, bool> dhm_it;
1182
+ dhm[1] = 2; // test a different method of inserting
1183
+ dhm_it = dhm.insert(pair<const int, int>(1, 3));
1184
+ EXPECT_EQ(false, dhm_it.second);
1185
+ EXPECT_EQ(1, dhm_it.first->first);
1186
+ EXPECT_EQ(2, dhm_it.first->second);
1187
+ dhm_it.first->second = 20;
1188
+ EXPECT_EQ(20, dhm[1]);
1189
+
1190
+ dhm_it = dhm.insert(pair<const int, int>(2, 4));
1191
+ EXPECT_EQ(true, dhm_it.second);
1192
+ EXPECT_EQ(2, dhm_it.first->first);
1193
+ EXPECT_EQ(4, dhm_it.first->second);
1194
+ EXPECT_EQ(4, dhm[2]);
1195
+ }
1196
+
1197
+ TYPED_TEST(HashtableStringTest, EmptyKey) {
1198
+ // Only run the string tests, to make it easier to know what the
1199
+ // empty key should be.
1200
+ if (!this->ht_.supports_empty_key())
1201
+ return;
1202
+ EXPECT_EQ(kEmptyString, this->ht_.empty_key());
1203
+ }
1204
+
1205
+ TYPED_TEST(HashtableAllTest, DeletedKey) {
1206
+ if (!this->ht_.supports_deleted_key())
1207
+ return;
1208
+ this->ht_.insert(this->UniqueObject(10));
1209
+ this->ht_.insert(this->UniqueObject(20));
1210
+ this->ht_.set_deleted_key(this->UniqueKey(1));
1211
+ EXPECT_EQ(this->ht_.deleted_key(), this->UniqueKey(1));
1212
+ EXPECT_EQ(2u, this->ht_.size());
1213
+ this->ht_.erase(this->UniqueKey(20));
1214
+ EXPECT_EQ(1u, this->ht_.size());
1215
+
1216
+ // Changing the deleted key is fine.
1217
+ this->ht_.set_deleted_key(this->UniqueKey(2));
1218
+ EXPECT_EQ(this->ht_.deleted_key(), this->UniqueKey(2));
1219
+ EXPECT_EQ(1u, this->ht_.size());
1220
+ }
1221
+
1222
+ TYPED_TEST(HashtableAllTest, Erase) {
1223
+ this->ht_.set_deleted_key(this->UniqueKey(1));
1224
+ EXPECT_EQ(0u, this->ht_.erase(this->UniqueKey(20)));
1225
+ this->ht_.insert(this->UniqueObject(10));
1226
+ this->ht_.insert(this->UniqueObject(20));
1227
+ EXPECT_EQ(1u, this->ht_.erase(this->UniqueKey(20)));
1228
+ EXPECT_EQ(1u, this->ht_.size());
1229
+ EXPECT_EQ(0u, this->ht_.erase(this->UniqueKey(20)));
1230
+ EXPECT_EQ(1u, this->ht_.size());
1231
+ EXPECT_EQ(0u, this->ht_.erase(this->UniqueKey(19)));
1232
+ EXPECT_EQ(1u, this->ht_.size());
1233
+
1234
+ typename TypeParam::iterator it = this->ht_.find(this->UniqueKey(10));
1235
+ EXPECT_TRUE(it != this->ht_.end());
1236
+ this->ht_.erase(it);
1237
+ EXPECT_EQ(0u, this->ht_.size());
1238
+
1239
+ for (int i = 10; i < 100; i++)
1240
+ this->ht_.insert(this->UniqueObject(i));
1241
+ EXPECT_EQ(90u, this->ht_.size());
1242
+ this->ht_.erase(this->ht_.begin(), this->ht_.end());
1243
+ EXPECT_EQ(0u, this->ht_.size());
1244
+ }
1245
+
1246
+ TYPED_TEST(HashtableAllTest, EraseDoesNotResize) {
1247
+ this->ht_.set_deleted_key(this->UniqueKey(1));
1248
+ for (int i = 10; i < 2000; i++) {
1249
+ this->ht_.insert(this->UniqueObject(i));
1250
+ }
1251
+ const typename TypeParam::size_type old_count = this->ht_.bucket_count();
1252
+ for (int i = 10; i < 1000; i++) { // erase half one at a time
1253
+ EXPECT_EQ(1u, this->ht_.erase(this->UniqueKey(i)));
1254
+ }
1255
+ this->ht_.erase(this->ht_.begin(), this->ht_.end()); // and the rest at once
1256
+ EXPECT_EQ(0u, this->ht_.size());
1257
+ EXPECT_EQ(old_count, this->ht_.bucket_count());
1258
+ }
1259
+
1260
+ TYPED_TEST(HashtableAllTest, Equals) {
1261
+ // The real test here is whether two hashtables are equal if they
1262
+ // have the same items but in a different order.
1263
+ TypeParam ht1;
1264
+ TypeParam ht2;
1265
+
1266
+ EXPECT_TRUE(ht1 == ht1);
1267
+ EXPECT_FALSE(ht1 != ht1);
1268
+ EXPECT_TRUE(ht1 == ht2);
1269
+ EXPECT_FALSE(ht1 != ht2);
1270
+ ht1.set_deleted_key(this->UniqueKey(1));
1271
+ // Only the contents affect equality, not things like deleted-key.
1272
+ EXPECT_TRUE(ht1 == ht2);
1273
+ EXPECT_FALSE(ht1 != ht2);
1274
+ ht1.resize(2000);
1275
+ EXPECT_TRUE(ht1 == ht2);
1276
+
1277
+ // The choice of allocator/etc doesn't matter either.
1278
+ Hasher hasher(1);
1279
+ Alloc<typename TypeParam::key_type> alloc(2, NULL);
1280
+ TypeParam ht3(5, hasher, hasher, alloc);
1281
+ EXPECT_TRUE(ht1 == ht3);
1282
+ EXPECT_FALSE(ht1 != ht3);
1283
+
1284
+ ht1.insert(this->UniqueObject(2));
1285
+ EXPECT_TRUE(ht1 != ht2);
1286
+ EXPECT_FALSE(ht1 == ht2); // this should hold as well!
1287
+
1288
+ ht2.insert(this->UniqueObject(2));
1289
+ EXPECT_TRUE(ht1 == ht2);
1290
+
1291
+ for (int i = 3; i <= 2000; i++) {
1292
+ ht1.insert(this->UniqueObject(i));
1293
+ }
1294
+ for (int i = 2000; i >= 3; i--) {
1295
+ ht2.insert(this->UniqueObject(i));
1296
+ }
1297
+ EXPECT_TRUE(ht1 == ht2);
1298
+ }
1299
+
1300
+ TEST(HashtableTest, IntIO) {
1301
+ // Since dense_hash_* doesn't support IO yet, and the set case is
1302
+ // just a special (easier) case than the map case, I just test on
1303
+ // sparse_hash_map. This handles the easy case where we can use the
1304
+ // standard reader and writer.
1305
+ sparse_hash_map<int, int> ht_out;
1306
+ ht_out.set_deleted_key(0);
1307
+ for (int i = 1; i < 1000; i++) {
1308
+ ht_out[i] = i * i;
1309
+ }
1310
+ ht_out.erase(563); // just to test having some erased keys when we write.
1311
+ ht_out.erase(22);
1312
+
1313
+ string file(TmpFile("/intio"));
1314
+ FILE* fp = fopen(file.c_str(), "wb");
1315
+ EXPECT_TRUE(fp != NULL);
1316
+ EXPECT_TRUE(ht_out.write_metadata(fp));
1317
+ EXPECT_TRUE(ht_out.write_nopointer_data(fp));
1318
+ fclose(fp);
1319
+
1320
+ sparse_hash_map<int, int> ht_in;
1321
+ fp = fopen(file.c_str(), "rb");
1322
+ EXPECT_TRUE(fp != NULL);
1323
+ EXPECT_TRUE(ht_in.read_metadata(fp));
1324
+ EXPECT_TRUE(ht_in.read_nopointer_data(fp));
1325
+ fclose(fp);
1326
+
1327
+ EXPECT_EQ(1, ht_in[1]);
1328
+ EXPECT_EQ(998001, ht_in[999]);
1329
+ EXPECT_EQ(100, ht_in[10]);
1330
+ EXPECT_EQ(441, ht_in[21]);
1331
+ EXPECT_EQ(0, ht_in[22]); // should not have been saved
1332
+ EXPECT_EQ(0, ht_in[563]);
1333
+ }
1334
+
1335
+ TEST(HashtableTest, StringIO) {
1336
+ // Since dense_hash_* doesn't support IO yet, and the set case is
1337
+ // just a special (easier) case than the map case, I just test on
1338
+ // sparse_hash_map. This handles the difficult case where we have
1339
+ // to write our own custom reader/writer for the data.
1340
+ sparse_hash_map<string, string, Hasher, Hasher> ht_out;
1341
+ ht_out.set_deleted_key(string(""));
1342
+ for (int i = 32; i < 128; i++) {
1343
+ // This maps 'a' to 32 a's, 'b' to 33 b's, etc.
1344
+ ht_out[string(1, i)] = string(i, i);
1345
+ }
1346
+ ht_out.erase("c"); // just to test having some erased keys when we write.
1347
+ ht_out.erase("y");
1348
+
1349
+ string file(TmpFile("/stringio"));
1350
+ FILE* fp = fopen(file.c_str(), "wb");
1351
+ EXPECT_TRUE(fp != NULL);
1352
+ EXPECT_TRUE(ht_out.write_metadata(fp));
1353
+ for (sparse_hash_map<string, string, Hasher, Hasher>::const_iterator
1354
+ it = ht_out.begin(); it != ht_out.end(); ++it) {
1355
+ const string::size_type first_size = it->first.length();
1356
+ fwrite(&first_size, sizeof(first_size), 1, fp); // ignore endianness issues
1357
+ fwrite(it->first.c_str(), first_size, 1, fp);
1358
+
1359
+ const string::size_type second_size = it->second.length();
1360
+ fwrite(&second_size, sizeof(second_size), 1, fp);
1361
+ fwrite(it->second.c_str(), second_size, 1, fp);
1362
+ }
1363
+ fclose(fp);
1364
+
1365
+ sparse_hash_map<string, string, Hasher, Hasher> ht_in;
1366
+ fp = fopen(file.c_str(), "rb");
1367
+ EXPECT_TRUE(fp != NULL);
1368
+ EXPECT_TRUE(ht_in.read_metadata(fp));
1369
+ for (sparse_hash_map<string, string, Hasher, Hasher>::iterator
1370
+ it = ht_in.begin(); it != ht_in.end(); ++it) {
1371
+ string::size_type first_size;
1372
+ fread(&first_size, sizeof(first_size), 1, fp);
1373
+ char* first = new char[first_size];
1374
+ fread(first, first_size, 1, fp);
1375
+
1376
+ string::size_type second_size;
1377
+ fread(&second_size, sizeof(second_size), 1, fp);
1378
+ char* second = new char[second_size];
1379
+ fread(second, second_size, 1, fp);
1380
+
1381
+ // it points to garbage, so we have to use placement-new to initialize.
1382
+ // We also have to use const-cast since it->first is const.
1383
+ new(const_cast<string*>(&it->first)) string(first, first_size);
1384
+ new(&it->second) string(second, second_size);
1385
+ delete[] first;
1386
+ delete[] second;
1387
+ }
1388
+ fclose(fp);
1389
+
1390
+ EXPECT_EQ(string(" "), ht_in[" "]);
1391
+ EXPECT_EQ(string("+++++++++++++++++++++++++++++++++++++++++++"), ht_in["+"]);
1392
+ EXPECT_EQ(string(""), ht_in["c"]); // should not have been saved
1393
+ EXPECT_EQ(string(""), ht_in["y"]);
1394
+ }
1395
+
1396
+ // ------------------------------------------------------------------------
1397
+ // The above tests test the general API for correctness. These tests
1398
+ // test a few corner cases that have tripped us up in the past, and
1399
+ // more general, cross-API issues like memory management.
1400
+
1401
+ TYPED_TEST(HashtableAllTest, BracketOperatorCrashing) {
1402
+ this->ht_.set_deleted_key(this->UniqueKey(1));
1403
+ for (int iters = 0; iters < 10; iters++) {
1404
+ // We start at 33 because after shrinking, we'll be at 32 buckets.
1405
+ for (int i = 33; i < 133; i++) {
1406
+ this->ht_.bracket_assign(this->UniqueKey(i),
1407
+ this->ht_.get_data(this->UniqueObject(i)));
1408
+ }
1409
+ this->ht_.clear_no_resize();
1410
+ // This will force a shrink on the next insert, which we want to test.
1411
+ this->ht_.bracket_assign(this->UniqueKey(2),
1412
+ this->ht_.get_data(this->UniqueObject(2)));
1413
+ this->ht_.erase(this->UniqueKey(2));
1414
+ }
1415
+ }
1416
+
1417
+ // For data types with trivial copy-constructors and destructors, we
1418
+ // should use an optimized routine for data-copying, that involves
1419
+ // memmove. We test this by keeping count of how many times the
1420
+ // copy-constructor is called; it should be much less with the
1421
+ // optimized code.
1422
+ struct Memmove {
1423
+ public:
1424
+ Memmove(): i(0) {}
1425
+ explicit Memmove(int ival): i(ival) {}
1426
+ Memmove(const Memmove& that) { this->i = that.i; num_copies++; }
1427
+ int i;
1428
+ static int num_copies;
1429
+ };
1430
+ int Memmove::num_copies = 0;
1431
+
1432
+ struct NoMemmove {
1433
+ public:
1434
+ NoMemmove(): i(0) {}
1435
+ explicit NoMemmove(int ival): i(ival) {}
1436
+ NoMemmove(const NoMemmove& that) { this->i = that.i; num_copies++; }
1437
+ int i;
1438
+ static int num_copies;
1439
+ };
1440
+ int NoMemmove::num_copies = 0;
1441
+
1442
+ } // unnamed namespace
1443
+
1444
+ // This is what tells the hashtable code it can use memmove for this class:
1445
+ _START_GOOGLE_NAMESPACE_
1446
+ template<> struct has_trivial_copy<Memmove> : true_type { };
1447
+ template<> struct has_trivial_destructor<Memmove> : true_type { };
1448
+ _END_GOOGLE_NAMESPACE_
1449
+
1450
+ namespace {
1451
+
1452
+ TEST(HashtableTest, SimpleDataTypeOptimizations) {
1453
+ // Only sparsehashtable optimizes moves in this way.
1454
+ sparse_hash_map<int, Memmove, Hasher, Hasher> memmove;
1455
+ sparse_hash_map<int, NoMemmove, Hasher, Hasher> nomemmove;
1456
+ sparse_hash_map<int, Memmove, Hasher, Hasher, Alloc<int> >
1457
+ memmove_nonstandard_alloc;
1458
+
1459
+ Memmove::num_copies = 0;
1460
+ for (int i = 10000; i > 0; i--) {
1461
+ memmove[i] = Memmove(i);
1462
+ }
1463
+ const int memmove_copies = Memmove::num_copies;
1464
+
1465
+ NoMemmove::num_copies = 0;
1466
+ for (int i = 10000; i > 0; i--) {
1467
+ nomemmove[i] = NoMemmove(i);
1468
+ }
1469
+ const int nomemmove_copies = NoMemmove::num_copies;
1470
+
1471
+ Memmove::num_copies = 0;
1472
+ for (int i = 10000; i > 0; i--) {
1473
+ memmove_nonstandard_alloc[i] = Memmove(i);
1474
+ }
1475
+ const int memmove_nonstandard_alloc_copies = Memmove::num_copies;
1476
+
1477
+ EXPECT_GT(nomemmove_copies, memmove_copies);
1478
+ EXPECT_EQ(nomemmove_copies, memmove_nonstandard_alloc_copies);
1479
+ }
1480
+
1481
+ TYPED_TEST(HashtableAllTest, ResizeHysteresis) {
1482
+ // We want to make sure that when we create a hashtable, and then
1483
+ // add and delete one element, the size of the hashtable doesn't
1484
+ // change.
1485
+ this->ht_.set_deleted_key(this->UniqueKey(1));
1486
+ typename TypeParam::size_type old_bucket_count = this->ht_.bucket_count();
1487
+ this->ht_.insert(this->UniqueObject(4));
1488
+ this->ht_.erase(this->UniqueKey(4));
1489
+ this->ht_.insert(this->UniqueObject(4));
1490
+ this->ht_.erase(this->UniqueKey(4));
1491
+ EXPECT_EQ(old_bucket_count, this->ht_.bucket_count());
1492
+
1493
+ // Try it again, but with a hashtable that starts very small
1494
+ TypeParam ht(2);
1495
+ EXPECT_LT(ht.bucket_count(), 32u); // verify we really do start small
1496
+ ht.set_deleted_key(this->UniqueKey(1));
1497
+ old_bucket_count = ht.bucket_count();
1498
+ ht.insert(this->UniqueObject(4));
1499
+ ht.erase(this->UniqueKey(4));
1500
+ ht.insert(this->UniqueObject(4));
1501
+ ht.erase(this->UniqueKey(4));
1502
+ EXPECT_EQ(old_bucket_count, ht.bucket_count());
1503
+ }
1504
+
1505
+ TEST(HashtableTest, ConstKey) {
1506
+ // Sometimes people write hash_map<const int, int>, even though the
1507
+ // const isn't necessary. Make sure we handle this cleanly.
1508
+ sparse_hash_map<const int, int, Hasher, Hasher> shm;
1509
+ shm.set_deleted_key(1);
1510
+ shm[10] = 20;
1511
+
1512
+ dense_hash_map<const int, int, Hasher, Hasher> dhm;
1513
+ dhm.set_empty_key(1);
1514
+ dhm.set_deleted_key(2);
1515
+ dhm[10] = 20;
1516
+ }
1517
+
1518
+ TYPED_TEST(HashtableAllTest, ResizeActuallyResizes) {
1519
+ // This tests for a problem we had where we could repeatedly "resize"
1520
+ // a hashtable to the same size it was before, on every insert.
1521
+ const typename TypeParam::size_type kSize = 1<<10; // Pick any power of 2
1522
+ const float kResize = 0.8f; // anything between 0.5 and 1 is fine.
1523
+ const int kThreshold = static_cast<int>(kSize * kResize - 1);
1524
+ this->ht_.set_resizing_parameters(0, kResize);
1525
+ this->ht_.set_deleted_key(this->UniqueKey(kThreshold + 100));
1526
+
1527
+ // Get right up to the resizing threshold.
1528
+ for (int i = 0; i <= kThreshold; i++) {
1529
+ this->ht_.insert(this->UniqueObject(i+1));
1530
+ }
1531
+ // The bucket count should equal kSize.
1532
+ EXPECT_EQ(kSize, this->ht_.bucket_count());
1533
+
1534
+ // Now start doing erase+insert pairs. This should cause us to
1535
+ // copy the hashtable at most once.
1536
+ const int pre_copies = this->ht_.num_table_copies();
1537
+ for (int i = 0; i < static_cast<int>(kSize); i++) {
1538
+ this->ht_.erase(this->UniqueKey(kThreshold));
1539
+ this->ht_.insert(this->UniqueObject(kThreshold));
1540
+ }
1541
+ EXPECT_LT(this->ht_.num_table_copies(), pre_copies + 2);
1542
+
1543
+ // Now create a hashtable where we go right to the threshold, then
1544
+ // delete everything and do one insert. Even though our hashtable
1545
+ // is now tiny, we should still have at least kSize buckets, because
1546
+ // our shrink threshhold is 0.
1547
+ TypeParam ht2;
1548
+ ht2.set_deleted_key(this->UniqueKey(kThreshold + 100));
1549
+ ht2.set_resizing_parameters(0, kResize);
1550
+ EXPECT_LT(ht2.bucket_count(), kSize);
1551
+ for (int i = 0; i <= kThreshold; i++) {
1552
+ ht2.insert(this->UniqueObject(i+1));
1553
+ }
1554
+ EXPECT_EQ(ht2.bucket_count(), kSize);
1555
+ for (int i = 0; i <= kThreshold; i++) {
1556
+ ht2.erase(this->UniqueKey(i+1));
1557
+ EXPECT_EQ(ht2.bucket_count(), kSize);
1558
+ }
1559
+ ht2.insert(this->UniqueObject(kThreshold+2));
1560
+ EXPECT_GE(ht2.bucket_count(), kSize);
1561
+ }
1562
+
1563
+ template<typename T> class DenseIntMap : public dense_hash_map<int, T> {
1564
+ public:
1565
+ DenseIntMap() { this->set_empty_key(0); }
1566
+ };
1567
+
1568
+ class DenseStringSet : public dense_hash_set<string, Hasher, Hasher> {
1569
+ public:
1570
+ DenseStringSet() { this->set_empty_key(string("")); }
1571
+ };
1572
+
1573
+ TEST(HashtableTest, NestedHashtables) {
1574
+ // People can do better than to have a hash_map of hash_maps, but we
1575
+ // should still support it. I try a few different mappings.
1576
+ sparse_hash_map<string, sparse_hash_map<int, string>, Hasher, Hasher> ht1;
1577
+ sparse_hash_map<string, DenseStringSet, Hasher, Hasher> ht2;
1578
+ dense_hash_map<int, DenseIntMap<int>, Hasher, Hasher> ht3;
1579
+ ht3.set_empty_key(0);
1580
+
1581
+ ht1["hi"]; // create a sub-ht with the default values
1582
+ ht1["lo"][1] = "there";
1583
+ sparse_hash_map<string, sparse_hash_map<int, string>, Hasher, Hasher>
1584
+ ht1copy = ht1;
1585
+
1586
+ ht2["hi"];
1587
+ ht2["hi"].insert("lo");
1588
+ sparse_hash_map<string, DenseStringSet, Hasher, Hasher> ht2copy = ht2;
1589
+
1590
+ ht3[1];
1591
+ ht3[2][3] = 4;
1592
+ dense_hash_map<int, DenseIntMap<int>, Hasher, Hasher> ht3copy = ht3;
1593
+ }
1594
+
1595
+ TEST(HashtableDeathTest, ResizeOverflow) {
1596
+ dense_hash_map<int, int> ht;
1597
+ try {
1598
+ ht.resize(static_cast<size_t>(-1));
1599
+ EXPECT_TRUE(false && "dense_hash_map reszie should have failed");
1600
+ } catch (const STL_NAMESPACE::length_error&) {
1601
+ // Good, the resize failed.
1602
+ }
1603
+
1604
+ sparse_hash_map<int, int> ht2;
1605
+ try {
1606
+ ht2.resize(static_cast<size_t>(-1));
1607
+ EXPECT_TRUE(false && "sparse_hash_map reszie should have failed");
1608
+ } catch (const STL_NAMESPACE::length_error&) {
1609
+ // Good, the resize failed.
1610
+ }
1611
+ }
1612
+
1613
+ TEST(HashtableDeathTest, InsertSizeTypeOverflow) {
1614
+ static const int kMax = 256;
1615
+ vector<int> test_data(kMax);
1616
+ for (int i = 0; i < kMax; ++i) {
1617
+ test_data[i] = i+1000;
1618
+ }
1619
+
1620
+ sparse_hash_set<int, Hasher, Hasher, Alloc<int, uint8, 10> > shs;
1621
+ dense_hash_set<int, Hasher, Hasher, Alloc<int, uint8, 10> > dhs;
1622
+ dhs.set_empty_key(-1);
1623
+
1624
+ // Test we are using the correct allocator
1625
+ EXPECT_TRUE(shs.get_allocator().is_custom_alloc());
1626
+ EXPECT_TRUE(dhs.get_allocator().is_custom_alloc());
1627
+
1628
+ // Test size_type overflow in insert(it, it)
1629
+ try {
1630
+ dhs.insert(test_data.begin(), test_data.end());
1631
+ EXPECT_TRUE(false && "dense_hash_map::insert(it,it) should have overflown");
1632
+ } catch (const STL_NAMESPACE::length_error&) {
1633
+ // Good, the operation failed.
1634
+ }
1635
+ try {
1636
+ shs.insert(test_data.begin(), test_data.end());
1637
+ EXPECT_TRUE(false && "sparse_hash_map::insert(it,it) should have overflown");
1638
+ } catch (const STL_NAMESPACE::length_error&) {
1639
+ // Good, the operation failed.
1640
+ }
1641
+ }
1642
+
1643
+ TEST(HashtableDeathTest, InsertMaxSizeOverflow) {
1644
+ static const int kMax = 256;
1645
+ vector<int> test_data(kMax);
1646
+ for (int i = 0; i < kMax; ++i) {
1647
+ test_data[i] = i+1000;
1648
+ }
1649
+
1650
+ sparse_hash_set<int, Hasher, Hasher, Alloc<int, uint8, 10> > shs;
1651
+ dense_hash_set<int, Hasher, Hasher, Alloc<int, uint8, 10> > dhs;
1652
+ dhs.set_empty_key(-1);
1653
+
1654
+ // Test max_size overflow
1655
+ try {
1656
+ dhs.insert(test_data.begin(), test_data.begin() + 11);
1657
+ EXPECT_TRUE(false && "dense_hash_map max_size check should have failed");
1658
+ } catch (const STL_NAMESPACE::length_error&) {
1659
+ // Good, the operation failed.
1660
+ }
1661
+ try {
1662
+ shs.insert(test_data.begin(), test_data.begin() + 11);
1663
+ EXPECT_TRUE(false && "sparse_hash_map max_size check should have failed");
1664
+ } catch (const STL_NAMESPACE::length_error&) {
1665
+ // Good, the operation failed.
1666
+ }
1667
+ }
1668
+
1669
+ TEST(HashtableDeathTest, ResizeSizeTypeOverflow) {
1670
+ // Test min-buckets overflow, when we want to resize too close to size_type
1671
+ sparse_hash_set<int, Hasher, Hasher, Alloc<int, uint8, 10> > shs;
1672
+ dense_hash_set<int, Hasher, Hasher, Alloc<int, uint8, 10> > dhs;
1673
+ dhs.set_empty_key(-1);
1674
+
1675
+ try {
1676
+ dhs.resize(250); // 9+250 > 25
1677
+ EXPECT_TRUE(false && "dense_hash_map resize should have seen overflow");
1678
+ } catch (const STL_NAMESPACE::length_error&) {
1679
+ // Good, the operation failed.
1680
+ }
1681
+ try {
1682
+ shs.resize(250);
1683
+ EXPECT_TRUE(false && "sparse_hash_map resize should have seen overflow");
1684
+ } catch (const STL_NAMESPACE::length_error&) {
1685
+ // Good, the operation failed.
1686
+ }
1687
+ }
1688
+
1689
+ TEST(HashtableDeathTest, ResizeDeltaOverflow) {
1690
+ static const int kMax = 256;
1691
+ vector<int> test_data(kMax);
1692
+ for (int i = 0; i < kMax; ++i) {
1693
+ test_data[i] = i+1000;
1694
+ }
1695
+
1696
+ sparse_hash_set<int, Hasher, Hasher, Alloc<int, uint8, 255> > shs;
1697
+ dense_hash_set<int, Hasher, Hasher, Alloc<int, uint8, 255> > dhs;
1698
+ dhs.set_empty_key(-1);
1699
+ for (int i = 0; i < 9; i++) {
1700
+ dhs.insert(i);
1701
+ shs.insert(i);
1702
+ }
1703
+ try {
1704
+ dhs.insert(test_data.begin(), test_data.begin() + 250);
1705
+ EXPECT_TRUE(false && "dense_hash_map big insert should have overflowed");
1706
+ } catch (const STL_NAMESPACE::length_error&) {
1707
+ // Good, the operation failed.
1708
+ }
1709
+ try {
1710
+ shs.insert(test_data.begin(), test_data.begin() + 250);
1711
+ EXPECT_TRUE(false && "sparse_hash_map big insert should have overflowed");
1712
+ } catch (const STL_NAMESPACE::length_error&) {
1713
+ // Good, the operation failed.
1714
+ }
1715
+ }
1716
+
1717
+ // ------------------------------------------------------------------------
1718
+ // This informational "test" comes last so it's easy to see.
1719
+ // Also, benchmarks.
1720
+
1721
+ TYPED_TEST(HashtableAllTest, ClassSizes) {
1722
+ cout << "sizeof(" << typeid(TypeParam).name() << "): "
1723
+ << sizeof(this->ht_) << "\n";
1724
+ }
1725
+
1726
+ } // unnamed namespace
1727
+
1728
+ int main(int, char **) {
1729
+ // All the work is done in the static constructors. If they don't
1730
+ // die, the tests have all passed.
1731
+ cout << "PASS\n";
1732
+ return 0;
1733
+ }