google_hash 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/README +61 -27
  2. data/Rakefile +4 -1
  3. data/TODO +5 -0
  4. data/VERSION +1 -1
  5. data/changelog +3 -0
  6. data/ext/extconf.rb +10 -5
  7. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/AUTHORS +0 -0
  8. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/COPYING +0 -0
  9. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/ChangeLog +47 -0
  10. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/INSTALL +0 -0
  11. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/Makefile.am +29 -14
  12. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/Makefile.in +77 -42
  13. data/ext/sparsehash-1.8.1/NEWS +71 -0
  14. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/README +0 -0
  15. data/ext/{sparsehash-1.5.2/README.windows → sparsehash-1.8.1/README_windows.txt} +25 -25
  16. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/TODO +0 -0
  17. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/aclocal.m4 +0 -0
  18. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/compile +0 -0
  19. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/config.guess +0 -0
  20. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/config.sub +0 -0
  21. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/configure +3690 -4560
  22. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/configure.ac +1 -1
  23. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/depcomp +0 -0
  24. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/dense_hash_map.html +65 -5
  25. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/dense_hash_set.html +65 -5
  26. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/designstyle.css +0 -0
  27. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/implementation.html +11 -5
  28. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/index.html +0 -0
  29. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/performance.html +0 -0
  30. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparse_hash_map.html +65 -5
  31. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparse_hash_set.html +65 -5
  32. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparsetable.html +0 -0
  33. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/Makefile +0 -0
  34. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/README +0 -0
  35. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/example.c +0 -0
  36. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/libchash.c +0 -0
  37. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/libchash.h +0 -0
  38. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/google-sparsehash.sln +17 -1
  39. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/install-sh +0 -0
  40. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/acx_pthread.m4 +0 -0
  41. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/google_namespace.m4 +0 -0
  42. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/namespaces.m4 +0 -0
  43. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_hash.m4 +0 -0
  44. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_hash_fun.m4 +0 -0
  45. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_namespace.m4 +0 -0
  46. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/missing +0 -0
  47. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/mkinstalldirs +0 -0
  48. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb.sh +0 -0
  49. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/README +0 -0
  50. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/changelog +24 -0
  51. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/compat +0 -0
  52. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/control +1 -1
  53. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/copyright +0 -0
  54. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/docs +0 -0
  55. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/rules +0 -0
  56. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/sparsehash.dirs +0 -0
  57. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/sparsehash.install +0 -0
  58. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/rpm.sh +0 -0
  59. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/rpm/rpm.spec +1 -1
  60. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/config.h.in +3 -0
  61. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/config.h.include +0 -0
  62. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/dense_hash_map +43 -27
  63. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/dense_hash_set +40 -19
  64. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparse_hash_map +32 -23
  65. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparse_hash_set +31 -21
  66. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsehash/densehashtable.h +481 -298
  67. data/ext/sparsehash-1.8.1/src/google/sparsehash/hashtable-common.h +178 -0
  68. data/ext/sparsehash-1.8.1/src/google/sparsehash/libc_allocator_with_realloc.h +121 -0
  69. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsehash/sparsehashtable.h +404 -233
  70. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsetable +173 -83
  71. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/type_traits.h +3 -29
  72. data/ext/sparsehash-1.8.1/src/hash_test_interface.h +1011 -0
  73. data/ext/sparsehash-1.8.1/src/hashtable_test.cc +1733 -0
  74. data/ext/sparsehash-1.8.1/src/libc_allocator_with_realloc_test.cc +129 -0
  75. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/simple_test.cc +1 -1
  76. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/sparsetable_unittest.cc +202 -6
  77. data/ext/sparsehash-1.8.1/src/testutil.h +251 -0
  78. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/time_hash_map.cc +128 -54
  79. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/type_traits_unittest.cc +30 -20
  80. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/config.h +0 -0
  81. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/google/sparsehash/sparseconfig.h +0 -0
  82. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/port.cc +0 -0
  83. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/port.h +0 -0
  84. data/ext/sparsehash-1.8.1/vsprojects/hashtable_test/hashtable_test.vcproj +197 -0
  85. data/ext/{sparsehash-1.5.2/vsprojects/hashtable_unittest/hashtable_unittest.vcproj → sparsehash-1.8.1/vsprojects/simple_test/simple_test.vcproj} +9 -8
  86. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +0 -2
  87. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/time_hash_map/time_hash_map.vcproj +3 -2
  88. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +0 -2
  89. data/ext/template/google_hash.cpp.erb +2 -1
  90. data/ext/template/main.cpp.erb +1 -1
  91. data/results.txt +6 -22
  92. data/spec/benchmark.rb +57 -0
  93. data/spec/spec.google_hash.rb +1 -8
  94. metadata +140 -130
  95. data/ext/benchmark.rb +0 -47
  96. data/ext/sparsehash-1.5.2/NEWS +0 -0
  97. data/ext/sparsehash-1.5.2/src/hashtable_unittest.cc +0 -1375
  98. data/ext/sparsehash-1.5.2/src/words +0 -8944
  99. data/types.txt +0 -18
@@ -40,10 +40,15 @@
40
40
  // because all iterators for sets are const (you obviously can't
41
41
  // change the key, and for sets there is no value).
42
42
  //
43
- // We adhere mostly to the STL semantics for hash-set. One important
44
- // exception is that insert() invalidates iterators entirely. On the
45
- // plus side, though, delete() doesn't invalidate iterators at all, or
46
- // even change the ordering of elements.
43
+ // We adhere mostly to the STL semantics for hash-map. One important
44
+ // exception is that insert() may invalidate iterators entirely -- STL
45
+ // semantics are that insert() may reorder iterators, but they all
46
+ // still refer to something valid in the hashtable. Not so for us.
47
+ // Likewise, insert() may invalidate pointers into the hashtable.
48
+ // (Whether insert invalidates iterators and pointers depends on
49
+ // whether it results in a hashtable resize). On the plus side,
50
+ // delete() doesn't invalidate iterators or pointers at all, or even
51
+ // change the ordering of elements.
47
52
  //
48
53
  // Here are a few "power user" tips:
49
54
  //
@@ -62,19 +67,20 @@
62
67
  // Setting the minimum load factor to 0.0 guarantees that
63
68
  // the hash table will never shrink.
64
69
  //
65
- // Guide to what kind of hash_set to use:
66
- // (1) dense_hash_set: fastest, uses the most memory
70
+ // Roughly speaking:
71
+ // (1) dense_hash_set: fastest, uses the most memory unless entries are small
67
72
  // (2) sparse_hash_set: slowest, uses the least memory
68
- // (3) hash_set /unordered_set (STL): in the middle
73
+ // (3) hash_set / unordered_set (STL): in the middle
74
+ //
69
75
  // Typically I use sparse_hash_set when I care about space and/or when
70
76
  // I need to save the hashtable on disk. I use hash_set otherwise. I
71
77
  // don't personally use dense_hash_set ever; some people use it for
72
78
  // small sets with lots of lookups.
73
79
  //
74
- // - dense_hash_set has, typically, a factor of 2 memory overhead (if your
75
- // data takes up X bytes, the hash_set uses X more bytes in overhead).
76
- // - sparse_hash_set has about 2 bits overhead per entry.
77
- // - sparse_hash_map can be 3-7 times slower than the others for lookup and,
80
+ // - dense_hash_set has, typically, about 78% memory overhead (if your
81
+ // data takes up X bytes, the hash_set uses .78X more bytes in overhead).
82
+ // - sparse_hash_set has about 4 bits overhead per entry.
83
+ // - sparse_hash_set can be 3-7 times slower than the others for lookup and,
78
84
  // especially, inserts. See time_hash_map.cc for details.
79
85
  //
80
86
  // See /usr/(local/)?doc/sparsehash-*/sparse_hash_set.html
@@ -90,6 +96,7 @@
90
96
  #include <memory> // for alloc<>
91
97
  #include <utility> // for pair<>
92
98
  #include HASH_FUN_H // defined in config.h
99
+ #include <google/sparsehash/libc_allocator_with_realloc.h>
93
100
  #include <google/sparsehash/sparsehashtable.h>
94
101
 
95
102
  _START_GOOGLE_NAMESPACE_
@@ -99,7 +106,7 @@ using STL_NAMESPACE::pair;
99
106
  template <class Value,
100
107
  class HashFcn = SPARSEHASH_HASH<Value>, // defined in sparseconfig.h
101
108
  class EqualKey = STL_NAMESPACE::equal_to<Value>,
