google_hash 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }