1 /*******************************************************************************
2 3 Template for a class implementing a set of hashed keys. The set is built on
4 top of an efficient bucket algorithm, allowing for fast look up of keys in
5 the set.
6 7 Usage example:
8 9 ---
10 11 import ocean.util.container.map.HashSet;
12 13 // A set of hash_t's
14 auto set = new HashSet;
15 16 hash_t hash = 232323;
17 18 // Add a hash
19 set.put(hash);
20 21 // Check if a hash exists in the set (null if not found)
22 auto exists = hash in set;
23 24 // Remove a hash from the set
25 set.remove(hash);
26 27 // Clear the set
28 set.clear();
29 30 ---
31 32 Copyright:
33 Copyright (c) 2009-2016 dunnhumby Germany GmbH.
34 All rights reserved.
35 36 License:
37 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
38 Alternatively, this file may be distributed under the terms of the Tango
39 3-Clause BSD License (see LICENSE_BSD.txt for details).
40 41 *******************************************************************************/42 43 moduleocean.util.container.map.Set;
44 45 46 47 importocean.meta.types.Qualifiers;
48 49 importocean.util.container.map.model.BucketSet;
50 51 importocean.util.container.map.model.Bucket;
52 53 importocean.util.container.map.model.MapIterator;
54 55 importocean.util.container.map.model.StandardHash;
56 57 version (UnitTestVerbose) importocean.io.Stdout;
58 59 /*******************************************************************************
60 61 Debug switch for verbose unittest output (uncomment if desired)
62 63 *******************************************************************************/64 65 //version = UnitTestVerbose;66 67 version ( UnitTestVerbose )
68 {
69 importocean.io.Stdout;
70 }
71 72 /*******************************************************************************
73 74 StandardKeyHashingSet class template. Manages a set of K's with fast lookup
75 using a standard way of hash calculation:
76 77 - If K is a primitive type (integer, floating point, character), the hash
78 value is calculated from the raw key data using the FNV1a hash function.
79 - If K is a dynamic or static array of a primitive type, the hash value is
80 calculated from the raw data of the key array content using the FNV1a hash
81 function.
82 - If K is a class, struct or union, it is expected to implement toHash(),
83 which will be used.
84 - Other key types (arrays of non-primitive types, classes/structs/unions
85 which do not implement toHash(), pointers, function references, delegates,
86 associative arrays) are not supported by this class template.
87 88 *******************************************************************************/89 90 publicclassStandardHashingSet ( K ) : Set!(K)
91 {
92 /***************************************************************************
93 94 Constructor.
95 96 Params:
97 n = expected number of elements in mapping
98 load_factor = ratio of n to the number of internal buckets. The
99 desired (approximate) number of elements per bucket. For
100 example, 0.5 sets the number of buckets to double n; for 2 the
101 number of buckets is the half of n. load_factor must be greater
102 than 0. The load factor is basically a trade-off between memory
103 usage (number of buckets) and search time (number of elements
104 per bucket).
105 106 ***************************************************************************/107 108 publicthis ( size_tn, floatload_factor = 0.75 )
109 {
110 super(n, load_factor);
111 }
112 113 /***************************************************************************
114 115 Constructor.
116 117 Params:
118 allocator = custom bucket elements allocator
119 n = expected number of elements in mapping
120 load_factor = ratio of n to the number of internal buckets. The
121 desired (approximate) number of elements per bucket. For
122 example, 0.5 sets the number of buckets to double n; for 2 the
123 number of buckets is the half of n. load_factor must be greater
124 than 0. The load factor is basically a trade-off between memory
125 usage (number of buckets) and search time (number of elements
126 per bucket).
127 128 ***************************************************************************/129 130 publicthis ( IAllocatorallocator, size_tn, floatload_factor = 0.75 )
131 {
132 super(allocator, n, load_factor);
133 }
134 135 /***************************************************************************
136 137 Mixin of the toHash() method which is declared abstract in BucketSet.
138 139 ***************************************************************************/140 141 override:
142 mixinStandardHash.toHash!(K);
143 }
144 145 146 /*******************************************************************************
147 148 Set class. Manages a set of K's with fast lookup. The toHash() method must
149 be implemented.
150 151 *******************************************************************************/152 153 publicabstractclassSet ( K ) : BucketSet!(0, K)
154 {
155 privatealias .MapIterator!(void, K) SetIterator;
156 157 /***************************************************************************
158 159 Mixin of the specialized iterator classes which inherit from
160 BucketSet.Iterator.
161 162 This makes available three iterator classes that can be newed to allow
163 certain iteration behaviors:
164 165 * Iterator — just a normal iterator
166 * InterruptibleIterator — an iterator that can be interrupted and
167 resumed, but that has to be manually reset with reset() if the
168 iteration is meant to be repeated
169 170 If the map is modified between interrupted iterations, it can happen
171 that new elements that were added in the mean time won't appear in the
172 iteratation, depending on whether they end up in a bucket that was
173 already iterated or not.
174 175 Iterator usage example
176 ---
177 auto map = new HashMap!(size_t);
178 179 auto it = map.new Iterator();
180 181 // A normal iteration over the map
182 foreach ( k, v; it )
183 {
184 ..
185 }
186 187 // Equal to
188 foreach ( k, v; map )
189 {
190 ..
191 }
192 ---
193 194 InterruptibleIterator
195 ---
196 auto map = new HashMap!(size_t);
197 198 auto interruptible_it = map.new InterruptibleIterator();
199 200 // Iterate over the first 100k elements
201 foreach ( i, k, v; interruptible_it )
202 {
203 ..
204 // Break after 100k elements
205 if ( i % 100_000 == 0 ) break;
206 }
207 208 // Iterate over the next 100k elments
209 foreach ( i, k, v; interruptible_it )
210 {
211 ..
212 // Break after 100k elements
213 if ( i % 100_000 == 0 ) break;
214 }
215 216 // Assuming the map had 150k elements, the iteration is done now,
217 // so this won't do anything
218 foreach ( i, k, v; interruptible_it )
219 {
220 ..
221 // Break after 100k elements
222 if ( i % 100_000 == 0 ) break;
223 }
224 225 assert ( interruptible_it.finished() == true );
226 ---
227 228 See also: BucketSet.Iterator, MapIterator.IteratorClass
229 230 ***************************************************************************/231 232 mixinIteratorClass!(BucketSet!(0,K).Iterator, SetIterator);
233 234 /***************************************************************************
235 236 Constructor.
237 238 Params:
239 n = expected number of elements in mapping
240 load_factor = ratio of n to the number of internal buckets. The
241 desired (approximate) number of elements per bucket. For
242 example, 0.5 sets the number of buckets to double n; for 2 the
243 number of buckets is the half of n. load_factor must be greater
244 than 0. The load factor is basically a trade-off between memory
245 usage (number of buckets) and search time (number of elements
246 per bucket).
247 248 ***************************************************************************/249 250 protectedthis ( size_tn, floatload_factor = 0.75 )
251 {
252 super(n, load_factor);
253 }
254 255 /***************************************************************************
256 257 Constructor.
258 259 Params:
260 allocator = custom bucket elements allocator
261 n = expected number of elements in mapping
262 load_factor = ratio of n to the number of internal buckets. The
263 desired (approximate) number of elements per bucket. For
264 example, 0.5 sets the number of buckets to double n; for 2 the
265 number of buckets is the half of n. load_factor must be greater
266 than 0. The load factor is basically a trade-off between memory
267 usage (number of buckets) and search time (number of elements
268 per bucket).
269 270 ***************************************************************************/271 272 protectedthis ( IAllocatorallocator, size_tn, floatload_factor = 0.75 )
273 {
274 super(allocator, n, load_factor);
275 }
276 277 278 /***************************************************************************
279 280 Looks up key in the set.
281 282 Params:
283 key = key to look up
284 285 Returns:
286 true if found or false if not.
287 288 ***************************************************************************/289 290 publicboolopIn_r ( Kkey )
291 {
292 returnthis.get_(key) !isnull;
293 }
294 295 296 /***************************************************************************
297 298 Support for the 'in' operator
299 300 Aliased to opIn_r, for backwards compatibility
301 302 ***************************************************************************/303 304 publicaliasopBinaryRight ( istringop : "in" ) = opIn_r;
305 306 307 /***************************************************************************
308 309 Puts key into the set.
310 311 Params:
312 key = key to put into set
313 314 Returns:
315 true if the key was already on the set, false otherwise
316 317 ***************************************************************************/318 319 publicboolput ( Kkey )
320 {
321 booladded;
322 323 this.put_(key, added);
324 325 return !added;
326 }
327 328 329 /***************************************************************************
330 331 'foreach' iteration over set.
332 333 Note: It is possible to have interruptible iterations, see documentation
334 for mixin of IteratorClass
335 336 See also: BucketSet.Iterator, MapIterator.IteratorClass
337 338 Notes:
339 - During iteration it is forbidden to call clear() or redistribute() or
340 remove map elements. If elements are added, the iteration may or may
341 not include these elements.
342 - If K is a static array, the iteration variable is a dynamic array of
343 the same base type and slices the key of the element in the map.
344 (The reason is that static array 'ref' parameters are forbidden in D.)
345 In this case DO NOT modify the key in any way!
346 - It is not recommended to do a 'ref' iteration over the keys. If you do
347 it anyway, DO NOT modify the key in-place!
348 349 ***************************************************************************/350 351 publicintopApply ( SetIterator.Dgdg )
352 {
353 scopeit = this.newIterator;
354 355 returnit.opApply(dg);
356 }
357 358 /***************************************************************************
359 360 Same as above, but includes a counter
361 362 ***************************************************************************/363 364 publicintopApply ( SetIterator.Dgidgi )
365 {
366 scopeit = this.newIterator;
367 368 returnit.opApply(dgi);
369 }
370 }