google_hash 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 *