1 /*******************************************************************************
2 3 Class implementing a set of hashes. The set is built on top of an efficient
4 bucket algorithm, allowing for fast look up of hashes in the set.
5 6 Usage example:
7 8 ---
9 10 import ocean.util.container.map.HashSet;
11 12 // A set of hash_t's
13 auto set = new HashSet;
14 15 hash_t hash = 232323;
16 17 // Add a hash
18 set.put(hash);
19 20 // Check if a hash exists in the set (null if not found)
21 auto exists = hash in set;
22 23 // Remove a hash from the set
24 set.remove(hash);
25 26 // Clear the set
27 set.clear();
28 29 ---
30 31 Copyright:
32 Copyright (c) 2009-2016 dunnhumby Germany GmbH.
33 All rights reserved.
34 35 License:
36 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
37 Alternatively, this file may be distributed under the terms of the Tango
38 3-Clause BSD License (see LICENSE_BSD.txt for details).
39 40 *******************************************************************************/41 42 moduleocean.util.container.map.HashSet;
43 44 45 46 47 importocean.util.container.map.Set;
48 49 version (UnitTestVerbose) importocean.io.Stdout;
50 version (unittest) importocean.core.Test;
51 52 53 54 /*******************************************************************************
55 56 Debug switch for verbose unittest output (uncomment if desired)
57 58 *******************************************************************************/59 60 //version = UnitTestVerbose;61 62 version ( UnitTestVerbose )
63 {
64 importocean.io.Stdout;
65 }
66 67 /*******************************************************************************
68 69 HashSet class. Manages a set of hash_t's with fast lookup.
70 71 *******************************************************************************/72 73 publicclassHashSet : Set!(hash_t)
74 {
75 /***************************************************************************
76 77 Constructor, sets the number of buckets to n * load_factor
78 79 Params:
80 n = expected number of elements
81 load_factor = ratio of n to the number of internal buckets. The
82 desired (approximate) number of elements per bucket. For
83 example, 0.5 sets the number of buckets to double n; for 2 the
84 number of buckets is the half of n. load_factor must be greater
85 than 0. The load factor is basically a trade-off between memory
86 usage (number of buckets) and search time (number of elements
87 per bucket).
88 89 ***************************************************************************/90 91 publicthis ( size_tn, floatload_factor = 0.75 )
92 {
93 super(n, load_factor);
94 }
95 96 /***************************************************************************
97 98 Constructor.
99 100 Params:
101 allocator = custom bucket elements allocator
102 n = expected number of elements in mapping
103 load_factor = ratio of n to the number of internal buckets. The
104 desired (approximate) number of elements per bucket. For
105 example, 0.5 sets the number of buckets to double n; for 2 the
106 number of buckets is the half of n. load_factor must be greater
107 than 0. The load factor is basically a trade-off between memory
108 usage (number of buckets) and search time (number of elements
109 per bucket).
110 111 ***************************************************************************/112 113 publicthis ( IAllocatorallocator, size_tn, floatload_factor = 0.75 )
114 {
115 super(allocator, n, load_factor);
116 }
117 118 /***************************************************************************
119 120 Calculates the hash value from key. Uses the identity since key is
121 expected to be a suitable hash value.
122 123 Params:
124 key = key to hash
125 126 Returns:
127 the hash value that corresponds to key, which is key itself.
128 129 ***************************************************************************/130 131 publicoverridehash_ttoHash ( inhash_tkey )
132 {
133 returnkey;
134 }
135 }
136 137 /***************************************************************************
138 139 HashSet unittest.
140 141 ***************************************************************************/142 143 unittest144 {
145 version ( UnitTestVerbose )
146 {
147 Stdout.formatln("{} unittest ---------------",
148 typeof(this).stringof);
149 scope ( exit ) Stdout.formatln("{} unittest ---------------",
150 typeof(this).stringof);
151 }
152 153 scopeset = newHashSet(10);
154 155 version ( UnitTestVerbose ) voidprintState ( )
156 {
157 Stdout.formatln(" :: len={}, load={}, max_load={}, pool={} ({} busy)",
158 set.length, set.load, set.max_load,
159 set.bucket_elements.length, set.bucket_elements.num_busy);
160 }
161 162 boollengthIs ( size_texpected )
163 {
164 test(set.length == expected);
165 166 intc;
167 foreach ( k; set )
168 {
169 c++;
170 }
171 returnc == expected;
172 }
173 174 voidput ( hash_tkey, boolshould_exist )
175 {
176 autolen = set.length;
177 178 test(!!(keyinset) == should_exist);
179 180 autoe = set.put(key);
181 version ( UnitTestVerbose )
182 {
183 Stdout.format("put {}: {}", key, e);
184 printState();
185 }
186 187 test(keyinset);
188 test(lengthIs(len + (should_exist ? 0 : 1)));
189 }
190 191 voidremove ( hash_tkey, boolshould_exist )
192 {
193 autolen = set.length;
194 autopool_len = set.bucket_info.num_buckets;
195 196 test(!!(keyinset) == should_exist);
197 198 autoe = set.remove(key);
199 version ( UnitTestVerbose )
200 {
201 Stdout.format("remove {}: {}", key, e);
202 printState();
203 }
204 205 test(!(keyinset));
206 test(lengthIs(len - (should_exist ? 1 : 0)));
207 test(pool_len == set.bucket_info.num_buckets);
208 }
209 210 voidclear ( )
211 {
212 autopool_len = set.bucket_info.num_buckets;
213 214 set.clear();
215 version ( UnitTestVerbose )
216 {
217 Stdout.format("clear");
218 printState();
219 }
220 221 test(lengthIs(0));
222 223 test(pool_len == set.bucket_info.num_buckets);
224 }
225 226 put(4711, false); // put227 put(4711, true); // double put228 put(23, false); // put229 put(12, false); // put230 remove(23, true); // remove231 remove(23, false); // double remove232 put(23, false); // put233 put(23, true); // double put234 235 clear();
236 237 put(4711, false); // put238 put(11, false); // put239 put(11, true); // double put240 put(12, false); // put241 remove(23, false); // remove242 put(23, false); // put243 put(23, true); // double put244 245 clear();
246 }