google_hash 0.0.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 (85) hide show
  1. data/README +21 -0
  2. data/Rakefile +11 -0
  3. data/VERSION +1 -0
  4. data/ext/extconf.rb +15 -0
  5. data/ext/go.cpp +109 -0
  6. data/ext/sparsehash-1.5.2/AUTHORS +2 -0
  7. data/ext/sparsehash-1.5.2/COPYING +28 -0
  8. data/ext/sparsehash-1.5.2/ChangeLog +167 -0
  9. data/ext/sparsehash-1.5.2/INSTALL +236 -0
  10. data/ext/sparsehash-1.5.2/Makefile.am +157 -0
  11. data/ext/sparsehash-1.5.2/Makefile.in +1019 -0
  12. data/ext/sparsehash-1.5.2/NEWS +0 -0
  13. data/ext/sparsehash-1.5.2/README +149 -0
  14. data/ext/sparsehash-1.5.2/README.windows +25 -0
  15. data/ext/sparsehash-1.5.2/TODO +28 -0
  16. data/ext/sparsehash-1.5.2/aclocal.m4 +868 -0
  17. data/ext/sparsehash-1.5.2/compile +99 -0
  18. data/ext/sparsehash-1.5.2/config.guess +1516 -0
  19. data/ext/sparsehash-1.5.2/config.sub +1626 -0
  20. data/ext/sparsehash-1.5.2/configure +8054 -0
  21. data/ext/sparsehash-1.5.2/configure.ac +74 -0
  22. data/ext/sparsehash-1.5.2/depcomp +530 -0
  23. data/ext/sparsehash-1.5.2/doc/dense_hash_map.html +1591 -0
  24. data/ext/sparsehash-1.5.2/doc/dense_hash_set.html +1445 -0
  25. data/ext/sparsehash-1.5.2/doc/designstyle.css +115 -0
  26. data/ext/sparsehash-1.5.2/doc/implementation.html +365 -0
  27. data/ext/sparsehash-1.5.2/doc/index.html +69 -0
  28. data/ext/sparsehash-1.5.2/doc/performance.html +96 -0
  29. data/ext/sparsehash-1.5.2/doc/sparse_hash_map.html +1527 -0
  30. data/ext/sparsehash-1.5.2/doc/sparse_hash_set.html +1376 -0
  31. data/ext/sparsehash-1.5.2/doc/sparsetable.html +1393 -0
  32. data/ext/sparsehash-1.5.2/experimental/Makefile +9 -0
  33. data/ext/sparsehash-1.5.2/experimental/README +14 -0
  34. data/ext/sparsehash-1.5.2/experimental/example.c +54 -0
  35. data/ext/sparsehash-1.5.2/experimental/libchash.c +1537 -0
  36. data/ext/sparsehash-1.5.2/experimental/libchash.h +252 -0
  37. data/ext/sparsehash-1.5.2/google-sparsehash.sln +47 -0
  38. data/ext/sparsehash-1.5.2/install-sh +323 -0
  39. data/ext/sparsehash-1.5.2/m4/acx_pthread.m4 +363 -0
  40. data/ext/sparsehash-1.5.2/m4/google_namespace.m4 +42 -0
  41. data/ext/sparsehash-1.5.2/m4/namespaces.m4 +15 -0
  42. data/ext/sparsehash-1.5.2/m4/stl_hash.m4 +70 -0
  43. data/ext/sparsehash-1.5.2/m4/stl_hash_fun.m4 +36 -0
  44. data/ext/sparsehash-1.5.2/m4/stl_namespace.m4 +25 -0
  45. data/ext/sparsehash-1.5.2/missing +360 -0
  46. data/ext/sparsehash-1.5.2/mkinstalldirs +158 -0
  47. data/ext/sparsehash-1.5.2/packages/deb.sh +74 -0
  48. data/ext/sparsehash-1.5.2/packages/deb/README +7 -0
  49. data/ext/sparsehash-1.5.2/packages/deb/changelog +107 -0
  50. data/ext/sparsehash-1.5.2/packages/deb/compat +1 -0
  51. data/ext/sparsehash-1.5.2/packages/deb/control +17 -0
  52. data/ext/sparsehash-1.5.2/packages/deb/copyright +35 -0
  53. data/ext/sparsehash-1.5.2/packages/deb/docs +16 -0
  54. data/ext/sparsehash-1.5.2/packages/deb/rules +117 -0
  55. data/ext/sparsehash-1.5.2/packages/deb/sparsehash.dirs +2 -0
  56. data/ext/sparsehash-1.5.2/packages/deb/sparsehash.install +2 -0
  57. data/ext/sparsehash-1.5.2/packages/rpm.sh +86 -0
  58. data/ext/sparsehash-1.5.2/packages/rpm/rpm.spec +61 -0
  59. data/ext/sparsehash-1.5.2/src/config.h.in +131 -0
  60. data/ext/sparsehash-1.5.2/src/config.h.include +23 -0
  61. data/ext/sparsehash-1.5.2/src/google/dense_hash_map +310 -0
  62. data/ext/sparsehash-1.5.2/src/google/dense_hash_set +287 -0
  63. data/ext/sparsehash-1.5.2/src/google/sparse_hash_map +294 -0
  64. data/ext/sparsehash-1.5.2/src/google/sparse_hash_set +275 -0
  65. data/ext/sparsehash-1.5.2/src/google/sparsehash/densehashtable.h +1062 -0
  66. data/ext/sparsehash-1.5.2/src/google/sparsehash/sparsehashtable.h +1015 -0
  67. data/ext/sparsehash-1.5.2/src/google/sparsetable +1468 -0
  68. data/ext/sparsehash-1.5.2/src/google/type_traits.h +250 -0
  69. data/ext/sparsehash-1.5.2/src/hashtable_unittest.cc +1375 -0
  70. data/ext/sparsehash-1.5.2/src/simple_test.cc +103 -0
  71. data/ext/sparsehash-1.5.2/src/sparsetable_unittest.cc +696 -0
  72. data/ext/sparsehash-1.5.2/src/time_hash_map.cc +488 -0
  73. data/ext/sparsehash-1.5.2/src/type_traits_unittest.cc +492 -0
  74. data/ext/sparsehash-1.5.2/src/windows/config.h +149 -0
  75. data/ext/sparsehash-1.5.2/src/windows/google/sparsehash/sparseconfig.h +32 -0
  76. data/ext/sparsehash-1.5.2/src/windows/port.cc +63 -0
  77. data/ext/sparsehash-1.5.2/src/windows/port.h +81 -0
  78. data/ext/sparsehash-1.5.2/src/words +8944 -0
  79. data/ext/sparsehash-1.5.2/vsprojects/hashtable_unittest/hashtable_unittest.vcproj +187 -0
  80. data/ext/sparsehash-1.5.2/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +172 -0
  81. data/ext/sparsehash-1.5.2/vsprojects/time_hash_map/time_hash_map.vcproj +187 -0
  82. data/ext/sparsehash-1.5.2/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +169 -0
  83. data/ext/test.rb +10 -0
  84. data/test/spec.go +70 -0
  85. metadata +147 -0
