google_hash 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/ChangeLog.txt +2 -0
  2. data/VERSION +1 -1
  3. data/ext/clean.bat +0 -0
  4. data/ext/clean.sh +4 -0
  5. data/ext/extconf.rb +4 -5
  6. data/ext/go.bat +0 -0
  7. data/ext/sparsehash-2.0.2/AUTHORS +2 -0
  8. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/COPYING +0 -0
  9. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/ChangeLog +60 -0
  10. data/ext/sparsehash-2.0.2/INSTALL +365 -0
  11. data/ext/sparsehash-2.0.2/Makefile +1336 -0
  12. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/Makefile.am +97 -40
  13. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/Makefile.in +538 -256
  14. data/ext/sparsehash-2.0.2/NEWS +188 -0
  15. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/README +4 -10
  16. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/README_windows.txt +3 -3
  17. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/TODO +0 -0
  18. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/aclocal.m4 +266 -166
  19. data/ext/sparsehash-2.0.2/allocator.patch +31 -0
  20. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/config.guess +235 -234
  21. data/ext/sparsehash-2.0.2/config.status +1238 -0
  22. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/config.sub +198 -64
  23. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/configure +1118 -1000
  24. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/configure.ac +4 -5
  25. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/depcomp +136 -36
  26. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/dense_hash_map.html +182 -67
  27. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/dense_hash_set.html +173 -74
  28. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/designstyle.css +0 -6
  29. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/implementation.html +0 -0
  30. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/index.html +4 -5
  31. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/performance.html +1 -1
  32. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparse_hash_map.html +190 -58
  33. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparse_hash_set.html +180 -65
  34. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparsetable.html +1 -1
  35. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/Makefile +0 -0
  36. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/README +0 -0
  37. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/example.c +1 -0
  38. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/libchash.c +1 -0
  39. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/libchash.h +1 -0
  40. data/ext/sparsehash-2.0.2/install-sh +520 -0
  41. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/acx_pthread.m4 +34 -0
  42. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/google_namespace.m4 +0 -0
  43. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/namespaces.m4 +0 -0
  44. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/stl_hash.m4 +0 -0
  45. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/stl_hash_fun.m4 +0 -0
  46. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/missing +60 -44
  47. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb.sh +0 -0
  48. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/README +0 -0
  49. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/changelog +42 -0
  50. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/compat +0 -0
  51. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/control +1 -1
  52. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/copyright +5 -4
  53. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/docs +0 -0
  54. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/rules +0 -0
  55. data/ext/sparsehash-2.0.2/packages/deb/sparsehash.dirs +5 -0
  56. data/ext/sparsehash-2.0.2/packages/deb/sparsehash.install +6 -0
  57. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/rpm.sh +1 -1
  58. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/rpm/rpm.spec +5 -3
  59. data/ext/{sparsehash-1.8.1/google-sparsehash.sln → sparsehash-2.0.2/sparsehash.sln} +0 -0
  60. data/ext/sparsehash-2.0.2/src/config.h +132 -0
  61. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/config.h.in +0 -3
  62. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/config.h.include +0 -1
  63. data/ext/sparsehash-2.0.2/src/google/dense_hash_map +34 -0
  64. data/ext/sparsehash-2.0.2/src/google/dense_hash_set +34 -0
  65. data/ext/sparsehash-2.0.2/src/google/sparse_hash_map +34 -0
  66. data/ext/sparsehash-2.0.2/src/google/sparse_hash_set +34 -0
  67. data/ext/sparsehash-2.0.2/src/google/sparsehash/densehashtable.h +34 -0
  68. data/ext/sparsehash-2.0.2/src/google/sparsehash/hashtable-common.h +34 -0
  69. data/ext/sparsehash-2.0.2/src/google/sparsehash/libc_allocator_with_realloc.h +34 -0
  70. data/ext/sparsehash-2.0.2/src/google/sparsehash/sparsehashtable.h +34 -0
  71. data/ext/sparsehash-2.0.2/src/google/sparsetable +34 -0
  72. data/ext/sparsehash-2.0.2/src/google/template_util.h +34 -0
  73. data/ext/sparsehash-2.0.2/src/google/type_traits.h +34 -0
  74. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/hash_test_interface.h +64 -37
  75. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/hashtable_test.cc +415 -141
  76. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/libc_allocator_with_realloc_test.cc +16 -23
  77. data/ext/sparsehash-2.0.2/src/simple_compat_test.cc +106 -0
  78. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/simple_test.cc +8 -5
  79. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/dense_hash_map +80 -37
  80. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/dense_hash_set +64 -34
  81. data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/densehashtable.h +247 -173
  82. data/ext/sparsehash-2.0.2/src/sparsehash/internal/hashtable-common.h +381 -0
  83. data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/libc_allocator_with_realloc.h +5 -7
  84. data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/sparsehashtable.h +154 -93
  85. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparse_hash_map +96 -36
  86. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparse_hash_set +85 -32
  87. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparsetable +520 -258
  88. data/ext/sparsehash-2.0.2/src/sparsehash/template_util.h +134 -0
  89. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/type_traits.h +153 -35
  90. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/sparsetable_unittest.cc +108 -22
  91. data/ext/sparsehash-2.0.2/src/stamp-h1 +1 -0
  92. data/ext/sparsehash-2.0.2/src/template_util_unittest.cc +134 -0
  93. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/testutil.h +16 -1
  94. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/time_hash_map.cc +259 -94
  95. data/ext/sparsehash-2.0.2/src/type_traits_unittest.cc +636 -0
  96. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/config.h +4 -4
  97. data/ext/sparsehash-2.0.2/src/windows/google/sparsehash/sparseconfig.h +49 -0
  98. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/port.cc +1 -0
  99. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/port.h +4 -13
  100. data/ext/sparsehash-2.0.2/src/windows/sparsehash/internal/sparseconfig.h +49 -0
  101. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/hashtable_test/hashtable_test.vcproj +11 -11
  102. data/ext/sparsehash-2.0.2/vsprojects/libc_allocator_with_realloc_test/libc_allocator_with_realloc_test.vcproj +161 -0
  103. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/simple_test/simple_test.vcproj +10 -10
  104. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +4 -4
  105. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/time_hash_map/time_hash_map.vcproj +10 -10
  106. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +3 -3
  107. data/ext/spec.bat +0 -0
  108. data/ext/template/google_hash.cpp.erb +6 -5
  109. metadata +106 -86
  110. data/ext/sparsehash-1.8.1/AUTHORS +0 -2
  111. data/ext/sparsehash-1.8.1/INSTALL +0 -236
  112. data/ext/sparsehash-1.8.1/NEWS +0 -71
  113. data/ext/sparsehash-1.8.1/compile +0 -99
  114. data/ext/sparsehash-1.8.1/install-sh +0 -323
  115. data/ext/sparsehash-1.8.1/m4/stl_namespace.m4 +0 -25
  116. data/ext/sparsehash-1.8.1/mkinstalldirs +0 -158
  117. data/ext/sparsehash-1.8.1/packages/deb/sparsehash.dirs +0 -2
  118. data/ext/sparsehash-1.8.1/packages/deb/sparsehash.install +0 -2
  119. data/ext/sparsehash-1.8.1/src/google/sparsehash/hashtable-common.h +0 -178
  120. data/ext/sparsehash-1.8.1/src/type_traits_unittest.cc +0 -502
  121. data/ext/sparsehash-1.8.1/src/windows/google/sparsehash/sparseconfig.h +0 -32
