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.
Files changed (121) hide show
  1. data/ChangeLog.txt +2 -0
  2. data/VERSION +1 -1
  3. data/ext/clean.bat +0 -0
  4. data/ext/clean.sh +4 -0
  5. data/ext/extconf.rb +4 -5
  6. data/ext/go.bat +0 -0
  7. data/ext/sparsehash-2.0.2/AUTHORS +2 -0
  8. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/COPYING +0 -0
  9. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/ChangeLog +60 -0
  10. data/ext/sparsehash-2.0.2/INSTALL +365 -0
  11. data/ext/sparsehash-2.0.2/Makefile +1336 -0
  12. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/Makefile.am +97 -40
  13. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/Makefile.in +538 -256
  14. data/ext/sparsehash-2.0.2/NEWS +188 -0
  15. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/README +4 -10
  16. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/README_windows.txt +3 -3
  17. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/TODO +0 -0
  18. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/aclocal.m4 +266 -166
  19. data/ext/sparsehash-2.0.2/allocator.patch +31 -0
  20. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/config.guess +235 -234
  21. data/ext/sparsehash-2.0.2/config.status +1238 -0
  22. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/config.sub +198 -64
  23. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/configure +1118 -1000
  24. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/configure.ac +4 -5
  25. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/depcomp +136 -36
  26. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/dense_hash_map.html +182 -67
  27. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/dense_hash_set.html +173 -74
  28. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/designstyle.css +0 -6
  29. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/implementation.html +0 -0
  30. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/index.html +4 -5
  31. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/performance.html +1 -1
  32. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparse_hash_map.html +190 -58
  33. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparse_hash_set.html +180 -65
  34. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/doc/sparsetable.html +1 -1
  35. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/Makefile +0 -0
  36. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/README +0 -0
  37. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/example.c +1 -0
  38. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/libchash.c +1 -0
  39. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/experimental/libchash.h +1 -0
  40. data/ext/sparsehash-2.0.2/install-sh +520 -0
  41. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/acx_pthread.m4 +34 -0
  42. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/google_namespace.m4 +0 -0
  43. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/namespaces.m4 +0 -0
  44. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/stl_hash.m4 +0 -0
  45. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/m4/stl_hash_fun.m4 +0 -0
  46. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/missing +60 -44
  47. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb.sh +0 -0
  48. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/README +0 -0
  49. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/changelog +42 -0
  50. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/compat +0 -0
  51. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/control +1 -1
  52. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/copyright +5 -4
  53. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/docs +0 -0
  54. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/deb/rules +0 -0
  55. data/ext/sparsehash-2.0.2/packages/deb/sparsehash.dirs +5 -0
  56. data/ext/sparsehash-2.0.2/packages/deb/sparsehash.install +6 -0
  57. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/rpm.sh +1 -1
  58. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/packages/rpm/rpm.spec +5 -3
  59. data/ext/{sparsehash-1.8.1/google-sparsehash.sln → sparsehash-2.0.2/sparsehash.sln} +0 -0
  60. data/ext/sparsehash-2.0.2/src/config.h +132 -0
  61. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/config.h.in +0 -3
  62. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/config.h.include +0 -1
  63. data/ext/sparsehash-2.0.2/src/google/dense_hash_map +34 -0
  64. data/ext/sparsehash-2.0.2/src/google/dense_hash_set +34 -0
  65. data/ext/sparsehash-2.0.2/src/google/sparse_hash_map +34 -0
  66. data/ext/sparsehash-2.0.2/src/google/sparse_hash_set +34 -0
  67. data/ext/sparsehash-2.0.2/src/google/sparsehash/densehashtable.h +34 -0
  68. data/ext/sparsehash-2.0.2/src/google/sparsehash/hashtable-common.h +34 -0
  69. data/ext/sparsehash-2.0.2/src/google/sparsehash/libc_allocator_with_realloc.h +34 -0
  70. data/ext/sparsehash-2.0.2/src/google/sparsehash/sparsehashtable.h +34 -0
  71. data/ext/sparsehash-2.0.2/src/google/sparsetable +34 -0
  72. data/ext/sparsehash-2.0.2/src/google/template_util.h +34 -0
  73. data/ext/sparsehash-2.0.2/src/google/type_traits.h +34 -0
  74. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/hash_test_interface.h +64 -37
  75. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/hashtable_test.cc +415 -141
  76. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/libc_allocator_with_realloc_test.cc +16 -23
  77. data/ext/sparsehash-2.0.2/src/simple_compat_test.cc +106 -0
  78. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/simple_test.cc +8 -5
  79. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/dense_hash_map +80 -37
  80. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/dense_hash_set +64 -34
  81. data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/densehashtable.h +247 -173
  82. data/ext/sparsehash-2.0.2/src/sparsehash/internal/hashtable-common.h +381 -0
  83. data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/libc_allocator_with_realloc.h +5 -7
  84. data/ext/{sparsehash-1.8.1/src/google/sparsehash → sparsehash-2.0.2/src/sparsehash/internal}/sparsehashtable.h +154 -93
  85. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparse_hash_map +96 -36
  86. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparse_hash_set +85 -32
  87. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/sparsetable +520 -258
  88. data/ext/sparsehash-2.0.2/src/sparsehash/template_util.h +134 -0
  89. data/ext/{sparsehash-1.8.1/src/google → sparsehash-2.0.2/src/sparsehash}/type_traits.h +153 -35
  90. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/sparsetable_unittest.cc +108 -22
  91. data/ext/sparsehash-2.0.2/src/stamp-h1 +1 -0
  92. data/ext/sparsehash-2.0.2/src/template_util_unittest.cc +134 -0
  93. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/testutil.h +16 -1
  94. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/time_hash_map.cc +259 -94
  95. data/ext/sparsehash-2.0.2/src/type_traits_unittest.cc +636 -0
  96. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/config.h +4 -4
  97. data/ext/sparsehash-2.0.2/src/windows/google/sparsehash/sparseconfig.h +49 -0
  98. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/port.cc +1 -0
  99. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/src/windows/port.h +4 -13
  100. data/ext/sparsehash-2.0.2/src/windows/sparsehash/internal/sparseconfig.h +49 -0
  101. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/hashtable_test/hashtable_test.vcproj +11 -11
  102. data/ext/sparsehash-2.0.2/vsprojects/libc_allocator_with_realloc_test/libc_allocator_with_realloc_test.vcproj +161 -0
  103. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/simple_test/simple_test.vcproj +10 -10
  104. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +4 -4
  105. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/time_hash_map/time_hash_map.vcproj +10 -10
  106. data/ext/{sparsehash-1.8.1 → sparsehash-2.0.2}/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +3 -3
  107. data/ext/spec.bat +0 -0
  108. data/ext/template/google_hash.cpp.erb +6 -5
  109. metadata +106 -86
  110. data/ext/sparsehash-1.8.1/AUTHORS +0 -2
  111. data/ext/sparsehash-1.8.1/INSTALL +0 -236
  112. data/ext/sparsehash-1.8.1/NEWS +0 -71
  113. data/ext/sparsehash-1.8.1/compile +0 -99
  114. data/ext/sparsehash-1.8.1/install-sh +0 -323
  115. data/ext/sparsehash-1.8.1/m4/stl_namespace.m4 +0 -25
  116. data/ext/sparsehash-1.8.1/mkinstalldirs +0 -158
  117. data/ext/sparsehash-1.8.1/packages/deb/sparsehash.dirs +0 -2
  118. data/ext/sparsehash-1.8.1/packages/deb/sparsehash.install +0 -2
  119. data/ext/sparsehash-1.8.1/src/google/sparsehash/hashtable-common.h +0 -178
  120. data/ext/sparsehash-1.8.1/src/type_traits_unittest.cc +0 -502
  121. data/ext/sparsehash-1.8.1/src/windows/google/sparsehash/sparseconfig.h +0 -32