102
- class Alloc = STL_NAMESPACE::allocator<Value> >
109
+ class Alloc = libc_allocator_with_realloc<Value> >
103
110
  class sparse_hash_set {
104
111
  private:
105
112
  // Apparently identity is not stl-standard, so we define our own
@@ -113,9 +120,8 @@ class sparse_hash_set {
113
120
  }
114
121
  };
115
122
 
116
- // The actual data
117
- typedef sparse_hashtable<Value, Value, HashFcn,
118
- Identity, SetKey, EqualKey, Alloc> ht;
123
+ typedef sparse_hashtable<Value, Value, HashFcn, Identity, SetKey,
124
+ EqualKey, Alloc> ht;
119
125
  ht rep;
120
126
 
121
127
  public:
@@ -148,7 +154,7 @@ class sparse_hash_set {
148
154
 
149
155
 
150
156
  // Accessor functions
151
- // TODO(csilvers): implement Alloc get_allocator() const;
157
+ allocator_type get_allocator() const { return rep.get_allocator(); }
152
158
  hasher hash_funct() const { return rep.hash_funct(); }
153
159
  hasher hash_function() const { return hash_funct(); } // tr1 name
154
160
  key_equal key_eq() const { return rep.key_eq(); }
@@ -157,15 +163,18 @@ class sparse_hash_set {
157
163
  // Constructors
158
164
  explicit sparse_hash_set(size_type expected_max_items_in_table = 0,
159
165
  const hasher& hf = hasher(),
160
- const key_equal& eql = key_equal())
161
- : rep(expected_max_items_in_table, hf, eql) { }
166
+ const key_equal& eql = key_equal(),
167
+ const allocator_type& alloc = allocator_type())
168
+ : rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
169
+ }
162
170
 
163
171
  template <class InputIterator>
164
172
  sparse_hash_set(InputIterator f, InputIterator l,
165
173
  size_type expected_max_items_in_table = 0,
166
174
  const hasher& hf = hasher(),
167
- const key_equal& eql = key_equal())
168
- : rep(expected_max_items_in_table, hf, eql) {
175
+ const key_equal& eql = key_equal(),
176
+ const allocator_type& alloc = allocator_type())
177
+ : rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
169
178
  rep.insert(f, l);
170
179
  }
171
180
  // We use the default copy constructor
@@ -212,7 +221,7 @@ class sparse_hash_set {
212
221
  }
213
222
  // Deprecated; use min_load_factor() or max_load_factor() instead.
214
223
  void set_resizing_parameters(float shrink, float grow) {
215
- return rep.set_resizing_parameters(shrink, grow);
224
+ rep.set_resizing_parameters(shrink, grow);
216
225
  }
217
226
 
218
227
  void resize(size_type hint) { rep.resize(hint); }
