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.
- data/ChangeLog.txt +2 -0
- data/VERSION +1 -1
- data/ext/clean.bat +0 -0
- data/ext/clean.sh +4 -0
- data/ext/extconf.rb +4 -5
- data/ext/go.bat +0 -0
- data/ext/sparsehash-2.0.2/AUTHORS +2 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/COPYING +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/ChangeLog +60 -0
- data/ext/sparsehash-2.0.2/INSTALL +365 -0
- data/ext/sparsehash-2.0.2/Makefile +1336 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/Makefile.am +97 -40
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/Makefile.in +538 -256
- data/ext/sparsehash-2.0.2/NEWS +188 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/README +4 -10
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/README_windows.txt +3 -3
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/TODO +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/aclocal.m4 +266 -166
- data/ext/sparsehash-2.0.2/allocator.patch +31 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/config.guess +235 -234
- data/ext/sparsehash-2.0.2/config.status +1238 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/config.sub +198 -64
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/configure +1118 -1000
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/configure.ac +4 -5
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/depcomp +136 -36
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/dense_hash_map.html +182 -67
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/dense_hash_set.html +173 -74
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/designstyle.css +0 -6
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/implementation.html +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/index.html +4 -5
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/performance.html +1 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparse_hash_map.html +190 -58
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparse_hash_set.html +180 -65
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparsetable.html +1 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/Makefile +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/README +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/example.c +1 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/libchash.c +1 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/libchash.h +1 -0
- data/ext/sparsehash-2.0.2/install-sh +520 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/acx_pthread.m4 +34 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/google_namespace.m4 +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/namespaces.m4 +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/stl_hash.m4 +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/stl_hash_fun.m4 +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/missing +60 -44
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb.sh +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/README +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/changelog +42 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/compat +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/control +1 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/copyright +5 -4
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/docs +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/rules +0 -0
- data/ext/sparsehash-2.0.2/packages/deb/sparsehash.dirs +5 -0
- data/ext/sparsehash-2.0.2/packages/deb/sparsehash.install +6 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/rpm.sh +1 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/rpm/rpm.spec +5 -3
- data/ext/{sparsehash-1.8.1/google-sparsehash.sln → sparsehash-2.0.2/sparsehash.sln} +0 -0
- data/ext/sparsehash-2.0.2/src/config.h +132 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/config.h.in +0 -3
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/config.h.include +0 -1
- data/ext/sparsehash-2.0.2/src/google/dense_hash_map +34 -0
- data/ext/sparsehash-2.0.2/src/google/dense_hash_set +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparse_hash_map +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparse_hash_set +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsehash/densehashtable.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsehash/hashtable-common.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsehash/libc_allocator_with_realloc.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsehash/sparsehashtable.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsetable +34 -0
- data/ext/sparsehash-2.0.2/src/google/template_util.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/type_traits.h +34 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/hash_test_interface.h +64 -37
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/hashtable_test.cc +415 -141
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/libc_allocator_with_realloc_test.cc +16 -23
- data/ext/sparsehash-2.0.2/src/simple_compat_test.cc +106 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/simple_test.cc +8 -5
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/dense_hash_map +80 -37
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/dense_hash_set +64 -34
- data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/densehashtable.h +247 -173
- data/ext/sparsehash-2.0.2/src/sparsehash/internal/hashtable-common.h +381 -0
- data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/libc_allocator_with_realloc.h +5 -7
- data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/sparsehashtable.h +154 -93
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparse_hash_map +96 -36
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparse_hash_set +85 -32
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparsetable +520 -258
- data/ext/sparsehash-2.0.2/src/sparsehash/template_util.h +134 -0
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/type_traits.h +153 -35
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/sparsetable_unittest.cc +108 -22
- data/ext/sparsehash-2.0.2/src/stamp-h1 +1 -0
- data/ext/sparsehash-2.0.2/src/template_util_unittest.cc +134 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/testutil.h +16 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/time_hash_map.cc +259 -94
- data/ext/sparsehash-2.0.2/src/type_traits_unittest.cc +636 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/config.h +4 -4
- data/ext/sparsehash-2.0.2/src/windows/google/sparsehash/sparseconfig.h +49 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/port.cc +1 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/port.h +4 -13
- data/ext/sparsehash-2.0.2/src/windows/sparsehash/internal/sparseconfig.h +49 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/hashtable_test/hashtable_test.vcproj +11 -11
- data/ext/sparsehash-2.0.2/vsprojects/libc_allocator_with_realloc_test/libc_allocator_with_realloc_test.vcproj +161 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/simple_test/simple_test.vcproj +10 -10
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +4 -4
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/time_hash_map/time_hash_map.vcproj +10 -10
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +3 -3
- data/ext/spec.bat +0 -0
- data/ext/template/google_hash.cpp.erb +6 -5
- metadata +106 -86
- data/ext/sparsehash-1.8.1/AUTHORS +0 -2
- data/ext/sparsehash-1.8.1/INSTALL +0 -236
- data/ext/sparsehash-1.8.1/NEWS +0 -71
- data/ext/sparsehash-1.8.1/compile +0 -99
- data/ext/sparsehash-1.8.1/install-sh +0 -323
- data/ext/sparsehash-1.8.1/m4/stl_namespace.m4 +0 -25
- data/ext/sparsehash-1.8.1/mkinstalldirs +0 -158
- data/ext/sparsehash-1.8.1/packages/deb/sparsehash.dirs +0 -2
- data/ext/sparsehash-1.8.1/packages/deb/sparsehash.install +0 -2
- data/ext/sparsehash-1.8.1/src/google/sparsehash/hashtable-common.h +0 -178
- data/ext/sparsehash-1.8.1/src/type_traits_unittest.cc +0 -502
- 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 <
|
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
|
-
//
|
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,
|
168
|
+
typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,value_alloc_type>::nonempty_iterator
|
165
169
|
st_iterator;
|
166
170
|
|
167
|
-
typedef
|
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,
|
220
|
+
typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,value_alloc_type>::const_nonempty_iterator
|
217
221
|
st_iterator;
|
218
222
|
|
219
|
-
typedef
|
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,
|
274
|
+
typedef typename sparsetable<V,DEFAULT_GROUP_SIZE,value_alloc_type>::destructive_iterator
|
271
275
|
st_iterator;
|
272
276
|
|
273
|
-
typedef
|
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
|
-
|
468
|
-
|
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
|
-
|
495
|
-
|
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
|
-
|
499
|
-
|
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
|
-
|
503
|
-
|
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
|
-
|
507
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
(
|
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 < (
|
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
|
-
|
799
|
-
|
800
|
-
|
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)
|
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
|
-
|
927
|
-
|
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,
|
937
|
-
size_t dist =
|
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,
|
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,
|
986
|
+
insert(f, l,
|
987
|
+
typename std::iterator_traits<InputIterator>::iterator_category());
|
965
988
|
}
|
966
989
|
|
967
|
-
//
|
968
|
-
//
|
969
|
-
template <class
|
970
|
-
|
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)
|
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(
|
1003
|
+
return *insert_noresize(default_value(key)).first;
|
980
1004
|
} else { // no need to rehash, insert right here
|
981
|
-
return insert_at(
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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,
|
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
|
1174
|
+
class KeyInfo : public ExtractKey, public SetKey, public EqualKey {
|
1115
1175
|
public:
|
1116
|
-
KeyInfo(const ExtractKey& ek, const SetKey& sk, const
|
1176
|
+
KeyInfo(const ExtractKey& ek, const SetKey& sk, const EqualKey& eq)
|
1117
1177
|
: ExtractKey(ek),
|
1118
1178
|
SetKey(sk),
|
1119
|
-
|
1179
|
+
EqualKey(eq) {
|
1120
1180
|
}
|
1121
|
-
|
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
|
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
|
-
|
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 {
|