@@ -0,0 +1,381 @@
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
+ //
32
+ // Provides classes shared by both sparse and dense hashtable.
33
+ //
34
+ // sh_hashtable_settings has parameters for growing and shrinking
35
+ // a hashtable. It also packages zero-size functor (ie. hasher).
36
+ //
37
+ // Other functions and classes provide common code for serializing
38
+ // and deserializing hashtables to a stream (such as a FILE*).
39
+
40
+ #ifndef UTIL_GTL_HASHTABLE_COMMON_H_
41
+ #define UTIL_GTL_HASHTABLE_COMMON_H_
42
+
43
+ #include <sparsehash/internal/sparseconfig.h>
44
+ #include <assert.h>
45
+ #include <stdio.h>
46
+ #include <stddef.h> // for size_t
47
+ #include <iosfwd>
48
+ #include <stdexcept> // For length_error
49
+
50
+ _START_GOOGLE_NAMESPACE_
51
+
52
+ template <bool> struct SparsehashCompileAssert { };
53
+ #define SPARSEHASH_COMPILE_ASSERT(expr, msg) \
54
+ typedef SparsehashCompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
55
+
56
+ namespace sparsehash_internal {
57
+
58
+ // Adaptor methods for reading/writing data from an INPUT or OUPTUT
59
+ // variable passed to serialize() or unserialize(). For now we
60
+ // have implemented INPUT/OUTPUT for FILE*, istream*/ostream* (note
61
+ // they are pointers, unlike typical use), or else a pointer to
62
+ // something that supports a Read()/Write() method.
63
+ //
64
+ // For technical reasons, we implement read_data/write_data in two
65
+ // stages. The actual work is done in *_data_internal, which takes
66
+ // the stream argument twice: once as a template type, and once with
67
+ // normal type information. (We only use the second version.) We do
68
+ // this because of how C++ picks what function overload to use. If we
69
+ // implemented this the naive way:
70
+ // bool read_data(istream* is, const void* data, size_t length);
71
+ // template<typename T> read_data(T* fp, const void* data, size_t length);
72
+ // C++ would prefer the second version for every stream type except
73
+ // istream. However, we want C++ to prefer the first version for
74
+ // streams that are *subclasses* of istream, such as istringstream.
75
+ // This is not possible given the way template types are resolved. So
76
+ // we split the stream argument in two, one of which is templated and
77
+ // one of which is not. The specialized functions (like the istream
78
+ // version above) ignore the template arg and use the second, 'type'
79
+ // arg, getting subclass matching as normal. The 'catch-all'
80
+ // functions (the second version above) use the template arg to deduce
81
+ // the type, and use a second, void* arg to achieve the desired
82
+ // 'catch-all' semantics.
83
+
84
+ // ----- low-level I/O for FILE* ----
85
+
86
+ template<typename Ignored>
87
+ inline bool read_data_internal(Ignored*, FILE* fp,
88
+ void* data, size_t length) {
89
+ return fread(data, length, 1, fp) == 1;
90
+ }
91
+
92
+ template<typename Ignored>
93
+ inline bool write_data_internal(Ignored*, FILE* fp,
94
+ const void* data, size_t length) {
95
+ return fwrite(data, length, 1, fp) == 1;
96
+ }
97
+
98
+ // ----- low-level I/O for iostream ----
99
+
100
+ // We want the caller to be responsible for #including <iostream>, not
101
+ // us, because iostream is a big header! According to the standard,
102
+ // it's only legal to delay the instantiation the way we want to if
103
+ // the istream/ostream is a template type. So we jump through hoops.
104
+ template<typename ISTREAM>
105
+ inline bool read_data_internal_for_istream(ISTREAM* fp,
106
+ void* data, size_t length) {
107
+ return fp->read(reinterpret_cast<char*>(data), length).good();
108
+ }
109
+ template<typename Ignored>
110
+ inline bool read_data_internal(Ignored*, std::istream* fp,
111
+ void* data, size_t length) {
112
+ return read_data_internal_for_istream(fp, data, length);
113
+ }
114
+
115
+ template<typename OSTREAM>
116
+ inline bool write_data_internal_for_ostream(OSTREAM* fp,
117
+ const void* data, size_t length) {
118
+ return fp->write(reinterpret_cast<const char*>(data), length).good();
119
+ }
120
+ template<typename Ignored>
121
+ inline bool write_data_internal(Ignored*, std::ostream* fp,
122
+ const void* data, size_t length) {
123
+ return write_data_internal_for_ostream(fp, data, length);
124
+ }
125
+
126
+ // ----- low-level I/O for custom streams ----
127
+
128
+ // The INPUT type needs to support a Read() method that takes a
129
+ // buffer and a length and returns the number of bytes read.
130
+ template <typename INPUT>
131
+ inline bool read_data_internal(INPUT* fp, void*,
132
+ void* data, size_t length) {
133
+ return static_cast<size_t>(fp->Read(data, length)) == length;
134
+ }
135
+
136
+ // The OUTPUT type needs to support a Write() operation that takes
137
+ // a buffer and a length and returns the number of bytes written.
138
+ template <typename OUTPUT>
139
+ inline bool write_data_internal(OUTPUT* fp, void*,
140
+ const void* data, size_t length) {
141
+ return static_cast<size_t>(fp->Write(data, length)) == length;
142
+ }
143
+
144
+ // ----- low-level I/O: the public API ----
145
+
146
+ template <typename INPUT>
147
+ inline bool read_data(INPUT* fp, void* data, size_t length) {
148
+ return read_data_internal(fp, fp, data, length);
149
+ }
150
+
151
+ template <typename OUTPUT>
152
+ inline bool write_data(OUTPUT* fp, const void* data, size_t length) {
153
+ return write_data_internal(fp, fp, data, length);
154
+ }
155
+
156
+ // Uses read_data() and write_data() to read/write an integer.
157
+ // length is the number of bytes to read/write (which may differ
158
+ // from sizeof(IntType), allowing us to save on a 32-bit system
159
+ // and load on a 64-bit system). Excess bytes are taken to be 0.
160
+ // INPUT and OUTPUT must match legal inputs to read/write_data (above).
161
+ template <typename INPUT, typename IntType>
162
+ bool read_bigendian_number(INPUT* fp, IntType* value, size_t length) {
163
+ *value = 0;
164
+ unsigned char byte;
165
+ // We require IntType to be unsigned or else the shifting gets all screwy.
166
+ SPARSEHASH_COMPILE_ASSERT(static_cast<IntType>(-1) > static_cast<IntType>(0),
167
+ serializing_int_requires_an_unsigned_type);
168
+ for (size_t i = 0; i < length; ++i) {
169
+ if (!read_data(fp, &byte, sizeof(byte))) return false;
170
+ *value |= static_cast<IntType>(byte) << ((length - 1 - i) * 8);
171
+ }
172
+ return true;
173
+ }
174
+
175
+ template <typename OUTPUT, typename IntType>
176
+ bool write_bigendian_number(OUTPUT* fp, IntType value, size_t length) {
177
+ unsigned char byte;
178
+ // We require IntType to be unsigned or else the shifting gets all screwy.
179
+ SPARSEHASH_COMPILE_ASSERT(static_cast<IntType>(-1) > static_cast<IntType>(0),
180
+ serializing_int_requires_an_unsigned_type);
181
+ for (size_t i = 0; i < length; ++i) {
182
+ byte = (sizeof(value) <= length-1 - i)
183
+ ? 0 : static_cast<unsigned char>((value >> ((length-1 - i) * 8)) & 255);
184
+ if (!write_data(fp, &byte, sizeof(byte))) return false;
185
+ }
186
+ return true;
187
+ }
188
+
189
+ // If your keys and values are simple enough, you can pass this
190
+ // serializer to serialize()/unserialize(). "Simple enough" means
191
+ // value_type is a POD type that contains no pointers. Note,
192
+ // however, we don't try to normalize endianness.
193
+ // This is the type used for NopointerSerializer.
194
+ template <typename value_type> struct pod_serializer {
195
+ template <typename INPUT>
196
+ bool operator()(INPUT* fp, value_type* value) const {
197
+ return read_data(fp, value, sizeof(*value));
198
+ }
199
+
200
+ template <typename OUTPUT>
201
+ bool operator()(OUTPUT* fp, const value_type& value) const {
202
+ return write_data(fp, &value, sizeof(value));
203
+ }
204
+ };
205
+
206
+
207
+ // Settings contains parameters for growing and shrinking the table.
208
+ // It also packages zero-size functor (ie. hasher).
209
+ //
210
+ // It does some munging of the hash value in cases where we think
211
+ // (fear) the original hash function might not be very good. In
212
+ // particular, the default hash of pointers is the identity hash,
213
+ // so probably all the low bits are 0. We identify when we think
214
+ // we're hashing a pointer, and chop off the low bits. Note this
215
+ // isn't perfect: even when the key is a pointer, we can't tell
216
+ // for sure that the hash is the identity hash. If it's not, this
217
+ // is needless work (and possibly, though not likely, harmful).
218
+
219
+ template<typename Key, typename HashFunc,
220
+ typename SizeType, int HT_MIN_BUCKETS>
221
+ class sh_hashtable_settings : public HashFunc {
222
+ public:
223
+ typedef Key key_type;
224
+ typedef HashFunc hasher;
225
+ typedef SizeType size_type;
226
+
227
+ public:
228
+ sh_hashtable_settings(const hasher& hf,
229
+ const float ht_occupancy_flt,
230
+ const float ht_empty_flt)
231
+ : hasher(hf),
232
+ enlarge_threshold_(0),
233
+ shrink_threshold_(0),
234
+ consider_shrink_(false),
235
+ use_empty_(false),
236
+ use_deleted_(false),
237
+ num_ht_copies_(0) {
238
+ set_enlarge_factor(ht_occupancy_flt);
239
+ set_shrink_factor(ht_empty_flt);
240
+ }
241
+
242
+ size_type hash(const key_type& v) const {
243
+ // We munge the hash value when we don't trust hasher::operator().
244
+ return hash_munger<Key>::MungedHash(hasher::operator()(v));
245
+ }
246
+
247
+ float enlarge_factor() const {
248
+ return enlarge_factor_;
249
+ }
250
+ void set_enlarge_factor(float f) {
251
+ enlarge_factor_ = f;
252
+ }
253
+ float shrink_factor() const {
254
+ return shrink_factor_;
255
+ }
256
+ void set_shrink_factor(float f) {
257
+ shrink_factor_ = f;
258
+ }
259
+
260
+ size_type enlarge_threshold() const {
261
+ return enlarge_threshold_;
262
+ }
263
+ void set_enlarge_threshold(size_type t) {
264
+ enlarge_threshold_ = t;
265
+ }
266
+ size_type shrink_threshold() const {
267
+ return shrink_threshold_;
268
+ }
269
+ void set_shrink_threshold(size_type t) {
270
+ shrink_threshold_ = t;
271
+ }
272
+
273
+ size_type enlarge_size(size_type x) const {
274
+ return static_cast<size_type>(x * enlarge_factor_);
275
+ }
276
+ size_type shrink_size(size_type x) const {
277
+ return static_cast<size_type>(x * shrink_factor_);
278
+ }
279
+
280
+ bool consider_shrink() const {
281
+ return consider_shrink_;
282
+ }
283
+ void set_consider_shrink(bool t) {
284
+ consider_shrink_ = t;
285
+ }
286
+
287
+ bool use_empty() const {
288
+ return use_empty_;
289
+ }
290
+ void set_use_empty(bool t) {
291
+ use_empty_ = t;
292
+ }
293
+
294
+ bool use_deleted() const {
295
+ return use_deleted_;
296
+ }
297
+ void set_use_deleted(bool t) {
298
+ use_deleted_ = t;
299
+ }
300
+
301
+ size_type num_ht_copies() const {
302
+ return static_cast<size_type>(num_ht_copies_);
303
+ }
304
+ void inc_num_ht_copies() {
305
+ ++num_ht_copies_;
306
+ }
307
+
308
+ // Reset the enlarge and shrink thresholds
309
+ void reset_thresholds(size_type num_buckets) {
310
+ set_enlarge_threshold(enlarge_size(num_buckets));
311
+ set_shrink_threshold(shrink_size(num_buckets));
312
+ // whatever caused us to reset already considered
313
+ set_consider_shrink(false);
314
+ }
315
+
316
+ // Caller is resposible for calling reset_threshold right after
317
+ // set_resizing_parameters.
318
+ void set_resizing_parameters(float shrink, float grow) {
319
+ assert(shrink >= 0.0);
320
+ assert(grow <= 1.0);
321
+ if (shrink > grow/2.0f)
322
+ shrink = grow / 2.0f; // otherwise we thrash hashtable size
323
+ set_shrink_factor(shrink);
324
+ set_enlarge_factor(grow);
325
+ }
326
+
327
+ // This is the smallest size a hashtable can be without being too crowded
328
+ // If you like, you can give a min #buckets as well as a min #elts
329
+ size_type min_buckets(size_type num_elts, size_type min_buckets_wanted) {
330
+ float enlarge = enlarge_factor();
331
+ size_type sz = HT_MIN_BUCKETS; // min buckets allowed
332
+ while ( sz < min_buckets_wanted ||
333
+ num_elts >= static_cast<size_type>(sz * enlarge) ) {
334
+ // This just prevents overflowing size_type, since sz can exceed
335
+ // max_size() here.
336
+ if (static_cast<size_type>(sz * 2) < sz) {
337
+ throw std::length_error("resize overflow"); // protect against overflow
338
+ }
339
+ sz *= 2;
340
+ }
341
+ return sz;
342
+ }
343
+
344
+ private:
345
+ template<class HashKey> class hash_munger {
346
+ public:
347
+ static size_t MungedHash(size_t hash) {
348
+ return hash;
349
+ }
350
+ };
351
+ // This matches when the hashtable key is a pointer.
352
+ template<class HashKey> class hash_munger<HashKey*> {
353
+ public:
354
+ static size_t MungedHash(size_t hash) {
355
+ // TODO(csilvers): consider rotating instead:
356
+ // static const int shift = (sizeof(void *) == 4) ? 2 : 3;
357
+ // return (hash << (sizeof(hash) * 8) - shift)) | (hash >> shift);
358
+ // This matters if we ever change sparse/dense_hash_* to compare
359
+ // hashes before comparing actual values. It's speedy on x86.
360
+ return hash / sizeof(void*); // get rid of known-0 bits
361
+ }
362
+ };
363
+
364
+ size_type enlarge_threshold_; // table.size() * enlarge_factor
365
+ size_type shrink_threshold_; // table.size() * shrink_factor
366
+ float enlarge_factor_; // how full before resize
367
+ float shrink_factor_; // how empty before resize
368
+ // consider_shrink=true if we should try to shrink before next insert
369
+ bool consider_shrink_;
370
+ bool use_empty_; // used only by densehashtable, not sparsehashtable
371
+ bool use_deleted_; // false until delkey has been set
372
+ // num_ht_copies is a counter incremented every Copy/Move
373
+ unsigned int num_ht_copies_;
374
+ };
375
+
376
+ } // namespace sparsehash_internal
377
+
378
+ #undef SPARSEHASH_COMPILE_ASSERT
379
+ _END_GOOGLE_NAMESPACE_
380
+
381
+ #endif // UTIL_GTL_HASHTABLE_COMMON_H_
@@ -1,10 +1,10 @@
1
1
  // Copyright (c) 2010, Google Inc.
