google_hash 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/README +21 -0
  2. data/Rakefile +11 -0
  3. data/VERSION +1 -0
  4. data/ext/extconf.rb +15 -0
  5. data/ext/go.cpp +109 -0
  6. data/ext/sparsehash-1.5.2/AUTHORS +2 -0
  7. data/ext/sparsehash-1.5.2/COPYING +28 -0
  8. data/ext/sparsehash-1.5.2/ChangeLog +167 -0
  9. data/ext/sparsehash-1.5.2/INSTALL +236 -0
  10. data/ext/sparsehash-1.5.2/Makefile.am +157 -0
  11. data/ext/sparsehash-1.5.2/Makefile.in +1019 -0
  12. data/ext/sparsehash-1.5.2/NEWS +0 -0
  13. data/ext/sparsehash-1.5.2/README +149 -0
  14. data/ext/sparsehash-1.5.2/README.windows +25 -0
  15. data/ext/sparsehash-1.5.2/TODO +28 -0
  16. data/ext/sparsehash-1.5.2/aclocal.m4 +868 -0
  17. data/ext/sparsehash-1.5.2/compile +99 -0
  18. data/ext/sparsehash-1.5.2/config.guess +1516 -0
  19. data/ext/sparsehash-1.5.2/config.sub +1626 -0
  20. data/ext/sparsehash-1.5.2/configure +8054 -0
  21. data/ext/sparsehash-1.5.2/configure.ac +74 -0
  22. data/ext/sparsehash-1.5.2/depcomp +530 -0
  23. data/ext/sparsehash-1.5.2/doc/dense_hash_map.html +1591 -0
  24. data/ext/sparsehash-1.5.2/doc/dense_hash_set.html +1445 -0
  25. data/ext/sparsehash-1.5.2/doc/designstyle.css +115 -0
  26. data/ext/sparsehash-1.5.2/doc/implementation.html +365 -0
  27. data/ext/sparsehash-1.5.2/doc/index.html +69 -0
  28. data/ext/sparsehash-1.5.2/doc/performance.html +96 -0
  29. data/ext/sparsehash-1.5.2/doc/sparse_hash_map.html +1527 -0
  30. data/ext/sparsehash-1.5.2/doc/sparse_hash_set.html +1376 -0
  31. data/ext/sparsehash-1.5.2/doc/sparsetable.html +1393 -0
  32. data/ext/sparsehash-1.5.2/experimental/Makefile +9 -0
  33. data/ext/sparsehash-1.5.2/experimental/README +14 -0
  34. data/ext/sparsehash-1.5.2/experimental/example.c +54 -0
  35. data/ext/sparsehash-1.5.2/experimental/libchash.c +1537 -0
  36. data/ext/sparsehash-1.5.2/experimental/libchash.h +252 -0
  37. data/ext/sparsehash-1.5.2/google-sparsehash.sln +47 -0
  38. data/ext/sparsehash-1.5.2/install-sh +323 -0
  39. data/ext/sparsehash-1.5.2/m4/acx_pthread.m4 +363 -0
  40. data/ext/sparsehash-1.5.2/m4/google_namespace.m4 +42 -0
  41. data/ext/sparsehash-1.5.2/m4/namespaces.m4 +15 -0
  42. data/ext/sparsehash-1.5.2/m4/stl_hash.m4 +70 -0
  43. data/ext/sparsehash-1.5.2/m4/stl_hash_fun.m4 +36 -0
  44. data/ext/sparsehash-1.5.2/m4/stl_namespace.m4 +25 -0
  45. data/ext/sparsehash-1.5.2/missing +360 -0
  46. data/ext/sparsehash-1.5.2/mkinstalldirs +158 -0
  47. data/ext/sparsehash-1.5.2/packages/deb.sh +74 -0
  48. data/ext/sparsehash-1.5.2/packages/deb/README +7 -0
  49. data/ext/sparsehash-1.5.2/packages/deb/changelog +107 -0
  50. data/ext/sparsehash-1.5.2/packages/deb/compat +1 -0
  51. data/ext/sparsehash-1.5.2/packages/deb/control +17 -0
  52. data/ext/sparsehash-1.5.2/packages/deb/copyright +35 -0
  53. data/ext/sparsehash-1.5.2/packages/deb/docs +16 -0
  54. data/ext/sparsehash-1.5.2/packages/deb/rules +117 -0
  55. data/ext/sparsehash-1.5.2/packages/deb/sparsehash.dirs +2 -0
  56. data/ext/sparsehash-1.5.2/packages/deb/sparsehash.install +2 -0
  57. data/ext/sparsehash-1.5.2/packages/rpm.sh +86 -0
  58. data/ext/sparsehash-1.5.2/packages/rpm/rpm.spec +61 -0
  59. data/ext/sparsehash-1.5.2/src/config.h.in +131 -0
  60. data/ext/sparsehash-1.5.2/src/config.h.include +23 -0
  61. data/ext/sparsehash-1.5.2/src/google/dense_hash_map +310 -0
  62. data/ext/sparsehash-1.5.2/src/google/dense_hash_set +287 -0
  63. data/ext/sparsehash-1.5.2/src/google/sparse_hash_map +294 -0
  64. data/ext/sparsehash-1.5.2/src/google/sparse_hash_set +275 -0
  65. data/ext/sparsehash-1.5.2/src/google/sparsehash/densehashtable.h +1062 -0
  66. data/ext/sparsehash-1.5.2/src/google/sparsehash/sparsehashtable.h +1015 -0
  67. data/ext/sparsehash-1.5.2/src/google/sparsetable +1468 -0
  68. data/ext/sparsehash-1.5.2/src/google/type_traits.h +250 -0
  69. data/ext/sparsehash-1.5.2/src/hashtable_unittest.cc +1375 -0
  70. data/ext/sparsehash-1.5.2/src/simple_test.cc +103 -0
  71. data/ext/sparsehash-1.5.2/src/sparsetable_unittest.cc +696 -0
  72. data/ext/sparsehash-1.5.2/src/time_hash_map.cc +488 -0
  73. data/ext/sparsehash-1.5.2/src/type_traits_unittest.cc +492 -0
  74. data/ext/sparsehash-1.5.2/src/windows/config.h +149 -0
  75. data/ext/sparsehash-1.5.2/src/windows/google/sparsehash/sparseconfig.h +32 -0
  76. data/ext/sparsehash-1.5.2/src/windows/port.cc +63 -0
  77. data/ext/sparsehash-1.5.2/src/windows/port.h +81 -0
  78. data/ext/sparsehash-1.5.2/src/words +8944 -0
  79. data/ext/sparsehash-1.5.2/vsprojects/hashtable_unittest/hashtable_unittest.vcproj +187 -0
  80. data/ext/sparsehash-1.5.2/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +172 -0
  81. data/ext/sparsehash-1.5.2/vsprojects/time_hash_map/time_hash_map.vcproj +187 -0
  82. data/ext/sparsehash-1.5.2/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +169 -0
  83. data/ext/test.rb +10 -0
  84. data/test/spec.go +70 -0
  85. metadata +147 -0
