google_hash 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog.txt +2 -0
- data/VERSION +1 -1
- data/ext/clean.bat +0 -0
- data/ext/clean.sh +4 -0
- data/ext/extconf.rb +4 -5
- data/ext/go.bat +0 -0
- data/ext/sparsehash-2.0.2/AUTHORS +2 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/COPYING +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/ChangeLog +60 -0
- data/ext/sparsehash-2.0.2/INSTALL +365 -0
- data/ext/sparsehash-2.0.2/Makefile +1336 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/Makefile.am +97 -40
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/Makefile.in +538 -256
- data/ext/sparsehash-2.0.2/NEWS +188 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/README +4 -10
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/README_windows.txt +3 -3
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/TODO +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/aclocal.m4 +266 -166
- data/ext/sparsehash-2.0.2/allocator.patch +31 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/config.guess +235 -234
- data/ext/sparsehash-2.0.2/config.status +1238 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/config.sub +198 -64
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/configure +1118 -1000
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/configure.ac +4 -5
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/depcomp +136 -36
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/dense_hash_map.html +182 -67
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/dense_hash_set.html +173 -74
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/designstyle.css +0 -6
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/implementation.html +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/index.html +4 -5
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/performance.html +1 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparse_hash_map.html +190 -58
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparse_hash_set.html +180 -65
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparsetable.html +1 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/Makefile +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/README +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/example.c +1 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/libchash.c +1 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/libchash.h +1 -0
- data/ext/sparsehash-2.0.2/install-sh +520 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/acx_pthread.m4 +34 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/google_namespace.m4 +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/namespaces.m4 +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/stl_hash.m4 +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/stl_hash_fun.m4 +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/missing +60 -44
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb.sh +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/README +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/changelog +42 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/compat +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/control +1 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/copyright +5 -4
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/docs +0 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/rules +0 -0
- data/ext/sparsehash-2.0.2/packages/deb/sparsehash.dirs +5 -0
- data/ext/sparsehash-2.0.2/packages/deb/sparsehash.install +6 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/rpm.sh +1 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/rpm/rpm.spec +5 -3
- data/ext/{sparsehash-1.8.1/google-sparsehash.sln → sparsehash-2.0.2/sparsehash.sln} +0 -0
- data/ext/sparsehash-2.0.2/src/config.h +132 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/config.h.in +0 -3
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/config.h.include +0 -1
- data/ext/sparsehash-2.0.2/src/google/dense_hash_map +34 -0
- data/ext/sparsehash-2.0.2/src/google/dense_hash_set +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparse_hash_map +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparse_hash_set +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsehash/densehashtable.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsehash/hashtable-common.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsehash/libc_allocator_with_realloc.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsehash/sparsehashtable.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/sparsetable +34 -0
- data/ext/sparsehash-2.0.2/src/google/template_util.h +34 -0
- data/ext/sparsehash-2.0.2/src/google/type_traits.h +34 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/hash_test_interface.h +64 -37
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/hashtable_test.cc +415 -141
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/libc_allocator_with_realloc_test.cc +16 -23
- data/ext/sparsehash-2.0.2/src/simple_compat_test.cc +106 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/simple_test.cc +8 -5
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/dense_hash_map +80 -37
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/dense_hash_set +64 -34
- data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/densehashtable.h +247 -173
- data/ext/sparsehash-2.0.2/src/sparsehash/internal/hashtable-common.h +381 -0
- data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/libc_allocator_with_realloc.h +5 -7
- data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/sparsehashtable.h +154 -93
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparse_hash_map +96 -36
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparse_hash_set +85 -32
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparsetable +520 -258
- data/ext/sparsehash-2.0.2/src/sparsehash/template_util.h +134 -0
- data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/type_traits.h +153 -35
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/sparsetable_unittest.cc +108 -22
- data/ext/sparsehash-2.0.2/src/stamp-h1 +1 -0
- data/ext/sparsehash-2.0.2/src/template_util_unittest.cc +134 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/testutil.h +16 -1
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/time_hash_map.cc +259 -94
- data/ext/sparsehash-2.0.2/src/type_traits_unittest.cc +636 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/config.h +4 -4
- data/ext/sparsehash-2.0.2/src/windows/google/sparsehash/sparseconfig.h +49 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/port.cc +1 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/port.h +4 -13
- data/ext/sparsehash-2.0.2/src/windows/sparsehash/internal/sparseconfig.h +49 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/hashtable_test/hashtable_test.vcproj +11 -11
- data/ext/sparsehash-2.0.2/vsprojects/libc_allocator_with_realloc_test/libc_allocator_with_realloc_test.vcproj +161 -0
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/simple_test/simple_test.vcproj +10 -10
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +4 -4
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/time_hash_map/time_hash_map.vcproj +10 -10
- data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +3 -3
- data/ext/spec.bat +0 -0
- data/ext/template/google_hash.cpp.erb +6 -5
- metadata +106 -86
- data/ext/sparsehash-1.8.1/AUTHORS +0 -2
- data/ext/sparsehash-1.8.1/INSTALL +0 -236
- data/ext/sparsehash-1.8.1/NEWS +0 -71
- data/ext/sparsehash-1.8.1/compile +0 -99
- data/ext/sparsehash-1.8.1/install-sh +0 -323
- data/ext/sparsehash-1.8.1/m4/stl_namespace.m4 +0 -25
- data/ext/sparsehash-1.8.1/mkinstalldirs +0 -158
- data/ext/sparsehash-1.8.1/packages/deb/sparsehash.dirs +0 -2
- data/ext/sparsehash-1.8.1/packages/deb/sparsehash.install +0 -2
- data/ext/sparsehash-1.8.1/src/google/sparsehash/hashtable-common.h +0 -178
- data/ext/sparsehash-1.8.1/src/type_traits_unittest.cc +0 -502
- data/ext/sparsehash-1.8.1/src/windows/google/sparsehash/sparseconfig.h +0 -32
@@ -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 *
|