2
2
  // All rights reserved.
3
- //
3
+ //
4
4
  // Redistribution and use in source and binary forms, with or without
5
5
  // modification, are permitted provided that the following conditions are
6
6
  // met:
7
- //
7
+ //
8
8
  // * Redistributions of source code must retain the above copyright
9
9
  // notice, this list of conditions and the following disclaimer.
10
10
  // * Redistributions in binary form must reproduce the above
@@ -14,7 +14,7 @@
14
14
  // * Neither the name of Google Inc. nor the names of its
15
15
  // contributors may be used to endorse or promote products derived from
16
16
  // this software without specific prior written permission.
17
- //
17
+ //
18
18
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
19
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
20
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -28,16 +28,14 @@
28
28
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
 
30
30
  // ---
31
- // Author: Guilin Chen
32
31
 
33
32
  #ifndef UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
34
33
  #define UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
35
34
 
36
- #include <google/sparsehash/sparseconfig.h>
37
-
35
+ #include <sparsehash/internal/sparseconfig.h>
38
36
  #include <stdlib.h> // for malloc/realloc/free
39
37
  #include <stddef.h> // for ptrdiff_t
40
-
38
+ #include <new> // for placement new
41
39
 
42
40
  _START_GOOGLE_NAMESPACE_
43
41
 