@@ -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
- // <google/dense_hash_map> or <google/dense_hash_set> instead.
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 _JUMP below if you really want to.
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
- // The probing method
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 <stdlib.h> // for abort()
94
+ #include <stdio.h> // for FILE, fwrite, fread
104
95
  #include <algorithm> // For swap(), eg
105
- #include <stdexcept> // For length_error
106
- #include <iostream> // For cerr
107
- #include <memory> // For uninitialized_fill, uninitialized_copy
108
- #include <utility> // for pair<>
109
- #include <iterator> // for facts about iterator tags
110
- #include <limits> // for numeric_limits<>
111
- #include <google/sparsehash/libc_allocator_with_realloc.h>
112
- #include <google/sparsehash/hashtable-common.h>
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
- using STL_NAMESPACE::pair;
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 STL_NAMESPACE::forward_iterator_tag iterator_category;
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 STL_NAMESPACE::forward_iterator_tag iterator_category;
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; // = 50 (out of 100)
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; // = 0.4 * HT_OCCUPANCY_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 { return allocator; }
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
- // The num_deleted test is crucial for read(): after read(), the ht values
376
- // are garbage, and we don't want to think some of them are deleted.
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
- return test_deleted_key(get_key(table[bucknum]));
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
- return test_deleted_key(get_key(*it));
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
- return test_deleted_key(get_key(*it));
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
- assert(settings.use_deleted());
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
- assert(settings.use_deleted());
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
- assert(settings.use_deleted());
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
- assert(settings.use_deleted());
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
- STL_NAMESPACE::uninitialized_fill(table_start, table_end, emptyval);
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 = allocator.allocate(num_buckets);
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(sjackman): return a key_type rather than a value_type
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 allocator.max_size(); }
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 >= (STL_NAMESPACE::numeric_limits<size_type>::max)() - delta)
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 < (STL_NAMESPACE::numeric_limits<size_type>::max)() / 2) {
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 = allocator.realloc_or_die(table, new_size);
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
- allocator.deallocate(table, old_size);
607
- table = allocator.allocate(new_size);
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
- emptyval(),
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
- emptyval(ht.emptyval),
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
- allocator.deallocate(table, num_buckets);
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
- STL_NAMESPACE::swap(settings, ht.settings);
735
- STL_NAMESPACE::swap(key_info, ht.key_info);
736
- STL_NAMESPACE::swap(num_deleted, ht.num_deleted);
737
- STL_NAMESPACE::swap(num_elements, ht.num_elements);
738
- STL_NAMESPACE::swap(num_buckets, ht.num_buckets);
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
- STL_NAMESPACE::swap(table, ht.table);
745
- settings.reset_thresholds(bucket_count()); // this also resets consider_shrink
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 = allocator.allocate(new_num_buckets);
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
- libc_allocator_with_realloc<value_type> >::value>
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) const {
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), get_key(emptyval)))
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, STL_NAMESPACE::forward_iterator_tag) {
925
- size_t dist = STL_NAMESPACE::distance(f, l);
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, STL_NAMESPACE::input_iterator_tag) {
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, typename STL_NAMESPACE::iterator_traits<InputIterator>::iterator_category());
975
+ insert(f, l,
976
+ typename std::iterator_traits<InputIterator>::iterator_category());
953
977
  }
