187 mike 1.11
188 /*- Removes the bucket with the given key. This method uses the
189 _BucketBase::equal() method to compare keys.
190 @param hashCode hash code generated by caller's hash function.
191 @param key void pointer to key.
192 @return true if entry found and removed and false otherwise.
193 */
194 Boolean remove(Uint32 hashCode, const void* key);
195
196 _BucketBase** getChains() const { return _chains; }
197
198 Uint32 getNumChains() const { return _numChains; }
199
200 protected:
201
202 Uint32 _size;
203 Uint32 _numChains;
204 _BucketBase** _chains;
205 };
206
207 /* The _Bucket class is used to implement the HashTable class.
208 mike 1.11 */
209 template<class K, class V, class E>
210 class _Bucket : public _BucketBase
211 {
212 public:
213
214 _Bucket(const K& key, const V& value) : _key(key), _value(value) { }
215
216 virtual ~_Bucket();
217
218 virtual Boolean equal(const void* key) const;
219
220 virtual _BucketBase* clone() const;
221
222 K& getKey() { return _key; }
223
224 V& getValue() { return _value; }
225
226 private:
227
228 K _key;
229 mike 1.11 V _value;
230 };
231
232 template<class K, class V, class E>
233 Boolean _Bucket<K, V, E>::equal(const void* key) const
234 {
235 return E::equal(*((K*)key), _key);
236 }
237
238 template<class K, class V, class E>
239 _Bucket<K, V, E>::~_Bucket()
240 {
241
242 }
243
244 template<class K, class V, class E>
245 _BucketBase* _Bucket<K, V, E>::clone() const
246 {
247 return new _Bucket<K, V, E>(_key, _value);
248 }
249
250 mike 1.11 /* Iterator for HashTable class. */
251 template<class K, class V, class E>
252 class _HashTableIterator : public _HashTableIteratorBase
253 {
254 public:
255
256 _HashTableIterator()
257 : _HashTableIteratorBase() { }
258
259 _HashTableIterator(_BucketBase** first, _BucketBase** last)
260 : _HashTableIteratorBase(first, last) { }
261
262 const K& key() const { return ((_Bucket<K, V, E>*)_bucket)->getKey(); }
263
264 const V& value() const { return ((_Bucket<K, V, E>*)_bucket)->getValue(); }
265 };
266
267 /** The HashTable class provides a simple hash table implementation which
268 associates key-value pairs.
269
270 This implementation minimizes template bloat considerably by factoring out
271 mike 1.11 most of the code into a common non-template class (see _HashTableRep).
272 The HashTable class is mostly a wrapper to add proper type semantics to the
273 use of its representation class.
274
275 Hashing as always is O(1).
276
277 HashTable uses the most popular hash table implementation which utilizes
278 an array of pointers to bucket chains. This is organized as follows:
279
280 <pre>
281 +---+
282 | | +-----+-------+
283 0 | ----->| key | value |
284 | | +-----+-------+
285 +---+
286 | | +-----+-------+ +-----+-------+ +-----+-------+
287 1 | ----->| key | value |-->| key | value |-->| key | value |
288 | | +-----+-------+ +-----+-------+ +-----+-------+
289 +---+
290 .
291 .
292 mike 1.11 .
293 +---+
294 | | +-----+-------+ +-----+-------+
295 N-1| ----->| key | value |-->| key | value |
296 | | +-----+-------+ +-----+-------+
297 +---+
298 </pre>
299
300 To locate an item a hash function is applied to the key to produce an
301 integer value. Then the modulo of that integer is taken with N to select
302 a chain (as shown above). Then the chain is searched for a bucket whose
303 key value is the same as the target key.
304
305 The number of chains default to DEFAULT_NUM_CHAINS but should be about
306 one-third the number of expected entries (so that the average chain
307 will be three long). Making the number of chains too large will waste
308 space causing the hash table to be very sparse. But for optimal efficiency,
309 one might set the number of chains to be the same as the expected number
310 of entries.
311
312 This implementation does have NOT an adaptive growth algorithm yet which
313 mike 1.11 would allow it to increase the number of chains periodically based on some
314 statistic (e.g., when the number of entries is more than three times the
315 number of chains; this would keep the average chain length below three).
316
317 The following example shows how to instantiate a HashTable which associates
318 String keys with Uint32 values.
319
320 <pre>
321 typedef HashTable<String, Uint32> HT;
322 HT ht;
323 </pre>
324
325 Some of the template arguments are defaulted in the above example (the
326 third and forth). The instantiation is explicitly qualified like this
327 (which by the way has exactly the same effect).
328
329 <pre>
330 typedef HashTable<String, Uint32, EqualFunc<String>, HashFunc<String>> HT;
331 </pre>
332
333 The third and forth arguments are described more in detail later.
334 mike 1.11
335 Then, entries may be inserted like this:
336
337 <pre>
338 ht.insert("Red", 111);
339 ht.insert("Green", 222);
340 ht.insert("Blue", 222);
341 </pre>
342
343 And entries may be looked up as follows:
344
345 <pre>
346 Uint32 value;
347 ht.lookup("Red", value);
348 </pre>
349
350 And entries may be removed like this:
351
352 <pre>
353 h.remove("Red");
354 </pre>
355 mike 1.11
356 Iteration is done like this:
357
358 <pre>
359 for (HT::Iterator i = ht.start(); i; i++)
360 {
361 // To access the key call i.key()!
362 // To access the value call i.value()!
363 }
364 </pre>
365
366 Note that only forward iteration is supported (no backwards iteration).
367
368 Equality of keys is determined using the EqualFunc class which is
369 the default third argument of the template argument list. A new function
370 object may be defined and passed to modify the behavior (for example, one
371 might define equality of strings to ignore whitespace). Here is how to
372 define and use a new equality function object:
373
374 <pre>
375 struct MyEqualFunc
376 mike 1.11 {
377 static Boolean equal(const String& x, const String& y)
378 {
379 // do something here to test for equality!
380 }
381 };
382
383 ...
384
385 EqualFunc<String, Uint32, MyEqualFunc> ht;
386 </pre>
387
388 When the lookup(), insert(), and remove() methods are called, the
389 MyEqualFunc::equal() method will be used to determine equality.
390
391 Hash functions are provided for common types (as part of the default
392 HashFunc class). For other types it is possible to define a custom function
393 object as follows:
394
395 <pre>
396 struct MyHashFunc
397 mike 1.11 {
398 static Uint32 hash(const String& x)
399 {
400 // Do some hashing here!
401 }
402 };
403
404 ...
405
406 EqualFunc<String, Uint32, MyEqualFunc, MyHashFunc> ht;
407 </pre>
408
409 As always, the hash function should provide a reasonably uniform
410 distrubtion so that all of the entries don't get crowded into a few
411 chains. Note that a hash function which returns zero, would force
412 the pathalogical case in which all entries are placed in the first
413 chain.
414 */
415 template<class K, class V, class E , class H >
416 class HashTable
417 {
418 mike 1.11 public:
419
420 typedef _HashTableIterator<K, V, E> Iterator;
421
422 /* By default, we create this many chains initially */
423 enum { DEFAULT_NUM_CHAINS = 32 };
424
425 /** Constructor.
426 @param numChains number of chains to create.
427 */
428 HashTable(Uint32 numChains = DEFAULT_NUM_CHAINS) : _rep(numChains)
429 {
430
431 }
432
433 /** Copy constructor. */
434 HashTable(const HashTable<K,V,E,H>& x) : _rep(x._rep)
435 {
436
437 }
438
439 mike 1.11 /** Assignment operator. */
440 HashTable<K,V,E,H>& operator=(const HashTable<K,V,E,H>& x)
441 {
442 if (this != &x)
443 _rep = x._rep;
444 return *this;
445 }
446
447 /** Returns the size of this hash table (the number of entries). */
448 Uint32 size() const { return _rep.size(); }
449
450 /** Clears the contents of this hash table. After this is called, the
451 size() method returns zero.
452 */
453 void clear() { _rep.clear(); }
454
455 /** Inserts new key-value pair into hash table.
456 @param key key component.
457 @param value value component.
458 @return true on success; false if duplicate key.
459 */
460 mike 1.11 Boolean insert(const K& key, const V& value)
461 {
462 return _rep.insert(
463 H::hash(key), new _Bucket<K, V, E>(key, value), &key);
464 }
465
466 /** Checks to see if hash table contains an entry with the given key.
467 @param key key to be searched for
468 @return true if hash table contains an entry with the given key.
469 */
|