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 module ocean.util.container.map.HashSet; 43 44 45 46 47 import ocean.util.container.map.Set; 48 49 version (UnitTestVerbose) import ocean.io.Stdout; 50 version (unittest) import ocean.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 import ocean.io.Stdout; 65 } 66 67 /******************************************************************************* 68 69 HashSet class. Manages a set of hash_t's with fast lookup. 70 71 *******************************************************************************/ 72 73 public class HashSet : 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 public this ( size_t n, float load_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 public this ( IAllocator allocator, size_t n, float load_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 public override hash_t toHash ( in hash_t key ) 132 { 133 return key; 134 } 135 } 136 137 /*************************************************************************** 138 139 HashSet unittest. 140 141 ***************************************************************************/ 142 143 unittest 144 { 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 scope set = new HashSet(10); 154 155 version ( UnitTestVerbose ) void printState ( ) 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 bool lengthIs ( size_t expected ) 163 { 164 test(set.length == expected); 165 166 int c; 167 foreach ( k; set ) 168 { 169 c++; 170 } 171 return c == expected; 172 } 173 174 void put ( hash_t key, bool should_exist ) 175 { 176 auto len = set.length; 177 178 test(!!(key in set) == should_exist); 179 180 auto e = set.put(key); 181 version ( UnitTestVerbose ) 182 { 183 Stdout.format("put {}: {}", key, e); 184 printState(); 185 } 186 187 test(key in set); 188 test(lengthIs(len + (should_exist ? 0 : 1))); 189 } 190 191 void remove ( hash_t key, bool should_exist ) 192 { 193 auto len = set.length; 194 auto pool_len = set.bucket_info.num_buckets; 195 196 test(!!(key in set) == should_exist); 197 198 auto e = set.remove(key); 199 version ( UnitTestVerbose ) 200 { 201 Stdout.format("remove {}: {}", key, e); 202 printState(); 203 } 204 205 test(!(key in set)); 206 test(lengthIs(len - (should_exist ? 1 : 0))); 207 test(pool_len == set.bucket_info.num_buckets); 208 } 209 210 void clear ( ) 211 { 212 auto pool_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); // put 227 put(4711, true); // double put 228 put(23, false); // put 229 put(12, false); // put 230 remove(23, true); // remove 231 remove(23, false); // double remove 232 put(23, false); // put 233 put(23, true); // double put 234 235 clear(); 236 237 put(4711, false); // put 238 put(11, false); // put 239 put(11, true); // double put 240 put(12, false); // put 241 remove(23, false); // remove 242 put(23, false); // put 243 put(23, true); // double put 244 245 clear(); 246 }