954
978
 
955
- // This is public only because dense_hash_map::operator[] uses it.
956
- // It does the minimal amount of work to implement operator[].
957
- template <class DataType>
958
- DataType& find_or_insert(const key_type& key) {
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].second;
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(value_type(key, DataType())).first->second;
994
+ return *insert_noresize(default_value(key)).first;
970
995
  } else { // no need to rehash, insert right here
971
- return insert_at(value_type(key, DataType()), pos.second)->second;
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
- // NOTE: These functions are currently TODO. They've not been implemented.
1061
- bool write_metadata(FILE *fp) {
1062
- squash_deleted(); // so we don't have to worry about delkey
1063
- return false; // TODO
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
- bool read_metadata(FILE *fp) {
1067
- num_deleted = 0; // since we got rid before writing
1068
- assert(settings.use_empty() && "empty_key not set for read_metadata");
1069
- if (table) allocator.deallocate(table, num_buckets); // we'll make our own
1070
- // TODO: read magic number
1071
- // TODO: read num_buckets
1072
- settings.reset_thresholds(bucket_count());
1073
- table = allocator.allocate(num_buckets);
1074
- assert(table);
1075
- fill_range_with_empty(table, table + num_buckets);
1076
- // TODO: read num_elements
1077
- for ( size_type i = 0; i < num_elements; ++i ) {
1078
- // TODO: read bucket_num
1079
- // TODO: set with non-empty, non-deleted value
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 false; // TODO
1126
+ return true;
1082
1127
  }
1083
1128
 
1084
- // If your keys and values are simple enough, we can write them to
1085
- // disk for you. "simple enough" means value_type is a POD type
1086
- // that contains no pointers. However, we don't try to normalize
1087
- // endianness
1088
- bool write_nopointer_data(FILE *fp) const {
1089
- for ( const_iterator it = begin(); it != end(); ++it ) {
1090
- // TODO: skip empty/deleted values
1091
- if ( !fwrite(&*it, sizeof(*it), 1, fp) ) return false;
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
- return false;
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
- // When reading, we have to override the potential const-ness of *it
1097
- bool read_nopointer_data(FILE *fp) {
1098
- for ( iterator it = begin(); it != end(); ++it ) {
1099
- // TODO: skip empty/deleted values
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 false;
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, size_type n) {
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, size_type, HT_MIN_BUCKETS> {
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, size_type, HT_MIN_BUCKETS>(
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 key_equal {
1237
+ class KeyInfo : public ExtractKey, public SetKey, public EqualKey {
1166
1238
  public:
1167
- KeyInfo(const ExtractKey& ek, const SetKey& sk, const key_equal& eq)
1239
+ KeyInfo(const ExtractKey& ek, const SetKey& sk, const EqualKey& eq)
1168
1240
  : ExtractKey(ek),
1169
1241
  SetKey(sk),
1170
- key_equal(eq) {
1242
+ EqualKey(eq) {
1171
1243
  }
1172
- const key_type get_key(const_reference v) const {
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 key_equal::operator()(a, b);
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
- const key_type get_key(const_reference v) const {
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
- value_type emptyval; // which key marks unused entries
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 *