@@ -0,0 +1,275 @@
1
+ // Copyright (c) 2005, Google Inc.
2
+ // All rights reserved.
3
+ //
4
+ // Redistribution and use in source and binary forms, with or without
5
+ // modification, are permitted provided that the following conditions are
6
+ // met:
7
+ //
8
+ // * Redistributions of source code must retain the above copyright
9
+ // notice, this list of conditions and the following disclaimer.
10
+ // * Redistributions in binary form must reproduce the above
11
+ // copyright notice, this list of conditions and the following disclaimer
12
+ // in the documentation and/or other materials provided with the
13
+ // distribution.
14
+ // * Neither the name of Google Inc. nor the names of its
15
+ // contributors may be used to endorse or promote products derived from
16
+ // this software without specific prior written permission.
17
+ //
18
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ // ---
31
+ // Author: Craig Silverstein
32
+ //
33
+ // This is just a very thin wrapper over sparsehashtable.h, just
34
+ // like sgi stl's stl_hash_set is a very thin wrapper over
35
+ // stl_hashtable. The major thing we define is operator[], because
36
+ // we have a concept of a data_type which stl_hashtable doesn't
37
+ // (it only has a key and a value).
38
+ //
39
+ // This is more different from sparse_hash_map than you might think,
40
+ // because all iterators for sets are const (you obviously can't
41
+ // change the key, and for sets there is no value).
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.
47
+ //
48
+ // Here are a few "power user" tips:
49
+ //
50
+ // 1) set_deleted_key():
51
+ // Unlike STL's hash_map, if you want to use erase() you
52
+ // *must* call set_deleted_key() after construction.
53
+ //
54
+ // 2) resize(0):
55
+ // When an item is deleted, its memory isn't freed right
56
+ // away. This allows you to iterate over a hashtable,
57
+ // and call erase(), without invalidating the iterator.
58
+ // To force the memory to be freed, call resize(0).
59
+ // For tr1 compatibility, this can also be called as rehash(0).
60
+ //
61
+ // 3) min_load_factor(0.0)
62
+ // Setting the minimum load factor to 0.0 guarantees that
63
+ // the hash table will never shrink.
64
+ //
65
+ // Guide to what kind of hash_set to use:
66
+ // (1) dense_hash_set: fastest, uses the most memory
67
+ // (2) sparse_hash_set: slowest, uses the least memory
68
+ // (3) hash_set /unordered_set (STL): in the middle
69
+ // Typically I use sparse_hash_set when I care about space and/or when
70
+ // I need to save the hashtable on disk. I use hash_set otherwise. I
71
+ // don't personally use dense_hash_set ever; some people use it for
72
+ // small sets with lots of lookups.
73
+ //
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,
78
+ // especially, inserts. See time_hash_map.cc for details.
79
+ //
80
+ // See /usr/(local/)?doc/sparsehash-*/sparse_hash_set.html
81
+ // for information about how to use this class.
82
+
83
+ #ifndef _SPARSE_HASH_SET_H_
84
+ #define _SPARSE_HASH_SET_H_
85
+
86
+ #include <google/sparsehash/sparseconfig.h>
87
+ #include <stdio.h> // for FILE * in read()/write()
88
+ #include <algorithm> // for the default template args
89
+ #include <functional> // for equal_to
90
+ #include <memory> // for alloc<>
91
+ #include <utility> // for pair<>
92
+ #include HASH_FUN_H // defined in config.h
93
+ #include <google/sparsehash/sparsehashtable.h>
94
+
95
+ _START_GOOGLE_NAMESPACE_
96
+
97
+ using STL_NAMESPACE::pair;
98
+
99
+ template <class Value,
100
+ class HashFcn = SPARSEHASH_HASH<Value>, // defined in sparseconfig.h
101
+ class EqualKey = STL_NAMESPACE::equal_to<Value>,
102
+ class Alloc = STL_NAMESPACE::allocator<Value> >
103
+ class sparse_hash_set {
104
+ private:
105
+ // Apparently identity is not stl-standard, so we define our own
106
+ struct Identity {
107
+ Value& operator()(Value& v) const { return v; }
108
+ const Value& operator()(const Value& v) const { return v; }
109
+ };
110
+ struct SetKey {
111
+ void operator()(Value* value, const Value& new_key) const {
112
+ *value = new_key;
113
+ }
114
+ };
115
+
116
+ // The actual data
117
+ typedef sparse_hashtable<Value, Value, HashFcn,
118
+ Identity, SetKey, EqualKey, Alloc> ht;
119
+ ht rep;
120
+
121
+ public:
122
+ typedef typename ht::key_type key_type;
123
+ typedef typename ht::value_type value_type;
124
+ typedef typename ht::hasher hasher;
125
+ typedef typename ht::key_equal key_equal;
126
+ typedef Alloc allocator_type;
127
+
128
+ typedef typename ht::size_type size_type;
129
+ typedef typename ht::difference_type difference_type;
130
+ typedef typename ht::const_pointer pointer;
131
+ typedef typename ht::const_pointer const_pointer;
132
+ typedef typename ht::const_reference reference;
133
+ typedef typename ht::const_reference const_reference;
134
+
135
+ typedef typename ht::const_iterator iterator;
136
+ typedef typename ht::const_iterator const_iterator;
137
+ typedef typename ht::const_local_iterator local_iterator;
138
+ typedef typename ht::const_local_iterator const_local_iterator;
139
+
140
+
141
+ // Iterator functions -- recall all iterators are const
142
+ iterator begin() const { return rep.begin(); }
143
+ iterator end() const { return rep.end(); }
144
+
145
+ // These come from tr1's unordered_set. For us, a bucket has 0 or 1 elements.
146
+ local_iterator begin(size_type i) const { return rep.begin(i); }
147
+ local_iterator end(size_type i) const { return rep.end(i); }
148
+
149
+
150
+ // Accessor functions
151
+ // TODO(csilvers): implement Alloc get_allocator() const;
152
+ hasher hash_funct() const { return rep.hash_funct(); }
153
+ hasher hash_function() const { return hash_funct(); } // tr1 name
154
+ key_equal key_eq() const { return rep.key_eq(); }
155
+
156
+
157
+ // Constructors
158
+ explicit sparse_hash_set(size_type expected_max_items_in_table = 0,
159
+ const hasher& hf = hasher(),
160
+ const key_equal& eql = key_equal())
161
+ : rep(expected_max_items_in_table, hf, eql) { }
162
+
163
+ template <class InputIterator>
164
+ sparse_hash_set(InputIterator f, InputIterator l,
165
+ size_type expected_max_items_in_table = 0,
166
+ const hasher& hf = hasher(),
167
+ const key_equal& eql = key_equal())
168
+ : rep(expected_max_items_in_table, hf, eql) {
169
+ rep.insert(f, l);
170
+ }
171
+ // We use the default copy constructor
172
+ // We use the default operator=()
173
+ // We use the default destructor
174
+
175
+ void clear() { rep.clear(); }
176
+ void swap(sparse_hash_set& hs) { rep.swap(hs.rep); }
177
+
178
+
179
+ // Functions concerning size
180
+ size_type size() const { return rep.size(); }
181
+ size_type max_size() const { return rep.max_size(); }
182
+ bool empty() const { return rep.empty(); }
183
+ size_type bucket_count() const { return rep.bucket_count(); }
184
+ size_type max_bucket_count() const { return rep.max_bucket_count(); }
185
+
186
+ // These are tr1 methods. bucket() is the bucket the key is or would be in.
187
+ size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
188
+ size_type bucket(const key_type& key) const { return rep.bucket(key); }
189
+ float load_factor() const {
190
+ return size() * 1.0f / bucket_count();
191
+ }
192
+ float max_load_factor() const {
193
+ float shrink, grow;
194
+ rep.get_resizing_parameters(&shrink, &grow);
195
+ return grow;
196
+ }
197
+ void max_load_factor(float new_grow) {
198
+ float shrink, grow;
199
+ rep.get_resizing_parameters(&shrink, &grow);
200
+ rep.set_resizing_parameters(shrink, new_grow);
201
+ }
202
+ // These aren't tr1 methods but perhaps ought to be.
203
+ float min_load_factor() const {
204
+ float shrink, grow;
205
+ rep.get_resizing_parameters(&shrink, &grow);
206
+ return shrink;
207
+ }
208
+ void min_load_factor(float new_shrink) {
209
+ float shrink, grow;
210
+ rep.get_resizing_parameters(&shrink, &grow);
211
+ rep.set_resizing_parameters(new_shrink, grow);
212
+ }
213
+ // Deprecated; use min_load_factor() or max_load_factor() instead.
214
+ void set_resizing_parameters(float shrink, float grow) {
215
+ return rep.set_resizing_parameters(shrink, grow);
216
+ }
217
+
218
+ void resize(size_type hint) { rep.resize(hint); }
219
+ void rehash(size_type hint) { resize(hint); } // the tr1 name
220
+
221
+ // Lookup routines
222
+ iterator find(const key_type& key) const { return rep.find(key); }
223
+
224
+ size_type count(const key_type& key) const { return rep.count(key); }
225
+
226
+ pair<iterator, iterator> equal_range(const key_type& key) const {
227
+ return rep.equal_range(key);
228
+ }
229
+
230
+ // Insertion routines
231
+ pair<iterator, bool> insert(const value_type& obj) {
232
+ pair<typename ht::iterator, bool> p = rep.insert(obj);
233
+ return pair<iterator, bool>(p.first, p.second); // const to non-const
234
+ }
235
+ template <class InputIterator>
236
+ void insert(InputIterator f, InputIterator l) { rep.insert(f, l); }
237
+ void insert(const_iterator f, const_iterator l) { rep.insert(f, l); }
238
+ // required for std::insert_iterator; the passed-in iterator is ignored
239
+ iterator insert(iterator, const value_type& obj) { return insert(obj).first; }
240
+
241
+
242
+ // Deletion routines
243
+ // THESE ARE NON-STANDARD! I make you specify an "impossible" key
244
+ // value to identify deleted buckets. You can change the key as
245
+ // time goes on, or get rid of it entirely to be insert-only.
246
+ void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
247
+ void clear_deleted_key() { rep.clear_deleted_key(); }
248
+
249
+ // These are standard
250
+ size_type erase(const key_type& key) { return rep.erase(key); }
251
+ void erase(iterator it) { rep.erase(it); }
252
+ void erase(iterator f, iterator l) { rep.erase(f, l); }
253
+
254
+
255
+ // Comparison
256
+ bool operator==(const sparse_hash_set& hs) const { return rep == hs.rep; }
257
+ bool operator!=(const sparse_hash_set& hs) const { return rep != hs.rep; }
258
+
259
+
260
+ // I/O -- this is an add-on for writing metainformation to disk
261
+ bool write_metadata(FILE *fp) { return rep.write_metadata(fp); }
262
+ bool read_metadata(FILE *fp) { return rep.read_metadata(fp); }
263
+ bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
264
+ bool read_nopointer_data(FILE *fp) { return rep.read_nopointer_data(fp); }
265
+ };
266
+
267
+ template <class Val, class HashFcn, class EqualKey, class Alloc>
268
+ inline void swap(sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
269
+ sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
270
+ hs1.swap(hs2);
271
+ }
272
+
273
+ _END_GOOGLE_NAMESPACE_
274
+
275
+ #endif /* _SPARSE_HASH_SET_H_ */
@@ -0,0 +1,1062 @@
1
+ // Copyright (c) 2005, Google Inc.
2
+ // All rights reserved.
3
+ //
4
+ // Redistribution and use in source and binary forms, with or without
5
+ // modification, are permitted provided that the following conditions are
6
+ // met:
7
+ //
8
+ // * Redistributions of source code must retain the above copyright
9
+ // notice, this list of conditions and the following disclaimer.
10
+ // * Redistributions in binary form must reproduce the above
11
+ // copyright notice, this list of conditions and the following disclaimer
12
+ // in the documentation and/or other materials provided with the
13
+ // distribution.
14
+ // * Neither the name of Google Inc. nor the names of its
15
+ // contributors may be used to endorse or promote products derived from
16
+ // this software without specific prior written permission.
17
+ //
18
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ // ---
31
+ // Author: Craig Silverstein
32
+ //
33
+ // A dense hashtable is a particular implementation of
34
+ // a hashtable: one that is meant to minimize memory allocation.
35
+ // It does this by using an array to store all the data. We
36
+ // steal a value from the key space to indicate "empty" array
37
+ // elements (ie indices where no item lives) and another to indicate
38
+ // "deleted" elements.
39
+ //
40
+ // (Note it is possible to change the value of the delete key
41
+ // on the fly; you can even remove it, though after that point
42
+ // the hashtable is insert_only until you set it again. The empty
43
+ // value however can't be changed.)
44
+ //
45
+ // To minimize allocation and pointer overhead, we use internal
46
+ // probing, in which the hashtable is a single table, and collisions
47
+ // are resolved by trying to insert again in another bucket. The
48
+ // most cache-efficient internal probing schemes are linear probing
49
+ // (which suffers, alas, from clumping) and quadratic probing, which
50
+ // is what we implement by default.
51
+ //
52
+ // Type requirements: value_type is required to be Copy Constructible
53
+ // and Default Constructible. It is not required to be (and commonly
54
+ // isn't) Assignable.
55
+ //
56
+ // You probably shouldn't use this code directly. Use
57
+ // <google/dense_hash_map> or <google/dense_hash_set> instead.
58
+
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
62
+ // HT_MIN_BUCKETS -- default smallest bucket size
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().
67
+ //
68
+ // How to decide what values to use?
69
+ // shrink_resize_percent's default of .4 * OCCUPANCY_FLT, is probably good.
70
+ // HT_MIN_BUCKETS is probably unnecessary since you can specify
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
73
+ // expected lookup time to the space taken up. By default, this
74
+ // code uses quadratic probing, though you can change it to linear
75
+ // via _JUMP below if you really want to.
76
+ //
77
+ // From http://www.augustana.ca/~mohrj/courses/1999.fall/csc210/lecture_notes/hashing.html
78
+ // NUMBER OF PROBES / LOOKUP Successful Unsuccessful
79
+ // Quadratic collision resolution 1 - ln(1-L) - L/2 1/(1-L) - L - ln(1-L)
80
+ // Linear collision resolution [1+1/(1-L)]/2 [1+1/(1-L)2]/2
81
+ //
82
+ // -- enlarge_resize_percent -- 0.10 0.50 0.60 0.75 0.80 0.90 0.99
83
+ // QUADRATIC COLLISION RES.
84
+ // probes/successful lookup 1.05 1.44 1.62 2.01 2.21 2.85 5.11
85
+ // probes/unsuccessful lookup 1.11 2.19 2.82 4.64 5.81 11.4 103.6
86
+ // LINEAR COLLISION RES.
87
+ // probes/successful lookup 1.06 1.5 1.75 2.5 3.0 5.5 50.5
88
+ // probes/unsuccessful lookup 1.12 2.5 3.6 8.5 13.0 50.0 5000.0
89
+
90
+ #ifndef _DENSEHASHTABLE_H_
91
+ #define _DENSEHASHTABLE_H_
92
+
93
+ // The probing method
94
+ // Linear probing
95
+ // #define JUMP_(key, num_probes) ( 1 )
96
+ // Quadratic-ish probing
97
+ #define JUMP_(key, num_probes) ( num_probes )
98
+
99
+
100
+ #include <google/sparsehash/sparseconfig.h>
101
+ #include <assert.h>
102
+ #include <stdio.h>
103
+ #include <stdlib.h> // for abort()
104
+ #include <algorithm> // For swap(), eg
105
+ #include <iostream> // For cerr
106
+ #include <memory> // For uninitialized_fill, uninitialized_copy
107
+ #include <utility> // for pair<>
108
+ #include <iterator> // for facts about iterator tags
109
+ #include <google/type_traits.h> // for true_type, integral_constant, etc.
110
+
111
+ _START_GOOGLE_NAMESPACE_
112
+
113
+ using STL_NAMESPACE::pair;
114
+
115
+ // Hashtable class, used to implement the hashed associative containers
116
+ // hash_set and hash_map.
117
+
118
+ // Value: what is stored in the table (each bucket is a Value).
119
+ // Key: something in a 1-to-1 correspondence to a Value, that can be used
120
+ // to search for a Value in the table (find() takes a Key).
121
+ // HashFcn: Takes a Key and returns an integer, the more unique the better.
122
+ // ExtractKey: given a Value, returns the unique Key associated with it.
123
+ // SetKey: given a Value* and a Key, modifies the value such that
124
+ // ExtractKey(value) == key. We guarantee this is only called
125
+ // with key == deleted_key or key == empty_key.
126
+ // EqualKey: Given two Keys, says whether they are the same (that is,
127
+ // if they are both associated with the same Value).
128
+ // Alloc: STL allocator to use to allocate memory. Currently ignored.
129
+
130
+ template <class Value, class Key, class HashFcn,
131
+ class ExtractKey, class SetKey, class EqualKey, class Alloc>
132
+ class dense_hashtable;
133
+
134
+ template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
135
+ struct dense_hashtable_iterator;
136
+
137
+ template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
138
+ struct dense_hashtable_const_iterator;
139
+
140
+ // We're just an array, but we need to skip over empty and deleted elements
141
+ template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
142
+ struct dense_hashtable_iterator {
143
+ public:
144
+ typedef dense_hashtable_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
145
+ typedef dense_hashtable_const_iterator<V,K,HF,ExK,SetK,EqK,A> const_iterator;
146
+
147
+ typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
148
+ 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;
153
+
154
+ // "Real" constructor and default constructor
155
+ dense_hashtable_iterator(const dense_hashtable<V,K,HF,ExK,SetK,EqK,A> *h,
156
+ pointer it, pointer it_end, bool advance)
157
+ : ht(h), pos(it), end(it_end) {
158
+ if (advance) advance_past_empty_and_deleted();
159
+ }
160
+ dense_hashtable_iterator() { }
161
+ // The default destructor is fine; we don't define one
162
+ // The default operator= is fine; we don't define one
163
+
164
+ // Happy dereferencer
165
+ reference operator*() const { return *pos; }
166
+ pointer operator->() const { return &(operator*()); }
167
+
168
+ // Arithmetic. The only hard part is making sure that
169
+ // we're not on an empty or marked-deleted array element
170
+ void advance_past_empty_and_deleted() {
171
+ while ( pos != end && (ht->test_empty(*this) || ht->test_deleted(*this)) )
172
+ ++pos;
173
+ }
174
+ iterator& operator++() {
175
+ assert(pos != end); ++pos; advance_past_empty_and_deleted(); return *this;
176
+ }
177
+ iterator operator++(int) { iterator tmp(*this); ++*this; return tmp; }
178
+
179
+ // Comparison.
180
+ bool operator==(const iterator& it) const { return pos == it.pos; }
181
+ bool operator!=(const iterator& it) const { return pos != it.pos; }
182
+
183
+
184
+ // The actual data
185
+ const dense_hashtable<V,K,HF,ExK,SetK,EqK,A> *ht;
186
+ pointer pos, end;
187
+ };
188
+
189
+
190
+ // Now do it all again, but with const-ness!
191
+ template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
192
+ struct dense_hashtable_const_iterator {
193
+ public:
194
+ typedef dense_hashtable_iterator<V,K,HF,ExK,SetK,EqK,A> iterator;
195
+ typedef dense_hashtable_const_iterator<V,K,HF,ExK,SetK,EqK,A> const_iterator;
196
+
197
+ typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
198
+ 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;
203
+
204
+ // "Real" constructor and default constructor
205
+ dense_hashtable_const_iterator(
206
+ const dense_hashtable<V,K,HF,ExK,SetK,EqK,A> *h,
207
+ pointer it, pointer it_end, bool advance)
208
+ : ht(h), pos(it), end(it_end) {
209
+ if (advance) advance_past_empty_and_deleted();
210
+ }
211
+ dense_hashtable_const_iterator() { }
212
+ // This lets us convert regular iterators to const iterators
213
+ dense_hashtable_const_iterator(const iterator &it)
214
+ : ht(it.ht), pos(it.pos), end(it.end) { }
215
+ // The default destructor is fine; we don't define one
216
+ // The default operator= is fine; we don't define one
217
+
218
+ // Happy dereferencer
219
+ reference operator*() const { return *pos; }
220
+ pointer operator->() const { return &(operator*()); }
221
+
222
+ // Arithmetic. The only hard part is making sure that
223
+ // we're not on an empty or marked-deleted array element
224
+ void advance_past_empty_and_deleted() {
225
+ while ( pos != end && (ht->test_empty(*this) || ht->test_deleted(*this)) )
226
+ ++pos;
227
+ }
228
+ const_iterator& operator++() {
229
+ assert(pos != end); ++pos; advance_past_empty_and_deleted(); return *this;
230
+ }
231
+ const_iterator operator++(int) { const_iterator tmp(*this); ++*this; return tmp; }
232
+
233
+ // Comparison.
234
+ bool operator==(const const_iterator& it) const { return pos == it.pos; }
235
+ bool operator!=(const const_iterator& it) const { return pos != it.pos; }
236
+
237
+
238
+ // The actual data
239
+ const dense_hashtable<V,K,HF,ExK,SetK,EqK,A> *ht;
240
+ pointer pos, end;
241
+ };
242
+
243
+ template <class Value, class Key, class HashFcn,
244
+ class ExtractKey, class SetKey, class EqualKey, class Alloc>
245
+ class dense_hashtable {
246
+ public:
247
+ typedef Key key_type;
248
+ typedef Value value_type;
249
+ typedef HashFcn hasher;
250
+ 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;
258
+ typedef dense_hashtable_iterator<Value, Key, HashFcn,
259
+ ExtractKey, SetKey, EqualKey, Alloc>
260
+ iterator;
261
+
262
+ typedef dense_hashtable_const_iterator<Value, Key, HashFcn,
263
+ ExtractKey, SetKey, EqualKey, Alloc>
264
+ const_iterator;
265
+
266
+ // These come from tr1. For us they're the same as regular iterators.
267
+ typedef iterator local_iterator;
268
+ typedef const_iterator const_local_iterator;
269
+
270
+ // How full we let the table get before we resize, by default.
271
+ // Knuth says .8 is good -- higher causes us to probe too much,
272
+ // though it saves memory.
273
+ static const float HT_OCCUPANCY_FLT; // = 0.5;
274
+
275
+ // How empty we let the table get before we resize lower, by default.
276
+ // (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
279
+
280
+ // Minimum size we're willing to let hashtables be.
281
+ // Must be a power of two, and at least 4.
282
+ // Note, however, that for a given hashtable, the initial size is a
283
+ // function of the first constructor arg, and may be >HT_MIN_BUCKETS.
284
+ static const size_t HT_MIN_BUCKETS = 4;
285
+
286
+ // By default, if you don't specify a hashtable size at
287
+ // construction-time, we use this size. Must be a power of two, and
288
+ // at least HT_MIN_BUCKETS.
289
+ static const size_t HT_DEFAULT_STARTING_BUCKETS = 32;
290
+
291
+
292
+ // ITERATOR FUNCTIONS
293
+ iterator begin() { return iterator(this, table,
294
+ table + num_buckets, true); }
295
+ iterator end() { return iterator(this, table + num_buckets,
296
+ table + num_buckets, true); }
297
+ const_iterator begin() const { return const_iterator(this, table,
298
+ table+num_buckets,true);}
299
+ const_iterator end() const { return const_iterator(this, table + num_buckets,
300
+ table+num_buckets,true);}
301
+
302
+ // 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.
307
+ local_iterator begin(size_type i) {
308
+ return local_iterator(this, table + i, table + i+1, false);
309
+ }
310
+ local_iterator end(size_type i) {
311
+ local_iterator it = begin(i);
312
+ if (!test_empty(i) && !test_deleted(i))
313
+ ++it;
314
+ return it;
315
+ }
316
+ const_local_iterator begin(size_type i) const {
317
+ return const_local_iterator(this, table + i, table + i+1, false);
318
+ }
319
+ const_local_iterator end(size_type i) const {
320
+ const_local_iterator it = begin(i);
321
+ if (!test_empty(i) && !test_deleted(i))
322
+ ++it;
323
+ return it;
324
+ }
325
+
326
+ // ACCESSOR FUNCTIONS for the things we templatize on, basically
327
+ hasher hash_funct() const { return hash; }
328
+ key_equal key_eq() const { return equals; }
329
+
330
+ private:
331
+ // Annoyingly, we can't copy values around, because they might have
332
+ // const components (they're probably pair<const X, Y>). We use
333
+ // explicit destructor invocation and placement new to get around
334
+ // this. Arg.
335
+ void set_value(value_type* dst, const value_type& src) {
336
+ dst->~value_type();
337
+ new(dst) value_type(src);
338
+ }
339
+
340
+ void destroy_buckets(size_type first, size_type last) {
341
+ for ( ; first != last; ++first)
342
+ table[first].~value_type();
343
+ }
344
+
345
+ // DELETE HELPER FUNCTIONS
346
+ // This lets the user describe a key that will indicate deleted
347
+ // table entries. This key should be an "impossible" entry --
348
+ // if you try to insert it for real, you won't be able to retrieve it!
349
+ // (NB: while you pass in an entire value, only the key part is looked
350
+ // at. This is just because I don't know how to assign just a key.)
351
+ private:
352
+ void squash_deleted() { // gets rid of any deleted entries we have
353
+ if ( num_deleted ) { // get rid of deleted before writing
354
+ dense_hashtable tmp(*this); // copying will get rid of deleted
355
+ swap(tmp); // now we are tmp
356
+ }
357
+ assert(num_deleted == 0);
358
+ }
359
+
360
+ public:
361
+ void set_deleted_key(const key_type &key) {
362
+ // the empty indicator (if specified) and the deleted indicator
363
+ // must be different
364
+ assert(!use_empty || !equals(key, get_key(emptyval)));
365
+ // It's only safe to change what "deleted" means if we purge deleted guys
366
+ squash_deleted();
367
+ use_deleted = true;
368
+ delkey = key;
369
+ }
370
+ void clear_deleted_key() {
371
+ squash_deleted();
372
+ use_deleted = false;
373
+ }
374
+
375
+ // These are public so the iterators can use them
376
+ // True if the item at position bucknum is "deleted" marker
377
+ 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])));
382
+ }
383
+ bool test_deleted(const iterator &it) const {
384
+ return (use_deleted && num_deleted > 0 &&
385
+ equals(delkey, get_key(*it)));
386
+ }
387
+ bool test_deleted(const const_iterator &it) const {
388
+ return (use_deleted && num_deleted > 0 &&
389
+ equals(delkey, get_key(*it)));
390
+ }
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
393
+ bool set_deleted(const_iterator &it) {
394
+ assert(use_deleted); // bad if set_deleted_key() wasn't called
395
+ bool retval = !test_deleted(it);
396
+ // &* converts from iterator to value-type
397
+ set_key(const_cast<value_type*>(&(*it)), delkey);
398
+ return retval;
399
+ }
400
+ // Set it so test_deleted is false. true if object used to be deleted
401
+ 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
404
+ return test_deleted(it);
405
+ }
406
+
407
+ // EMPTY HELPER FUNCTIONS
408
+ // This lets the user describe a key that will indicate empty (unused)
409
+ // table entries. This key should be an "impossible" entry --
410
+ // if you try to insert it for real, you won't be able to retrieve it!
411
+ // (NB: while you pass in an entire value, only the key part is looked
412
+ // at. This is just because I don't know how to assign just a key.)
413
+ public:
414
+ // These are public so the iterators can use them
415
+ // True if the item at position bucknum is "empty" marker
416
+ bool test_empty(size_type bucknum) const {
417
+ assert(use_empty); // we always need to know what's empty!
418
+ return equals(get_key(emptyval), get_key(table[bucknum]));
419
+ }
420
+ bool test_empty(const iterator &it) const {
421
+ assert(use_empty); // we always need to know what's empty!
422
+ return equals(get_key(emptyval), get_key(*it));
423
+ }
424
+ bool test_empty(const const_iterator &it) const {
425
+ assert(use_empty); // we always need to know what's empty!
426
+ return equals(get_key(emptyval), get_key(*it));
427
+ }
428
+
429
+ 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
437
+ STL_NAMESPACE::uninitialized_fill(table_start, table_end, emptyval);
438
+ }
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
+
445
+ public:
446
+ // TODO(csilvers): change all callers of this to pass in a key instead,
447
+ // and take a const key_type instead of const value_type.
448
+ void set_empty_key(const value_type &val) {
449
+ // Once you set the empty key, you can't change it
450
+ assert(!use_empty);
451
+ // The deleted indicator (if specified) and the empty indicator
452
+ // must be different.
453
+ assert(!use_deleted || !equals(get_key(val), delkey));
454
+ use_empty = true;
455
+ set_value(&emptyval, val);
456
+
457
+ assert(!table); // must set before first use
458
+ // num_buckets was set in constructor even though table was NULL
459
+ table = (value_type *) malloc(num_buckets * sizeof(*table));
460
+ assert(table);
461
+ fill_range_with_empty(table, table + num_buckets);
462
+ }
463
+
464
+ // FUNCTIONS CONCERNING SIZE
465
+ public:
466
+ 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; }
469
+ bool empty() const { return size() == 0; }
470
+ size_type bucket_count() const { return num_buckets; }
471
+ size_type max_bucket_count() const { return max_size(); }
472
+ size_type nonempty_bucket_count() const { return num_elements; }
473
+ // These are tr1 methods. Their idea of 'bucket' doesn't map well to
474
+ // what we do. We just say every bucket has 0 or 1 items in it.
475
+ size_type bucket_size(size_type i) const {
476
+ return begin(i) == end(i) ? 0 : 1;
477
+ }
478
+
479
+
480
+
481
+ private:
482
+ // Because of the above, size_type(-1) is never legal; use it for errors
483
+ static const size_type ILLEGAL_BUCKET = size_type(-1);
484
+
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() {
497
+ assert(num_elements >= num_deleted);
498
+ assert((bucket_count() & (bucket_count()-1)) == 0); // is a power of two
499
+ assert(bucket_count() >= HT_MIN_BUCKETS);
500
+
501
+ // If you construct a hashtable with < HT_DEFAULT_STARTING_BUCKETS,
502
+ // we'll never shrink until you get relatively big, and we'll never
503
+ // shrink below HT_DEFAULT_STARTING_BUCKETS. Otherwise, something
504
+ // like "dense_hash_set<int> x; x.insert(4); x.erase(4);" will
505
+ // 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 ) {
509
+ 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 )
512
+ sz /= 2; // stay a power of 2
513
+ dense_hashtable tmp(*this, sz); // Do the actual resizing
514
+ swap(tmp); // now we are tmp
515
+ }
516
+ consider_shrink = false; // because we just considered it
517
+ }
518
+
519
+ // We'll let you resize a hashtable -- though this makes us copy all!
520
+ // 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
527
+
528
+ // Sometimes, we need to resize just to get rid of all the
529
+ // "deleted" buckets that are clogging up the hashtable. So when
530
+ // deciding whether to resize, count the deleted buckets (which
531
+ // are currently taking up room). But later, when we decide what
532
+ // size to resize to, *don't* count deleted buckets, since they
533
+ // 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
540
+ }
541
+ }
542
+
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);
553
+ }
554
+
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;
567
+ }
568
+
569
+ // Used to actually do the rehashing when we grow/shrink a hashtable
570
+ 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
+ }
584
+
585
+ // We use a normal iterator to get non-deleted bcks from ht
586
+ // We could use insert() here, but since we know there are
587
+ // no duplicates and no deleted items, we can be more efficient
588
+ assert((bucket_count() & (bucket_count()-1)) == 0); // a power of two
589
+ for ( const_iterator it = ht.begin(); it != ht.end(); ++it ) {
590
+ size_type num_probes = 0; // how many times we've probed
591
+ size_type bucknum;
592
+ const size_type bucket_count_minus_one = bucket_count() - 1;
593
+ for (bucknum = hash(get_key(*it)) & bucket_count_minus_one;
594
+ !test_empty(bucknum); // not empty
595
+ bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one) {
596
+ ++num_probes;
597
+ assert(num_probes < bucket_count()); // or else the hashtable is full
598
+ }
599
+ set_value(&table[bucknum], *it); // copies the value to here
600
+ num_elements++;
601
+ }
602
+ }
603
+
604
+ // Required by the spec for hashed associative container
605
+ public:
606
+ // 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
608
+ // req_elements==0 will cause us to shrink if we can, saving space.
609
+ void resize(size_type req_elements) { // resize to this or larger
610
+ if ( consider_shrink || req_elements == 0 )
611
+ maybe_shrink();
612
+ if ( req_elements > num_elements )
613
+ return resize_delta(req_elements - num_elements);
614
+ }
615
+
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.
620
+ void get_resizing_parameters(float* shrink, float* grow) const {
621
+ *shrink = shrink_resize_percent;
622
+ *grow = enlarge_resize_percent;
623
+ }
624
+ 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();
632
+ }
633
+
634
+ // CONSTRUCTORS -- as required by the specs, we take a size,
635
+ // but also let you specify a hashfunction, key comparator,
636
+ // and key extractor. We also define a copy constructor and =.
637
+ // DESTRUCTOR -- needs to free the table
638
+ explicit dense_hashtable(size_type expected_max_items_in_table = 0,
639
+ const HashFcn& hf = HashFcn(),
640
+ const EqualKey& eql = EqualKey(),
641
+ 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) {
651
+ // table is NULL until emptyval is set. However, we set num_buckets
652
+ // here so we know how much space to allocate once emptyval is set
653
+ reset_thresholds();
654
+ }
655
+
656
+ // As a convenience for resize(), we allow an optional second argument
657
+ // which lets you make this new hashtable a different size than ht
658
+ dense_hashtable(const dense_hashtable& ht,
659
+ 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();
668
+ copy_from(ht, min_buckets_wanted); // copy_from() ignores deleted entries
669
+ }
670
+
671
+ dense_hashtable& operator= (const dense_hashtable& ht) {
672
+ 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;
681
+ 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
685
+ return *this;
686
+ }
687
+
688
+ ~dense_hashtable() {
689
+ if (table) {
690
+ destroy_buckets(0, num_buckets);
691
+ free(table);
692
+ }
693
+ }
694
+
695
+ // Many STL algorithms use swap instead of copy constructors
696
+ 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);
701
+ 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);
707
+ { value_type tmp; // for annoying reasons, swap() doesn't work
708
+ set_value(&tmp, emptyval);
709
+ set_value(&emptyval, ht.emptyval);
710
+ set_value(&ht.emptyval, tmp);
711
+ }
712
+ 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();
717
+ }
718
+
719
+ // It's always nice to be able to clear a table without deallocating it
720
+ void clear() {
721
+ if (table)
722
+ 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));
726
+ assert(table);
727
+ fill_range_with_empty(table, table + num_buckets);
728
+ num_elements = 0;
729
+ num_deleted = 0;
730
+ }
731
+
732
+ // Clear the table without resizing it.
733
+ // Mimicks the stl_hashtable's behaviour when clear()-ing in that it
734
+ // does not modify the bucket count
735
+ void clear_no_resize() {
736
+ if (table) {
737
+ set_empty(0, num_buckets);
738
+ }
739
+ // don't consider to shrink before another erase()
740
+ reset_thresholds();
741
+ num_elements = 0;
742
+ num_deleted = 0;
743
+ }
744
+
745
+ // LOOKUP ROUTINES
746
+ private:
747
+ // Returns a pair of positions: 1st where the object is, 2nd where
748
+ // it would go if you wanted to insert it. 1st is ILLEGAL_BUCKET
749
+ // if object is not found; 2nd is ILLEGAL_BUCKET if it is.
750
+ // Note: because of deletions where-to-insert is not trivial: it's the
751
+ // first deleted bucket we see, as long as we don't find the key later
752
+ pair<size_type, size_type> find_position(const key_type &key) const {
753
+ size_type num_probes = 0; // how many times we've probed
754
+ const size_type bucket_count_minus_one = bucket_count() - 1;
755
+ size_type bucknum = hash(key) & bucket_count_minus_one;
756
+ size_type insert_pos = ILLEGAL_BUCKET; // where we would insert
757
+ while ( 1 ) { // probe until something happens
758
+ if ( test_empty(bucknum) ) { // bucket is empty
759
+ if ( insert_pos == ILLEGAL_BUCKET ) // found no prior place to insert
760
+ return pair<size_type,size_type>(ILLEGAL_BUCKET, bucknum);
761
+ else
762
+ return pair<size_type,size_type>(ILLEGAL_BUCKET, insert_pos);
763
+
764
+ } else if ( test_deleted(bucknum) ) {// keep searching, but mark to insert
765
+ if ( insert_pos == ILLEGAL_BUCKET )
766
+ insert_pos = bucknum;
767
+
768
+ } else if ( equals(key, get_key(table[bucknum])) ) {
769
+ return pair<size_type,size_type>(bucknum, ILLEGAL_BUCKET);
770
+ }
771
+ ++num_probes; // we're doing another probe
772
+ bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one;
773
+ assert(num_probes < bucket_count()); // don't probe too many times!
774
+ }
775
+ }
776
+
777
+ public:
778
+ iterator find(const key_type& key) {
779
+ if ( size() == 0 ) return end();
780
+ pair<size_type, size_type> pos = find_position(key);
781
+ if ( pos.first == ILLEGAL_BUCKET ) // alas, not there
782
+ return end();
783
+ else
784
+ return iterator(this, table + pos.first, table + num_buckets, false);
785
+ }
786
+
787
+ const_iterator find(const key_type& key) const {
788
+ if ( size() == 0 ) return end();
789
+ pair<size_type, size_type> pos = find_position(key);
790
+ if ( pos.first == ILLEGAL_BUCKET ) // alas, not there
791
+ return end();
792
+ else
793
+ return const_iterator(this, table + pos.first, table+num_buckets, false);
794
+ }
795
+
796
+ // This is a tr1 method: the bucket a given key is in, or what bucket
797
+ // it would be put in, if it were to be inserted. Shrug.
798
+ size_type bucket(const key_type& key) const {
799
+ pair<size_type, size_type> pos = find_position(key);
800
+ return pos.first == ILLEGAL_BUCKET ? pos.second : pos.first;
801
+ }
802
+
803
+ // Counts how many elements have key key. For maps, it's either 0 or 1.
804
+ size_type count(const key_type &key) const {
805
+ pair<size_type, size_type> pos = find_position(key);
806
+ return pos.first == ILLEGAL_BUCKET ? 0 : 1;
807
+ }
808
+
809
+ // Likewise, equal_range doesn't really make sense for us. Oh well.
810
+ pair<iterator,iterator> equal_range(const key_type& key) {
811
+ iterator pos = find(key); // either an iterator or end
812
+ if (pos == end()) {
813
+ return pair<iterator,iterator>(pos, pos);
814
+ } else {
815
+ const iterator startpos = pos++;
816
+ return pair<iterator,iterator>(startpos, pos);
817
+ }
818
+ }
819
+ pair<const_iterator,const_iterator> equal_range(const key_type& key) const {
820
+ const_iterator pos = find(key); // either an iterator or end
821
+ if (pos == end()) {
822
+ return pair<const_iterator,const_iterator>(pos, pos);
823
+ } else {
824
+ const const_iterator startpos = pos++;
825
+ return pair<const_iterator,const_iterator>(startpos, pos);
826
+ }
827
+ }
828
+
829
+
830
+ // INSERTION ROUTINES
831
+ private:
832
+ // If you know *this is big enough to hold obj, use this routine
833
+ pair<iterator, bool> insert_noresize(const value_type& obj) {
834
+ // 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));
837
+ const pair<size_type,size_type> pos = find_position(get_key(obj));
838
+ if ( pos.first != ILLEGAL_BUCKET) { // object was already there
839
+ return pair<iterator,bool>(iterator(this, table + pos.first,
840
+ table + num_buckets, false),
841
+ false); // false: we didn't insert
842
+ } 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
856
+ }
857
+ }
858
+
859
+ public:
860
+ // This is the normal insert routine, used by the outside world
861
+ pair<iterator, bool> insert(const value_type& obj) {
862
+ resize_delta(1); // adding an object, grow if need be
863
+ return insert_noresize(obj);
864
+ }
865
+
866
+ // When inserting a lot at a time, we specialize on the type of iterator
867
+ template <class InputIterator>
868
+ void insert(InputIterator f, InputIterator l) {
869
+ // specializes on iterator type
870
+ insert(f, l, typename STL_NAMESPACE::iterator_traits<InputIterator>::iterator_category());
871
+ }
872
+
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);
889
+ }
890
+
891
+
892
+ // DELETION ROUTINES
893
+ 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));
897
+ const_iterator pos = find(key); // shrug: shouldn't need to be const
898
+ if ( pos != end() ) {
899
+ assert(!test_deleted(pos)); // or find() shouldn't have returned it
900
+ set_deleted(pos);
901
+ ++num_deleted;
902
+ consider_shrink = true; // will think about shrink after next insert
903
+ return 1; // because we deleted one thing
904
+ } else {
905
+ return 0; // because we deleted nothing
906
+ }
907
+ }
908
+
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) {
913
+ if ( pos == end() ) return; // sanity check
914
+ if ( set_deleted(pos) ) { // true if object has been newly deleted
915
+ ++num_deleted;
916
+ consider_shrink = true; // will think about shrink after next insert
917
+ }
918
+ }
919
+
920
+ void erase(const_iterator f, const_iterator l) {
921
+ for ( ; f != l; ++f) {
922
+ if ( set_deleted(f) ) // should always be true
923
+ ++num_deleted;
924
+ }
925
+ consider_shrink = true; // will think about shrink after next insert
926
+ }
927
+
928
+
929
+ // COMPARISON
930
+ bool operator==(const dense_hashtable& ht) const {
931
+ if (size() != ht.size()) {
932
+ return false;
933
+ } else if (this == &ht) {
934
+ return true;
935
+ } else {
936
+ // Iterate through the elements in "this" and see if the
937
+ // corresponding element is in ht
938
+ for ( const_iterator it = begin(); it != end(); ++it ) {
939
+ const_iterator it2 = ht.find(get_key(*it));
940
+ if ((it2 == ht.end()) || (*it != *it2)) {
941
+ return false;
942
+ }
943
+ }
944
+ return true;
945
+ }
946
+ }
947
+ bool operator!=(const dense_hashtable& ht) const {
948
+ return !(*this == ht);
949
+ }
950
+
951
+
952
+ // I/O
953
+ // We support reading and writing hashtables to disk. Alas, since
954
+ // I don't know how to write a hasher or key_equal, you have to make
955
+ // sure everything but the table is the same. We compact before writing
956
+ //
957
+ // NOTE: These functions are currently TODO. They've not been implemented.
958
+ bool write_metadata(FILE *fp) {
959
+ squash_deleted(); // so we don't have to worry about delkey
960
+ return false; // TODO
961
+ }
962
+
963
+ bool read_metadata(FILE *fp) {
964
+ 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
967
+ // TODO: read magic number
968
+ // TODO: read num_buckets
969
+ reset_thresholds();
970
+ table = (value_type *) malloc(num_buckets * sizeof(*table));
971
+ assert(table);
972
+ fill_range_with_empty(table, table + num_buckets);
973
+ // TODO: read num_elements
974
+ for ( size_type i = 0; i < num_elements; ++i ) {
975
+ // TODO: read bucket_num
976
+ // TODO: set with non-empty, non-deleted value
977
+ }
978
+ return false; // TODO
979
+ }
980
+
981
+ // If your keys and values are simple enough, we can write them to
982
+ // disk for you. "simple enough" means value_type is a POD type
983
+ // that contains no pointers. However, we don't try to normalize
984
+ // endianness
985
+ bool write_nopointer_data(FILE *fp) const {
986
+ for ( const_iterator it = begin(); it != end(); ++it ) {
987
+ // TODO: skip empty/deleted values
988
+ if ( !fwrite(&*it, sizeof(*it), 1, fp) ) return false;
989
+ }
990
+ return false;
991
+ }
992
+
993
+ // When reading, we have to override the potential const-ness of *it
994
+ bool read_nopointer_data(FILE *fp) {
995
+ for ( iterator it = begin(); it != end(); ++it ) {
996
+ // TODO: skip empty/deleted values
997
+ if ( !fread(reinterpret_cast<void*>(&(*it)), sizeof(*it), 1, fp) )
998
+ return false;
999
+ }
1000
+ return false;
1001
+ }
1002
+
1003
+ 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
1023
+
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
1030
+ }
1031
+ };
1032
+
1033
+ // We need a global swap as well
1034
+ template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
1035
+ inline void swap(dense_hashtable<V,K,HF,ExK,SetK,EqK,A> &x,
1036
+ dense_hashtable<V,K,HF,ExK,SetK,EqK,A> &y) {
1037
+ x.swap(y);
1038
+ }
1039
+
1040
+ #undef JUMP_
1041
+
1042
+ template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
1043
+ 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;
1045
+
1046
+ // How full we let the table get before we resize. Knuth says .8 is
1047
+ // good -- higher causes us to probe too much, though saves memory.
1048
+ // However, we go with .5, getting better performance at the cost of
1049
+ // more space (a trade-off densehashtable explicitly chooses to make).
1050
+ // Feel free to play around with different values, though.
1051
+ 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;
1053
+
1054
+ // How empty we let the table get before we resize lower.
1055
+ // It should be less than OCCUPANCY_FLT / 2 or we thrash resizing
1056
+ 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;
1059
+
1060
+ _END_GOOGLE_NAMESPACE_
1061
+
1062
+ #endif /* _DENSEHASHTABLE_H_ */