@@ -245,6 +254,7 @@ class sparse_hash_set {
245
254
  // time goes on, or get rid of it entirely to be insert-only.
246
255
  void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
247
256
  void clear_deleted_key() { rep.clear_deleted_key(); }
257
+ key_type deleted_key() const { return rep.deleted_key(); }
248
258
 
249
259
  // These are standard
250
260
  size_type erase(const key_type& key) { return rep.erase(key); }
@@ -57,19 +57,19 @@
57
57
  // <google/dense_hash_map> or <google/dense_hash_set> instead.
58
58
 
59
59
  // You can change the following below:
60
- // HT_OCCUPANCY_FLT -- how full before we double size
61
- // HT_EMPTY_FLT -- how empty before we halve size
60
+ // HT_OCCUPANCY_PCT -- how full before we double size
61
+ // HT_EMPTY_PCT -- how empty before we halve size
62
62
  // HT_MIN_BUCKETS -- default smallest bucket size
63
63
  //
64
- // You can also change enlarge_resize_percent (which defaults to
65
- // HT_OCCUPANCY_FLT), and shrink_resize_percent (which defaults to
66
- // HT_EMPTY_FLT) with set_resizing_parameters().
64
+ // You can also change enlarge_factor (which defaults to
65
+ // HT_OCCUPANCY_PCT), and shrink_factor (which defaults to
66
+ // HT_EMPTY_PCT) with set_resizing_parameters().
67
67
  //
68
68
  // How to decide what values to use?
69
- // shrink_resize_percent's default of .4 * OCCUPANCY_FLT, is probably good.
69
+ // shrink_factor's default of .4 * OCCUPANCY_PCT, is probably good.
70
70
  // HT_MIN_BUCKETS is probably unnecessary since you can specify
71
71
  // (indirectly) the starting number of buckets at construct-time.
72
- // For enlarge_resize_percent, you can use this chart to try to trade-off
72
+ // For enlarge_factor, you can use this chart to try to trade-off
73
73
  // expected lookup time to the space taken up. By default, this
74
74
  // code uses quadratic probing, though you can change it to linear
75
75
  // via _JUMP below if you really want to.
@@ -79,7 +79,7 @@
79
79
  // Quadratic collision resolution 1 - ln(1-L) - L/2 1/(1-L) - L - ln(1-L)
80
80
  // Linear collision resolution [1+1/(1-L)]/2 [1+1/(1-L)2]/2
81
81
  //
82
- // -- enlarge_resize_percent -- 0.10 0.50 0.60 0.75 0.80 0.90 0.99
82
+ // -- enlarge_factor -- 0.10 0.50 0.60 0.75 0.80 0.90 0.99
83
83
  // QUADRATIC COLLISION RES.
84
84
  // probes/successful lookup 1.05 1.44 1.62 2.01 2.21 2.85 5.11
85
85
  // probes/unsuccessful lookup 1.11 2.19 2.82 4.64 5.81 11.4 103.6
@@ -93,19 +93,23 @@
93
93
  // The probing method
94
94
  // Linear probing
95
95
  // #define JUMP_(key, num_probes) ( 1 )
96
- // Quadratic-ish probing
96
+ // Quadratic probing
97
97
  #define JUMP_(key, num_probes) ( num_probes )
98
98
 
99
99
 
100
100
  #include <google/sparsehash/sparseconfig.h>
101
- #include <assert.h>
102
101
  #include <stdio.h>
102
+ #include <assert.h>
103
103
  #include <stdlib.h> // for abort()
104
104
  #include <algorithm> // For swap(), eg
105
+ #include <stdexcept> // For length_error
105
106
  #include <iostream> // For cerr
106
107
  #include <memory> // For uninitialized_fill, uninitialized_copy
107
108
  #include <utility> // for pair<>
108
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>
109
113
  #include <google/type_traits.h> // for true_type, integral_constant, etc.
110
114
 
111
115
  _START_GOOGLE_NAMESPACE_
@@ -125,7 +129,7 @@ using STL_NAMESPACE::pair;
125
129
  // with key == deleted_key or key == empty_key.
126
130
  // EqualKey: Given two Keys, says whether they are the same (that is,
127
131
  // if they are both associated with the same Value).
128
- // Alloc: STL allocator to use to allocate memory. Currently ignored.
132
+ // Alloc: STL allocator to use to allocate memory.
129
133
 
130
134
  template <class Value, class Key, class HashFcn,
131
135
  class ExtractKey, class SetKey, class EqualKey, class Alloc>
@@ -140,16 +144,19 @@ struct dense_hashtable_const_iterator;
140
144
  // We're just an array, but we need to skip over empty and deleted elements
141
145
  template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
142
146
  struct dense_hashtable_iterator {
147
+ private:
148
+ typedef typename A::template rebind<V>::other value_alloc_type;
149
+
143
150
  public:
144
151
  typedef dense_hashtable_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
145
152
  typedef dense_hashtable_const_iterator<V,K,HF,ExK,SetK,EqK,A> const_iterator;
146
153
 
147
154
  typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
148
155
  typedef V value_type;
149
- typedef ptrdiff_t difference_type;
150
- typedef size_t size_type;
151
- typedef V& reference; // Value
152
- typedef V* pointer;
156
+ typedef typename value_alloc_type::difference_type difference_type;
157
+ typedef typename value_alloc_type::size_type size_type;
158
+ typedef typename value_alloc_type::reference reference;
159
+ typedef typename value_alloc_type::pointer pointer;
153
160
 
154
161
  // "Real" constructor and default constructor
155
162
  dense_hashtable_iterator(const dense_hashtable<V,K,HF,ExK,SetK,EqK,A> *h,
@@ -190,16 +197,19 @@ struct dense_hashtable_iterator {
190
197
  // Now do it all again, but with const-ness!
191
198
  template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
192
199
  struct dense_hashtable_const_iterator {
200
+ private:
201
+ typedef typename A::template rebind<V>::other value_alloc_type;
202
+
193
203
  public:
194
204
  typedef dense_hashtable_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
195
205
  typedef dense_hashtable_const_iterator<V,K,HF,ExK,SetK,EqK,A> const_iterator;
196
206
 
197
207
  typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
198
208
  typedef V value_type;
199
- typedef ptrdiff_t difference_type;
200
- typedef size_t size_type;
201
- typedef const V& reference; // Value
202
- typedef const V* pointer;
209
+ typedef typename value_alloc_type::difference_type difference_type;
210
+ typedef typename value_alloc_type::size_type size_type;
211
+ typedef typename value_alloc_type::const_reference reference;
212
+ typedef typename value_alloc_type::const_pointer pointer;
203
213
 
204
214
  // "Real" constructor and default constructor
205
215
  dense_hashtable_const_iterator(
@@ -243,18 +253,22 @@ struct dense_hashtable_const_iterator {
243
253
  template <class Value, class Key, class HashFcn,
244
254
  class ExtractKey, class SetKey, class EqualKey, class Alloc>
245
255
  class dense_hashtable {
256
+ private:
257
+ typedef typename Alloc::template rebind<Value>::other value_alloc_type;
258
+
246
259
  public:
247
260
  typedef Key key_type;
248
261
  typedef Value value_type;
249
262
  typedef HashFcn hasher;
250
263
  typedef EqualKey key_equal;
251
-
252
- typedef size_t size_type;
253
- typedef ptrdiff_t difference_type;
254
- typedef value_type* pointer;
255
- typedef const value_type* const_pointer;
256
- typedef value_type& reference;
257
- typedef const value_type& const_reference;
264
+ typedef Alloc allocator_type;
265
+
266
+ typedef typename value_alloc_type::size_type size_type;
267
+ typedef typename value_alloc_type::difference_type difference_type;
268
+ typedef typename value_alloc_type::reference reference;
269
+ typedef typename value_alloc_type::const_reference const_reference;
270
+ typedef typename value_alloc_type::pointer pointer;
271
+ typedef typename value_alloc_type::const_pointer const_pointer;
258
272
  typedef dense_hashtable_iterator<Value, Key, HashFcn,
259
273
  ExtractKey, SetKey, EqualKey, Alloc>
260
274
  iterator;
@@ -270,24 +284,23 @@ class dense_hashtable {
270
284
  // How full we let the table get before we resize, by default.
271
285
  // Knuth says .8 is good -- higher causes us to probe too much,
272
286
  // though it saves memory.
273
- static const float HT_OCCUPANCY_FLT; // = 0.5;
287
+ static const int HT_OCCUPANCY_PCT; // = 50 (out of 100)
274
288
 
275
289
  // How empty we let the table get before we resize lower, by default.
276
290
  // (0.0 means never resize lower.)
277
- // It should be less than OCCUPANCY_FLT / 2 or we thrash resizing
278
- static const float HT_EMPTY_FLT; // = 0.4 * HT_OCCUPANCY_FLT
291
+ // It should be less than OCCUPANCY_PCT / 2 or we thrash resizing
292
+ static const int HT_EMPTY_PCT; // = 0.4 * HT_OCCUPANCY_PCT;
279
293
 
280
294
  // Minimum size we're willing to let hashtables be.
281
295
  // Must be a power of two, and at least 4.
282
296
  // Note, however, that for a given hashtable, the initial size is a
283
297
  // function of the first constructor arg, and may be >HT_MIN_BUCKETS.
284
- static const size_t HT_MIN_BUCKETS = 4;
298
+ static const size_type HT_MIN_BUCKETS = 4;
285
299
 
286
300
  // By default, if you don't specify a hashtable size at
287
301
  // construction-time, we use this size. Must be a power of two, and
288
302
  // at least HT_MIN_BUCKETS.
289
- static const size_t HT_DEFAULT_STARTING_BUCKETS = 32;
290
-
303
+ static const size_type HT_DEFAULT_STARTING_BUCKETS = 32;
291
304
 
292
305
  // ITERATOR FUNCTIONS
293
306
  iterator begin() { return iterator(this, table,
@@ -300,10 +313,7 @@ class dense_hashtable {
300
313
  table+num_buckets,true);}
301
314
 
302
315
  // These come from tr1 unordered_map. They iterate over 'bucket' n.
303
- // For sparsehashtable, we could consider each 'group' to be a bucket,
304
- // I guess, but I don't really see the point. We'll just consider
305
- // bucket n to be the n-th element of the sparsetable, if it's occupied,
306
- // or some empty element, otherwise.
316
+ // We'll just consider bucket n to be the n-th element of the table.
307
317
  local_iterator begin(size_type i) {
308
318
  return local_iterator(this, table + i, table + i+1, false);
309
319
  }
@@ -324,16 +334,20 @@ class dense_hashtable {
324
334
  }
325
335
 
326
336
  // ACCESSOR FUNCTIONS for the things we templatize on, basically
327
- hasher hash_funct() const { return hash; }
328
- key_equal key_eq() const { return equals; }
337
+ hasher hash_funct() const { return settings; }
338
+ key_equal key_eq() const { return key_info; }
339
+ allocator_type get_allocator() const { return allocator; }
340
+
341
+ // Accessor function for statistics gathering.
342
+ int num_table_copies() const { return settings.num_ht_copies(); }
329
343
 
330
344
  private:
331
345
  // Annoyingly, we can't copy values around, because they might have
332
346
  // const components (they're probably pair<const X, Y>). We use
333
347
  // explicit destructor invocation and placement new to get around
334
348
  // this. Arg.
335
- void set_value(value_type* dst, const value_type& src) {
336
- dst->~value_type();
349
+ void set_value(pointer dst, const_reference src) {
350
+ dst->~value_type(); // delete the old value, if any
337
351
  new(dst) value_type(src);
338
352
  }
339
353
 
@@ -357,50 +371,77 @@ class dense_hashtable {
357
371
  assert(num_deleted == 0);
358
372
  }
359
373
 
374
+ 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);
380
+ }
381
+
360
382
  public:
361
383
  void set_deleted_key(const key_type &key) {
362
384
  // the empty indicator (if specified) and the deleted indicator
363
385
  // must be different
364
- assert(!use_empty || !equals(key, get_key(emptyval)));
386
+ assert((!settings.use_empty() || !equals(key, get_key(emptyval)))
387
+ && "Passed the empty-key to set_deleted_key");
365
388
  // It's only safe to change what "deleted" means if we purge deleted guys
366
389
  squash_deleted();
367
- use_deleted = true;
368
- delkey = key;
390
+ settings.set_use_deleted(true);
391
+ key_info.delkey = key;
369
392
  }
370
393
  void clear_deleted_key() {
371
394
  squash_deleted();
372
- use_deleted = false;
395
+ settings.set_use_deleted(false);
396
+ }
397
+ key_type deleted_key() const {
398
+ assert(settings.use_deleted()
399
+ && "Must set deleted key before calling deleted_key");
400
+ return key_info.delkey;
373
401
  }
374
402
 
375
403
  // These are public so the iterators can use them
376
404
  // True if the item at position bucknum is "deleted" marker
377
405
  bool test_deleted(size_type bucknum) const {
378
- // The num_deleted test is crucial for read(): after read(), the ht values
379
- // are garbage, and we don't want to think some of them are deleted.
380
- return (use_deleted && num_deleted > 0 &&
381
- equals(delkey, get_key(table[bucknum])));
406
+ return test_deleted_key(get_key(table[bucknum]));
382
407
  }
383
408
  bool test_deleted(const iterator &it) const {
384
- return (use_deleted && num_deleted > 0 &&
385
- equals(delkey, get_key(*it)));
409
+ return test_deleted_key(get_key(*it));
386
410
  }
387
411
  bool test_deleted(const const_iterator &it) const {
388
- return (use_deleted && num_deleted > 0 &&
389
- equals(delkey, get_key(*it)));
412
+ return test_deleted_key(get_key(*it));
413
+ }
414
+
415
+ private:
416
+ // Set it so test_deleted is true. true if object didn't used to be deleted.
417
+ bool set_deleted(iterator &it) {
418
+ assert(settings.use_deleted());
419
+ bool retval = !test_deleted(it);
420
+ // &* converts from iterator to value-type.
421
+ set_key(&(*it), key_info.delkey);
422
+ return retval;
390
423
  }
391
- // Set it so test_deleted is true. true if object didn't used to be deleted
392
- // See below (at erase()) to explain why we allow const_iterators
424
+ // Set it so test_deleted is false. true if object used to be deleted.
425
+ bool clear_deleted(iterator &it) {
426
+ assert(settings.use_deleted());
427
+ // Happens automatically when we assign something else in its place.
428
+ return test_deleted(it);
429
+ }
430
+
431
+ // We also allow to set/clear the deleted bit on a const iterator.
432
+ // We allow a const_iterator for the same reason you can delete a
433
+ // const pointer: it's convenient, and semantically you can't use
434
+ // 'it' after it's been deleted anyway, so its const-ness doesn't
435
+ // really matter.
393
436
  bool set_deleted(const_iterator &it) {
394
- assert(use_deleted); // bad if set_deleted_key() wasn't called
437
+ assert(settings.use_deleted());
395
438
  bool retval = !test_deleted(it);
396
- // &* converts from iterator to value-type
397
- set_key(const_cast<value_type*>(&(*it)), delkey);
439
+ set_key(const_cast<pointer>(&(*it)), key_info.delkey);
398
440
  return retval;
399
441
  }
400
- // Set it so test_deleted is false. true if object used to be deleted
442
+ // Set it so test_deleted is false. true if object used to be deleted.
401
443
  bool clear_deleted(const_iterator &it) {
402
- assert(use_deleted); // bad if set_deleted_key() wasn't called
403
- // happens automatically when we assign something else in its place
444
+ assert(settings.use_deleted());
404
445
  return test_deleted(it);
405
446
  }
406
447
 
@@ -414,58 +455,52 @@ class dense_hashtable {
414
455
  // These are public so the iterators can use them
415
456
  // True if the item at position bucknum is "empty" marker
416
457
  bool test_empty(size_type bucknum) const {
417
- assert(use_empty); // we always need to know what's empty!
458
+ assert(settings.use_empty()); // we always need to know what's empty!
418
459
  return equals(get_key(emptyval), get_key(table[bucknum]));
419
460
  }
420
461
  bool test_empty(const iterator &it) const {
421
- assert(use_empty); // we always need to know what's empty!
462
+ assert(settings.use_empty()); // we always need to know what's empty!
422
463
  return equals(get_key(emptyval), get_key(*it));
423
464
  }
424
465
  bool test_empty(const const_iterator &it) const {
425
- assert(use_empty); // we always need to know what's empty!
466
+ assert(settings.use_empty()); // we always need to know what's empty!
426
467
  return equals(get_key(emptyval), get_key(*it));
427
468
  }
428
469
 
429
470
  private:
430
- // You can either set a range empty or an individual element
431
- void set_empty(size_type bucknum) {
432
- assert(use_empty);
433
- set_value(&table[bucknum], emptyval);
434
- }
435
- void fill_range_with_empty(value_type* table_start, value_type* table_end) {
436
- // Like set_empty(range), but doesn't destroy previous contents
471
+ void fill_range_with_empty(pointer table_start, pointer table_end) {
437
472
  STL_NAMESPACE::uninitialized_fill(table_start, table_end, emptyval);
438
473
  }
439
- void set_empty(size_type buckstart, size_type buckend) {
440
- assert(use_empty);
441
- destroy_buckets(buckstart, buckend);
442
- fill_range_with_empty(table + buckstart, table + buckend);
443
- }
444
474
 
445
475
  public:
446
476
  // TODO(csilvers): change all callers of this to pass in a key instead,
447
477
  // and take a const key_type instead of const value_type.
448
- void set_empty_key(const value_type &val) {
478
+ void set_empty_key(const_reference val) {
449
479
  // Once you set the empty key, you can't change it
450
- assert(!use_empty);
480
+ assert(!settings.use_empty() && "Calling set_empty_key multiple times");
451
481
  // The deleted indicator (if specified) and the empty indicator
452
482
  // must be different.
453
- assert(!use_deleted || !equals(get_key(val), delkey));
454
- use_empty = true;
483
+ assert((!settings.use_deleted() || !equals(get_key(val), key_info.delkey))
484
+ && "Setting the empty key the same as the deleted key");
485
+ settings.set_use_empty(true);
455
486
  set_value(&emptyval, val);
456
487
 
457
488
  assert(!table); // must set before first use
458
489
  // num_buckets was set in constructor even though table was NULL
459
- table = (value_type *) malloc(num_buckets * sizeof(*table));
490
+ table = allocator.allocate(num_buckets);
460
491
  assert(table);
461
492
  fill_range_with_empty(table, table + num_buckets);
462
493
  }
494
+ // TODO(sjackman): return a key_type rather than a value_type
495
+ value_type empty_key() const {
496
+ assert(settings.use_empty());
497
+ return emptyval;
498
+ }
463
499
 
464
500
  // FUNCTIONS CONCERNING SIZE
465
501
  public:
466
502
  size_type size() const { return num_elements - num_deleted; }
467
- // Buckets are always a power of 2
468
- size_type max_size() const { return (size_type(-1) >> 1U) + 1; }
503
+ size_type max_size() const { return allocator.max_size(); }
469
504
  bool empty() const { return size() == 0; }
470
505
  size_type bucket_count() const { return num_buckets; }
471
506
  size_type max_bucket_count() const { return max_size(); }
@@ -476,54 +511,56 @@ class dense_hashtable {
476
511
  return begin(i) == end(i) ? 0 : 1;
477
512
  }
478
513
 
479
-
480
-
481
514
  private:
482
515
  // Because of the above, size_type(-1) is never legal; use it for errors
483
516
  static const size_type ILLEGAL_BUCKET = size_type(-1);
484
517
 
485
- private:
486
- // This is the smallest size a hashtable can be without being too crowded
487
- // If you like, you can give a min #buckets as well as a min #elts
488
- size_type min_size(size_type num_elts, size_type min_buckets_wanted) {
489
- size_type sz = HT_MIN_BUCKETS; // min buckets allowed
490
- while ( sz < min_buckets_wanted || num_elts >= sz * enlarge_resize_percent )
491
- sz *= 2;
492
- return sz;
493
- }
494
-
495
- // Used after a string of deletes
496
- void maybe_shrink() {
518
+ // Used after a string of deletes. Returns true if we actually shrunk.
519
+ // TODO(csilvers): take a delta so we can take into account inserts
520
+ // done after shrinking. Maybe make part of the Settings class?
521
+ bool maybe_shrink() {
497
522
  assert(num_elements >= num_deleted);
498
523
  assert((bucket_count() & (bucket_count()-1)) == 0); // is a power of two
499
524
  assert(bucket_count() >= HT_MIN_BUCKETS);
525
+ bool retval = false;
500
526
 
501
527
  // If you construct a hashtable with < HT_DEFAULT_STARTING_BUCKETS,
502
528
  // we'll never shrink until you get relatively big, and we'll never
503
529
  // shrink below HT_DEFAULT_STARTING_BUCKETS. Otherwise, something
504
530
  // like "dense_hash_set<int> x; x.insert(4); x.erase(4);" will
505
531
  // shrink us down to HT_MIN_BUCKETS buckets, which is too small.
506
- if (shrink_threshold > 0 &&
507
- (num_elements-num_deleted) < shrink_threshold &&
508
- bucket_count() > HT_DEFAULT_STARTING_BUCKETS ) {
532
+ const size_type num_remain = num_elements - num_deleted;
533
+ const size_type shrink_threshold = settings.shrink_threshold();
534
+ if (shrink_threshold > 0 && num_remain < shrink_threshold &&
535
+ bucket_count() > HT_DEFAULT_STARTING_BUCKETS) {
536
+ const float shrink_factor = settings.shrink_factor();
509
537
  size_type sz = bucket_count() / 2; // find how much we should shrink
510
- while ( sz > HT_DEFAULT_STARTING_BUCKETS &&
511
- (num_elements - num_deleted) < sz * shrink_resize_percent )
538
+ while (sz > HT_DEFAULT_STARTING_BUCKETS &&
539
+ num_remain < sz * shrink_factor) {
512
540
  sz /= 2; // stay a power of 2
541
+ }
513
542
  dense_hashtable tmp(*this, sz); // Do the actual resizing
514
543
  swap(tmp); // now we are tmp
544
+ retval = true;
515
545
  }
516
- consider_shrink = false; // because we just considered it
546
+ settings.set_consider_shrink(false); // because we just considered it
547
+ return retval;
517
548
  }
518
549
 
519
550
  // We'll let you resize a hashtable -- though this makes us copy all!
520
551
  // When you resize, you say, "make it big enough for this many more elements"
521
- void resize_delta(size_type delta) {
522
- if ( consider_shrink ) // see if lots of deletes happened
523
- maybe_shrink();
524
- if ( bucket_count() > HT_MIN_BUCKETS &&
525
- (num_elements + delta) <= enlarge_threshold )
526
- return; // we're ok as we are
552
+ // Returns true if we actually resized, false if size was already ok.
553
+ bool resize_delta(size_type delta) {
554
+ bool did_resize = false;
555
+ if ( settings.consider_shrink() ) { // see if lots of deletes happened
556
+ if ( maybe_shrink() )
557
+ did_resize = true;
558
+ }
559
+ if (num_elements >= (STL_NAMESPACE::numeric_limits<size_type>::max)() - delta)
560
+ throw std::length_error("resize overflow");
561
+ if ( bucket_count() >= HT_MIN_BUCKETS &&
562
+ (num_elements + delta) <= settings.enlarge_threshold() )
563
+ return did_resize; // we're ok as we are
527
564
 
528
565
  // Sometimes, we need to resize just to get rid of all the
529
566
  // "deleted" buckets that are clogging up the hashtable. So when
@@ -531,56 +568,48 @@ class dense_hashtable {
531
568
  // are currently taking up room). But later, when we decide what
532
569
  // size to resize to, *don't* count deleted buckets, since they
533
570
  // get discarded during the resize.
534
- const size_type needed_size = min_size(num_elements + delta, 0);
535
- if ( needed_size > bucket_count() ) { // we don't have enough buckets
536
- const size_type resize_to = min_size(num_elements - num_deleted + delta,
537
- 0);
538
- dense_hashtable tmp(*this, resize_to);
539
- swap(tmp); // now we are tmp
571
+ const size_type needed_size = settings.min_buckets(num_elements + delta, 0);
572
+ if ( needed_size <= bucket_count() ) // we have enough buckets
573
+ return did_resize;
574
+
575
+ size_type resize_to =
576
+ settings.min_buckets(num_elements - num_deleted + delta, bucket_count());
577
+
578
+ if (resize_to < needed_size && // may double resize_to
579
+ resize_to < (STL_NAMESPACE::numeric_limits<size_type>::max)() / 2) {
580
+ // This situation means that we have enough deleted elements,
581
+ // that once we purge them, we won't actually have needed to
582
+ // grow. But we may want to grow anyway: if we just purge one
583
+ // element, say, we'll have to grow anyway next time we
584
+ // insert. Might as well grow now, since we're already going
585
+ // through the trouble of copying (in order to purge the
586
+ // deleted elements).
587
+ const size_type target =
588
+ static_cast<size_type>(settings.shrink_size(resize_to*2));
589
+ if (num_elements - num_deleted + delta >= target) {
590
+ // Good, we won't be below the shrink threshhold even if we double.
591
+ resize_to *= 2;
592
+ }
540
593
  }
594
+ dense_hashtable tmp(*this, resize_to);
595
+ swap(tmp); // now we are tmp
596
+ return true;
541
597
  }
542
598
 
543
- // Increase number of buckets, assuming value_type has trivial copy
544
- // constructor and destructor. (Really, we want it to have "trivial
545
- // move", because that's what realloc does. But there's no way to
546
- // capture that using type_traits, so we pretend that move(x, y) is
547
- // equivalent to "x.~T(); new(x) T(y);" which is pretty much
548
- // correct, if a bit conservative.)
549
- void expand_array(size_t resize_to, true_type) {
550
- table = (value_type *) realloc(table, resize_to * sizeof(value_type));
551
- assert(table);
552
- fill_range_with_empty(table + num_buckets, table + resize_to);
599
+ // We require table be not-NULL and empty before calling this.
600
+ void resize_table(size_type /*old_size*/, size_type new_size,
601
+ true_type) {
602
+ table = allocator.realloc_or_die(table, new_size);
553
603
  }
554
604
 
555
- // Increase number of buckets, without special assumptions about value_type.
556
- // TODO(austern): make this exception safe. Handle exceptions from
557
- // value_type's copy constructor.
558
- void expand_array(size_t resize_to, false_type) {
559
- value_type* new_table =
560
- (value_type *) malloc(resize_to * sizeof(value_type));
561
- assert(new_table);
562
- STL_NAMESPACE::uninitialized_copy(table, table + num_buckets, new_table);
563
- fill_range_with_empty(new_table + num_buckets, new_table + resize_to);
564
- destroy_buckets(0, num_buckets);
565
- free(table);
566
- table = new_table;
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);
567
608
  }
568
609
 
569
610
  // Used to actually do the rehashing when we grow/shrink a hashtable
570
611
  void copy_from(const dense_hashtable &ht, size_type min_buckets_wanted) {
571
- clear(); // clear table, set num_deleted to 0
572
-
573
- // If we need to change the size of our table, do it now
574
- const size_type resize_to = min_size(ht.size(), min_buckets_wanted);
575
- if ( resize_to > bucket_count() ) { // we don't have enough buckets
576
- typedef integral_constant<bool,
577
- (has_trivial_copy<value_type>::value &&
578
- has_trivial_destructor<value_type>::value)>
579
- realloc_ok; // we pretend mv(x,y) == "x.~T(); new(x) T(y)"
580
- expand_array(resize_to, realloc_ok());
581
- num_buckets = resize_to;
582
- reset_thresholds();
583
- }
612
+ clear_to_size(settings.min_buckets(ht.size(), min_buckets_wanted));
584
613
 
585
614
  // We use a normal iterator to get non-deleted bcks from ht
586
615
  // We could use insert() here, but since we know there are
@@ -594,41 +623,38 @@ class dense_hashtable {
594
623
  !test_empty(bucknum); // not empty
595
624
  bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one) {
596
625
  ++num_probes;
597
- assert(num_probes < bucket_count()); // or else the hashtable is full
626
+ assert(num_probes < bucket_count()
627
+ && "Hashtable is full: an error in key_equal<> or hash<>");
598
628
  }
599
629
  set_value(&table[bucknum], *it); // copies the value to here
600
630
  num_elements++;
601
631
  }
632
+ settings.inc_num_ht_copies();
602
633
  }
603
634
 
604
635
  // Required by the spec for hashed associative container
605
636
  public:
606
637
  // Though the docs say this should be num_buckets, I think it's much
607
- // more useful as req_elements. As a special feature, calling with
638
+ // more useful as num_elements. As a special feature, calling with
608
639
  // req_elements==0 will cause us to shrink if we can, saving space.
609
640
  void resize(size_type req_elements) { // resize to this or larger
610
- if ( consider_shrink || req_elements == 0 )
641
+ if ( settings.consider_shrink() || req_elements == 0 )
611
642
  maybe_shrink();
612
643
  if ( req_elements > num_elements )
613
- return resize_delta(req_elements - num_elements);
644
+ resize_delta(req_elements - num_elements);
614
645
  }
615
646
 
616
- // Get and change the value of shrink_resize_percent and
617
- // enlarge_resize_percent. The description at the beginning of this
618
- // file explains how to choose the values. Setting the shrink
619
- // parameter to 0.0 ensures that the table never shrinks.
647
+ // Get and change the value of shrink_factor and enlarge_factor. The
648
+ // description at the beginning of this file explains how to choose
649
+ // the values. Setting the shrink parameter to 0.0 ensures that the
650
+ // table never shrinks.
620
651
  void get_resizing_parameters(float* shrink, float* grow) const {
621
- *shrink = shrink_resize_percent;
622
- *grow = enlarge_resize_percent;
652
+ *shrink = settings.shrink_factor();
653
+ *grow = settings.enlarge_factor();
623
654
  }
624
655
  void set_resizing_parameters(float shrink, float grow) {
625
- assert(shrink >= 0.0);
626
- assert(grow <= 1.0);
627
- if (shrink > grow/2.0f)
628
- shrink = grow / 2.0f; // otherwise we thrash hashtable size
629
- shrink_resize_percent = shrink;
630
- enlarge_resize_percent = grow;
631
- reset_thresholds();
656
+ settings.set_resizing_parameters(shrink, grow);
657
+ settings.reset_thresholds(bucket_count());
632
658
  }
633
659
 
634
660
  // CONSTRUCTORS -- as required by the specs, we take a size,
@@ -639,105 +665,133 @@ class dense_hashtable {
639
665
  const HashFcn& hf = HashFcn(),
640
666
  const EqualKey& eql = EqualKey(),
641
667
  const ExtractKey& ext = ExtractKey(),
642
- const SetKey& set = SetKey())
643
- : hash(hf), equals(eql), get_key(ext), set_key(set), num_deleted(0),
644
- use_deleted(false), use_empty(false),
645
- delkey(), emptyval(), enlarge_resize_percent(HT_OCCUPANCY_FLT),
646
- shrink_resize_percent(HT_EMPTY_FLT), table(NULL),
647
- num_buckets(expected_max_items_in_table == 0
648
- ? HT_DEFAULT_STARTING_BUCKETS
649
- : min_size(expected_max_items_in_table, 0)),
650
- num_elements(0) {
668
+ const SetKey& set = SetKey(),
669
+ const Alloc& alloc = Alloc())
670
+ : settings(hf),
671
+ key_info(ext, set, eql),
672
+ allocator(alloc),
673
+ num_deleted(0),
674
+ num_elements(0),
675
+ num_buckets(expected_max_items_in_table == 0
676
+ ? HT_DEFAULT_STARTING_BUCKETS
677
+ : settings.min_buckets(expected_max_items_in_table, 0)),
678
+ emptyval(),
679
+ table(NULL) {
651
680
  // table is NULL until emptyval is set. However, we set num_buckets
652
681
  // here so we know how much space to allocate once emptyval is set
653
- reset_thresholds();
682
+ settings.reset_thresholds(bucket_count());
654
683
  }
655
684
 
656
685
  // As a convenience for resize(), we allow an optional second argument
657
686
  // which lets you make this new hashtable a different size than ht
658
687
  dense_hashtable(const dense_hashtable& ht,
659
688
  size_type min_buckets_wanted = HT_DEFAULT_STARTING_BUCKETS)
660
- : hash(ht.hash), equals(ht.equals),
661
- get_key(ht.get_key), set_key(ht.set_key), num_deleted(0),
662
- use_deleted(ht.use_deleted), use_empty(ht.use_empty),
663
- delkey(ht.delkey), emptyval(ht.emptyval),
664
- enlarge_resize_percent(ht.enlarge_resize_percent),
665
- shrink_resize_percent(ht.shrink_resize_percent), table(NULL),
666
- num_buckets(0), num_elements(0) {
667
- reset_thresholds();
689
+ : settings(ht.settings),
690
+ key_info(ht.key_info),
691
+ allocator(ht.allocator),
692
+ num_deleted(0),
693
+ num_elements(0),
694
+ num_buckets(0),
695
+ emptyval(ht.emptyval),
696
+ table(NULL) {
697
+ if (!ht.settings.use_empty()) {
698
+ // If use_empty isn't set, copy_from will crash, so we do our own copying.
699
+ assert(ht.empty());
700
+ num_buckets = settings.min_buckets(ht.size(), min_buckets_wanted);
701
+ settings.reset_thresholds(bucket_count());
702
+ return;
703
+ }
704
+ settings.reset_thresholds(bucket_count());
668
705
  copy_from(ht, min_buckets_wanted); // copy_from() ignores deleted entries
669
706
  }
670
707
 
671
708
  dense_hashtable& operator= (const dense_hashtable& ht) {
672
709
  if (&ht == this) return *this; // don't copy onto ourselves
673
- clear();
674
- hash = ht.hash;
675
- equals = ht.equals;
676
- get_key = ht.get_key;
677
- set_key = ht.set_key;
678
- use_deleted = ht.use_deleted;
679
- use_empty = ht.use_empty;
680
- delkey = ht.delkey;
710
+ if (!ht.settings.use_empty()) {
711
+ assert(ht.empty());
712
+ dense_hashtable empty_table(ht); // empty table with ht's thresholds
713
+ this->swap(empty_table);
714
+ return *this;
715
+ }
716
+ settings = ht.settings;
717
+ key_info = ht.key_info;
681
718
  set_value(&emptyval, ht.emptyval);
682
- enlarge_resize_percent = ht.enlarge_resize_percent;
683
- shrink_resize_percent = ht.shrink_resize_percent;
684
- copy_from(ht, HT_MIN_BUCKETS); // sets num_deleted to 0 too
719
+ // copy_from() calls clear and sets num_deleted to 0 too
720
+ copy_from(ht, HT_MIN_BUCKETS);
721
+ // we purposefully don't copy the allocator, which may not be copyable
685
722
  return *this;
686
723
  }
687
724
 
688
725
  ~dense_hashtable() {
689
726
  if (table) {
690
727
  destroy_buckets(0, num_buckets);
691
- free(table);
728
+ allocator.deallocate(table, num_buckets);
692
729
  }
693
730
  }
694
731
 
695
732
  // Many STL algorithms use swap instead of copy constructors
696
733
  void swap(dense_hashtable& ht) {
697
- STL_NAMESPACE::swap(hash, ht.hash);
698
- STL_NAMESPACE::swap(equals, ht.equals);
699
- STL_NAMESPACE::swap(get_key, ht.get_key);
700
- STL_NAMESPACE::swap(set_key, ht.set_key);
734
+ STL_NAMESPACE::swap(settings, ht.settings);
735
+ STL_NAMESPACE::swap(key_info, ht.key_info);
701
736
  STL_NAMESPACE::swap(num_deleted, ht.num_deleted);
702
- STL_NAMESPACE::swap(use_deleted, ht.use_deleted);
703
- STL_NAMESPACE::swap(use_empty, ht.use_empty);
704
- STL_NAMESPACE::swap(enlarge_resize_percent, ht.enlarge_resize_percent);
705
- STL_NAMESPACE::swap(shrink_resize_percent, ht.shrink_resize_percent);
706
- STL_NAMESPACE::swap(delkey, ht.delkey);
737
+ STL_NAMESPACE::swap(num_elements, ht.num_elements);
738
+ STL_NAMESPACE::swap(num_buckets, ht.num_buckets);
707
739
  { value_type tmp; // for annoying reasons, swap() doesn't work
708
740
  set_value(&tmp, emptyval);
709
741
  set_value(&emptyval, ht.emptyval);
710
742
  set_value(&ht.emptyval, tmp);
711
743
  }
712
744
  STL_NAMESPACE::swap(table, ht.table);
713
- STL_NAMESPACE::swap(num_buckets, ht.num_buckets);
714
- STL_NAMESPACE::swap(num_elements, ht.num_elements);
715
- reset_thresholds();
716
- ht.reset_thresholds();
745
+ settings.reset_thresholds(bucket_count()); // this also resets consider_shrink
746
+ ht.settings.reset_thresholds(bucket_count());
747
+ // we purposefully don't swap the allocator, which may not be swap-able
717
748
  }
718
749
 
719
- // It's always nice to be able to clear a table without deallocating it
720
- void clear() {
721
- if (table)
750
+ private:
751
+ void clear_to_size(size_type new_num_buckets) {
752
+ if (!table) {
753
+ table = allocator.allocate(new_num_buckets);
754
+ } else {
722
755
  destroy_buckets(0, num_buckets);
723
- num_buckets = min_size(0,0); // our new size
724
- reset_thresholds();
725
- table = (value_type *) realloc(table, num_buckets * sizeof(*table));
756
+ 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>
760
+ realloc_ok;
761
+ resize_table(num_buckets, new_num_buckets, realloc_ok());
762
+ }
763
+ }
726
764
  assert(table);
727
- fill_range_with_empty(table, table + num_buckets);
765
+ fill_range_with_empty(table, table + new_num_buckets);
728
766
  num_elements = 0;
729
767
  num_deleted = 0;
768
+ num_buckets = new_num_buckets; // our new size
769
+ settings.reset_thresholds(bucket_count());
770
+ }
771
+
772
+ public:
773
+ // It's always nice to be able to clear a table without deallocating it
774
+ void clear() {
775
+ // If the table is already empty, and the number of buckets is
776
+ // already as we desire, there's nothing to do.
777
+ const size_type new_num_buckets = settings.min_buckets(0, 0);
778
+ if (num_elements == 0 && new_num_buckets == num_buckets) {
779
+ return;
780
+ }
781
+ clear_to_size(new_num_buckets);
730
782
  }
731
783
 
732
784
  // Clear the table without resizing it.
733
785
  // Mimicks the stl_hashtable's behaviour when clear()-ing in that it
734
786
  // does not modify the bucket count
735
787
  void clear_no_resize() {
736
- if (table) {
737
- set_empty(0, num_buckets);
788
+ if (num_elements > 0) {
789
+ assert(table);
790
+ destroy_buckets(0, num_buckets);
791
+ fill_range_with_empty(table, table + num_buckets);
738
792
  }
739
793
  // don't consider to shrink before another erase()
740
- reset_thresholds();
794
+ settings.reset_thresholds(bucket_count());
741
795
  num_elements = 0;
742
796
  num_deleted = 0;
743
797
  }
@@ -770,7 +824,8 @@ class dense_hashtable {
770
824
  }
771
825
  ++num_probes; // we're doing another probe
772
826
  bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one;
773
- assert(num_probes < bucket_count()); // don't probe too many times!
827
+ assert(num_probes < bucket_count()
828
+ && "Hashtable is full: an error in key_equal<> or hash<>");
774
829
  }
775
830
  }
776
831
 
@@ -829,36 +884,63 @@ class dense_hashtable {
829
884
 
830
885
  // INSERTION ROUTINES
831
886
  private:
887
+ // Private method used by insert_noresize and find_or_insert.
888
+ iterator insert_at(const_reference obj, size_type pos) {
889
+ if (size() >= max_size())
890
+ throw std::length_error("insert overflow");
891
+ if ( test_deleted(pos) ) { // just replace if it's been del.
892
+ // shrug: shouldn't need to be const.
893
+ const_iterator delpos(this, table + pos, table + num_buckets, false);
894
+ clear_deleted(delpos);
895
+ assert( num_deleted > 0);
896
+ --num_deleted; // used to be, now it isn't
897
+ } else {
898
+ ++num_elements; // replacing an empty bucket
899
+ }
900
+ set_value(&table[pos], obj);
901
+ return iterator(this, table + pos, table + num_buckets, false);
902
+ }
903
+
832
904
  // If you know *this is big enough to hold obj, use this routine
833
- pair<iterator, bool> insert_noresize(const value_type& obj) {
905
+ pair<iterator, bool> insert_noresize(const_reference obj) {
834
906
  // First, double-check we're not inserting delkey or emptyval
835
- assert(!use_empty || !equals(get_key(obj), get_key(emptyval)));
836
- assert(!use_deleted || !equals(get_key(obj), delkey));
907
+ assert((!settings.use_empty() || !equals(get_key(obj), get_key(emptyval)))
908
+ && "Inserting the empty key");
909
+ assert((!settings.use_deleted() || !equals(get_key(obj), key_info.delkey))
910
+ && "Inserting the deleted key");
837
911
  const pair<size_type,size_type> pos = find_position(get_key(obj));
838
912
  if ( pos.first != ILLEGAL_BUCKET) { // object was already there
839
913
  return pair<iterator,bool>(iterator(this, table + pos.first,
840
914
  table + num_buckets, false),
841
915
  false); // false: we didn't insert
842
916
  } else { // pos.second says where to put it
843
- if ( test_deleted(pos.second) ) { // just replace if it's been del.
844
- const_iterator delpos(this, table + pos.second, // shrug:
845
- table + num_buckets, false);// shouldn't need const
846
- clear_deleted(delpos);
847
- assert( num_deleted > 0);
848
- --num_deleted; // used to be, now it isn't
849
- } else {
850
- ++num_elements; // replacing an empty bucket
851
- }
852
- set_value(&table[pos.second], obj);
853
- return pair<iterator,bool>(iterator(this, table + pos.second,
854
- table + num_buckets, false),
855
- true); // true: we did insert
917
+ return pair<iterator,bool>(insert_at(obj, pos.second), true);
856
918
  }
857
919
  }
858
920
 
921
+ // Specializations of insert(it, it) depending on the power of the iterator:
922
+ // (1) Iterator supports operator-, resize before inserting
923
+ 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)())
927
+ throw std::length_error("insert-range overflow");
928
+ resize_delta(static_cast<size_type>(dist));
929
+ for ( ; dist > 0; --dist, ++f) {
930
+ insert_noresize(*f);
931
+ }
932
+ }
933
+
934
+ // (2) Arbitrary iterator, can't tell how much to resize
935
+ template <class InputIterator>
936
+ void insert(InputIterator f, InputIterator l, STL_NAMESPACE::input_iterator_tag) {
937
+ for ( ; f != l; ++f)
938
+ insert(*f);
939
+ }
940
+
859
941
  public:
860
942
  // This is the normal insert routine, used by the outside world
861
- pair<iterator, bool> insert(const value_type& obj) {
943
+ pair<iterator, bool> insert(const_reference obj) {
862
944
  resize_delta(1); // adding an object, grow if need be
863
945
  return insert_noresize(obj);
864
946
  }
@@ -870,59 +952,80 @@ class dense_hashtable {
870
952
  insert(f, l, typename STL_NAMESPACE::iterator_traits<InputIterator>::iterator_category());
871
953
  }
872
954
 
873
- // Iterator supports operator-, resize before inserting
874
- template <class ForwardIterator>
875
- void insert(ForwardIterator f, ForwardIterator l,
876
- STL_NAMESPACE::forward_iterator_tag) {
877
- size_type n = STL_NAMESPACE::distance(f, l); // TODO(csilvers): standard?
878
- resize_delta(n);
879
- for ( ; n > 0; --n, ++f)
880
- insert_noresize(*f);
881
- }
882
-
883
- // Arbitrary iterator, can't tell how much to resize
884
- template <class InputIterator>
885
- void insert(InputIterator f, InputIterator l,
886
- STL_NAMESPACE::input_iterator_tag) {
887
- for ( ; f != l; ++f)
888
- insert(*f);
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) {
959
+ // First, double-check we're not inserting emptykey or delkey
960
+ assert((!settings.use_empty() || !equals(key, get_key(emptyval)))
961
+ && "Inserting the empty key");
962
+ assert((!settings.use_deleted() || !equals(key, key_info.delkey))
963
+ && "Inserting the deleted key");
964
+ const pair<size_type,size_type> pos = find_position(key);
965
+ if ( pos.first != ILLEGAL_BUCKET) { // object was already there
966
+ return table[pos.first].second;
967
+ } else if (resize_delta(1)) { // needed to rehash to make room
968
+ // Since we resized, we can't use pos, so recalculate where to insert.
969
+ return insert_noresize(value_type(key, DataType())).first->second;
970
+ } else { // no need to rehash, insert right here
971
+ return insert_at(value_type(key, DataType()), pos.second)->second;
972
+ }
889
973
  }
890
974
 
891
-
892
975
  // DELETION ROUTINES
893
976
  size_type erase(const key_type& key) {
894
- // First, double-check we're not trying to erase delkey or emptyval
895
- assert(!use_empty || !equals(key, get_key(emptyval)));
896
- assert(!use_deleted || !equals(key, delkey));
977
+ // First, double-check we're not trying to erase delkey or emptyval.
978
+ assert((!settings.use_empty() || !equals(key, get_key(emptyval)))
979
+ && "Erasing the empty key");
980
+ assert((!settings.use_deleted() || !equals(key, key_info.delkey))
981
+ && "Erasing the deleted key");
897
982
  const_iterator pos = find(key); // shrug: shouldn't need to be const
898
983
  if ( pos != end() ) {
899
984
  assert(!test_deleted(pos)); // or find() shouldn't have returned it
900
985
  set_deleted(pos);
901
986
  ++num_deleted;
902
- consider_shrink = true; // will think about shrink after next insert
987
+ settings.set_consider_shrink(true); // will think about shrink after next insert
903
988
  return 1; // because we deleted one thing
904
989
  } else {
905
990
  return 0; // because we deleted nothing
906
991
  }
907
992
  }
908
993
 
909
- // This is really evil: really it should be iterator, not const_iterator.
910
- // But...the only reason keys are const is to allow lookup.
911
- // Since that's a moot issue for deleted keys, we allow const_iterators
912
- void erase(const_iterator pos) {
994
+ // We return the iterator past the deleted item.
995
+ void erase(iterator pos) {
913
996
  if ( pos == end() ) return; // sanity check
914
997
  if ( set_deleted(pos) ) { // true if object has been newly deleted
915
998
  ++num_deleted;
916
- consider_shrink = true; // will think about shrink after next insert
999
+ settings.set_consider_shrink(true); // will think about shrink after next insert
1000
+ }
1001
+ }
1002
+
1003
+ void erase(iterator f, iterator l) {
1004
+ for ( ; f != l; ++f) {
1005
+ if ( set_deleted(f) ) // should always be true
1006
+ ++num_deleted;
917
1007
  }
1008
+ settings.set_consider_shrink(true); // will think about shrink after next insert
918
1009
  }
919
1010
 
1011
+ // We allow you to erase a const_iterator just like we allow you to
1012
+ // erase an iterator. This is in parallel to 'delete': you can delete
1013
+ // a const pointer just like a non-const pointer. The logic is that
1014
+ // you can't use the object after it's erased anyway, so it doesn't matter
1015
+ // if it's const or not.
1016
+ void erase(const_iterator pos) {
1017
+ if ( pos == end() ) return; // sanity check
1018
+ if ( set_deleted(pos) ) { // true if object has been newly deleted
1019
+ ++num_deleted;
1020
+ settings.set_consider_shrink(true); // will think about shrink after next insert
1021
+ }
1022
+ }
920
1023
  void erase(const_iterator f, const_iterator l) {
921
1024
  for ( ; f != l; ++f) {
922
1025
  if ( set_deleted(f) ) // should always be true
923
1026
  ++num_deleted;
924
1027
  }
925
- consider_shrink = true; // will think about shrink after next insert
1028
+ settings.set_consider_shrink(true); // will think about shrink after next insert
926
1029
  }
927
1030
 
928
1031
 
@@ -962,12 +1065,12 @@ class dense_hashtable {
962
1065
 
963
1066
  bool read_metadata(FILE *fp) {
964
1067
  num_deleted = 0; // since we got rid before writing
965
- assert(use_empty); // have to set this before calling us
966
- if (table) free(table); // we'll make our own
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
967
1070
  // TODO: read magic number
968
1071
  // TODO: read num_buckets
969
- reset_thresholds();
970
- table = (value_type *) malloc(num_buckets * sizeof(*table));
1072
+ settings.reset_thresholds(bucket_count());
1073
+ table = allocator.allocate(num_buckets);
971
1074
  assert(table);
972
1075
  fill_range_with_empty(table, table + num_buckets);
973
1076
  // TODO: read num_elements
@@ -1001,35 +1104,114 @@ class dense_hashtable {
1001
1104
  }
1002
1105
 
1003
1106
  private:
1004
- // The actual data
1005
- hasher hash; // required by hashed_associative_container
1006
- key_equal equals;
1007
- ExtractKey get_key;
1008
- SetKey set_key;
1009
- size_type num_deleted; // how many occupied buckets are marked deleted
1010
- bool use_deleted; // false until delkey has been set
1011
- bool use_empty; // you must do this before you start
1012
- // TODO(csilvers): make a pointer, and get rid of use_deleted (benchmark!)
1013
- key_type delkey; // which key marks deleted entries
1014
- value_type emptyval; // which key marks unused entries
1015
- float enlarge_resize_percent; // how full before resize
1016
- float shrink_resize_percent; // how empty before resize
1017
- size_type shrink_threshold; // num_buckets * shrink_resize_percent
1018
- size_type enlarge_threshold; // num_buckets * enlarge_resize_percent
1019
- value_type *table;
1020
- size_type num_buckets;
1021
- size_type num_elements;
1022
- bool consider_shrink; // true if we should try to shrink before next insert
1107
+ template <class A>
1108
+ class alloc_impl : public A {
1109
+ public:
1110
+ typedef typename A::pointer pointer;
1111
+ typedef typename A::size_type size_type;
1112
+
1113
+ // Convert a normal allocator to one that has realloc_or_die()
1114
+ alloc_impl(const A& a) : A(a) { }
1115
+
1116
+ // realloc_or_die should only be used when using the default
1117
+ // allocator (libc_allocator_with_realloc).
1118
+ pointer realloc_or_die(pointer ptr, size_type n) {
1119
+ fprintf(stderr, "realloc_or_die is only supported for "
1120
+ "libc_allocator_with_realloc");
1121
+ exit(1);
1122
+ return NULL;
1123
+ }
1124
+ };
1125
+
1126
+ // A template specialization of alloc_impl for
1127
+ // libc_allocator_with_realloc that can handle realloc_or_die.
1128
+ template <class A>
1129
+ class alloc_impl<libc_allocator_with_realloc<A> >
1130
+ : public libc_allocator_with_realloc<A> {
1131
+ public:
1132
+ typedef typename libc_allocator_with_realloc<A>::pointer pointer;
1133
+ typedef typename libc_allocator_with_realloc<A>::size_type size_type;
1134
+
1135
+ alloc_impl(const libc_allocator_with_realloc<A>& a)
1136
+ : libc_allocator_with_realloc<A>(a) { }
1137
+
1138
+ pointer realloc_or_die(pointer ptr, size_type n) {
1139
+ pointer retval = this->reallocate(ptr, n);
1140
+ 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
+ fprintf(stderr, "sparsehash: FATAL ERROR: failed to reallocate "
1145
+ "%lu elements for ptr %p",
1146
+ static_cast<unsigned long>(n), ptr);
1147
+ exit(1);
1148
+ }
1149
+ return retval;
1150
+ }
1151
+ };
1152
+
1153
+ // Package functors with another class to eliminate memory needed for
1154
+ // zero-size functors. Since ExtractKey and hasher's operator() might
1155
+ // have the same function signature, they must be packaged in
1156
+ // different classes.
1157
+ struct Settings :
1158
+ sh_hashtable_settings<key_type, hasher, size_type, HT_MIN_BUCKETS> {
1159
+ explicit Settings(const hasher& hf)
1160
+ : sh_hashtable_settings<key_type, hasher, size_type, HT_MIN_BUCKETS>(
1161
+ hf, HT_OCCUPANCY_PCT / 100.0f, HT_EMPTY_PCT / 100.0f) {}
1162
+ };
1163
+
1164
+ // Packages ExtractKey and SetKey functors.
1165
+ class KeyInfo : public ExtractKey, public SetKey, public key_equal {
1166
+ public:
1167
+ KeyInfo(const ExtractKey& ek, const SetKey& sk, const key_equal& eq)
1168
+ : ExtractKey(ek),
1169
+ SetKey(sk),
1170
+ key_equal(eq) {
1171
+ }
1172
+ const key_type get_key(const_reference v) const {
1173
+ return ExtractKey::operator()(v);
1174
+ }
1175
+ void set_key(pointer v, const key_type& k) const {
1176
+ SetKey::operator()(v, k);
1177
+ }
1178
+ bool equals(const key_type& a, const key_type& b) const {
1179
+ return key_equal::operator()(a, b);
1180
+ }
1181
+
1182
+ // Which key marks deleted entries.
1183
+ // TODO(csilvers): make a pointer, and get rid of use_deleted (benchmark!)
1184
+ typename remove_const<key_type>::type delkey;
1185
+ };
1023
1186
 
1024
- void reset_thresholds() {
1025
- enlarge_threshold = static_cast<size_type>(num_buckets
1026
- * enlarge_resize_percent);
1027
- shrink_threshold = static_cast<size_type>(num_buckets
1028
- * shrink_resize_percent);
1029
- consider_shrink = false; // whatever caused us to reset already considered
1187
+ // Utility functions to access the templated operators
1188
+ size_type hash(const key_type& v) const {
1189
+ return settings.hash(v);
1190
+ }
1191
+ bool equals(const key_type& a, const key_type& b) const {
1192
+ return key_info.equals(a, b);
1193
+ }
1194
+ const key_type get_key(const_reference v) const {
1195
+ return key_info.get_key(v);
1030
1196
  }
1197
+ void set_key(pointer v, const key_type& k) const {
1198
+ key_info.set_key(v, k);
1199
+ }
1200
+
1201
+ private:
1202
+ // Actual data
1203
+ Settings settings;
1204
+ KeyInfo key_info;
1205
+ alloc_impl<value_alloc_type> allocator;
1206
+
1207
+ size_type num_deleted; // how many occupied buckets are marked deleted
1208
+ size_type num_elements;
1209
+ size_type num_buckets;
1210
+ value_type emptyval; // which key marks unused entries
1211
+ pointer table;
1031
1212
  };
1032
1213
 
1214
+
1033
1215
  // We need a global swap as well
1034
1216
  template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
1035
1217
  inline void swap(dense_hashtable<V,K,HF,ExK,SetK,EqK,A> &x,
@@ -1041,7 +1223,7 @@ inline void swap(dense_hashtable<V,K,HF,ExK,SetK,EqK,A> &x,
1041
1223
 
1042
1224
  template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
1043
1225
  const typename dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::size_type
1044
- dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::ILLEGAL_BUCKET;
1226
+ dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::ILLEGAL_BUCKET;
1045
1227
 
1046
1228
  // How full we let the table get before we resize. Knuth says .8 is
1047
1229
  // good -- higher causes us to probe too much, though saves memory.
@@ -1049,13 +1231,14 @@ dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::ILLEGAL_BUCKET;
1049
1231
  // more space (a trade-off densehashtable explicitly chooses to make).
1050
1232
  // Feel free to play around with different values, though.
1051
1233
  template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
1052
- const float dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_OCCUPANCY_FLT = 0.5f;
1234
+ const int dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_OCCUPANCY_PCT = 50;
1053
1235
 
1054
1236
  // How empty we let the table get before we resize lower.
1055
- // It should be less than OCCUPANCY_FLT / 2 or we thrash resizing
1237
+ // It should be less than OCCUPANCY_PCT / 2 or we thrash resizing
1056
1238
  template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
1057
- const float dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_EMPTY_FLT
1058
- = 0.4f * dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_OCCUPANCY_FLT;
1239
+ const int dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_EMPTY_PCT
1240
+ = static_cast<int>(0.4 *
1241
+ dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_OCCUPANCY_PCT);
1059
1242
 
1060
1243
  _END_GOOGLE_NAMESPACE_
1061
1244