google_hash 0.8.1 → 0.8.2

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 (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 {