@@ -28,7 +28,6 @@
28
28
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
 
30
30
  // ---
31
- // Author: Craig Silverstein
32
31
  //
33
32
  // A sparse hashtable is a particular implementation of
34
33
  // a hashtable: one that is meant to minimize memory use.
@@ -56,7 +55,7 @@
56
55
  // the hashtable is insert_only until you set it again.
57
56
  //
58
57
  // You probably shouldn't use this code directly. Use
59
- // <google/sparse_hash_table> or <google/sparse_hash_set> instead.
58
+ // sparse_hash_map<> or sparse_hash_set<> instead.
60
59
  //
61
60
  // You can modify the following, below:
62
61
  // HT_OCCUPANCY_PCT -- how full before we double size
@@ -96,6 +95,23 @@
96
95
  #ifndef _SPARSEHASHTABLE_H_
97
96
  #define _SPARSEHASHTABLE_H_
98
97
 
98
+ #include <sparsehash/internal/sparseconfig.h>
99
+ #include <assert.h>
100
+ #include <algorithm> // For swap(), eg
101
+ #include <iterator> // for iterator tags
102
+ #include <limits> // for numeric_limits
103
+ #include <utility> // for pair
104
+ #include <sparsehash/type_traits.h> // for remove_const
105
+ #include <sparsehash/internal/hashtable-common.h>
106
+ #include <sparsehash/sparsetable> // IWYU pragma: export
107
+ #include <stdexcept> // For length_error
108
+
109
+ _START_GOOGLE_NAMESPACE_
110
+
111
+ namespace base { // just to make google->opensource transition easier
112
+ using GOOGLE_NAMESPACE::remove_const;
113
+ }
114
+
99
115
  #ifndef SPARSEHASH_STAT_UPDATE
100
116
  #define SPARSEHASH_STAT_UPDATE(x) ((void) 0)
101
117
  #endif
@@ -106,20 +122,6 @@
106
122
  // Quadratic probing
107
123
  #define JUMP_(key, num_probes) ( num_probes )
108
124
 
109
- #include <google/sparsehash/sparseconfig.h>
110
- #include <assert.h>
111
- #include <algorithm> // For swap(), eg
112
- #include <stdexcept> // For length_error
113
- #include <iterator> // for facts about iterator tags
114
- #include <limits> // for numeric_limits<>
115
- #include <utility> // for pair<>
116
- #include <google/sparsehash/hashtable-common.h>
117
- #include <google/sparsetable> // Since that's basically what we are
118
-
119
- _START_GOOGLE_NAMESPACE_
120
-
121
- using STL_NAMESPACE::pair;
122
-
123
125
  // The smaller this is, the faster lookup is (because the group bitmap is
