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
|
@@ -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 dense hashtable is a particular implementation of
|
|
34
33
|
// a hashtable: one that is meant to minimize memory allocation.
|
|
@@ -53,8 +52,8 @@
|
|
|
53
52
|
// and Default Constructible. It is not required to be (and commonly
|
|
54
53
|
// isn't) Assignable.
|
|
55
54
|
//
|
|
56
|
-
// You probably shouldn't use this code directly. Use
|
|
57
|
-
//
|
|
55
|
+
// You probably shouldn't use this code directly. Use dense_hash_map<>
|
|
56
|
+
// or dense_hash_set<> instead.
|
|
58
57
|
|
|
59
58
|
// You can change the following below:
|
|
60
59
|
// HT_OCCUPANCY_PCT -- how full before we double size
|
|
@@ -72,7 +71,7 @@
|
|
|
72
71
|
// For enlarge_factor, you can use this chart to try to trade-off
|
|
73
72
|
// expected lookup time to the space taken up. By default, this
|
|
74
73
|
// code uses quadratic probing, though you can change it to linear
|
|
75
|
-
// via
|
|
74
|
+
// via JUMP_ below if you really want to.
|
|
76
75
|
//
|
|
77
76
|
// From http://www.augustana.ca/~mohrj/courses/1999.fall/csc210/lecture_notes/hashing.html
|
|
78
77
|
// NUMBER OF PROBES / LOOKUP Successful Unsuccessful
|
|
@@ -90,31 +89,34 @@
|
|
|
90
89
|
#ifndef _DENSEHASHTABLE_H_
|
|
91
90
|
#define _DENSEHASHTABLE_H_
|
|
92
91
|
|
|
93
|
-
|
|
94
|
-
// Linear probing
|
|
95
|
-
// #define JUMP_(key, num_probes) ( 1 )
|
|
96
|
-
// Quadratic probing
|
|
97
|
-
#define JUMP_(key, num_probes) ( num_probes )
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
#include <google/sparsehash/sparseconfig.h>
|
|
101
|
-
#include <stdio.h>
|
|
92
|
+
#include <sparsehash/internal/sparseconfig.h>
|
|
102
93
|
#include <assert.h>
|
|
103
|
-
#include <
|
|
94
|
+
#include <stdio.h> // for FILE, fwrite, fread
|
|
104
95
|
#include <algorithm> // For swap(), eg
|
|
105
|
-
#include <
|
|
106
|
-
#include <
|
|
107
|
-
#include <memory> // For uninitialized_fill
|
|
108
|
-
#include <utility> // for pair
|
|
109
|
-
#include <
|
|
110
|
-
#include <
|
|
111
|
-
#include <
|
|
112
|
-
#include <
|
|
113
|
-
#include <google/type_traits.h> // for true_type, integral_constant, etc.
|
|
96
|
+
#include <iterator> // For iterator tags
|
|
97
|
+
#include <limits> // for numeric_limits
|
|
98
|
+
#include <memory> // For uninitialized_fill
|
|
99
|
+
#include <utility> // for pair
|
|
100
|
+
#include <sparsehash/internal/hashtable-common.h>
|
|
101
|
+
#include <sparsehash/internal/libc_allocator_with_realloc.h>
|
|
102
|
+
#include <sparsehash/type_traits.h>
|
|
103
|
+
#include <stdexcept> // For length_error
|
|
114
104
|
|
|
115
105
|
_START_GOOGLE_NAMESPACE_
|
|
116
106
|
|
|
117
|
-
|
|
107
|
+
namespace base { // just to make google->opensource transition easier
|
|
108
|
+
using GOOGLE_NAMESPACE::true_type;
|
|
109
|
+
using GOOGLE_NAMESPACE::false_type;
|
|
110
|
+
using GOOGLE_NAMESPACE::integral_constant;
|
|
111
|
+
using GOOGLE_NAMESPACE::is_same;
|
|
112
|
+
using GOOGLE_NAMESPACE::remove_const;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// The probing method
|
|
116
|
+
// Linear probing
|
|
117
|
+
// #define JUMP_(key, num_probes) ( 1 )
|
|
118
|
+
// Quadratic probing
|
|
119
|
+
#define JUMP_(key, num_probes) ( num_probes )
|
|
118
120
|
|
|
119
121
|
// Hashtable class, used to implement the hashed associative containers
|
|
120
122
|
// hash_set and hash_map.
|
|
@@ -124,6 +126,8 @@ using STL_NAMESPACE::pair;
|
|
|
124
126
|
// to search for a Value in the table (find() takes a Key).
|
|
125
127
|
// HashFcn: Takes a Key and returns an integer, the more unique the better.
|
|
126
128
|
// ExtractKey: given a Value, returns the unique Key associated with it.
|
|
129
|
+
// Must inherit from unary_function, or at least have a
|
|
130
|
+
// result_type enum indicating the return type of operator().
|
|
127
131
|
// SetKey: given a Value* and a Key, modifies the value such that
|
|
128
132
|
// ExtractKey(value) == key. We guarantee this is only called
|
|
129
133
|
// with key == deleted_key or key == empty_key.
|
|
@@ -151,7 +155,7 @@ struct dense_hashtable_iterator {
|
|
|
151
155
|
typedef dense_hashtable_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
|
|
152
156
|
typedef dense_hashtable_const_iterator<V,K,HF,ExK,SetK,EqK,A> const_iterator;
|
|
153
157
|
|
|
154
|
-
typedef
|
|
158
|
+
typedef std::forward_iterator_tag iterator_category; // very little defined!
|
|
155
159
|
typedef V value_type;
|
|
156
160
|
typedef typename value_alloc_type::difference_type difference_type;
|
|
157
161
|
typedef typename value_alloc_type::size_type size_type;
|
|
@@ -204,7 +208,7 @@ struct dense_hashtable_const_iterator {
|
|
|
204
208
|
typedef dense_hashtable_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
|
|
205
209
|
typedef dense_hashtable_const_iterator<V,K,HF,ExK,SetK,EqK,A> const_iterator;
|
|
206
210
|
|
|
207
|
-
typedef
|
|
211
|
+
typedef std::forward_iterator_tag iterator_category; // very little defined!
|
|
208
212
|
typedef V value_type;
|
|
209
213
|
typedef typename value_alloc_type::difference_type difference_type;
|
|
210
214
|
typedef typename value_alloc_type::size_type size_type;
|
|
@@ -218,7 +222,8 @@ struct dense_hashtable_const_iterator {
|
|
|
218
222
|
: ht(h), pos(it), end(it_end) {
|
|
219
223
|
if (advance) advance_past_empty_and_deleted();
|
|
220
224
|
}
|
|
221
|
-
dense_hashtable_const_iterator()
|
|
225
|
+
dense_hashtable_const_iterator()
|
|
226
|
+
: ht(NULL), pos(pointer()), end(pointer()) { }
|
|
222
227
|
// This lets us convert regular iterators to const iterators
|
|
223
228
|
dense_hashtable_const_iterator(const iterator &it)
|
|
224
229
|
: ht(it.ht), pos(it.pos), end(it.end) { }
|
|
@@ -284,12 +289,12 @@ class dense_hashtable {
|
|
|
284
289
|
// How full we let the table get before we resize, by default.
|
|
285
290
|
// Knuth says .8 is good -- higher causes us to probe too much,
|
|
286
291
|
// though it saves memory.
|
|
287
|
-
static const int HT_OCCUPANCY_PCT;
|
|
292
|
+
static const int HT_OCCUPANCY_PCT; // defined at the bottom of this file
|
|
288
293
|
|
|
289
294
|
// How empty we let the table get before we resize lower, by default.
|
|
290
295
|
// (0.0 means never resize lower.)
|
|
291
296
|
// It should be less than OCCUPANCY_PCT / 2 or we thrash resizing
|
|
292
|
-
static const int HT_EMPTY_PCT;
|
|
297
|
+
static const int HT_EMPTY_PCT; // defined at the bottom of this file
|
|
293
298
|
|
|
294
299
|
// Minimum size we're willing to let hashtables be.
|
|
295
300
|
// Must be a power of two, and at least 4.
|
|
@@ -336,7 +341,9 @@ class dense_hashtable {
|
|
|
336
341
|
// ACCESSOR FUNCTIONS for the things we templatize on, basically
|
|
337
342
|
hasher hash_funct() const { return settings; }
|
|
338
343
|
key_equal key_eq() const { return key_info; }
|
|
339
|
-
allocator_type get_allocator() const
|
|
344
|
+
allocator_type get_allocator() const {
|
|
345
|
+
return allocator_type(val_info);
|
|
346
|
+
}
|
|
340
347
|
|
|
341
348
|
// Accessor function for statistics gathering.
|
|
342
349
|
int num_table_copies() const { return settings.num_ht_copies(); }
|
|
@@ -371,19 +378,19 @@ class dense_hashtable {
|
|
|
371
378
|
assert(num_deleted == 0);
|
|
372
379
|
}
|
|
373
380
|
|
|
381
|
+
// Test if the given key is the deleted indicator. Requires
|
|
382
|
+
// num_deleted > 0, for correctness of read(), and because that
|
|
383
|
+
// guarantees that key_info.delkey is valid.
|
|
374
384
|
bool test_deleted_key(const key_type& key) const {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
// Invariant: !use_deleted implies num_deleted is 0.
|
|
378
|
-
assert(settings.use_deleted() || num_deleted == 0);
|
|
379
|
-
return num_deleted > 0 && equals(key_info.delkey, key);
|
|
385
|
+
assert(num_deleted > 0);
|
|
386
|
+
return equals(key_info.delkey, key);
|
|
380
387
|
}
|
|
381
388
|
|
|
382
389
|
public:
|
|
383
390
|
void set_deleted_key(const key_type &key) {
|
|
384
391
|
// the empty indicator (if specified) and the deleted indicator
|
|
385
392
|
// must be different
|
|
386
|
-
assert((!settings.use_empty() || !equals(key, get_key(emptyval)))
|
|
393
|
+
assert((!settings.use_empty() || !equals(key, get_key(val_info.emptyval)))
|
|
387
394
|
&& "Passed the empty-key to set_deleted_key");
|
|
388
395
|
// It's only safe to change what "deleted" means if we purge deleted guys
|
|
389
396
|
squash_deleted();
|
|
@@ -403,19 +410,30 @@ class dense_hashtable {
|
|
|
403
410
|
// These are public so the iterators can use them
|
|
404
411
|
// True if the item at position bucknum is "deleted" marker
|
|
405
412
|
bool test_deleted(size_type bucknum) const {
|
|
406
|
-
|
|
413
|
+
// Invariant: !use_deleted() implies num_deleted is 0.
|
|
414
|
+
assert(settings.use_deleted() || num_deleted == 0);
|
|
415
|
+
return num_deleted > 0 && test_deleted_key(get_key(table[bucknum]));
|
|
407
416
|
}
|
|
408
417
|
bool test_deleted(const iterator &it) const {
|
|
409
|
-
|
|
418
|
+
// Invariant: !use_deleted() implies num_deleted is 0.
|
|
419
|
+
assert(settings.use_deleted() || num_deleted == 0);
|
|
420
|
+
return num_deleted > 0 && test_deleted_key(get_key(*it));
|
|
410
421
|
}
|
|
411
422
|
bool test_deleted(const const_iterator &it) const {
|
|
412
|
-
|
|
423
|
+
// Invariant: !use_deleted() implies num_deleted is 0.
|
|
424
|
+
assert(settings.use_deleted() || num_deleted == 0);
|
|
425
|
+
return num_deleted > 0 && test_deleted_key(get_key(*it));
|
|
413
426
|
}
|
|
414
427
|
|
|
415
428
|
private:
|
|
429
|
+
void check_use_deleted(const char* caller) {
|
|
430
|
+
(void)caller; // could log it if the assert failed
|
|
431
|
+
assert(settings.use_deleted());
|
|
432
|
+
}
|
|
433
|
+
|
|
416
434
|
// Set it so test_deleted is true. true if object didn't used to be deleted.
|
|
417
435
|
bool set_deleted(iterator &it) {
|
|
418
|
-
|
|
436
|
+
check_use_deleted("set_deleted()");
|
|
419
437
|
bool retval = !test_deleted(it);
|
|
420
438
|
// &* converts from iterator to value-type.
|
|
421
439
|
set_key(&(*it), key_info.delkey);
|
|
@@ -423,7 +441,7 @@ class dense_hashtable {
|
|
|
423
441
|
}
|
|
424
442
|
// Set it so test_deleted is false. true if object used to be deleted.
|
|
425
443
|
bool clear_deleted(iterator &it) {
|
|
426
|
-
|
|
444
|
+
check_use_deleted("clear_deleted()");
|
|
427
445
|
// Happens automatically when we assign something else in its place.
|
|
428
446
|
return test_deleted(it);
|
|
429
447
|
}
|
|
@@ -434,14 +452,14 @@ class dense_hashtable {
|
|
|
434
452
|
// 'it' after it's been deleted anyway, so its const-ness doesn't
|
|
435
453
|
// really matter.
|
|
436
454
|
bool set_deleted(const_iterator &it) {
|
|
437
|
-
|
|
455
|
+
check_use_deleted("set_deleted()");
|
|
438
456
|
bool retval = !test_deleted(it);
|
|
439
457
|
set_key(const_cast<pointer>(&(*it)), key_info.delkey);
|
|
440
458
|
return retval;
|
|
441
459
|
}
|
|
442
460
|
// Set it so test_deleted is false. true if object used to be deleted.
|
|
443
461
|
bool clear_deleted(const_iterator &it) {
|
|
444
|
-
|
|
462
|
+
check_use_deleted("clear_deleted()");
|
|
445
463
|
return test_deleted(it);
|
|
446
464
|
}
|
|
447
465
|
|
|
@@ -456,20 +474,20 @@ class dense_hashtable {
|
|
|
456
474
|
// True if the item at position bucknum is "empty" marker
|
|
457
475
|
bool test_empty(size_type bucknum) const {
|
|
458
476
|
assert(settings.use_empty()); // we always need to know what's empty!
|
|
459
|
-
return equals(get_key(emptyval), get_key(table[bucknum]));
|
|
477
|
+
return equals(get_key(val_info.emptyval), get_key(table[bucknum]));
|
|
460
478
|
}
|
|
461
479
|
bool test_empty(const iterator &it) const {
|
|
462
480
|
assert(settings.use_empty()); // we always need to know what's empty!
|
|
463
|
-
return equals(get_key(emptyval), get_key(*it));
|
|
481
|
+
return equals(get_key(val_info.emptyval), get_key(*it));
|
|
464
482
|
}
|
|
465
483
|
bool test_empty(const const_iterator &it) const {
|
|
466
484
|
assert(settings.use_empty()); // we always need to know what's empty!
|
|
467
|
-
return equals(get_key(emptyval), get_key(*it));
|
|
485
|
+
return equals(get_key(val_info.emptyval), get_key(*it));
|
|
468
486
|
}
|
|
469
487
|
|
|
470
488
|
private:
|
|
471
489
|
void fill_range_with_empty(pointer table_start, pointer table_end) {
|
|
472
|
-
|
|
490
|
+
std::uninitialized_fill(table_start, table_end, val_info.emptyval);
|
|
473
491
|
}
|
|
474
492
|
|
|
475
493
|
public:
|
|
@@ -483,24 +501,24 @@ class dense_hashtable {
|
|
|
483
501
|
assert((!settings.use_deleted() || !equals(get_key(val), key_info.delkey))
|
|
484
502
|
&& "Setting the empty key the same as the deleted key");
|
|
485
503
|
settings.set_use_empty(true);
|
|
486
|
-
set_value(&emptyval, val);
|
|
504
|
+
set_value(&val_info.emptyval, val);
|
|
487
505
|
|
|
488
506
|
assert(!table); // must set before first use
|
|
489
507
|
// num_buckets was set in constructor even though table was NULL
|
|
490
|
-
table =
|
|
508
|
+
table = val_info.allocate(num_buckets);
|
|
491
509
|
assert(table);
|
|
492
510
|
fill_range_with_empty(table, table + num_buckets);
|
|
493
511
|
}
|
|
494
|
-
// TODO(
|
|
512
|
+
// TODO(user): return a key_type rather than a value_type
|
|
495
513
|
value_type empty_key() const {
|
|
496
514
|
assert(settings.use_empty());
|
|
497
|
-
return emptyval;
|
|
515
|
+
return val_info.emptyval;
|
|
498
516
|
}
|
|
499
517
|
|
|
500
518
|
// FUNCTIONS CONCERNING SIZE
|
|
501
519
|
public:
|
|
502
520
|
size_type size() const { return num_elements - num_deleted; }
|
|
503
|
-
size_type max_size() const { return
|
|
521
|
+
size_type max_size() const { return val_info.max_size(); }
|
|
504
522
|
bool empty() const { return size() == 0; }
|
|
505
523
|
size_type bucket_count() const { return num_buckets; }
|
|
506
524
|
size_type max_bucket_count() const { return max_size(); }
|
|
@@ -556,8 +574,10 @@ class dense_hashtable {
|
|
|
556
574
|
if ( maybe_shrink() )
|
|
557
575
|
did_resize = true;
|
|
558
576
|
}
|
|
559
|
-
if (num_elements >=
|
|
577
|
+
if (num_elements >=
|
|
578
|
+
(std::numeric_limits<size_type>::max)() - delta) {
|
|
560
579
|
throw std::length_error("resize overflow");
|
|
580
|
+
}
|
|
561
581
|
if ( bucket_count() >= HT_MIN_BUCKETS &&
|
|
562
582
|
(num_elements + delta) <= settings.enlarge_threshold() )
|
|
563
583
|
return did_resize; // we're ok as we are
|
|
@@ -576,7 +596,7 @@ class dense_hashtable {
|
|
|
576
596
|
settings.min_buckets(num_elements - num_deleted + delta, bucket_count());
|
|
577
597
|
|
|
578
598
|
if (resize_to < needed_size && // may double resize_to
|
|
579
|
-
resize_to < (
|
|
599
|
+
resize_to < (std::numeric_limits<size_type>::max)() / 2) {
|
|
580
600
|
// This situation means that we have enough deleted elements,
|
|
581
601
|
// that once we purge them, we won't actually have needed to
|
|
582
602
|
// grow. But we may want to grow anyway: if we just purge one
|
|
@@ -598,13 +618,13 @@ class dense_hashtable {
|
|
|
598
618
|
|
|
599
619
|
// We require table be not-NULL and empty before calling this.
|
|
600
620
|
void resize_table(size_type /*old_size*/, size_type new_size,
|
|
601
|
-
true_type) {
|
|
602
|
-
table =
|
|
621
|
+
base::true_type) {
|
|
622
|
+
table = val_info.realloc_or_die(table, new_size);
|
|
603
623
|
}
|
|
604
624
|
|
|
605
|
-
void resize_table(size_type old_size, size_type new_size, false_type) {
|
|
606
|
-
|
|
607
|
-
table =
|
|
625
|
+
void resize_table(size_type old_size, size_type new_size, base::false_type) {
|
|
626
|
+
val_info.deallocate(table, old_size);
|
|
627
|
+
table = val_info.allocate(new_size);
|
|
608
628
|
}
|
|
609
629
|
|
|
610
630
|
// Used to actually do the rehashing when we grow/shrink a hashtable
|
|
@@ -669,13 +689,12 @@ class dense_hashtable {
|
|
|
669
689
|
const Alloc& alloc = Alloc())
|
|
670
690
|
: settings(hf),
|
|
671
691
|
key_info(ext, set, eql),
|
|
672
|
-
allocator(alloc),
|
|
673
692
|
num_deleted(0),
|
|
674
693
|
num_elements(0),
|
|
675
694
|
num_buckets(expected_max_items_in_table == 0
|
|
676
695
|
? HT_DEFAULT_STARTING_BUCKETS
|
|
677
696
|
: settings.min_buckets(expected_max_items_in_table, 0)),
|
|
678
|
-
|
|
697
|
+
val_info(alloc_impl<value_alloc_type>(alloc)),
|
|
679
698
|
table(NULL) {
|
|
680
699
|
// table is NULL until emptyval is set. However, we set num_buckets
|
|
681
700
|
// here so we know how much space to allocate once emptyval is set
|
|
@@ -688,11 +707,10 @@ class dense_hashtable {
|
|
|
688
707
|
size_type min_buckets_wanted = HT_DEFAULT_STARTING_BUCKETS)
|
|
689
708
|
: settings(ht.settings),
|
|
690
709
|
key_info(ht.key_info),
|
|
691
|
-
allocator(ht.allocator),
|
|
692
710
|
num_deleted(0),
|
|
693
711
|
num_elements(0),
|
|
694
712
|
num_buckets(0),
|
|
695
|
-
|
|
713
|
+
val_info(ht.val_info),
|
|
696
714
|
table(NULL) {
|
|
697
715
|
if (!ht.settings.use_empty()) {
|
|
698
716
|
// If use_empty isn't set, copy_from will crash, so we do our own copying.
|
|
@@ -715,7 +733,7 @@ class dense_hashtable {
|
|
|
715
733
|
}
|
|
716
734
|
settings = ht.settings;
|
|
717
735
|
key_info = ht.key_info;
|
|
718
|
-
set_value(&emptyval, ht.emptyval);
|
|
736
|
+
set_value(&val_info.emptyval, ht.val_info.emptyval);
|
|
719
737
|
// copy_from() calls clear and sets num_deleted to 0 too
|
|
720
738
|
copy_from(ht, HT_MIN_BUCKETS);
|
|
721
739
|
// we purposefully don't copy the allocator, which may not be copyable
|
|
@@ -725,38 +743,38 @@ class dense_hashtable {
|
|
|
725
743
|
~dense_hashtable() {
|
|
726
744
|
if (table) {
|
|
727
745
|
destroy_buckets(0, num_buckets);
|
|
728
|
-
|
|
746
|
+
val_info.deallocate(table, num_buckets);
|
|
729
747
|
}
|
|
730
748
|
}
|
|
731
749
|
|
|
732
750
|
// Many STL algorithms use swap instead of copy constructors
|
|
733
751
|
void swap(dense_hashtable& ht) {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
752
|
+
std::swap(settings, ht.settings);
|
|
753
|
+
std::swap(key_info, ht.key_info);
|
|
754
|
+
std::swap(num_deleted, ht.num_deleted);
|
|
755
|
+
std::swap(num_elements, ht.num_elements);
|
|
756
|
+
std::swap(num_buckets, ht.num_buckets);
|
|
739
757
|
{ value_type tmp; // for annoying reasons, swap() doesn't work
|
|
740
|
-
set_value(&tmp, emptyval);
|
|
741
|
-
set_value(&emptyval, ht.emptyval);
|
|
742
|
-
set_value(&ht.emptyval, tmp);
|
|
758
|
+
set_value(&tmp, val_info.emptyval);
|
|
759
|
+
set_value(&val_info.emptyval, ht.val_info.emptyval);
|
|
760
|
+
set_value(&ht.val_info.emptyval, tmp);
|
|
743
761
|
}
|
|
744
|
-
|
|
745
|
-
settings.reset_thresholds(bucket_count()); //
|
|
746
|
-
ht.settings.reset_thresholds(bucket_count());
|
|
762
|
+
std::swap(table, ht.table);
|
|
763
|
+
settings.reset_thresholds(bucket_count()); // also resets consider_shrink
|
|
764
|
+
ht.settings.reset_thresholds(ht.bucket_count());
|
|
747
765
|
// we purposefully don't swap the allocator, which may not be swap-able
|
|
748
766
|
}
|
|
749
767
|
|
|
750
768
|
private:
|
|
751
769
|
void clear_to_size(size_type new_num_buckets) {
|
|
752
770
|
if (!table) {
|
|
753
|
-
table =
|
|
771
|
+
table = val_info.allocate(new_num_buckets);
|
|
754
772
|
} else {
|
|
755
773
|
destroy_buckets(0, num_buckets);
|
|
756
774
|
if (new_num_buckets != num_buckets) { // resize, if necessary
|
|
757
|
-
typedef integral_constant<bool,
|
|
758
|
-
is_same<value_alloc_type,
|
|
759
|
-
|
|
775
|
+
typedef base::integral_constant<bool,
|
|
776
|
+
base::is_same<value_alloc_type,
|
|
777
|
+
libc_allocator_with_realloc<value_type> >::value>
|
|
760
778
|
realloc_ok;
|
|
761
779
|
resize_table(num_buckets, new_num_buckets, realloc_ok());
|
|
762
780
|
}
|
|
@@ -803,7 +821,7 @@ class dense_hashtable {
|
|
|
803
821
|
// if object is not found; 2nd is ILLEGAL_BUCKET if it is.
|
|
804
822
|
// Note: because of deletions where-to-insert is not trivial: it's the
|
|
805
823
|
// first deleted bucket we see, as long as we don't find the key later
|
|
806
|
-
pair<size_type, size_type> find_position(const key_type &key) const {
|
|
824
|
+
std::pair<size_type, size_type> find_position(const key_type &key) const {
|
|
807
825
|
size_type num_probes = 0; // how many times we've probed
|
|
808
826
|
const size_type bucket_count_minus_one = bucket_count() - 1;
|
|
809
827
|
size_type bucknum = hash(key) & bucket_count_minus_one;
|
|
@@ -811,16 +829,16 @@ class dense_hashtable {
|
|
|
811
829
|
while ( 1 ) { // probe until something happens
|
|
812
830
|
if ( test_empty(bucknum) ) { // bucket is empty
|
|
813
831
|
if ( insert_pos == ILLEGAL_BUCKET ) // found no prior place to insert
|
|
814
|
-
return pair<size_type,size_type>(ILLEGAL_BUCKET, bucknum);
|
|
832
|
+
return std::pair<size_type,size_type>(ILLEGAL_BUCKET, bucknum);
|
|
815
833
|
else
|
|
816
|
-
return pair<size_type,size_type>(ILLEGAL_BUCKET, insert_pos);
|
|
834
|
+
return std::pair<size_type,size_type>(ILLEGAL_BUCKET, insert_pos);
|
|
817
835
|
|
|
818
836
|
} else if ( test_deleted(bucknum) ) {// keep searching, but mark to insert
|
|
819
837
|
if ( insert_pos == ILLEGAL_BUCKET )
|
|
820
838
|
insert_pos = bucknum;
|
|
821
839
|
|
|
822
840
|
} else if ( equals(key, get_key(table[bucknum])) ) {
|
|
823
|
-
return pair<size_type,size_type>(bucknum, ILLEGAL_BUCKET);
|
|
841
|
+
return std::pair<size_type,size_type>(bucknum, ILLEGAL_BUCKET);
|
|
824
842
|
}
|
|
825
843
|
++num_probes; // we're doing another probe
|
|
826
844
|
bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one;
|
|
@@ -830,9 +848,10 @@ class dense_hashtable {
|
|
|
830
848
|
}
|
|
831
849
|
|
|
832
850
|
public:
|
|
851
|
+
|
|
833
852
|
iterator find(const key_type& key) {
|
|
834
853
|
if ( size() == 0 ) return end();
|
|
835
|
-
pair<size_type, size_type> pos = find_position(key);
|
|
854
|
+
std::pair<size_type, size_type> pos = find_position(key);
|
|
836
855
|
if ( pos.first == ILLEGAL_BUCKET ) // alas, not there
|
|
837
856
|
return end();
|
|
838
857
|
else
|
|
@@ -841,7 +860,7 @@ class dense_hashtable {
|
|
|
841
860
|
|
|
842
861
|
const_iterator find(const key_type& key) const {
|
|
843
862
|
if ( size() == 0 ) return end();
|
|
844
|
-
pair<size_type, size_type> pos = find_position(key);
|
|
863
|
+
std::pair<size_type, size_type> pos = find_position(key);
|
|
845
864
|
if ( pos.first == ILLEGAL_BUCKET ) // alas, not there
|
|
846
865
|
return end();
|
|
847
866
|
else
|
|
@@ -851,33 +870,34 @@ class dense_hashtable {
|
|
|
851
870
|
// This is a tr1 method: the bucket a given key is in, or what bucket
|
|
852
871
|
// it would be put in, if it were to be inserted. Shrug.
|
|
853
872
|
size_type bucket(const key_type& key) const {
|
|
854
|
-
pair<size_type, size_type> pos = find_position(key);
|
|
873
|
+
std::pair<size_type, size_type> pos = find_position(key);
|
|
855
874
|
return pos.first == ILLEGAL_BUCKET ? pos.second : pos.first;
|
|
856
875
|
}
|
|
857
876
|
|
|
858
877
|
// Counts how many elements have key key. For maps, it's either 0 or 1.
|
|
859
878
|
size_type count(const key_type &key) const {
|
|
860
|
-
pair<size_type, size_type> pos = find_position(key);
|
|
879
|
+
std::pair<size_type, size_type> pos = find_position(key);
|
|
861
880
|
return pos.first == ILLEGAL_BUCKET ? 0 : 1;
|
|
862
881
|
}
|
|
863
882
|
|
|
864
883
|
// Likewise, equal_range doesn't really make sense for us. Oh well.
|
|
865
|
-
pair<iterator,iterator> equal_range(const key_type& key) {
|
|
884
|
+
std::pair<iterator,iterator> equal_range(const key_type& key) {
|
|
866
885
|
iterator pos = find(key); // either an iterator or end
|
|
867
886
|
if (pos == end()) {
|
|
868
|
-
return pair<iterator,iterator>(pos, pos);
|
|
887
|
+
return std::pair<iterator,iterator>(pos, pos);
|
|
869
888
|
} else {
|
|
870
889
|
const iterator startpos = pos++;
|
|
871
|
-
return pair<iterator,iterator>(startpos, pos);
|
|
890
|
+
return std::pair<iterator,iterator>(startpos, pos);
|
|
872
891
|
}
|
|
873
892
|
}
|
|
874
|
-
pair<const_iterator,const_iterator> equal_range(const key_type& key)
|
|
893
|
+
std::pair<const_iterator,const_iterator> equal_range(const key_type& key)
|
|
894
|
+
const {
|
|
875
895
|
const_iterator pos = find(key); // either an iterator or end
|
|
876
896
|
if (pos == end()) {
|
|
877
|
-
return pair<const_iterator,const_iterator>(pos, pos);
|
|
897
|
+
return std::pair<const_iterator,const_iterator>(pos, pos);
|
|
878
898
|
} else {
|
|
879
899
|
const const_iterator startpos = pos++;
|
|
880
|
-
return pair<const_iterator,const_iterator>(startpos, pos);
|
|
900
|
+
return std::pair<const_iterator,const_iterator>(startpos, pos);
|
|
881
901
|
}
|
|
882
902
|
}
|
|
883
903
|
|
|
@@ -886,8 +906,9 @@ class dense_hashtable {
|
|
|
886
906
|
private:
|
|
887
907
|
// Private method used by insert_noresize and find_or_insert.
|
|
888
908
|
iterator insert_at(const_reference obj, size_type pos) {
|
|
889
|
-
if (size() >= max_size())
|
|
909
|
+
if (size() >= max_size()) {
|
|
890
910
|
throw std::length_error("insert overflow");
|
|
911
|
+
}
|
|
891
912
|
if ( test_deleted(pos) ) { // just replace if it's been del.
|
|
892
913
|
// shrug: shouldn't need to be const.
|
|
893
914
|
const_iterator delpos(this, table + pos, table + num_buckets, false);
|
|
@@ -902,29 +923,31 @@ class dense_hashtable {
|
|
|
902
923
|
}
|
|
903
924
|
|
|
904
925
|
// If you know *this is big enough to hold obj, use this routine
|
|
905
|
-
pair<iterator, bool> insert_noresize(const_reference obj) {
|
|
926
|
+
std::pair<iterator, bool> insert_noresize(const_reference obj) {
|
|
906
927
|
// First, double-check we're not inserting delkey or emptyval
|
|
907
|
-
assert((!settings.use_empty() || !equals(get_key(obj),
|
|
928
|
+
assert((!settings.use_empty() || !equals(get_key(obj),
|
|
929
|
+
get_key(val_info.emptyval)))
|
|
908
930
|
&& "Inserting the empty key");
|
|
909
931
|
assert((!settings.use_deleted() || !equals(get_key(obj), key_info.delkey))
|
|
910
932
|
&& "Inserting the deleted key");
|
|
911
|
-
const pair<size_type,size_type> pos = find_position(get_key(obj));
|
|
933
|
+
const std::pair<size_type,size_type> pos = find_position(get_key(obj));
|
|
912
934
|
if ( pos.first != ILLEGAL_BUCKET) { // object was already there
|
|
913
|
-
return pair<iterator,bool>(iterator(this, table + pos.first,
|
|
935
|
+
return std::pair<iterator,bool>(iterator(this, table + pos.first,
|
|
914
936
|
table + num_buckets, false),
|
|
915
937
|
false); // false: we didn't insert
|
|
916
938
|
} else { // pos.second says where to put it
|
|
917
|
-
return pair<iterator,bool>(insert_at(obj, pos.second), true);
|
|
939
|
+
return std::pair<iterator,bool>(insert_at(obj, pos.second), true);
|
|
918
940
|
}
|
|
919
941
|
}
|
|
920
942
|
|
|
921
943
|
// Specializations of insert(it, it) depending on the power of the iterator:
|
|
922
944
|
// (1) Iterator supports operator-, resize before inserting
|
|
923
945
|
template <class ForwardIterator>
|
|
924
|
-
void insert(ForwardIterator f, ForwardIterator l,
|
|
925
|
-
size_t dist =
|
|
926
|
-
if (dist >= (std::numeric_limits<size_type>::max)())
|
|
946
|
+
void insert(ForwardIterator f, ForwardIterator l, std::forward_iterator_tag) {
|
|
947
|
+
size_t dist = std::distance(f, l);
|
|
948
|
+
if (dist >= (std::numeric_limits<size_type>::max)()) {
|
|
927
949
|
throw std::length_error("insert-range overflow");
|
|
950
|
+
}
|
|
928
951
|
resize_delta(static_cast<size_type>(dist));
|
|
929
952
|
for ( ; dist > 0; --dist, ++f) {
|
|
930
953
|
insert_noresize(*f);
|
|
@@ -933,14 +956,14 @@ class dense_hashtable {
|
|
|
933
956
|
|
|
934
957
|
// (2) Arbitrary iterator, can't tell how much to resize
|
|
935
958
|
template <class InputIterator>
|
|
936
|
-
void insert(InputIterator f, InputIterator l,
|
|
959
|
+
void insert(InputIterator f, InputIterator l, std::input_iterator_tag) {
|
|
937
960
|
for ( ; f != l; ++f)
|
|
938
961
|
insert(*f);
|
|
939
962
|
}
|
|
940
963
|
|
|
941
964
|
public:
|
|
942
965
|
// This is the normal insert routine, used by the outside world
|
|
943
|
-
pair<iterator, bool> insert(const_reference obj) {
|
|
966
|
+
std::pair<iterator, bool> insert(const_reference obj) {
|
|
944
967
|
resize_delta(1); // adding an object, grow if need be
|
|
945
968
|
return insert_noresize(obj);
|
|
946
969
|
}
|
|
@@ -949,33 +972,36 @@ class dense_hashtable {
|
|
|
949
972
|
template <class InputIterator>
|
|
950
973
|
void insert(InputIterator f, InputIterator l) {
|
|
951
974
|
// specializes on iterator type
|
|
952
|
-
insert(f, l,
|
|
975
|
+
insert(f, l,
|
|
976
|
+
typename std::iterator_traits<InputIterator>::iterator_category());
|
|
953
977
|
}
|
|
954
978
|
|
|
955
|
-
//
|
|
956
|
-
//
|
|
957
|
-
template <class
|
|
958
|
-
|
|
979
|
+
// DefaultValue is a functor that takes a key and returns a value_type
|
|
980
|
+
// representing the default value to be inserted if none is found.
|
|
981
|
+
template <class DefaultValue>
|
|
982
|
+
value_type& find_or_insert(const key_type& key) {
|
|
959
983
|
// First, double-check we're not inserting emptykey or delkey
|
|
960
|
-
assert((!settings.use_empty() || !equals(key, get_key(emptyval)))
|
|
984
|
+
assert((!settings.use_empty() || !equals(key, get_key(val_info.emptyval)))
|
|
961
985
|
&& "Inserting the empty key");
|
|
962
986
|
assert((!settings.use_deleted() || !equals(key, key_info.delkey))
|
|
963
987
|
&& "Inserting the deleted key");
|
|
964
|
-
const pair<size_type,size_type> pos = find_position(key);
|
|
988
|
+
const std::pair<size_type,size_type> pos = find_position(key);
|
|
989
|
+
DefaultValue default_value;
|
|
965
990
|
if ( pos.first != ILLEGAL_BUCKET) { // object was already there
|
|
966
|
-
return table[pos.first]
|
|
991
|
+
return table[pos.first];
|
|
967
992
|
} else if (resize_delta(1)) { // needed to rehash to make room
|
|
968
993
|
// Since we resized, we can't use pos, so recalculate where to insert.
|
|
969
|
-
return insert_noresize(
|
|
994
|
+
return *insert_noresize(default_value(key)).first;
|
|
970
995
|
} else { // no need to rehash, insert right here
|
|
971
|
-
return insert_at(
|
|
996
|
+
return *insert_at(default_value(key), pos.second);
|
|
972
997
|
}
|
|
973
998
|
}
|
|
974
999
|
|
|
1000
|
+
|
|
975
1001
|
// DELETION ROUTINES
|
|
976
1002
|
size_type erase(const key_type& key) {
|
|
977
1003
|
// First, double-check we're not trying to erase delkey or emptyval.
|
|
978
|
-
assert((!settings.use_empty() || !equals(key, get_key(emptyval)))
|
|
1004
|
+
assert((!settings.use_empty() || !equals(key, get_key(val_info.emptyval)))
|
|
979
1005
|
&& "Erasing the empty key");
|
|
980
1006
|
assert((!settings.use_deleted() || !equals(key, key_info.delkey))
|
|
981
1007
|
&& "Erasing the deleted key");
|
|
@@ -1055,52 +1081,83 @@ class dense_hashtable {
|
|
|
1055
1081
|
// I/O
|
|
1056
1082
|
// We support reading and writing hashtables to disk. Alas, since
|
|
1057
1083
|
// I don't know how to write a hasher or key_equal, you have to make
|
|
1058
|
-
// sure everything but the table is the same. We compact before writing
|
|
1084
|
+
// sure everything but the table is the same. We compact before writing.
|
|
1085
|
+
private:
|
|
1086
|
+
// Every time the disk format changes, this should probably change too
|
|
1087
|
+
typedef unsigned long MagicNumberType;
|
|
1088
|
+
static const MagicNumberType MAGIC_NUMBER = 0x13578642;
|
|
1089
|
+
|
|
1090
|
+
public:
|
|
1091
|
+
// I/O -- this is an add-on for writing hash table to disk
|
|
1059
1092
|
//
|
|
1060
|
-
//
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1093
|
+
// INPUT and OUTPUT must be either a FILE, *or* a C++ stream
|
|
1094
|
+
// (istream, ostream, etc) *or* a class providing
|
|
1095
|
+
// Read(void*, size_t) and Write(const void*, size_t)
|
|
1096
|
+
// (respectively), which writes a buffer into a stream
|
|
1097
|
+
// (which the INPUT/OUTPUT instance presumably owns).
|
|
1065
1098
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
//
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1099
|
+
typedef sparsehash_internal::pod_serializer<value_type> NopointerSerializer;
|
|
1100
|
+
|
|
1101
|
+
// ValueSerializer: a functor. operator()(OUTPUT*, const value_type&)
|
|
1102
|
+
template <typename ValueSerializer, typename OUTPUT>
|
|
1103
|
+
bool serialize(ValueSerializer serializer, OUTPUT *fp) {
|
|
1104
|
+
squash_deleted(); // so we don't have to worry about delkey
|
|
1105
|
+
if ( !sparsehash_internal::write_bigendian_number(fp, MAGIC_NUMBER, 4) )
|
|
1106
|
+
return false;
|
|
1107
|
+
if ( !sparsehash_internal::write_bigendian_number(fp, num_buckets, 8) )
|
|
1108
|
+
return false;
|
|
1109
|
+
if ( !sparsehash_internal::write_bigendian_number(fp, num_elements, 8) )
|
|
1110
|
+
return false;
|
|
1111
|
+
// Now write a bitmap of non-empty buckets.
|
|
1112
|
+
for ( size_type i = 0; i < num_buckets; i += 8 ) {
|
|
1113
|
+
unsigned char bits = 0;
|
|
1114
|
+
for ( int bit = 0; bit < 8; ++bit ) {
|
|
1115
|
+
if ( i + bit < num_buckets && !test_empty(i + bit) )
|
|
1116
|
+
bits |= (1 << bit);
|
|
1117
|
+
}
|
|
1118
|
+
if ( !sparsehash_internal::write_data(fp, &bits, sizeof(bits)) )
|
|
1119
|
+
return false;
|
|
1120
|
+
for ( int bit = 0; bit < 8; ++bit ) {
|
|
1121
|
+
if ( bits & (1 << bit) ) {
|
|
1122
|
+
if ( !serializer(fp, table[i + bit]) ) return false;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1080
1125
|
}
|
|
1081
|
-
return
|
|
1126
|
+
return true;
|
|
1082
1127
|
}
|
|
1083
1128
|
|
|
1084
|
-
//
|
|
1085
|
-
//
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1129
|
+
// INPUT: anything we've written an overload of read_data() for.
|
|
1130
|
+
// ValueSerializer: a functor. operator()(INPUT*, value_type*)
|
|
1131
|
+
template <typename ValueSerializer, typename INPUT>
|
|
1132
|
+
bool unserialize(ValueSerializer serializer, INPUT *fp) {
|
|
1133
|
+
assert(settings.use_empty() && "empty_key not set for read");
|
|
1134
|
+
|
|
1135
|
+
clear(); // just to be consistent
|
|
1136
|
+
MagicNumberType magic_read;
|
|
1137
|
+
if ( !sparsehash_internal::read_bigendian_number(fp, &magic_read, 4) )
|
|
1138
|
+
return false;
|
|
1139
|
+
if ( magic_read != MAGIC_NUMBER ) {
|
|
1140
|
+
return false;
|
|
1092
1141
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1142
|
+
size_type new_num_buckets;
|
|
1143
|
+
if ( !sparsehash_internal::read_bigendian_number(fp, &new_num_buckets, 8) )
|
|
1144
|
+
return false;
|
|
1145
|
+
clear_to_size(new_num_buckets);
|
|
1146
|
+
if ( !sparsehash_internal::read_bigendian_number(fp, &num_elements, 8) )
|
|
1147
|
+
return false;
|
|
1095
1148
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
if ( !fread(reinterpret_cast<void*>(&(*it)), sizeof(*it), 1, fp) )
|
|
1149
|
+
// Read the bitmap of non-empty buckets.
|
|
1150
|
+
for (size_type i = 0; i < num_buckets; i += 8) {
|
|
1151
|
+
unsigned char bits;
|
|
1152
|
+
if ( !sparsehash_internal::read_data(fp, &bits, sizeof(bits)) )
|
|
1101
1153
|
return false;
|
|
1154
|
+
for ( int bit = 0; bit < 8; ++bit ) {
|
|
1155
|
+
if ( i + bit < num_buckets && (bits & (1 << bit)) ) { // not empty
|
|
1156
|
+
if ( !serializer(fp, &table[i + bit]) ) return false;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1102
1159
|
}
|
|
1103
|
-
return
|
|
1160
|
+
return true;
|
|
1104
1161
|
}
|
|
1105
1162
|
|
|
1106
1163
|
private:
|
|
@@ -1115,9 +1172,9 @@ class dense_hashtable {
|
|
|
1115
1172
|
|
|
1116
1173
|
// realloc_or_die should only be used when using the default
|
|
1117
1174
|
// allocator (libc_allocator_with_realloc).
|
|
1118
|
-
pointer realloc_or_die(pointer ptr
|
|
1175
|
+
pointer realloc_or_die(pointer /*ptr*/, size_type /*n*/) {
|
|
1119
1176
|
fprintf(stderr, "realloc_or_die is only supported for "
|
|
1120
|
-
"libc_allocator_with_realloc");
|
|
1177
|
+
"libc_allocator_with_realloc\n");
|
|
1121
1178
|
exit(1);
|
|
1122
1179
|
return NULL;
|
|
1123
1180
|
}
|
|
@@ -1138,50 +1195,67 @@ class dense_hashtable {
|
|
|
1138
1195
|
pointer realloc_or_die(pointer ptr, size_type n) {
|
|
1139
1196
|
pointer retval = this->reallocate(ptr, n);
|
|
1140
1197
|
if (retval == NULL) {
|
|
1141
|
-
// We really should use PRIuS here, but I don't want to have to add
|
|
1142
|
-
// a whole new configure option, with concomitant macro namespace
|
|
1143
|
-
// pollution, just to print this (unlikely) error message. So I cast.
|
|
1144
1198
|
fprintf(stderr, "sparsehash: FATAL ERROR: failed to reallocate "
|
|
1145
|
-
"%lu elements for ptr %p",
|
|
1146
|
-
static_cast<unsigned long>(n), ptr);
|
|
1199
|
+
"%lu elements for ptr %p", static_cast<unsigned long>(n), ptr);
|
|
1147
1200
|
exit(1);
|
|
1148
1201
|
}
|
|
1149
1202
|
return retval;
|
|
1150
1203
|
}
|
|
1151
1204
|
};
|
|
1152
1205
|
|
|
1206
|
+
// Package allocator with emptyval to eliminate memory needed for
|
|
1207
|
+
// the zero-size allocator.
|
|
1208
|
+
// If new fields are added to this class, we should add them to
|
|
1209
|
+
// operator= and swap.
|
|
1210
|
+
class ValInfo : public alloc_impl<value_alloc_type> {
|
|
1211
|
+
public:
|
|
1212
|
+
typedef typename alloc_impl<value_alloc_type>::value_type value_type;
|
|
1213
|
+
|
|
1214
|
+
ValInfo(const alloc_impl<value_alloc_type>& a)
|
|
1215
|
+
: alloc_impl<value_alloc_type>(a), emptyval() { }
|
|
1216
|
+
ValInfo(const ValInfo& v)
|
|
1217
|
+
: alloc_impl<value_alloc_type>(v), emptyval(v.emptyval) { }
|
|
1218
|
+
|
|
1219
|
+
value_type emptyval; // which key marks unused entries
|
|
1220
|
+
};
|
|
1221
|
+
|
|
1222
|
+
|
|
1153
1223
|
// Package functors with another class to eliminate memory needed for
|
|
1154
1224
|
// zero-size functors. Since ExtractKey and hasher's operator() might
|
|
1155
1225
|
// have the same function signature, they must be packaged in
|
|
1156
1226
|
// different classes.
|
|
1157
1227
|
struct Settings :
|
|
1158
|
-
sh_hashtable_settings<key_type, hasher,
|
|
1228
|
+
sparsehash_internal::sh_hashtable_settings<key_type, hasher,
|
|
1229
|
+
size_type, HT_MIN_BUCKETS> {
|
|
1159
1230
|
explicit Settings(const hasher& hf)
|
|
1160
|
-
: sh_hashtable_settings<key_type, hasher,
|
|
1231
|
+
: sparsehash_internal::sh_hashtable_settings<key_type, hasher,
|
|
1232
|
+
size_type, HT_MIN_BUCKETS>(
|
|
1161
1233
|
hf, HT_OCCUPANCY_PCT / 100.0f, HT_EMPTY_PCT / 100.0f) {}
|
|
1162
1234
|
};
|
|
1163
1235
|
|
|
1164
1236
|
// Packages ExtractKey and SetKey functors.
|
|
1165
|
-
class KeyInfo : public ExtractKey, public SetKey, public
|
|
1237
|
+
class KeyInfo : public ExtractKey, public SetKey, public EqualKey {
|
|
1166
1238
|
public:
|
|
1167
|
-
KeyInfo(const ExtractKey& ek, const SetKey& sk, const
|
|
1239
|
+
KeyInfo(const ExtractKey& ek, const SetKey& sk, const EqualKey& eq)
|
|
1168
1240
|
: ExtractKey(ek),
|
|
1169
1241
|
SetKey(sk),
|
|
1170
|
-
|
|
1242
|
+
EqualKey(eq) {
|
|
1171
1243
|
}
|
|
1172
|
-
|
|
1244
|
+
|
|
1245
|
+
// We want to return the exact same type as ExtractKey: Key or const Key&
|
|
1246
|
+
typename ExtractKey::result_type get_key(const_reference v) const {
|
|
1173
1247
|
return ExtractKey::operator()(v);
|
|
1174
1248
|
}
|
|
1175
1249
|
void set_key(pointer v, const key_type& k) const {
|
|
1176
1250
|
SetKey::operator()(v, k);
|
|
1177
1251
|
}
|
|
1178
1252
|
bool equals(const key_type& a, const key_type& b) const {
|
|
1179
|
-
return
|
|
1253
|
+
return EqualKey::operator()(a, b);
|
|
1180
1254
|
}
|
|
1181
1255
|
|
|
1182
1256
|
// Which key marks deleted entries.
|
|
1183
1257
|
// TODO(csilvers): make a pointer, and get rid of use_deleted (benchmark!)
|
|
1184
|
-
typename remove_const<key_type>::type delkey;
|
|
1258
|
+
typename base::remove_const<key_type>::type delkey;
|
|
1185
1259
|
};
|
|
1186
1260
|
|
|
1187
1261
|
// Utility functions to access the templated operators
|
|
@@ -1191,7 +1265,7 @@ class dense_hashtable {
|
|
|
1191
1265
|
bool equals(const key_type& a, const key_type& b) const {
|
|
1192
1266
|
return key_info.equals(a, b);
|
|
1193
1267
|
}
|
|
1194
|
-
|
|
1268
|
+
typename ExtractKey::result_type get_key(const_reference v) const {
|
|
1195
1269
|
return key_info.get_key(v);
|
|
1196
1270
|
}
|
|
1197
1271
|
void set_key(pointer v, const key_type& k) const {
|
|
@@ -1202,12 +1276,11 @@ class dense_hashtable {
|
|
|
1202
1276
|
// Actual data
|
|
1203
1277
|
Settings settings;
|
|
1204
1278
|
KeyInfo key_info;
|
|
1205
|
-
alloc_impl<value_alloc_type> allocator;
|
|
1206
1279
|
|
|
1207
1280
|
size_type num_deleted; // how many occupied buckets are marked deleted
|
|
1208
1281
|
size_type num_elements;
|
|
1209
1282
|
size_type num_buckets;
|
|
1210
|
-
|
|
1283
|
+
ValInfo val_info; // holds emptyval, and also the allocator
|
|
1211
1284
|
pointer table;
|
|
1212
1285
|
};
|
|
1213
1286
|
|
|
@@ -1229,12 +1302,13 @@ const typename dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::size_type
|
|
|
1229
1302
|
// good -- higher causes us to probe too much, though saves memory.
|
|
1230
1303
|
// However, we go with .5, getting better performance at the cost of
|
|
1231
1304
|
// more space (a trade-off densehashtable explicitly chooses to make).
|
|
1232
|
-
// Feel free to play around with different values, though
|
|
1305
|
+
// Feel free to play around with different values, though, via
|
|
1306
|
+
// max_load_factor() and/or set_resizing_parameters().
|
|
1233
1307
|
template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
|
|
1234
1308
|
const int dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_OCCUPANCY_PCT = 50;
|
|
1235
1309
|
|
|
1236
1310
|
// How empty we let the table get before we resize lower.
|
|
1237
|
-
// It should be less than OCCUPANCY_PCT / 2 or we thrash resizing
|
|
1311
|
+
// It should be less than OCCUPANCY_PCT / 2 or we thrash resizing.
|
|
1238
1312
|
template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
|
|
1239
1313
|
const int dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_EMPTY_PCT
|
|
1240
1314
|
= static_cast<int>(0.4 *
|