@@ -0,0 +1,250 @@
1
+ // Copyright (c) 2006, 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: Matt Austern
32
+ //
33
+ // Define a small subset of tr1 type traits. The traits we define are:
34
+ // is_integral
35
+ // is_floating_point
36
+ // is_pointer
37
+ // is_reference
38
+ // is_pod
39
+ // has_trivial_constructor
40
+ // has_trivial_copy
41
+ // has_trivial_assign
42
+ // has_trivial_destructor
43
+ // remove_const
44
+ // remove_volatile
45
+ // remove_cv
46
+ // remove_reference
47
+ // remove_pointer
48
+ // is_convertible
49
+ // We can add more type traits as required.
50
+
51
+ #ifndef BASE_TYPE_TRAITS_H_
52
+ #define BASE_TYPE_TRAITS_H_
53
+
54
+ #include <google/sparsehash/sparseconfig.h>
55
+ #include <utility> // For pair
56
+
57
+ _START_GOOGLE_NAMESPACE_
58
+
59
+ // integral_constant, defined in tr1, is a wrapper for an integer
60
+ // value. We don't really need this generality; we could get away
61
+ // with hardcoding the integer type to bool. We use the fully
62
+ // general integer_constant for compatibility with tr1.
63
+
64
+ template<class T, T v>
65
+ struct integral_constant {
66
+ static const T value = v;
67
+ typedef T value_type;
68
+ typedef integral_constant<T, v> type;
69
+ };
70
+
71
+ template <class T, T v> const T integral_constant<T, v>::value;
72
+
73
+ // Abbreviations: true_type and false_type are structs that represent
74
+ // boolean true and false values.
75
+ typedef integral_constant<bool, true> true_type;
76
+ typedef integral_constant<bool, false> false_type;
77
+
78
+ // Types small_ and big_ are guaranteed such that sizeof(small_) <
79
+ // sizeof(big_)
80
+ typedef char small_;
81
+
82
+ struct big_ {
83
+ char dummy[2];
84
+ };
85
+
86
+ // is_integral is false except for the built-in integer types.
87
+ template <class T> struct is_integral : false_type { };
88
+ template<> struct is_integral<bool> : true_type { };
89
+ template<> struct is_integral<char> : true_type { };
90
+ template<> struct is_integral<unsigned char> : true_type { };
91
+ template<> struct is_integral<signed char> : true_type { };
92
+ #if defined(_MSC_VER)
93
+ // wchar_t is not by default a distinct type from unsigned short in
94
+ // Microsoft C.
95
+ // See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx
96
+ template<> struct is_integral<__wchar_t> : true_type { };
97
+ #else
98
+ template<> struct is_integral<wchar_t> : true_type { };
99
+ #endif
100
+ template<> struct is_integral<short> : true_type { };
101
+ template<> struct is_integral<unsigned short> : true_type { };
102
+ template<> struct is_integral<int> : true_type { };
103
+ template<> struct is_integral<unsigned int> : true_type { };
104
+ template<> struct is_integral<long> : true_type { };
105
+ template<> struct is_integral<unsigned long> : true_type { };
106
+ #ifdef HAVE_LONG_LONG
107
+ template<> struct is_integral<long long> : true_type { };
108
+ template<> struct is_integral<unsigned long long> : true_type { };
109
+ #endif
110
+
111
+
112
+ // is_floating_point is false except for the built-in floating-point types.
113
+ template <class T> struct is_floating_point : false_type { };
114
+ template<> struct is_floating_point<float> : true_type { };
115
+ template<> struct is_floating_point<double> : true_type { };
116
+ template<> struct is_floating_point<long double> : true_type { };
117
+
118
+
119
+ // is_pointer is false except for pointer types.
120
+ template <class T> struct is_pointer : false_type { };
121
+ template <class T> struct is_pointer<T*> : true_type { };
122
+
123
+
124
+ // is_reference is false except for reference types.
125
+ template<typename T> struct is_reference : false_type {};
126
+ template<typename T> struct is_reference<T&> : true_type {};
127
+
128
+
129
+ // We can't get is_pod right without compiler help, so fail conservatively.
130
+ // We will assume it's false except for arithmetic types and pointers,
131
+ // and const versions thereof. Note that std::pair is not a POD.
132
+ template <class T> struct is_pod
133
+ : integral_constant<bool, (is_integral<T>::value ||
134
+ is_floating_point<T>::value ||
135
+ is_pointer<T>::value)> { };
136
+ template <class T> struct is_pod<const T> : is_pod<T> { };
137
+
138
+
139
+ // We can't get has_trivial_constructor right without compiler help, so
140
+ // fail conservatively. We will assume it's false except for: (1) types
141
+ // for which is_pod is true. (2) std::pair of types with trivial
142
+ // constructors. (3) array of a type with a trivial constructor.
143
+ // (4) const versions thereof.
144
+ template <class T> struct has_trivial_constructor : is_pod<T> { };
145
+ template <class T, class U> struct has_trivial_constructor<std::pair<T, U> >
146
+ : integral_constant<bool,
147
+ (has_trivial_constructor<T>::value &&
148
+ has_trivial_constructor<U>::value)> { };
149
+ template <class A, int N> struct has_trivial_constructor<A[N]>
150
+ : has_trivial_constructor<A> { };
151
+ template <class T> struct has_trivial_constructor<const T>
152
+ : has_trivial_constructor<T> { };
153
+
154
+ // We can't get has_trivial_copy right without compiler help, so fail
155
+ // conservatively. We will assume it's false except for: (1) types
156
+ // for which is_pod is true. (2) std::pair of types with trivial copy
157
+ // constructors. (3) array of a type with a trivial copy constructor.
158
+ // (4) const versions thereof.
159
+ template <class T> struct has_trivial_copy : is_pod<T> { };
160
+ template <class T, class U> struct has_trivial_copy<std::pair<T, U> >
161
+ : integral_constant<bool,
162
+ (has_trivial_copy<T>::value &&
163
+ has_trivial_copy<U>::value)> { };
164
+ template <class A, int N> struct has_trivial_copy<A[N]>
165
+ : has_trivial_copy<A> { };
166
+ template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { };
167
+
168
+ // We can't get has_trivial_assign right without compiler help, so fail
169
+ // conservatively. We will assume it's false except for: (1) types
170
+ // for which is_pod is true. (2) std::pair of types with trivial copy
171
+ // constructors. (3) array of a type with a trivial assign constructor.
172
+ template <class T> struct has_trivial_assign : is_pod<T> { };
173
+ template <class T, class U> struct has_trivial_assign<std::pair<T, U> >
174
+ : integral_constant<bool,
175
+ (has_trivial_assign<T>::value &&
176
+ has_trivial_assign<U>::value)> { };
177
+ template <class A, int N> struct has_trivial_assign<A[N]>
178
+ : has_trivial_assign<A> { };
179
+
180
+ // We can't get has_trivial_destructor right without compiler help, so
181
+ // fail conservatively. We will assume it's false except for: (1) types
182
+ // for which is_pod is true. (2) std::pair of types with trivial
183
+ // destructors. (3) array of a type with a trivial destructor.
184
+ // (4) const versions thereof.
185
+ template <class T> struct has_trivial_destructor : is_pod<T> { };
186
+ template <class T, class U> struct has_trivial_destructor<std::pair<T, U> >
187
+ : integral_constant<bool,
188
+ (has_trivial_destructor<T>::value &&
189
+ has_trivial_destructor<U>::value)> { };
190
+ template <class A, int N> struct has_trivial_destructor<A[N]>
191
+ : has_trivial_destructor<A> { };
192
+ template <class T> struct has_trivial_destructor<const T>
193
+ : has_trivial_destructor<T> { };
194
+
195
+ // Specified by TR1 [4.7.1]
196
+ template<typename T> struct remove_const { typedef T type; };
197
+ template<typename T> struct remove_const<T const> { typedef T type; };
198
+ template<typename T> struct remove_volatile { typedef T type; };
199
+ template<typename T> struct remove_volatile<T volatile> { typedef T type; };
200
+ template<typename T> struct remove_cv {
201
+ typedef typename remove_const<typename remove_volatile<T>::type>::type type;
202
+ };
203
+
204
+
205
+ // Specified by TR1 [4.7.2]
206
+ template<typename T> struct remove_reference { typedef T type; };
207
+ template<typename T> struct remove_reference<T&> { typedef T type; };
208
+
209
+ // Specified by TR1 [4.7.4] Pointer modifications.
210
+ template<typename T> struct remove_pointer { typedef T type; };
211
+ template<typename T> struct remove_pointer<T*> { typedef T type; };
212
+ template<typename T> struct remove_pointer<T* const> { typedef T type; };
213
+ template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
214
+ template<typename T> struct remove_pointer<T* const volatile> {
215
+ typedef T type; };
216
+
217
+ // Specified by TR1 [4.6] Relationships between types
218
+ #ifndef _MSC_VER
219
+ namespace internal {
220
+
221
+ // This class is an implementation detail for is_convertible, and you
222
+ // don't need to know how it works to use is_convertible. For those
223
+ // who care: we declare two different functions, one whose argument is
224
+ // of type To and one with a variadic argument list. We give them
225
+ // return types of different size, so we can use sizeof to trick the
226
+ // compiler into telling us which function it would have chosen if we
227
+ // had called it with an argument of type From. See Alexandrescu's
228
+ // _Modern C++ Design_ for more details on this sort of trick.
229
+
230
+ template <typename From, typename To>
231
+ struct ConvertHelper {
232
+ static small_ Test(To);
233
+ static big_ Test(...);
234
+ static From Create();
235
+ };
236
+ } // namespace internal
237
+
238
+ // Inherits from true_type if From is convertible to To, false_type otherwise.
239
+ template <typename From, typename To>
240
+ struct is_convertible
241
+ : integral_constant<bool,
242
+ sizeof(internal::ConvertHelper<From, To>::Test(
243
+ internal::ConvertHelper<From, To>::Create()))
244
+ == sizeof(small_)> {
245
+ };
246
+ #endif
247
+
248
+ _END_GOOGLE_NAMESPACE_
249
+
250
+ #endif // BASE_TYPE_TRAITS_H_
@@ -0,0 +1,1375 @@
1
+ // Copyright (c) 2005, 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 <google/sparsehash/densehashtable.h>
34
+ // This tests <google/dense_hash_set>
35
+ // This tests <google/dense_hash_map>
36
+ // This tests <google/sparsehash/sparsehashtable.h>
37
+ // This tests <google/sparse_hash_set>
38
+ // This tests <google/sparse_hash_map>
39
+
40
+ // Since {dense,sparse}hashtable is templatized, it's important that
41
+ // we test every function in every class in this file -- not just to
42
+ // see if it works, but even if it compiles.
43
+
44
+ #include "config.h"
45
+ #include <stdio.h>
46
+ #include <sys/stat.h> // for stat()
47
+ #ifdef HAVE_UNISTD_H
48
+ #include <unistd.h> // for unlink()
49
+ #endif
50
+ #include <string.h>
51
+ #include <time.h> // for silly random-number-seed generator
52
+ #include <math.h> // for sqrt()
53
+ #include <map>
54
+ #include <set>
55
+ #include <iterator> // for insert_iterator
56
+ #include <iostream>
57
+ #include <iomanip> // for setprecision()
58
+ #include <string>
59
+ #include HASH_FUN_H // defined in config.h
60
+ #include <google/type_traits.h>
61
+ #include <google/dense_hash_map>
62
+ #include <google/dense_hash_set>
63
+ #include <google/sparsehash/densehashtable.h>
64
+ #include <google/sparse_hash_map>
65
+ #include <google/sparse_hash_set>
66
+ #include <google/sparsehash/sparsehashtable.h>
67
+
68
+ // Otherwise, VC++7 warns about size_t -> int in the cout logging lines
69
+ #ifdef _MSC_VER
70
+ #pragma warning(disable:4267)
71
+ #endif
72
+
73
+ using GOOGLE_NAMESPACE::sparse_hash_map;
74
+ using GOOGLE_NAMESPACE::dense_hash_map;
75
+ using GOOGLE_NAMESPACE::sparse_hash_set;
76
+ using GOOGLE_NAMESPACE::dense_hash_set;
77
+ using GOOGLE_NAMESPACE::sparse_hashtable;
78
+ using GOOGLE_NAMESPACE::dense_hashtable;
79
+ using STL_NAMESPACE::map;
80
+ using STL_NAMESPACE::set;
81
+ using STL_NAMESPACE::pair;
82
+ using STL_NAMESPACE::make_pair;
83
+ using STL_NAMESPACE::string;
84
+ using STL_NAMESPACE::insert_iterator;
85
+ using STL_NAMESPACE::allocator;
86
+ using STL_NAMESPACE::equal_to;
87
+ using STL_NAMESPACE::ostream;
88
+
89
+ #define LOGF STL_NAMESPACE::cout // where we log to; LOGF is a historical name
90
+
91
+ #define CHECK(cond) do { \
92
+ if (!(cond)) { \
93
+ LOGF << "Test failed: " #cond "\n"; \
94
+ exit(1); \
95
+ } \
96
+ } while (0)
97
+
98
+ #define CHECK_EQ(a, b) CHECK((a) == (b))
99
+ #define CHECK_LT(a, b) CHECK((a) < (b))
100
+ #define CHECK_GE(a, b) CHECK((a) >= (b))
101
+
102
+ #ifndef _MSC_VER
103
+ static string TmpFile(const char* basename) {
104
+ return string("/tmp/") + basename;
105
+ }
106
+ #endif
107
+
108
+ const char *words[] = {"Baffin\n", // in /usr/dict/words
109
+ "Boffin\n", // not in
110
+ "baffin\n", // not in
111
+ "genial\n", // last word in
112
+ "Aarhus\n", // first word alphabetically
113
+ "Zurich\n", // last word alphabetically
114
+ "Getty\n",
115
+ };
116
+
117
+ const char *nwords[] = {"Boffin\n",
118
+ "baffin\n",
119
+ };
120
+
121
+ const char *default_dict[] = {"Aarhus\n",
122
+ "aback\n",
123
+ "abandon\n",
124
+ "Baffin\n",
125
+ "baffle\n",
126
+ "bagged\n",
127
+ "congenial\n",
128
+ "genial\n",
129
+ "Getty\n",
130
+ "indiscreet\n",
131
+ "linens\n",
132
+ "pence\n",
133
+ "reassure\n",
134
+ "sequel\n",
135
+ "zoning\n",
136
+ "zoo\n",
137
+ "Zurich\n",
138
+ };
139
+
140
+ // Apparently identity is not stl-standard, so we define our own
141
+ template<class Value>
142
+ struct Identity {
143
+ Value& operator()(Value& v) const { return v; }
144
+ const Value& operator()(const Value& v) const { return v; }
145
+ };
146
+
147
+ // Likewise, it's not standard to hash a string pre-tr1. Luckily, it is a char*
148
+ #ifdef HAVE_UNORDERED_MAP
149
+ typedef SPARSEHASH_HASH<string> StrHash;
150
+ struct CharStarHash {
151
+ size_t operator()(const char* s) const {
152
+ return StrHash()(string(s));
153
+ }
154
+ };
155
+ #else
156
+ typedef SPARSEHASH_HASH<const char*> CharStarHash;
157
+ struct StrHash {
158
+ size_t operator()(const string& s) const {
159
+ return SPARSEHASH_HASH<const char*>()(s.c_str());
160
+ }
161
+ };
162
+ #endif
163
+
164
+ // Let us log the pairs that make up a hash_map
165
+ template<class P1, class P2>
166
+ ostream& operator<<(ostream& s, const pair<P1, P2>& p) {
167
+ s << "pair(" << p.first << ", " << p.second << ")";
168
+ return s;
169
+ }
170
+
171
+ struct strcmp_fnc {
172
+ bool operator()(const char* s1, const char* s2) const {
173
+ return ((s1 == 0 && s2 == 0) ||
174
+ (s1 && s2 && *s1 == *s2 && strcmp(s1, s2) == 0));
175
+ }
176
+ };
177
+
178
+ namespace {
179
+
180
+ template <class T, class H, class I, class S, class C, class A>
181
+ void set_empty_key(sparse_hashtable<T,T,H,I,S,C,A> *ht, T val) {
182
+ }
183
+
184
+ template <class T, class H, class C>
185
+ void set_empty_key(sparse_hash_set<T,H,C> *ht, T val) {
186
+ }
187
+
188
+ template <class K, class V, class H, class C>
189
+ void set_empty_key(sparse_hash_map<K,V,H,C> *ht, K val) {
190
+ }
191
+
192
+ template <class T, class H, class I, class S, class C, class A>
193
+ void set_empty_key(dense_hashtable<T,T,H,I,S,C,A> *ht, T val) {
194
+ ht->set_empty_key(val);
195
+ }
196
+
197
+ template <class T, class H, class C>
198
+ void set_empty_key(dense_hash_set<T,H,C> *ht, T val) {
199
+ ht->set_empty_key(val);
200
+ }
201
+
202
+ template <class K, class V, class H, class C>
203
+ void set_empty_key(dense_hash_map<K,V,H,C> *ht, K val) {
204
+ ht->set_empty_key(val);
205
+ }
206
+
207
+ template <class T, class H, class I, class S, class C, class A>
208
+ bool clear_no_resize(sparse_hashtable<T,T,H,I,S,C,A> *ht) {
209
+ return false;
210
+ }
211
+
212
+ template <class T, class H, class C>
213
+ bool clear_no_resize(sparse_hash_set<T,H,C> *ht) {
214
+ return false;
215
+ }
216
+
217
+ template <class K, class V, class H, class C>
218
+ bool clear_no_resize(sparse_hash_map<K,V,H,C> *ht) {
219
+ return false;
220
+ }
221
+
222
+ template <class T, class H, class I, class S, class C, class A>
223
+ bool clear_no_resize(dense_hashtable<T,T,H,I,S,C,A> *ht) {
224
+ ht->clear_no_resize();
225
+ return true;
226
+ }
227
+
228
+ template <class T, class H, class C>
229
+ bool clear_no_resize(dense_hash_set<T,H,C> *ht) {
230
+ ht->clear_no_resize();
231
+ return true;
232
+ }
233
+
234
+ template <class K, class V, class H, class C>
235
+ bool clear_no_resize(dense_hash_map<K,V,H,C> *ht) {
236
+ ht->clear_no_resize();
237
+ return true;
238
+ }
239
+
240
+ template <class T, class H, class I, class S, class C, class A>
241
+ void insert(dense_hashtable<T,T,H,I,S,C,A> *ht, T val) {
242
+ ht->insert(val);
243
+ }
244
+
245
+ template <class T, class H, class C>
246
+ void insert(dense_hash_set<T,H,C> *ht, T val) {
247
+ ht->insert(val);
248
+ }
249
+
250
+ template <class K, class V, class H, class C>
251
+ void insert(dense_hash_map<K,V,H,C> *ht, K val) {
252
+ ht->insert(pair<K,V>(val,V()));
253
+ }
254
+
255
+ template <class T, class H, class I, class S, class C, class A>
256
+ void insert(sparse_hashtable<T,T,H,I,S,C,A> *ht, T val) {
257
+ ht->insert(val);
258
+ }
259
+
260
+ template <class T, class H, class C>
261
+ void insert(sparse_hash_set<T,H,C> *ht, T val) {
262
+ ht->insert(val);
263
+ }
264
+
265
+ template <class K, class V, class H, class C>
266
+ void insert(sparse_hash_map<K,V,H,C> *ht, K val) {
267
+ ht->insert(pair<K,V>(val,V()));
268
+ }
269
+
270
+ template <class HT, class Iterator>
271
+ void insert(HT *ht, Iterator begin, Iterator end) {
272
+ ht->insert(begin, end);
273
+ }
274
+
275
+ // For hashtable's and hash_set's, the iterator insert works fine (and
276
+ // is used). But for the hash_map's, the iterator insert expects the
277
+ // iterators to point to pair's. So by looping over and calling insert
278
+ // on each element individually, the code below automatically expands
279
+ // into inserting a pair.
280
+ template <class K, class V, class H, class C, class Iterator>
281
+ void insert(dense_hash_map<K,V,H,C> *ht, Iterator begin, Iterator end) {
282
+ while (begin != end) {
283
+ insert(ht, *begin);
284
+ ++begin;
285
+ }
286
+ }
287
+
288
+ template <class K, class V, class H, class C, class Iterator>
289
+ void insert(sparse_hash_map<K,V,H,C> *ht, Iterator begin, Iterator end) {
290
+ while (begin != end) {
291
+ insert(ht, *begin);
292
+ ++begin;
293
+ }
294
+ }
295
+
296
+ // A version of insert that uses the insert_iterator. But insert_iterator
297
+ // isn't defined for the low level hashtable classes, so we just punt to insert.
298
+
299
+ template <class T, class H, class I, class S, class C, class A>
300
+ void iterator_insert(dense_hashtable<T,T,H,I,S,C,A>* ht, T val,
301
+ insert_iterator<dense_hashtable<T,T,H,I,S,C,A> >* ) {
302
+ ht->insert(val);
303
+ }
304
+
305
+ template <class T, class H, class C>
306
+ void iterator_insert(dense_hash_set<T,H,C>* , T val,
307
+ insert_iterator<dense_hash_set<T,H,C> >* ii) {
308
+ *(*ii)++ = val;
309
+ }
310
+
311
+ template <class K, class V, class H, class C>
312
+ void iterator_insert(dense_hash_map<K,V,H,C>* , K val,
313
+ insert_iterator<dense_hash_map<K,V,H,C> >* ii) {
314
+ *(*ii)++ = pair<K,V>(val,V());
315
+ }
316
+
317
+ template <class T, class H, class I, class S, class C, class A>
318
+ void iterator_insert(sparse_hashtable<T,T,H,I,S,C,A>* ht, T val,
319
+ insert_iterator<sparse_hashtable<T,T,H,I,S,C,A> >* ) {
320
+ ht->insert(val);
321
+ }
322
+
323
+ template <class T, class H, class C>
324
+ void iterator_insert(sparse_hash_set<T,H,C>* , T val,
325
+ insert_iterator<sparse_hash_set<T,H,C> >* ii) {
326
+ *(*ii)++ = val;
327
+ }
328
+
329
+ template <class K, class V, class H, class C>
330
+ void iterator_insert(sparse_hash_map<K,V,H,C> *, K val,
331
+ insert_iterator<sparse_hash_map<K,V,H,C> >* ii) {
332
+ *(*ii)++ = pair<K,V>(val,V());
333
+ }
334
+
335
+
336
+ void write_item(FILE *fp, const char *val) {
337
+ fwrite(val, strlen(val), 1, fp); // \n serves to separate
338
+ }
339
+
340
+ // The weird 'const' declarations are desired by the compiler. Yucko.
341
+ void write_item(FILE *fp, const pair<char*const,int> &val) {
342
+ fwrite(val.first, strlen(val.first), 1, fp);
343
+ }
344
+
345
+ void write_item(FILE *fp, const string &val) {
346
+ fwrite(val.data(), val.length(), 1, fp); // \n serves to separate
347
+ }
348
+
349
+ // The weird 'const' declarations are desired by the compiler. Yucko.
350
+ void write_item(FILE *fp, const pair<const string,int> &val) {
351
+ fwrite(val.first.data(), val.first.length(), 1, fp);
352
+ }
353
+
354
+ char* read_line(FILE* fp, char* line, int linesize) {
355
+ if ( fgets(line, linesize, fp) == NULL )
356
+ return NULL;
357
+ // normalize windows files :-(
358
+ const size_t linelen = strlen(line);
359
+ if ( linelen >= 2 && line[linelen-2] == '\r' && line[linelen-1] == '\n' ) {
360
+ line[linelen-2] = '\n';
361
+ line[linelen-1] = '\0';
362
+ }
363
+ return line;
364
+ }
365
+
366
+ void read_item(FILE *fp, char*const* val) {
367
+ char line[1024];
368
+ read_line(fp, line, sizeof(line));
369
+ char **p = const_cast<char**>(val);
370
+ *p = strdup(line);
371
+ }
372
+
373
+ void read_item(FILE *fp, pair<char*const,int> *val) {
374
+ char line[1024];
375
+ read_line(fp, line, sizeof(line));
376
+ char **p = const_cast<char**>(&val->first);
377
+ *p = strdup(line);
378
+ }
379
+
380
+ void read_item(FILE *fp, const string* val) {
381
+ char line[1024];
382
+ read_line(fp, line, sizeof(line));
383
+ new(const_cast<string*>(val)) string(line); // need to use placement new
384
+ }
385
+
386
+ void read_item(FILE *fp, pair<const string,int> *val) {
387
+ char line[1024];
388
+ read_line(fp, line, sizeof(line));
389
+ new(const_cast<string*>(&val->first)) string(line);
390
+ }
391
+
392
+ void free_item(char*const* val) {
393
+ free(*val);
394
+ }
395
+
396
+ void free_item(pair<char*const,int> *val) {
397
+ free(val->first);
398
+ }
399
+
400
+ int get_int_item(int int_item) {
401
+ return int_item;
402
+ }
403
+
404
+ int get_int_item(pair<int, int> val) {
405
+ return val.first;
406
+ }
407
+
408
+ int getintkey(int i) { return i; }
409
+
410
+ int getintkey(const pair<int, int> &p) { return p.first; }
411
+
412
+ } // end anonymous namespace
413
+
414
+ // Performs tests where the hashtable's value type is assumed to be int.
415
+ template <class htint>
416
+ void test_int() {
417
+ htint x;
418
+ htint y(1000);
419
+ htint z(64);
420
+ set_empty_key(&x, 0xefefef);
421
+ set_empty_key(&y, 0xefefef);
422
+ set_empty_key(&z, 0xefefef);
423
+
424
+ CHECK(y.empty());
425
+ insert(&y, 1);
426
+ CHECK(!y.empty());
427
+ insert(&y, 11);
428
+ insert(&y, 111);
429
+ insert(&y, 1111);
430
+ insert(&y, 11111);
431
+ insert(&y, 111111);
432
+ insert(&y, 1111111); // 1M, more or less
433
+ insert(&y, 11111111);
434
+ insert(&y, 111111111);
435
+ insert(&y, 1111111111); // 1B, more or less
436
+ for ( int i = 0; i < 64; ++i )
437
+ insert(&z, i);
438
+ // test the second half of the insert with an insert_iterator
439
+ insert_iterator<htint> insert_iter(z, z.begin());
440
+ for ( int i = 32; i < 64; ++i )
441
+ iterator_insert(&z, i, &insert_iter);
442
+
443
+ // only perform the following CHECKs for
444
+ // dense{hashtable, _hash_set, _hash_map}
445
+ if (clear_no_resize(&x)) {
446
+ // make sure x has to increase its number of buckets
447
+ typename htint::size_type empty_bucket_count = x.bucket_count();
448
+ int last_element = 0;
449
+ while (x.bucket_count() == empty_bucket_count) {
450
+ insert(&x, last_element);
451
+ ++last_element;
452
+ }
453
+ // if clear_no_resize is supported (i.e. htint is a
454
+ // dense{hashtable,_hash_set,_hash_map}), it should leave the bucket_count
455
+ // as is.
456
+ typename htint::size_type last_bucket_count = x.bucket_count();
457
+ clear_no_resize(&x);
458
+ CHECK(last_bucket_count == x.bucket_count());
459
+ CHECK(x.empty());
460
+ LOGF << "x has " << x.bucket_count() << " buckets\n";
461
+ LOGF << "x size " << x.size() << "\n";
462
+ // when inserting the same number of elements again, no resize should be
463
+ // necessary
464
+ for (int i = 0; i < last_element; ++i) {
465
+ insert(&x, i);
466
+ CHECK(x.bucket_count() == last_bucket_count);
467
+ }
468
+ }
469
+
470
+ for ( typename htint::const_iterator it = y.begin(); it != y.end(); ++it )
471
+ LOGF << "y: " << get_int_item(*it) << "\n";
472
+ z.insert(y.begin(), y.end());
473
+ swap(y,z);
474
+ for ( typename htint::iterator it = y.begin(); it != y.end(); ++it )
475
+ LOGF << "y+z: " << get_int_item(*it) << "\n";
476
+ LOGF << "z has " << z.bucket_count() << " buckets\n";
477
+ LOGF << "y has " << y.bucket_count() << " buckets\n";
478
+ LOGF << "z size: " << z.size() << "\n";
479
+
480
+ for (int i = 0; i < 64; ++i)
481
+ CHECK(y.find(i) != y.end());
482
+
483
+ CHECK(z.size() == 10);
484
+ z.set_deleted_key(1010101010); // an unused value
485
+ z.erase(11111);
486
+ CHECK(z.size() == 9);
487
+ insert(&z, 11111); // should retake deleted value
488
+ CHECK(z.size() == 10);
489
+ // Do the delete/insert again. Last time we probably resized; this time no
490
+ z.erase(11111);
491
+ insert(&z, 11111); // should retake deleted value
492
+ CHECK(z.size() == 10);
493
+
494
+ z.erase(-11111); // shouldn't do anything
495
+ CHECK(z.size() == 10);
496
+ z.erase(1);
497
+ CHECK(z.size() == 9);
498
+
499
+ typename htint::iterator itdel = z.find(1111);
500
+ pair<typename htint::iterator,typename htint::iterator> itdel2
501
+ = z.equal_range(1111);
502
+ CHECK(itdel2.first != z.end());
503
+ CHECK(&*itdel2.first == &*itdel); // while we're here, check equal_range()
504
+ CHECK(itdel2.second == ++itdel2.first);
505
+ pair<typename htint::const_iterator,typename htint::const_iterator> itdel3
506
+ = const_cast<const htint*>(&z)->equal_range(1111);
507
+ CHECK(itdel3.first != z.end());
508
+ CHECK(&*itdel3.first == &*itdel);
509
+ CHECK(itdel3.second == ++itdel3.first);
510
+
511
+ z.erase(itdel);
512
+ CHECK(z.size() == 8);
513
+ itdel2 = z.equal_range(1111);
514
+ CHECK(itdel2.first == z.end());
515
+ CHECK(itdel2.second == itdel2.first);
516
+ itdel3 = const_cast<const htint*>(&z)->equal_range(1111);
517
+ CHECK(itdel3.first == z.end());
518
+ CHECK(itdel3.second == itdel3.first);
519
+
520
+ itdel = z.find(2222); // should be end()
521
+ z.erase(itdel); // shouldn't do anything
522
+ CHECK(z.size() == 8);
523
+ for ( typename htint::const_iterator it = z.begin(); it != z.end(); ++it )
524
+ LOGF << "y: " << get_int_item(*it) << "\n";
525
+ z.set_deleted_key(1010101011); // a different unused value
526
+ for ( typename htint::const_iterator it = z.begin(); it != z.end(); ++it )
527
+ LOGF << "y: " << get_int_item(*it) << "\n";
528
+ LOGF << "That's " << z.size() << " elements\n";
529
+ z.erase(z.begin(), z.end());
530
+ CHECK(z.empty());
531
+
532
+ y.clear();
533
+ CHECK(y.empty());
534
+ LOGF << "y has " << y.bucket_count() << " buckets\n";
535
+ }
536
+
537
+ // Performs tests where the hashtable's value type is assumed to be char*.
538
+ // The read_write parameters specifies whether the read/write tests
539
+ // should be performed. Note that densehashtable::write_metdata is not
540
+ // implemented, so we only do the read/write tests for the
541
+ // sparsehashtable varieties.
542
+ template <class ht>
543
+ void test_charptr(bool read_write) {
544
+ ht w;
545
+ set_empty_key(&w, (char*) NULL);
546
+ insert(&w, const_cast<char **>(nwords),
547
+ const_cast<char **>(nwords) + sizeof(nwords) / sizeof(*nwords));
548
+ LOGF << "w has " << w.size() << " items\n";
549
+ CHECK(w.size() == 2);
550
+ CHECK(w == w);
551
+
552
+ ht x;
553
+ set_empty_key(&x, (char*) NULL);
554
+ long dict_size = 1; // for size stats -- can't be 0 'cause of division
555
+
556
+ map<string, int> counts;
557
+ // Hash the dictionary
558
+ {
559
+ // automake says 'look for all data files in $srcdir.' OK.
560
+ string filestr = (string(getenv("srcdir") ? getenv("srcdir") : ".") +
561
+ "/src/words");
562
+ const char* file = filestr.c_str();
563
+ FILE *fp = fopen(file, "rb");
564
+ if ( fp == NULL ) {
565
+ LOGF << "Can't open " << file << ", using small, built-in dict...\n";
566
+ for (int i = 0; i < sizeof(default_dict)/sizeof(*default_dict); ++i) {
567
+ insert(&x, strdup(default_dict[i]));
568
+ counts[default_dict[i]] = 0;
569
+ }
570
+ } else {
571
+ char line[1024];
572
+ while ( read_line(fp, line, sizeof(line)) ) {
573
+ insert(&x, strdup(line));
574
+ counts[line] = 0;
575
+ }
576
+ LOGF << "Read " << x.size() << " words from " << file << "\n";
577
+ fclose(fp);
578
+ struct stat buf;
579
+ stat(file, &buf);
580
+ dict_size = buf.st_size;
581
+ LOGF << "Size of " << file << ": " << buf.st_size << " bytes\n";
582
+ }
583
+ for (char **word = const_cast<char **>(words);
584
+ word < const_cast<char **>(words) + sizeof(words) / sizeof(*words);
585
+ ++word ) {
586
+ if (x.find(*word) == x.end()) {
587
+ CHECK(w.find(*word) != w.end());
588
+ } else {
589
+ CHECK(w.find(*word) == w.end());
590
+ }
591
+ }
592
+ }
593
+ CHECK(counts.size() == x.size());
594
+
595
+ // Save the hashtable.
596
+ if (read_write) {
597
+ const string file_string = TmpFile("#hashtable_unittest_dicthash");
598
+ const char* file = file_string.c_str();
599
+ FILE *fp = fopen(file, "wb");
600
+ if ( fp == NULL ) {
601
+ // maybe we can't write to /tmp/. Try the current directory
602
+ file = "#hashtable_unittest_dicthash";
603
+ fp = fopen(file, "wb");
604
+ }
605
+ if ( fp == NULL ) {
606
+ LOGF << "Can't open " << file << " skipping hashtable save...\n";
607
+ } else {
608
+ x.write_metadata(fp); // this only writes meta-information
609
+ int write_count = 0;
610
+ for ( typename ht::iterator it = x.begin(); it != x.end(); ++it ) {
611
+ write_item(fp, *it);
612
+ free_item(&(*it));
613
+ ++write_count;
614
+ }
615
+ LOGF << "Wrote " << write_count << " words to " << file << "\n";
616
+ fclose(fp);
617
+ struct stat buf;
618
+ stat(file, &buf);
619
+ LOGF << "Size of " << file << ": " << buf.st_size << " bytes\n";
620
+ LOGF << STL_NAMESPACE::setprecision(3)
621
+ << "Hashtable overhead "
622
+ << (buf.st_size - dict_size) * 100.0 / dict_size
623
+ << "% ("
624
+ << (buf.st_size - dict_size) * 8.0 / write_count
625
+ << " bits/entry)\n";
626
+ x.clear();
627
+
628
+ // Load the hashtable
629
+ fp = fopen(file, "rb");
630
+ if ( fp == NULL ) {
631
+ LOGF << "Can't open " << file << " skipping hashtable reload...\n";
632
+ } else {
633
+ x.read_metadata(fp); // reads metainformation
634
+ LOGF << "Hashtable size: " << x.size() << "\n";
635
+ int read_count = 0;
636
+ for ( typename ht::iterator it = x.begin(); it != x.end(); ++it ) {
637
+ read_item(fp, &(*it));
638
+ ++read_count;
639
+ }
640
+ LOGF << "Read " << read_count << " words from " << file << "\n";
641
+ fclose(fp);
642
+ unlink(file);
643
+ for ( char **word = const_cast<char **>(words);
644
+ word < const_cast<char **>(words) + sizeof(words) / sizeof(*words);
645
+ ++word ) {
646
+ if (x.find(*word) == x.end()) {
647
+ CHECK(w.find(*word) != w.end());
648
+ } else {
649
+ CHECK(w.find(*word) == w.end());
650
+ }
651
+ }
652
+ }
653
+ }
654
+ }
655
+ for ( typename ht::iterator it = x.begin(); it != x.end(); ++it ) {
656
+ free_item(&(*it));
657
+ }
658
+ }
659
+
660
+ // Perform tests where the hashtable's value type is assumed to
661
+ // be string.
662
+ // TODO(austern): factor out the bulk of test_charptr and test_string
663
+ // into a common function.
664
+ template <class ht>
665
+ void test_string(bool read_write) {
666
+ ht w;
667
+ set_empty_key(&w, string("-*- empty key -*-"));
668
+ const int N = sizeof(nwords) / sizeof(*nwords);
669
+ string* nwords1 = new string[N];
670
+ for (int i = 0; i < N; ++i)
671
+ nwords1[i] = nwords[i];
672
+ insert(&w, nwords1, nwords1 + N);
673
+ delete[] nwords1;
674
+ LOGF << "w has " << w.size() << " items\n";
675
+ CHECK(w.size() == 2);
676
+ CHECK(w == w);
677
+
678
+ ht x;
679
+ set_empty_key(&x, string("-*- empty key -*-"));
680
+ long dict_size = 1; // for size stats -- can't be 0 'cause of division
681
+
682
+ map<string, int> counts;
683
+ // Hash the dictionary
684
+ {
685
+ // automake says 'look for all data files in $srcdir.' OK.
686
+ string filestr = (string(getenv("srcdir") ? getenv("srcdir") : ".") +
687
+ "/src/words");
688
+ const char* file = filestr.c_str();
689
+ FILE *fp = fopen(file, "rb");
690
+ if ( fp == NULL ) {
691
+ LOGF << "Can't open " << file << ", using small, built-in dict...\n";
692
+ for (int i = 0; i < sizeof(default_dict)/sizeof(*default_dict); ++i) {
693
+ insert(&x, string(default_dict[i]));
694
+ counts[default_dict[i]] = 0;
695
+ }
696
+ } else {
697
+ char line[1024];
698
+ while ( fgets(line, sizeof(line), fp) ) {
699
+ insert(&x, string(line));
700
+ counts[line] = 0;
701
+ }
702
+ LOGF << "Read " << x.size() << " words from " << file << "\n";
703
+ fclose(fp);
704
+ struct stat buf;
705
+ stat(file, &buf);
706
+ dict_size = buf.st_size;
707
+ LOGF << "Size of " << file << ": " << buf.st_size << " bytes\n";
708
+ }
709
+ for ( const char* const* word = words;
710
+ word < words + sizeof(words) / sizeof(*words);
711
+ ++word ) {
712
+ if (x.find(*word) == x.end()) {
713
+ CHECK(w.find(*word) != w.end());
714
+ } else {
715
+ CHECK(w.find(*word) == w.end());
716
+ }
717
+ }
718
+ }
719
+ CHECK(counts.size() == x.size());
720
+ {
721
+ // verify that size() works correctly
722
+ int xcount = 0;
723
+ for ( typename ht::iterator it = x.begin(); it != x.end(); ++it ) {
724
+ ++xcount;
725
+ }
726
+ CHECK(x.size() == xcount);
727
+ }
728
+
729
+ // Save the hashtable.
730
+ if (read_write) {
731
+ const string file_string = TmpFile("#hashtable_unittest_dicthash_str");
732
+ const char* file = file_string.c_str();
733
+ FILE *fp = fopen(file, "wb");
734
+ if ( fp == NULL ) {
735
+ // maybe we can't write to /tmp/. Try the current directory
736
+ file = "#hashtable_unittest_dicthash_str";
737
+ fp = fopen(file, "wb");
738
+ }
739
+ if ( fp == NULL ) {
740
+ LOGF << "Can't open " << file << " skipping hashtable save...\n";
741
+ } else {
742
+ x.write_metadata(fp); // this only writes meta-information
743
+ int write_count = 0;
744
+ for ( typename ht::iterator it = x.begin(); it != x.end(); ++it ) {
745
+ write_item(fp, *it);
746
+ ++write_count;
747
+ }
748
+ LOGF << "Wrote " << write_count << " words to " << file << "\n";
749
+ fclose(fp);
750
+ struct stat buf;
751
+ stat(file, &buf);
752
+ LOGF << "Size of " << file << ": " << buf.st_size << " bytes\n";
753
+ LOGF << STL_NAMESPACE::setprecision(3)
754
+ << "Hashtable overhead "
755
+ << (buf.st_size - dict_size) * 100.0 / dict_size
756
+ << "% ("
757
+ << (buf.st_size - dict_size) * 8.0 / write_count
758
+ << " bits/entry)\n";
759
+ x.clear();
760
+
761
+ // Load the hashtable
762
+ fp = fopen(file, "rb");
763
+ if ( fp == NULL ) {
764
+ LOGF << "Can't open " << file << " skipping hashtable reload...\n";
765
+ } else {
766
+ x.read_metadata(fp); // reads metainformation
767
+ LOGF << "Hashtable size: " << x.size() << "\n";
768
+ int count = 0;
769
+ for ( typename ht::iterator it = x.begin(); it != x.end(); ++it ) {
770
+ read_item(fp, &(*it));
771
+ ++count;
772
+ }
773
+ LOGF << "Read " << count << " words from " << file << "\n";
774
+ fclose(fp);
775
+ unlink(file);
776
+ for ( const char* const* word = words;
777
+ word < words + sizeof(words) / sizeof(*words);
778
+ ++word ) {
779
+ if (x.find(*word) == x.end()) {
780
+ CHECK(w.find(*word) != w.end());
781
+ } else {
782
+ CHECK(w.find(*word) == w.end());
783
+ }
784
+ }
785
+ }
786
+ }
787
+ }
788
+
789
+ // ensure that destruction is done properly in clear_no_resize()
790
+ if (!clear_no_resize(&w)) w.clear();
791
+ }
792
+
793
+ // The read_write parameters specifies whether the read/write tests
794
+ // should be performed. Note that densehashtable::write_metdata is not
795
+ // implemented, so we only do the read/write tests for the
796
+ // sparsehashtable varieties.
797
+ template<class ht, class htstr, class htint>
798
+ void test(bool read_write) {
799
+ test_int<htint>();
800
+ test_string<htstr>(read_write);
801
+ test_charptr<ht>(read_write);
802
+ }
803
+
804
+ // For data types with trivial copy-constructors and destructors, we
805
+ // should use an optimized routine for data-copying, that involves
806
+ // memmove. We test this by keeping count of how many times the
807
+ // copy-constructor is called; it should be much less with the
808
+ // optimized code.
809
+
810
+ class Memmove {
811
+ public:
812
+ Memmove(): i_(0) {}
813
+ explicit Memmove(int i): i_(i) {}
814
+ Memmove(const Memmove& that) {
815
+ this->i_ = that.i_;
816
+ num_copies_++;
817
+ }
818
+
819
+ int i_;
820
+ static int num_copies_;
821
+ };
822
+ int Memmove::num_copies_ = 0;
823
+
824
+
825
+ // This is what tells the hashtable code it can use memmove for this class:
826
+ _START_GOOGLE_NAMESPACE_
827
+ template<> struct has_trivial_copy<Memmove> : true_type { };
828
+ template<> struct has_trivial_destructor<Memmove> : true_type { };
829
+ _END_GOOGLE_NAMESPACE_
830
+
831
+ class NoMemmove {
832
+ public:
833
+ NoMemmove(): i_(0) {}
834
+ explicit NoMemmove(int i): i_(i) {}
835
+ NoMemmove(const NoMemmove& that) {
836
+ this->i_ = that.i_;
837
+ num_copies_++;
838
+ }
839
+
840
+ int i_;
841
+ static int num_copies_;
842
+ };
843
+ int NoMemmove::num_copies_ = 0;
844
+
845
+ void TestSimpleDataTypeOptimizations() {
846
+ {
847
+ sparse_hash_map<int, Memmove> memmove;
848
+ sparse_hash_map<int, NoMemmove> nomemmove;
849
+
850
+ Memmove::num_copies_ = 0; // reset
851
+ NoMemmove::num_copies_ = 0; // reset
852
+ for (int i = 10000; i > 0; i--) {
853
+ memmove[i] = Memmove(i);
854
+ }
855
+ for (int i = 10000; i > 0; i--) {
856
+ nomemmove[i] = NoMemmove(i);
857
+ }
858
+ LOGF << "sparse_hash_map copies for unoptimized/optimized cases: "
859
+ << NoMemmove::num_copies_ << "/" << Memmove::num_copies_ << "\n";
860
+ CHECK(NoMemmove::num_copies_ > Memmove::num_copies_);
861
+ }
862
+ // Same should hold true for dense_hash_map
863
+ {
864
+ dense_hash_map<int, Memmove> memmove;
865
+ dense_hash_map<int, NoMemmove> nomemmove;
866
+ memmove.set_empty_key(0);
867
+ nomemmove.set_empty_key(0);
868
+
869
+ Memmove::num_copies_ = 0; // reset
870
+ NoMemmove::num_copies_ = 0; // reset
871
+ for (int i = 10000; i > 0; i--) {
872
+ memmove[i] = Memmove(i);
873
+ }
874
+ for (int i = 10000; i > 0; i--) {
875
+ nomemmove[i] = NoMemmove(i);
876
+ }
877
+ LOGF << "dense_hash_map copies for unoptimized/optimized cases: "
878
+ << NoMemmove::num_copies_ << "/" << Memmove::num_copies_ << "\n";
879
+ CHECK(NoMemmove::num_copies_ > Memmove::num_copies_);
880
+ }
881
+ }
882
+
883
+ void TestShrinking() {
884
+ // We want to make sure that when we create a hashtable, and then
885
+ // add and delete one element, the size of the hashtable doesn't
886
+ // change.
887
+ {
888
+ sparse_hash_set<int> s;
889
+ s.set_deleted_key(0);
890
+ const int old_bucket_count = s.bucket_count();
891
+ s.insert(4);
892
+ s.erase(4);
893
+ s.insert(4);
894
+ s.erase(4);
895
+ CHECK_EQ(old_bucket_count, s.bucket_count());
896
+ }
897
+ {
898
+ dense_hash_set<int> s;
899
+ s.set_deleted_key(0);
900
+ s.set_empty_key(1);
901
+ const int old_bucket_count = s.bucket_count();
902
+ s.insert(4);
903
+ s.erase(4);
904
+ s.insert(4);
905
+ s.erase(4);
906
+ CHECK_EQ(old_bucket_count, s.bucket_count());
907
+ }
908
+ {
909
+ sparse_hash_set<int> s(2); // start small: only expects 2 items
910
+ CHECK_LT(s.bucket_count(), 32); // verify we actually do start small
911
+ s.set_deleted_key(0);
912
+ const int old_bucket_count = s.bucket_count();
913
+ s.insert(4);
914
+ s.erase(4);
915
+ s.insert(4);
916
+ s.erase(4);
917
+ CHECK_EQ(old_bucket_count, s.bucket_count());
918
+ }
919
+ {
920
+ dense_hash_set<int> s(2); // start small: only expects 2 items
921
+ CHECK_LT(s.bucket_count(), 32); // verify we actually do start small
922
+ s.set_deleted_key(0);
923
+ s.set_empty_key(1);
924
+ const int old_bucket_count = s.bucket_count();
925
+ s.insert(4);
926
+ s.erase(4);
927
+ s.insert(4);
928
+ s.erase(4);
929
+ CHECK_EQ(old_bucket_count, s.bucket_count());
930
+ }
931
+ }
932
+
933
+ class TestHashFcn : public SPARSEHASH_HASH<int> {
934
+ public:
935
+ explicit TestHashFcn(int i)
936
+ : id_(i) {
937
+ }
938
+
939
+ int id() const {
940
+ return id_;
941
+ }
942
+
943
+ private:
944
+ int id_;
945
+ };
946
+
947
+ class TestEqualTo : public equal_to<int> {
948
+ public:
949
+ explicit TestEqualTo(int i)
950
+ : id_(i) {
951
+ }
952
+
953
+ int id() const {
954
+ return id_;
955
+ }
956
+
957
+ private:
958
+ int id_;
959
+ };
960
+
961
+ template <template <class V, class H, class E, class A> class Hash>
962
+ void TestHash() {
963
+ typedef Hash<int, TestHashFcn, TestEqualTo, allocator<int> > TheHash;
964
+ const TestHashFcn fcn(1);
965
+ const TestEqualTo eqt(2);
966
+ {
967
+ const TheHash simple(0, fcn, eqt);
968
+ CHECK(fcn.id() == simple.hash_funct().id());
969
+ CHECK(eqt.id() == simple.key_eq().id());
970
+ }
971
+ {
972
+ const set<int> input;
973
+ const TheHash iterated(input.begin(), input.end(), 0, fcn, eqt);
974
+ CHECK(fcn.id() == iterated.hash_funct().id());
975
+ CHECK(eqt.id() == iterated.key_eq().id());
976
+ }
977
+ }
978
+
979
+ static void TestHashes() {
980
+ TestHash<sparse_hash_set>();
981
+ TestHash<dense_hash_set>();
982
+ }
983
+
984
+ template <template <class K, class T, class H, class E, class A> class Map>
985
+ void TestMap() {
986
+ typedef Map<int, int, TestHashFcn, TestEqualTo, allocator<int> > TheMap;
987
+ const TestHashFcn fcn(1);
988
+ const TestEqualTo eqt(2);
989
+ {
990
+ const TheMap simple(0, fcn, eqt);
991
+ CHECK(fcn.id() == simple.hash_funct().id());
992
+ CHECK(eqt.id() == simple.key_eq().id());
993
+ }
994
+ {
995
+ const map<int, int> input;
996
+ const TheMap iterated(input.begin(), input.end(), 0, fcn, eqt);
997
+ CHECK(fcn.id() == iterated.hash_funct().id());
998
+ CHECK(eqt.id() == iterated.key_eq().id());
999
+ }
1000
+ }
1001
+
1002
+ static void TestMaps() {
1003
+ TestMap<sparse_hash_map>();
1004
+ TestMap<dense_hash_map>();
1005
+ }
1006
+
1007
+ static void TestOperatorEquals() {
1008
+ {
1009
+ dense_hash_set<int> sa, sb;
1010
+ sa.set_empty_key(-1);
1011
+ sb.set_empty_key(-1);
1012
+ sa.set_deleted_key(-2);
1013
+ sb.set_deleted_key(-2);
1014
+ CHECK(sa == sb);
1015
+ sa.insert(1);
1016
+ CHECK(sa != sb);
1017
+ sa.insert(2);
1018
+ CHECK(sa != sb);
1019
+ sb.insert(2);
1020
+ CHECK(sa != sb);
1021
+ sb.insert(1);
1022
+ CHECK(sa == sb);
1023
+ sb.erase(1);
1024
+ CHECK(sa != sb);
1025
+ }
1026
+ {
1027
+ dense_hash_map<int, string> sa, sb;
1028
+ sa.set_empty_key(-1);
1029
+ sb.set_empty_key(-1);
1030
+ sa.set_deleted_key(-2);
1031
+ sb.set_deleted_key(-2);
1032
+ CHECK(sa == sb);
1033
+ sa.insert(make_pair(1, "a"));
1034
+ CHECK(sa != sb);
1035
+ sa.insert(make_pair(2, "b"));
1036
+ CHECK(sa != sb);
1037
+ sb.insert(make_pair(2, "b"));
1038
+ CHECK(sa != sb);
1039
+ sb.insert(make_pair(1, "a"));
1040
+ CHECK(sa == sb);
1041
+ sa[1] = "goodbye";
1042
+ CHECK(sa != sb);
1043
+ sb.erase(1);
1044
+ CHECK(sa != sb);
1045
+ }
1046
+ }
1047
+
1048
+ // Test the interface for setting the resize parameters in a
1049
+ // sparse_hash_set or dense_hash_set. If use_tr1_api is true,
1050
+ // we use the newer tr1-inspired functions to set resize_parameters,
1051
+ // rather than my old, home-grown API
1052
+ template<class HS, bool USE_TR1_API>
1053
+ static void TestResizingParameters() {
1054
+ const int kSize = 16536;
1055
+ // Check growing past various thresholds and then shrinking below
1056
+ // them.
1057
+ for (float grow_threshold = 0.2f;
1058
+ grow_threshold <= 0.8f;
1059
+ grow_threshold += 0.2f) {
1060
+ HS hs;
1061
+ hs.set_deleted_key(-1);
1062
+ set_empty_key(&hs, -2);
1063
+ if (USE_TR1_API) {
1064
+ hs.max_load_factor(grow_threshold);
1065
+ hs.min_load_factor(0.0);
1066
+ } else {
1067
+ hs.set_resizing_parameters(0.0, grow_threshold);
1068
+ }
1069
+ hs.resize(kSize);
1070
+ size_t bucket_count = hs.bucket_count();
1071
+ // Erase and insert an element to set consider_shrink = true,
1072
+ // which should not cause a shrink because the threshold is 0.0.
1073
+ insert(&hs, 1);
1074
+ hs.erase(1);
1075
+ for (int i = 0;; ++i) {
1076
+ insert(&hs, i);
1077
+ if (static_cast<float>(hs.size())/bucket_count < grow_threshold) {
1078
+ CHECK(hs.bucket_count() == bucket_count);
1079
+ } else {
1080
+ CHECK(hs.bucket_count() > bucket_count);
1081
+ break;
1082
+ }
1083
+ }
1084
+ // Now set a shrink threshold 1% below the current size and remove
1085
+ // items until the size falls below that.
1086
+ const float shrink_threshold = static_cast<float>(hs.size()) /
1087
+ hs.bucket_count() - 0.01f;
1088
+ if (USE_TR1_API) {
1089
+ hs.max_load_factor(1.0);
1090
+ hs.min_load_factor(shrink_threshold);
1091
+ } else {
1092
+ hs.set_resizing_parameters(shrink_threshold, 1.0);
1093
+ }
1094
+ bucket_count = hs.bucket_count();
1095
+ for (int i = 0;; ++i) {
1096
+ hs.erase(i);
1097
+ // A resize is only triggered by an insert, so add and remove a
1098
+ // value every iteration to trigger the shrink as soon as the
1099
+ // threshold is passed.
1100
+ hs.erase(i+1);
1101
+ insert(&hs, i+1);
1102
+ if (static_cast<float>(hs.size())/bucket_count > shrink_threshold) {
1103
+ CHECK(hs.bucket_count() == bucket_count);
1104
+ } else {
1105
+ CHECK(hs.bucket_count() < bucket_count);
1106
+ break;
1107
+ }
1108
+ }
1109
+ }
1110
+ }
1111
+
1112
+ // Tests the some of the tr1-inspired API features.
1113
+ template<class HS>
1114
+ static void TestTR1API() {
1115
+ HS hs;
1116
+ hs.set_deleted_key(-1);
1117
+ set_empty_key(&hs, -2);
1118
+
1119
+ typename HS::size_type expected_bucknum = hs.bucket(1);
1120
+ insert(&hs, 1);
1121
+ typename HS::size_type bucknum = hs.bucket(1);
1122
+ CHECK(expected_bucknum == bucknum);
1123
+ typename HS::const_local_iterator b = hs.begin(bucknum);
1124
+ typename HS::const_local_iterator e = hs.end(bucknum);
1125
+ CHECK(b != e);
1126
+ CHECK(getintkey(*b) == 1);
1127
+ b++;
1128
+ CHECK(b == e);
1129
+
1130
+ hs.erase(1);
1131
+ bucknum = hs.bucket(1);
1132
+ CHECK(expected_bucknum == bucknum);
1133
+ b = hs.begin(bucknum);
1134
+ e = hs.end(bucknum);
1135
+ CHECK(b == e);
1136
+
1137
+ // For very small sets, the min-bucket-size gets in the way, so
1138
+ // let's make our hash_set bigger.
1139
+ for (int i = 0; i < 10000; i++)
1140
+ insert(&hs, i);
1141
+ float f = hs.load_factor();
1142
+ CHECK(f >= hs.min_load_factor());
1143
+ CHECK(f <= hs.max_load_factor());
1144
+ }
1145
+
1146
+ class MemUsingKey {
1147
+ public:
1148
+ // TODO(csilvers): nix this when requirement for zero-arg keys goes away
1149
+ MemUsingKey() : data_(new int) {
1150
+ net_allocations_++;
1151
+ }
1152
+ MemUsingKey(int i) : data_(new int(i)) {
1153
+ net_allocations_++;
1154
+ }
1155
+ MemUsingKey(const MemUsingKey& that) : data_(new int(*that.data_)) {
1156
+ net_allocations_++;
1157
+ }
1158
+ ~MemUsingKey() {
1159
+ delete data_;
1160
+ net_allocations_--;
1161
+ CHECK_GE(net_allocations_, 0);
1162
+ }
1163
+ MemUsingKey& operator=(const MemUsingKey& that) {
1164
+ delete data_;
1165
+ data_ = new int(*that.data_);
1166
+ return *this;
1167
+ }
1168
+ struct Hash {
1169
+ size_t operator()(const MemUsingKey& x) const { return *x.data_; }
1170
+ };
1171
+ struct Equal {
1172
+ bool operator()(const MemUsingKey& x, const MemUsingKey& y) const {
1173
+ return *x.data_ == *y.data_;
1174
+ }
1175
+ };
1176
+ static int net_allocations() { return net_allocations_; }
1177
+ private:
1178
+ int* data_;
1179
+ static int net_allocations_;
1180
+ };
1181
+
1182
+ class MemUsingValue {
1183
+ public:
1184
+ // This also tests that value does not need to have a zero-arg constructor
1185
+ explicit MemUsingValue(const char* data) : data_(NULL) {
1186
+ Strcpy(data);
1187
+ }
1188
+ MemUsingValue(const MemUsingValue& that) : data_(NULL) {
1189
+ Strcpy(that.data_);
1190
+ }
1191
+ ~MemUsingValue() {
1192
+ if (data_) {
1193
+ free(data_);
1194
+ net_allocations_--;
1195
+ CHECK_GE(net_allocations_, 0);
1196
+ }
1197
+ }
1198
+ MemUsingValue& operator=(const MemUsingValue& that) {
1199
+ if (data_) {
1200
+ free(data_);
1201
+ net_allocations_--;
1202
+ CHECK_GE(net_allocations_, 0);
1203
+ }
1204
+ Strcpy(that.data_);
1205
+ return *this;
1206
+ }
1207
+ static int net_allocations() { return net_allocations_; }
1208
+ private:
1209
+ void Strcpy(const char* data) {
1210
+ if (data) {
1211
+ data_ = (char*)malloc(strlen(data) + 1); // use malloc this time
1212
+ strcpy(data_, data); // strdup isn't so portable
1213
+ net_allocations_++;
1214
+ } else {
1215
+ data_ = NULL;
1216
+ }
1217
+ }
1218
+ char* data_;
1219
+ static int net_allocations_;
1220
+ };
1221
+
1222
+ // TODO(csilvers): nix this when set_empty_key doesn't require zero-arg value
1223
+ class MemUsingValueWithZeroArgConstructor : public MemUsingValue {
1224
+ public:
1225
+ MemUsingValueWithZeroArgConstructor(const char* data=NULL)
1226
+ : MemUsingValue(data) { }
1227
+ MemUsingValueWithZeroArgConstructor(
1228
+ const MemUsingValueWithZeroArgConstructor& that)
1229
+ : MemUsingValue(that) { }
1230
+ MemUsingValueWithZeroArgConstructor& operator=(
1231
+ const MemUsingValueWithZeroArgConstructor& that) {
1232
+ *static_cast<MemUsingValue*>(this)
1233
+ = *static_cast<const MemUsingValue*>(&that);
1234
+ return *this;
1235
+ }
1236
+ };
1237
+
1238
+ int MemUsingKey::net_allocations_ = 0;
1239
+ int MemUsingValue::net_allocations_ = 0;
1240
+
1241
+
1242
+ void TestMemoryManagement() {
1243
+ MemUsingKey deleted_key(-1);
1244
+ MemUsingKey empty_key(-2);
1245
+
1246
+ {
1247
+ // TODO(csilvers): fix sparsetable to allow missing zero-arg value ctor
1248
+ sparse_hash_map<MemUsingKey, MemUsingValueWithZeroArgConstructor,
1249
+ MemUsingKey::Hash, MemUsingKey::Equal> ht;
1250
+ ht.set_deleted_key(deleted_key);
1251
+ for (int i = 0; i < 1000; i++) {
1252
+ ht.insert(pair<MemUsingKey,MemUsingValueWithZeroArgConstructor>(
1253
+ i, MemUsingValueWithZeroArgConstructor("hello!")));
1254
+ ht.erase(i);
1255
+ CHECK_EQ(0, MemUsingValue::net_allocations());
1256
+ }
1257
+ }
1258
+ // Various copies of deleted_key will be hanging around until the
1259
+ // hashtable is destroyed, so it's only safe to do this test now.
1260
+ CHECK_EQ(2, MemUsingKey::net_allocations()); // for deleted+empty_key
1261
+
1262
+ {
1263
+ dense_hash_map<MemUsingKey, MemUsingValueWithZeroArgConstructor,
1264
+ MemUsingKey::Hash, MemUsingKey::Equal> ht;
1265
+ ht.set_empty_key(empty_key);
1266
+ ht.set_deleted_key(deleted_key);
1267
+ for (int i = 0; i < 1000; i++) {
1268
+ // As long as we have a zero-arg constructor for the value anyway,
1269
+ // use operator[] rather than the more verbose insert().
1270
+ ht[i] = MemUsingValueWithZeroArgConstructor("hello!");
1271
+ ht.erase(i);
1272
+ CHECK_EQ(0, MemUsingValue::net_allocations());
1273
+ }
1274
+ }
1275
+ CHECK_EQ(2, MemUsingKey::net_allocations()); // for deleted+empty_key
1276
+ }
1277
+
1278
+ template<class Key>
1279
+ struct SetKey {
1280
+ void operator()(Key* key, const Key& new_key) const {
1281
+ *key = new_key;
1282
+ }
1283
+ };
1284
+
1285
+ int main(int argc, char **argv) {
1286
+ TestOperatorEquals();
1287
+
1288
+ // SPARSEHASH_HASH is defined in sparseconfig.h. It resolves to the
1289
+ // system hash function (usually, but not always, named "hash") on
1290
+ // whatever system we're on.
1291
+
1292
+ // First try with the low-level hashtable interface
1293
+ LOGF << "\n\nTEST WITH DENSE_HASHTABLE\n\n";
1294
+ test<dense_hashtable<char *, char *, CharStarHash,
1295
+ Identity<char *>, SetKey<char *>, strcmp_fnc,
1296
+ allocator<char *> >,
1297
+ dense_hashtable<string, string, StrHash,
1298
+ Identity<string>, SetKey<string>,
1299
+ equal_to<string>,
1300
+ allocator<string> >,
1301
+ dense_hashtable<int, int, SPARSEHASH_HASH<int>,
1302
+ Identity<int>, SetKey<int>, equal_to<int>,
1303
+ allocator<int> > >(
1304
+ false);
1305
+
1306
+ // Now try with hash_set, which should be equivalent
1307
+ LOGF << "\n\nTEST WITH DENSE_HASH_SET\n\n";
1308
+ test<dense_hash_set<char *, CharStarHash, strcmp_fnc>,
1309
+ dense_hash_set<string, StrHash>,
1310
+ dense_hash_set<int> >(false);
1311
+
1312
+ TestResizingParameters<dense_hash_set<int>, true>(); // use tr1 API
1313
+ TestResizingParameters<dense_hash_set<int>, false>(); // use older API
1314
+
1315
+ // Now try with hash_map, which differs only in insert()
1316
+ LOGF << "\n\nTEST WITH DENSE_HASH_MAP\n\n";
1317
+ test<dense_hash_map<char *, int, CharStarHash, strcmp_fnc>,
1318
+ dense_hash_map<string, int, StrHash>,
1319
+ dense_hash_map<int, int> >(false);
1320
+
1321
+ // First try with the low-level hashtable interface
1322
+ LOGF << "\n\nTEST WITH SPARSE_HASHTABLE\n\n";
1323
+ test<sparse_hashtable<char *, char *, CharStarHash,
1324
+ Identity<char *>, SetKey<char *>, strcmp_fnc,
1325
+ allocator<char *> >,
1326
+ sparse_hashtable<string, string, StrHash,
1327
+ Identity<string>, SetKey<string>, equal_to<string>,
1328
+ allocator<string> >,
1329
+ sparse_hashtable<int, int, SPARSEHASH_HASH<int>,
1330
+ Identity<int>, SetKey<int>, equal_to<int>,
1331
+ allocator<int> > >(
1332
+ true);
1333
+
1334
+ // Now try with hash_set, which should be equivalent
1335
+ LOGF << "\n\nTEST WITH SPARSE_HASH_SET\n\n";
1336
+ test<sparse_hash_set<char *, CharStarHash, strcmp_fnc>,
1337
+ sparse_hash_set<string, StrHash>,
1338
+ sparse_hash_set<int> >(true);
1339
+
1340
+ TestResizingParameters<sparse_hash_set<int>, true>();
1341
+ TestResizingParameters<sparse_hash_set<int>, false>();
1342
+
1343
+ // Now try with hash_map, which differs only in insert()
1344
+ LOGF << "\n\nTEST WITH SPARSE_HASH_MAP\n\n";
1345
+ test<sparse_hash_map<char *, int, CharStarHash, strcmp_fnc>,
1346
+ sparse_hash_map<string, int, StrHash>,
1347
+ sparse_hash_map<int, int> >(true);
1348
+
1349
+ // Test that we use the optimized routines for simple data types
1350
+ LOGF << "\n\nTesting simple-data-type optimizations\n";
1351
+ TestSimpleDataTypeOptimizations();
1352
+
1353
+ // Test shrinking to very small sizes
1354
+ LOGF << "\n\nTesting shrinking behavior";
1355
+ TestShrinking();
1356
+
1357
+ // Test that the hashers and key_equals are used properly in hash tables and
1358
+ // hash maps.
1359
+ LOGF << "\n\nTesting hashers and key_equals\n";
1360
+ TestHashes();
1361
+ TestMaps();
1362
+
1363
+ LOGF << "\n\nTesting tr1 API\n";
1364
+ TestTR1API<sparse_hash_map<int, int> >();
1365
+ TestTR1API<dense_hash_map<int, int> >();
1366
+ TestTR1API<sparse_hash_set<int> >();
1367
+ TestTR1API<dense_hash_set<int> >();
1368
+
1369
+ // Test memory management when the keys and values are non-trivial
1370
+ LOGF << "\n\nTesting memory management\n";
1371
+ TestMemoryManagement();
1372
+
1373
+ LOGF << "\nAll tests pass.\n";
1374
+ return 0;
1375
+ }