124
126
  // smaller) and the faster insert is, because there's less to move.
125
127
  // On the other hand, there are more groups. Since group::size_type is
@@ -134,6 +136,8 @@ static const u_int16_t DEFAULT_GROUP_SIZE = 48; // fits in 1.5 words
134
136
  // to search for a Value in the table (find() takes a Key).
135
137
  // HashFcn: Takes a Key and returns an integer, the more unique the better.
136
138
  // ExtractKey: given a Value, returns the unique Key associated with it.
139
+ // Must inherit from unary_function, or at least have a
140
+ // result_type enum indicating the return type of operator().
137
141
  // SetKey: given a Value* and a Key, modifies the value such that
138
142
  // ExtractKey(value) == key. We guarantee this is only called
139
143
  // with key == deleted_key.
@@ -161,10 +165,10 @@ struct sparse_hashtable_iterator {
161
165
  public:
162
166
  typedef sparse_hashtable_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
163
167
  typedef sparse_hashtable_const_iterator<V,K,HF,ExK,SetK,EqK,A> const_iterator;
164
- typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,A>::nonempty_iterator
168
+ typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,value_alloc_type>::nonempty_iterator
165
169
  st_iterator;
166
170
 
167
- typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
171
+ typedef std::forward_iterator_tag iterator_category; // very little defined!
168
172
  typedef V value_type;
169
173
  typedef typename value_alloc_type::difference_type difference_type;
170
174
  typedef typename value_alloc_type::size_type size_type;
@@ -213,10 +217,10 @@ struct sparse_hashtable_const_iterator {
213
217
  public:
214
218
  typedef sparse_hashtable_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
215
219
  typedef sparse_hashtable_const_iterator<V,K,HF,ExK,SetK,EqK,A> const_iterator;
216
- typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,A>::const_nonempty_iterator
220
+ typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,value_alloc_type>::const_nonempty_iterator
217
221
  st_iterator;
218
222
 
219
- typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
223
+ typedef std::forward_iterator_tag iterator_category; // very little defined!
220
224
  typedef V value_type;
221
225
  typedef typename value_alloc_type::difference_type difference_type;
222
226
  typedef typename value_alloc_type::size_type size_type;
@@ -267,10 +271,10 @@ struct sparse_hashtable_destructive_iterator {
267
271
 
268
272
  public:
269
273
  typedef sparse_hashtable_destructive_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
270
- typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,A>::destructive_iterator
274
+ typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,value_alloc_type>::destructive_iterator
271
275
  st_iterator;
272
276
 
273
- typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
277
+ typedef std::forward_iterator_tag iterator_category; // very little defined!
274
278
  typedef V value_type;
275
279
  typedef typename value_alloc_type::difference_type difference_type;
276
280
  typedef typename value_alloc_type::size_type size_type;
@@ -463,12 +467,12 @@ class sparse_hashtable {
463
467
  assert(num_deleted == 0);
464
468
  }
465
469
 
470
+ // Test if the given key is the deleted indicator. Requires
471
+ // num_deleted > 0, for correctness of read(), and because that
472
+ // guarantees that key_info.delkey is valid.
466
473
  bool test_deleted_key(const key_type& key) const {
467
- // The num_deleted test is crucial for read(): after read(), the ht values
468
- // are garbage, and we don't want to think some of them are deleted.
469
- // Invariant: !use_deleted implies num_deleted is 0.
470
- assert(settings.use_deleted() || num_deleted == 0);
471
- return num_deleted > 0 && equals(key_info.delkey, key);
474
+ assert(num_deleted > 0);
475
+ return equals(key_info.delkey, key);
472
476
  }
473
477
 
474
478
  public:
@@ -491,27 +495,37 @@ class sparse_hashtable {
491
495
  // These are public so the iterators can use them
492
496
  // True if the item at position bucknum is "deleted" marker
493
497
  bool test_deleted(size_type bucknum) const {
494
- if (num_deleted == 0 || !table.test(bucknum)) return false;
495
- return test_deleted_key(get_key(table.unsafe_get(bucknum)));
498
+ // Invariant: !use_deleted() implies num_deleted is 0.
499
+ assert(settings.use_deleted() || num_deleted == 0);
500
+ return num_deleted > 0 && table.test(bucknum) &&
501
+ test_deleted_key(get_key(table.unsafe_get(bucknum)));
496
502
  }
497
503
  bool test_deleted(const iterator &it) const {
498
- if (!settings.use_deleted()) return false;
499
- return test_deleted_key(get_key(*it));
504
+ // Invariant: !use_deleted() implies num_deleted is 0.
505
+ assert(settings.use_deleted() || num_deleted == 0);
506
+ return num_deleted > 0 && test_deleted_key(get_key(*it));
500
507
  }
501
508
  bool test_deleted(const const_iterator &it) const {
502
- if (!settings.use_deleted()) return false;
503
- return test_deleted_key(get_key(*it));
509
+ // Invariant: !use_deleted() implies num_deleted is 0.
510
+ assert(settings.use_deleted() || num_deleted == 0);
511
+ return num_deleted > 0 && test_deleted_key(get_key(*it));
504
512
  }
505
513
  bool test_deleted(const destructive_iterator &it) const {
506
- if (!settings.use_deleted()) return false;
507
- return test_deleted_key(get_key(*it));
514
+ // Invariant: !use_deleted() implies num_deleted is 0.
515
+ assert(settings.use_deleted() || num_deleted == 0);
516
+ return num_deleted > 0 && test_deleted_key(get_key(*it));
508
517
  }
509
518
 
510
519
  private:
520
+ void check_use_deleted(const char* caller) {
521
+ (void)caller; // could log it if the assert failed
522
+ assert(settings.use_deleted());
523
+ }
524
+
511
525
  // Set it so test_deleted is true. true if object didn't used to be deleted.
512
526
  // TODO(csilvers): make these private (also in densehashtable.h)
513
527
  bool set_deleted(iterator &it) {
514
- assert(settings.use_deleted());
528
+ check_use_deleted("set_deleted()");
515
529
  bool retval = !test_deleted(it);
516
530
  // &* converts from iterator to value-type.
517
531
  set_key(&(*it), key_info.delkey);
@@ -519,7 +533,7 @@ class sparse_hashtable {
519
533
  }
520
534
  // Set it so test_deleted is false. true if object used to be deleted.
521
535
  bool clear_deleted(iterator &it) {
522
- assert(settings.use_deleted());
536
+ check_use_deleted("clear_deleted()");
523
537
  // Happens automatically when we assign something else in its place.
524
538
  return test_deleted(it);
525
539
  }
@@ -530,14 +544,14 @@ class sparse_hashtable {
530
544
  // 'it' after it's been deleted anyway, so its const-ness doesn't
531
545
  // really matter.
532
546
  bool set_deleted(const_iterator &it) {
533
- assert(settings.use_deleted()); // bad if set_deleted_key() wasn't called
547
+ check_use_deleted("set_deleted()");
534
548
  bool retval = !test_deleted(it);
535
549
  set_key(const_cast<pointer>(&(*it)), key_info.delkey);
536
550
  return retval;
537
551
  }
538
552
  // Set it so test_deleted is false. true if object used to be deleted.
539
553
  bool clear_deleted(const_iterator &it) {
540
- assert(settings.use_deleted()); // bad if set_deleted_key() wasn't called
554
+ check_use_deleted("clear_deleted()");
541
555
  return test_deleted(it);
542
556
  }
543
557
 
@@ -600,8 +614,9 @@ class sparse_hashtable {
600
614
  did_resize = true;
601
615
  }
602
616
  if (table.num_nonempty() >=
603
- (STL_NAMESPACE::numeric_limits<size_type>::max)() - delta)
617
+ (std::numeric_limits<size_type>::max)() - delta) {
604
618
  throw std::length_error("resize overflow");
619
+ }
605
620
  if ( bucket_count() >= HT_MIN_BUCKETS &&
606
621
  (table.num_nonempty() + delta) <= settings.enlarge_threshold() )
607
622
  return did_resize; // we're ok as we are
@@ -621,7 +636,7 @@ class sparse_hashtable {
621
636
  settings.min_buckets(table.num_nonempty() - num_deleted + delta,
622
637
  bucket_count());
623
638
  if (resize_to < needed_size && // may double resize_to
624
- resize_to < (STL_NAMESPACE::numeric_limits<size_type>::max)() / 2) {
639
+ resize_to < (std::numeric_limits<size_type>::max)() / 2) {
625
640
  // This situation means that we have enough deleted elements,
626
641
  // that once we purge them, we won't actually have needed to
627
642
  // grow. But we may want to grow anyway: if we just purge one
@@ -795,10 +810,13 @@ class sparse_hashtable {
795
810
 
796
811
  // Many STL algorithms use swap instead of copy constructors
797
812
  void swap(sparse_hashtable& ht) {
798
- STL_NAMESPACE::swap(settings, ht.settings);
799
- STL_NAMESPACE::swap(key_info, ht.key_info);
800
- STL_NAMESPACE::swap(num_deleted, ht.num_deleted);
813
+ std::swap(settings, ht.settings);
814
+ std::swap(key_info, ht.key_info);
815
+ std::swap(num_deleted, ht.num_deleted);
801
816
  table.swap(ht.table);
817
+ settings.reset_thresholds(bucket_count()); // also resets consider_shrink
818
+ ht.settings.reset_thresholds(ht.bucket_count());
819
+ // we purposefully don't swap the allocator, which may not be swap-able
802
820
  }
803
821
 
804
822
  // It's always nice to be able to clear a table without deallocating it
@@ -817,7 +835,7 @@ class sparse_hashtable {
817
835
  // if object is not found; 2nd is ILLEGAL_BUCKET if it is.
818
836
  // Note: because of deletions where-to-insert is not trivial: it's the
819
837
  // first deleted bucket we see, as long as we don't find the key later
820
- pair<size_type, size_type> find_position(const key_type &key) const {
838
+ std::pair<size_type, size_type> find_position(const key_type &key) const {
821
839
  size_type num_probes = 0; // how many times we've probed
822
840
  const size_type bucket_count_minus_one = bucket_count() - 1;
823
841
  size_type bucknum = hash(key) & bucket_count_minus_one;
@@ -827,9 +845,9 @@ class sparse_hashtable {
827
845
  if ( !table.test(bucknum) ) { // bucket is empty
828
846
  SPARSEHASH_STAT_UPDATE(total_probes += num_probes);
829
847
  if ( insert_pos == ILLEGAL_BUCKET ) // found no prior place to insert
830
- return pair<size_type,size_type>(ILLEGAL_BUCKET, bucknum);
848
+ return std::pair<size_type,size_type>(ILLEGAL_BUCKET, bucknum);
831
849
  else
832
- return pair<size_type,size_type>(ILLEGAL_BUCKET, insert_pos);
850
+ return std::pair<size_type,size_type>(ILLEGAL_BUCKET, insert_pos);
833
851
 
834
852
  } else if ( test_deleted(bucknum) ) {// keep searching, but mark to insert
835
853
  if ( insert_pos == ILLEGAL_BUCKET )
@@ -837,7 +855,7 @@ class sparse_hashtable {
837
855
 
838
856
  } else if ( equals(key, get_key(table.unsafe_get(bucknum))) ) {
839
857
  SPARSEHASH_STAT_UPDATE(total_probes += num_probes);
840
- return pair<size_type,size_type>(bucknum, ILLEGAL_BUCKET);
858
+ return std::pair<size_type,size_type>(bucknum, ILLEGAL_BUCKET);
841
859
  }
842
860
  ++num_probes; // we're doing another probe
843
861
  bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one;
@@ -847,9 +865,10 @@ class sparse_hashtable {
847
865
  }
848
866
 
849
867
  public:
868
+
850
869
  iterator find(const key_type& key) {
851
870
  if ( size() == 0 ) return end();
852
- pair<size_type, size_type> pos = find_position(key);
871
+ std::pair<size_type, size_type> pos = find_position(key);
853
872
  if ( pos.first == ILLEGAL_BUCKET ) // alas, not there
854
873
  return end();
855
874
  else
@@ -858,7 +877,7 @@ class sparse_hashtable {
858
877
 
859
878
  const_iterator find(const key_type& key) const {
860
879
  if ( size() == 0 ) return end();
861
- pair<size_type, size_type> pos = find_position(key);
880
+ std::pair<size_type, size_type> pos = find_position(key);
862
881
  if ( pos.first == ILLEGAL_BUCKET ) // alas, not there
863
882
  return end();
864
883
  else
@@ -869,33 +888,34 @@ class sparse_hashtable {
869
888
  // This is a tr1 method: the bucket a given key is in, or what bucket
870
889
  // it would be put in, if it were to be inserted. Shrug.
871
890
  size_type bucket(const key_type& key) const {
872
- pair<size_type, size_type> pos = find_position(key);
891
+ std::pair<size_type, size_type> pos = find_position(key);
873
892
  return pos.first == ILLEGAL_BUCKET ? pos.second : pos.first;
874
893
  }
875
894
 
876
895
  // Counts how many elements have key key. For maps, it's either 0 or 1.
877
896
  size_type count(const key_type &key) const {
878
- pair<size_type, size_type> pos = find_position(key);
897
+ std::pair<size_type, size_type> pos = find_position(key);
879
898
  return pos.first == ILLEGAL_BUCKET ? 0 : 1;
880
899
  }
881
900
 
882
901
  // Likewise, equal_range doesn't really make sense for us. Oh well.
883
- pair<iterator,iterator> equal_range(const key_type& key) {
902
+ std::pair<iterator,iterator> equal_range(const key_type& key) {
884
903
  iterator pos = find(key); // either an iterator or end
885
904
  if (pos == end()) {
886
- return pair<iterator,iterator>(pos, pos);
905
+ return std::pair<iterator,iterator>(pos, pos);
887
906
  } else {
888
907
  const iterator startpos = pos++;
889
- return pair<iterator,iterator>(startpos, pos);
908
+ return std::pair<iterator,iterator>(startpos, pos);
890
909
  }
891
910
  }
892
- pair<const_iterator,const_iterator> equal_range(const key_type& key) const {
911
+ std::pair<const_iterator,const_iterator> equal_range(const key_type& key)
912
+ const {
893
913
  const_iterator pos = find(key); // either an iterator or end
894
914
  if (pos == end()) {
895
- return pair<const_iterator,const_iterator>(pos, pos);
915
+ return std::pair<const_iterator,const_iterator>(pos, pos);
896
916
  } else {
897
917
  const const_iterator startpos = pos++;
898
- return pair<const_iterator,const_iterator>(startpos, pos);
918
+ return std::pair<const_iterator,const_iterator>(startpos, pos);
899
919
  }
900
920
  }
901
921
 
@@ -904,8 +924,9 @@ class sparse_hashtable {
904
924
  private:
905
925
  // Private method used by insert_noresize and find_or_insert.
906
926
  iterator insert_at(const_reference obj, size_type pos) {
907
- if (size() >= max_size())
927
+ if (size() >= max_size()) {
908
928
  throw std::length_error("insert overflow");
929
+ }
909
930
  if ( test_deleted(pos) ) { // just replace if it's been deleted
910
931
  // The set() below will undelete this object. We just worry about stats
911
932
  assert(num_deleted > 0);
@@ -916,27 +937,28 @@ class sparse_hashtable {
916
937
  }
917
938
 
918
939
  // If you know *this is big enough to hold obj, use this routine
919
- pair<iterator, bool> insert_noresize(const_reference obj) {
940
+ std::pair<iterator, bool> insert_noresize(const_reference obj) {
920
941
  // First, double-check we're not inserting delkey
921
942
  assert((!settings.use_deleted() || !equals(get_key(obj), key_info.delkey))
922
943
  && "Inserting the deleted key");
923
- const pair<size_type,size_type> pos = find_position(get_key(obj));
944
+ const std::pair<size_type,size_type> pos = find_position(get_key(obj));
924
945
  if ( pos.first != ILLEGAL_BUCKET) { // object was already there
925
- return pair<iterator,bool>(iterator(this, table.get_iter(pos.first),
926
- table.nonempty_end()),
927
- false); // false: we didn't insert
946
+ return std::pair<iterator,bool>(iterator(this, table.get_iter(pos.first),
947
+ table.nonempty_end()),
948
+ false); // false: we didn't insert
928
949
  } else { // pos.second says where to put it
929
- return pair<iterator,bool>(insert_at(obj, pos.second), true);
950
+ return std::pair<iterator,bool>(insert_at(obj, pos.second), true);
930
951
  }
931
952
  }
932
953
 
933
954
  // Specializations of insert(it, it) depending on the power of the iterator:
934
955
  // (1) Iterator supports operator-, resize before inserting
935
956
  template <class ForwardIterator>
936
- void insert(ForwardIterator f, ForwardIterator l, STL_NAMESPACE::forward_iterator_tag) {
937
- size_t dist = STL_NAMESPACE::distance(f, l);
938
- if (dist >= (std::numeric_limits<size_type>::max)())
957
+ void insert(ForwardIterator f, ForwardIterator l, std::forward_iterator_tag) {
958
+ size_t dist = std::distance(f, l);
959
+ if (dist >= (std::numeric_limits<size_type>::max)()) {
939
960
  throw std::length_error("insert-range overflow");
961
+ }
940
962
  resize_delta(static_cast<size_type>(dist));
941
963
  for ( ; dist > 0; --dist, ++f) {
942
964
  insert_noresize(*f);
@@ -945,14 +967,14 @@ class sparse_hashtable {
945
967
 
946
968
  // (2) Arbitrary iterator, can't tell how much to resize
947
969
  template <class InputIterator>
948
- void insert(InputIterator f, InputIterator l, STL_NAMESPACE::input_iterator_tag) {
970
+ void insert(InputIterator f, InputIterator l, std::input_iterator_tag) {
949
971
  for ( ; f != l; ++f)
950
972
  insert(*f);
951
973
  }
952
974
 
953
975
  public:
954
976
  // This is the normal insert routine, used by the outside world
955
- pair<iterator, bool> insert(const_reference obj) {
977
+ std::pair<iterator, bool> insert(const_reference obj) {
956
978
  resize_delta(1); // adding an object, grow if need be
957
979
  return insert_noresize(obj);
958
980
  }
@@ -961,24 +983,26 @@ class sparse_hashtable {
961
983
  template <class InputIterator>
962
984
  void insert(InputIterator f, InputIterator l) {
963
985
  // specializes on iterator type
964
- insert(f, l, typename STL_NAMESPACE::iterator_traits<InputIterator>::iterator_category());
986
+ insert(f, l,
987
+ typename std::iterator_traits<InputIterator>::iterator_category());
965
988
  }
966
989
 
967
- // This is public only because sparse_hash_map::operator[] uses it.
968
- // It does the minimal amount of work to implement operator[].
969
- template <class DataType>
970
- DataType& find_or_insert(const key_type& key) {
990
+ // DefaultValue is a functor that takes a key and returns a value_type
991
+ // representing the default value to be inserted if none is found.
992
+ template <class DefaultValue>
993
+ value_type& find_or_insert(const key_type& key) {
971
994
  // First, double-check we're not inserting delkey
972
995
  assert((!settings.use_deleted() || !equals(key, key_info.delkey))
973
996
  && "Inserting the deleted key");
974
- const pair<size_type,size_type> pos = find_position(key);
997
+ const std::pair<size_type,size_type> pos = find_position(key);
998
+ DefaultValue default_value;
975
999
  if ( pos.first != ILLEGAL_BUCKET) { // object was already there
976
- return table.get_iter(pos.first)->second;
1000
+ return *table.get_iter(pos.first);
977
1001
  } else if (resize_delta(1)) { // needed to rehash to make room
978
1002
  // Since we resized, we can't use pos, so recalculate where to insert.
979
- return insert_noresize(value_type(key, DataType())).first->second;
1003
+ return *insert_noresize(default_value(key)).first;
980
1004
  } else { // no need to rehash, insert right here
981
- return insert_at(value_type(key, DataType()), pos.second)->second;
1005
+ return *insert_at(default_value(key), pos.second);
982
1006
  }
983
1007
  }
984
1008
 
@@ -1072,28 +1096,62 @@ class sparse_hashtable {
1072
1096
  // actually put in the hashtable! Alas, since I don't know how to
1073
1097
  // write a hasher or key_equal, you have to make sure everything
1074
1098
  // but the table is the same. We compact before writing.
1075
- bool write_metadata(FILE *fp) {
1099
+ //
1100
+ // The OUTPUT type needs to support a Write() operation. File and
1101
+ // OutputBuffer are appropriate types to pass in.
1102
+ //
1103
+ // The INPUT type needs to support a Read() operation. File and
1104
+ // InputBuffer are appropriate types to pass in.
1105
+ template <typename OUTPUT>
1106
+ bool write_metadata(OUTPUT *fp) {
1076
1107
  squash_deleted(); // so we don't have to worry about delkey
1077
1108
  return table.write_metadata(fp);
1078
1109
  }
1079
1110
 
1080
- bool read_metadata(FILE *fp) {
1111
+ template <typename INPUT>
1112
+ bool read_metadata(INPUT *fp) {
1081
1113
  num_deleted = 0; // since we got rid before writing
1082
- bool result = table.read_metadata(fp);
1114
+ const bool result = table.read_metadata(fp);
1083
1115
  settings.reset_thresholds(bucket_count());
1084
1116
  return result;
1085
1117
  }
1086
1118
 
1087
1119
  // Only meaningful if value_type is a POD.
1088
- bool write_nopointer_data(FILE *fp) {
1120
+ template <typename OUTPUT>
1121
+ bool write_nopointer_data(OUTPUT *fp) {
1089
1122
  return table.write_nopointer_data(fp);
1090
1123
  }
1091
1124
 
1092
1125
  // Only meaningful if value_type is a POD.
1093
- bool read_nopointer_data(FILE *fp) {
1126
+ template <typename INPUT>
1127
+ bool read_nopointer_data(INPUT *fp) {
1094
1128
  return table.read_nopointer_data(fp);
1095
1129
  }
1096
1130
 
1131
+ // INPUT and OUTPUT must be either a FILE, *or* a C++ stream
1132
+ // (istream, ostream, etc) *or* a class providing
1133
+ // Read(void*, size_t) and Write(const void*, size_t)
1134
+ // (respectively), which writes a buffer into a stream
1135
+ // (which the INPUT/OUTPUT instance presumably owns).
1136
+
1137
+ typedef sparsehash_internal::pod_serializer<value_type> NopointerSerializer;
1138
+
1139
+ // ValueSerializer: a functor. operator()(OUTPUT*, const value_type&)
1140
+ template <typename ValueSerializer, typename OUTPUT>
1141
+ bool serialize(ValueSerializer serializer, OUTPUT *fp) {
1142
+ squash_deleted(); // so we don't have to worry about delkey
1143
+ return table.serialize(serializer, fp);
1144
+ }
1145
+
1146
+ // ValueSerializer: a functor. operator()(INPUT*, value_type*)
1147
+ template <typename ValueSerializer, typename INPUT>
1148
+ bool unserialize(ValueSerializer serializer, INPUT *fp) {
1149
+ num_deleted = 0; // since we got rid before writing
1150
+ const bool result = table.unserialize(serializer, fp);
1151
+ settings.reset_thresholds(bucket_count());
1152
+ return result;
1153
+ }
1154
+
1097
1155
  private:
1098
1156
  // Table is the main storage class.
1099
1157
  typedef sparsetable<value_type, DEFAULT_GROUP_SIZE, value_alloc_type> Table;
@@ -1103,34 +1161,37 @@ class sparse_hashtable {
1103
1161
  // hasher's operator() might have the same function signature, they
1104
1162
  // must be packaged in different classes.
1105
1163
  struct Settings :
1106
- sh_hashtable_settings<key_type, hasher, size_type, HT_MIN_BUCKETS> {
1164
+ sparsehash_internal::sh_hashtable_settings<key_type, hasher,
1165
+ size_type, HT_MIN_BUCKETS> {
1107
1166
  explicit Settings(const hasher& hf)
1108
- : sh_hashtable_settings<key_type, hasher, size_type, HT_MIN_BUCKETS>(
1167
+ : sparsehash_internal::sh_hashtable_settings<key_type, hasher,
1168
+ size_type, HT_MIN_BUCKETS>(
1109
1169
  hf, HT_OCCUPANCY_PCT / 100.0f, HT_EMPTY_PCT / 100.0f) {}
1110
1170
  };
1111
1171
 
1112
1172
  // KeyInfo stores delete key and packages zero-size functors:
1113
1173
  // ExtractKey and SetKey.
1114
- class KeyInfo : public ExtractKey, public SetKey, public key_equal {
1174
+ class KeyInfo : public ExtractKey, public SetKey, public EqualKey {
1115
1175
  public:
1116
- KeyInfo(const ExtractKey& ek, const SetKey& sk, const key_equal& eq)
1176
+ KeyInfo(const ExtractKey& ek, const SetKey& sk, const EqualKey& eq)
1117
1177
  : ExtractKey(ek),
1118
1178
  SetKey(sk),
1119
- key_equal(eq) {
1179
+ EqualKey(eq) {
1120
1180
  }
1121
- const key_type get_key(const_reference v) const {
1181
+ // We want to return the exact same type as ExtractKey: Key or const Key&
1182
+ typename ExtractKey::result_type get_key(const_reference v) const {
1122
1183
  return ExtractKey::operator()(v);
1123
1184
  }
1124
1185
  void set_key(pointer v, const key_type& k) const {
1125
1186
  SetKey::operator()(v, k);
1126
1187
  }
1127
1188
  bool equals(const key_type& a, const key_type& b) const {
1128
- return key_equal::operator()(a, b);
1189
+ return EqualKey::operator()(a, b);
1129
1190
  }
1130
1191
 
1131
1192
  // Which key marks deleted entries.
1132
1193
  // TODO(csilvers): make a pointer, and get rid of use_deleted (benchmark!)
1133
- typename remove_const<key_type>::type delkey;
1194
+ typename base::remove_const<key_type>::type delkey;
1134
1195
  };
1135
1196
 
1136
1197
  // Utility functions to access the templated operators
@@ -1140,7 +1201,7 @@ class sparse_hashtable {
1140
1201
  bool equals(const key_type& a, const key_type& b) const {
1141
1202
  return key_info.equals(a, b);
1142
1203
  }
1143
- const key_type get_key(const_reference v) const {
1204
+ typename ExtractKey::result_type get_key(const_reference v) const {
1144
1205
  return key_info.get_key(v);
1145
1206
  }
1146
1207
  void set_key(pointer v, const key_type& k) const {