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