source: trunk/include/core/RpDict.h @ 106

Last change on this file since 106 was 106, checked in by cxsong, 19 years ago

removed #include <malloc.h> since stdlib.h contains malloc decl.

  • Property svn:executable set to *
File size: 26.1 KB
Line 
1#include <iostream>
2#include <cassert>
3#include <string>
4#include <stdlib.h>
5#include <errno.h>
6//#include <malloc.h>
7
8#ifndef _RpDICT_H
9#define _RpDICT_H
10
11/**************************************************************************/
12/**************************************************************************/
13
14template <typename KeyType, typename ValType> class RpDict;
15template <typename KeyType, typename ValType> class RpDictEntry;
16
17/**************************************************************************/
18
19template <typename KeyType, typename ValType> class RpDictIterator
20{
21
22    public:
23
24        // public data members
25
26        // public member functions
27
28        // retrieve the table the iterator is iterating
29        // virtual RpDict<KeyType,ValType>& getTable();
30
31        // send the search iterator to the beginning of the hash table
32        /*virtual*/ RpDictEntry<KeyType,ValType>* first();
33
34        // send the search iterator to the next element of the hash table
35        /*virtual*/ RpDictEntry<KeyType,ValType>* next();
36/*
37        RpDictIterator(RpDict* table_Ptr)
38            : tablePtr( (RpDict&) *table_Ptr),
39              srchNextEntryPtr(NULL),
40              srchNextIndex(0)
41        {
42        }
43*/
44        RpDictIterator(RpDict<KeyType,ValType>& table_Ptr)
45            : tablePtr(table_Ptr),
46              srchNextIndex(0),
47              srchNextEntryPtr(NULL)
48        {
49        }
50
51        // copy constructor
52        RpDictIterator(RpDictIterator<KeyType,ValType>& iterRef)
53            : tablePtr(iterRef.tablePtr),
54              srchNextIndex(iterRef.srchNextIndex),
55              srchNextEntryPtr(iterRef.srchNextEntryPtr)
56        {
57        }
58
59        // destructor
60
61    private:
62
63        RpDict<KeyType,ValType>&
64            tablePtr;                   /* pointer to the table we want to
65                                         * iterate */
66        int srchNextIndex;              /* Index of next bucket to be
67                                         * enumerated after present one. */
68        RpDictEntry<KeyType,ValType>*
69            srchNextEntryPtr;           /* Next entry to be enumerated in the
70                                         * the current bucket. */
71
72};
73
74
75template <typename KeyType, typename ValType> class RpDictEntry
76{
77    public:
78
79        // public member functions
80
81        operator int() const;
82        // operator==(const RpDictEntry& entry) const;
83        //
84        //operator!=(const RpDictEntry& lhs, const RpDictEntry& rhs) const
85        //{
86        //    if (lhs.key != rhs.key)
87        //}
88        const KeyType* getKey() const;
89        const ValType* getValue() const;
90        // const void* setValue(const void* value);
91        const ValType* setValue(const ValType& value);
92
93        // erases this entry from its table
94        void erase();
95
96        // template <KeyType,ValType> friend class RpDict;
97        // template <KeyType,ValType> friend class RpDictIterator;
98
99        friend class RpDict<KeyType,ValType>;
100        friend class RpDictIterator<KeyType,ValType>;
101
102        // no_arg constructor
103        // use the key and clientData's default [no-arg] constructor
104        RpDictEntry()
105           : nextPtr (NULL),
106             tablePtr (NULL),
107             hash (0) // ,
108             // clientData (),
109             // key ()
110        {
111        }
112
113        // one-arg constructor
114        // maybe get rid of this one?
115        RpDictEntry(KeyType newKey)
116           : nextPtr    (NULL),
117             tablePtr   (NULL),
118             hash       (0),
119             clientData (NULL),
120             key        (newKey)
121        {
122        }
123
124        // two-arg constructor
125        RpDictEntry(KeyType newKey, ValType newVal)
126           : nextPtr    (NULL),
127             tablePtr   (NULL),
128             hash       (0),
129             clientData (newVal),
130             key        (newKey)
131        {
132        }
133
134/*
135        RpDictEntry(KeyType* newKey, ValType* newVal)
136           : nextPtr    (NULL),
137             tablePtr   (NULL),
138             hash       (0),
139             clientData (*newVal),
140             key        (*newKey)
141        {
142        }
143
144        RpDictEntry(KeyType newKey, RpDict* table)
145           : nextPtr    (NULL),
146             tablePtr   (table),
147             hash       (0),
148             // clientData (NULL),
149             key        (newKey)
150        {
151        }
152*/
153        // copy constructor
154        RpDictEntry (const RpDictEntry<KeyType,ValType>& entry)
155        {
156            nextPtr     = entry.nextPtr;
157            tablePtr    = entry.tablePtr;
158            hash        = entry.hash;
159            clientData  = (ValType) entry.getValue();
160            key         = (KeyType) entry.getKey();
161        }
162
163    private:
164
165        // private data members
166        RpDictEntry<KeyType,ValType>*
167            nextPtr;                /* Pointer to next entry in this
168                                     * hash bucket, or NULL for end of
169                                     * chain. */
170
171        RpDict<KeyType,ValType>
172            *tablePtr;              /* Pointer to table containing entry. */
173
174        unsigned int hash;          /* Hash value. */
175
176        ValType clientData;        /* Application stores something here
177                                     * with Tcl_SetHashValue. */
178
179        KeyType key;               /* entry key */
180
181
182
183
184};
185
186
187template <typename KeyType, typename ValType> class RpDict
188{
189    public:
190
191
192        // functionality for the user to access/adjust data members
193
194        // checks table size
195        /*virtual*/ const int size() const;
196
197        // insert new object into table
198        // returns 0 on success (object inserted or already exists)
199        // returns !0 on failure (object cannot be inserted or dne)
200        //
201        /*virtual*/ RpDict<KeyType,ValType>&
202                        set(    KeyType& key,
203                                ValType& value,
204                                int *newPtr=NULL );   
205
206        // find an RpUnits object that should exist in RpUnitsTable
207        //
208        /*virtual*/ RpDictEntry<KeyType,ValType>&
209                        find( KeyType& key );
210
211        /*virtual*/ RpDictEntry<KeyType,ValType>& operator[]( KeyType& key)
212        {
213            return find(key);
214        }
215
216        // clear the entire table
217        // iterate through the table and call erase on each element
218        /*virtual*/ RpDict<KeyType,ValType>& clear();
219
220        // get the nullEntry hash entry for initialization of references
221        /*virtual*/ RpDictEntry<KeyType,ValType>& getNullEntry();
222
223        // template <KeyType, ValType> friend class RpDictEntry;
224        // template <KeyType, ValType> friend class RpDictIterator;
225
226        friend class RpDictEntry<KeyType, ValType>;
227        friend class RpDictIterator<KeyType, ValType>;
228
229        // default constructor
230        RpDict ()
231            : SMALL_RP_DICT_SIZE(4),
232              REBUILD_MULTIPLIER(3),
233              buckets(staticBuckets),
234              numBuckets(SMALL_RP_DICT_SIZE),
235              numEntries(0),
236              rebuildSize(SMALL_RP_DICT_SIZE*REBUILD_MULTIPLIER),
237              downShift(28),
238              mask(3)
239        {
240
241            staticBuckets[0] = staticBuckets[1] = 0;
242            staticBuckets[2] = staticBuckets[3] = 0;
243
244            // setup a dummy entry of NULL
245            nullEntry = new RpDictEntry<KeyType,ValType>();
246
247            // std::cout << "inside RpDict Constructor" << std::endl;
248
249        }
250
251        // copy constructor
252        // RpDict (const RpDict& dict);
253
254        // assignment operator
255        // RpDict& operator=(const RpDict& dict);
256
257        // destructor
258        /*virtual*/ ~RpDict()
259        {
260            // probably need to delete all the entries as well
261            delete nullEntry;
262        }
263        // make sure to go through the hash table and free all RpDictEntries
264        // because the space is malloc'd in RpDict::set()
265
266
267    private:
268        const int SMALL_RP_DICT_SIZE;
269        const int REBUILD_MULTIPLIER;
270
271        RpDictEntry<KeyType,ValType>
272                    **buckets;        /* Pointer to bucket array.  Each
273                                       * element points to first entry in
274                                       * bucket's hash chain, or NULL. */
275        // RpDictEntry *staticBuckets[SMALL_RP_DICT_SIZE];
276        RpDictEntry<KeyType,ValType>
277                    *staticBuckets[4];
278                                      /* Bucket array used for small tables
279                                       * (to avoid mallocs and frees). */
280        int numBuckets;               /* Total number of buckets allocated
281                                       * at **bucketPtr. */
282        int numEntries;               /* Total number of entries present
283                                       * in table. */
284        int rebuildSize;              /* Enlarge table when numEntries gets
285                                       * to be this large. */
286        int downShift;                /* Shift count used in hashing
287                                       * function.  Designed to use high-
288                                       * order bits of randomized keys. */
289        int mask;                     /* Mask value used in hashing
290                                       * function. */
291        RpDictEntry<KeyType,ValType>
292                    *nullEntry;   /* if not const, compiler complains*/
293
294
295
296        // private member fxns
297
298        // static void RpDict::RebuildTable ();
299        void RebuildTable ();
300
301        unsigned int hashFxn(const void* keyPtr) const;
302        unsigned int hashFxn(std::string* keyPtr) const;
303        unsigned int hashFxn(char* keyPtr) const;
304
305        int randomIndex(unsigned int hash);
306};
307
308
309/*--------------------------------------------------------------------------*/
310/*--------------------------------------------------------------------------*/
311
312
313// public RpDict member functions
314
315
316/**************************************************************************
317 *
318 * int RpDict::size()
319 *  retrieve the size of the structure
320 *
321 * Results:
322 *  Returns size of the hash table
323 *
324 * Side Effects:
325 *  none.
326 *
327 *
328 *************************************************************************/
329
330template <typename KeyType, typename ValType>
331const int
332RpDict<KeyType,ValType>::size() const
333{
334    return numEntries;
335}
336
337
338/**************************************************************************
339 *
340 * RpDict::set()
341 *  checks to make sure the table exists.
342 *  places a key/value pair into the hash table
343 *
344 * Results:
345 *  Returns a reference to the RpDict object allowing the user to chain
346 *  together different commands such as
347 *      rpdict_obj.set(key).find(a).erase(a);
348 *
349 * Side Effects:
350 *  if successful, the hash table will have a new entry
351 *
352 *
353 *************************************************************************/
354template <typename KeyType, typename ValType>
355RpDict<KeyType,ValType>&
356RpDict<KeyType,ValType>::set(   KeyType& key,
357                                ValType& value,
358                                int* newPtr)
359{
360    RpDictEntry<KeyType,ValType> *hPtr;
361    unsigned int hash;
362    int index;
363
364    assert(&key);
365    assert(&value);
366
367    // take care of the case where we are creating a NULL key entry.
368    if (&key) {
369        hash = (unsigned int) hashFxn(&key);
370    }
371    else {
372        hash = 0;
373    }
374
375    index = randomIndex(hash);
376
377    /*
378     * Search all of the entries in the appropriate bucket.
379     */
380    for (hPtr = buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) {
381        if (hash != (unsigned int) hPtr->hash) {
382            continue;
383        }
384        // if element already exists in hash, it should not be re-entered
385        if (key == *(hPtr->getKey())){
386
387            // adjust the new flag if it was provided
388            if (newPtr) {
389                *newPtr = 0;
390            }
391
392            // adjust the value if it was provided
393            // memory management is left as an exercize for the caller
394            if (&value) {
395                hPtr->setValue(value);
396            }
397
398            // return a reference to the dictionary object
399            return *this;
400        }
401    }
402
403    /*
404     * Entry not found.  Add a new one to the bucket.
405     */
406
407    if (newPtr) {
408        *newPtr = 1;
409    }
410
411    hPtr = new RpDictEntry<KeyType,ValType>(key,value);
412    // hPtr->setValue(value);
413    //
414    // this is just a pointer that was allocated on the heap
415    // it wont stick with the RpDictEntry after the fxn exits...
416    // need to fix still.
417    hPtr->tablePtr = this;
418    hPtr->hash = hash;
419    hPtr->nextPtr = buckets[index];
420    buckets[index] = hPtr;
421    numEntries++;
422
423    /*
424     * If the table has exceeded a decent size, rebuild it with many
425     * more buckets.
426     */
427
428    if (numEntries >= rebuildSize) {
429        RebuildTable();
430    }
431
432    // return a reference to the original object
433    return *this;
434}
435
436
437/*
438 *----------------------------------------------------------------------
439 *
440 *  RpDict::find(const char *key)
441 *
442 *  Given a hash table find the entry with a matching key.
443 *
444 * Results:
445 *  The return value is a token for the matching entry in the
446 *  hash table, or NULL if there was no matching entry.
447 *
448 * Side effects:
449 *  None.
450 *
451 *----------------------------------------------------------------------
452 */
453
454template <typename KeyType, typename ValType>
455RpDictEntry<KeyType,ValType>&
456RpDict<KeyType,ValType>::find(KeyType& key)
457{
458    RpDictEntry<KeyType,ValType> *hPtr;
459    unsigned int hash;
460    int index;
461
462    assert(&key);
463
464    // take care of the case where we are creating a NULL key entry.
465    if (&key) {
466        hash = (unsigned int) hashFxn(&key);
467    }
468    else {
469        hash = 0;
470    }
471
472    index = randomIndex(hash);
473
474    /*
475     * Search all of the entries in the appropriate bucket.
476     */
477
478    for (hPtr = buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) {
479        if (hash != (unsigned int) hPtr->hash) {
480            continue;
481        }
482        if (key == *(hPtr->getKey())) {
483            // return a reference to the found object
484            return *hPtr;
485        }
486    }
487
488    // return a reference to the null object
489    // find is not supposed to return a const, but i dont want the user
490    // changing this entry's data members... what to do?
491    return *nullEntry;
492
493}
494
495
496
497/**************************************************************************
498 *
499 * virtual RpDict& RpDictIterator::getTable()
500 *  send the search iterator to the beginning of the hash table
501 *
502 * Results:
503 *  returns pointer to the first hash entry of the hash table.
504 *
505 * Side Effects:
506 *  moves iterator to the beginning of the hash table.
507 *
508 *
509 *************************************************************************/
510/*
511template <typename KeyType,typename ValType>
512RpDict<KeyType,ValType>&
513RpDictIterator<KeyType,ValType>::getTable()
514{
515    return tablePtr;
516}
517*/
518
519/**************************************************************************
520 *
521 * virtual RpDictEntry& RpDict::first()
522 *  send the search iterator to the beginning of the hash table
523 *
524 * Results:
525 *  returns pointer to the first hash entry of the hash table.
526 *
527 * Side Effects:
528 *  moves iterator to the beginning of the hash table.
529 *
530 *
531 *************************************************************************/
532template <typename KeyType,typename ValType>
533RpDictEntry<KeyType,ValType>*
534RpDictIterator<KeyType,ValType>::first()
535{
536    srchNextIndex = 0;
537    srchNextEntryPtr = NULL;
538    return next();
539}
540
541/**************************************************************************
542 *
543 * Tcl_HashEntry * RpDict::next()
544 *  send the search iterator to the next entry of the hash table
545 *
546 * Results:
547 *  returns pointer to the next hash entry of the hash table.
548 *  if iterator is at the end of the hash table, NULL is returned
549 *  and the iterator is left at the end of the hash table.
550 *
551 * Side Effects:
552 *  moves iterator to the next entry of the hash table if it exists.
553 *
554 *
555 *************************************************************************/
556
557template <typename KeyType,typename ValType>
558RpDictEntry<KeyType,ValType>*
559RpDictIterator<KeyType,ValType>::next()
560{
561    RpDictEntry<KeyType,ValType>* hPtr;
562
563    while (srchNextEntryPtr == NULL) {
564        if (srchNextIndex >= tablePtr.numBuckets) {
565            return NULL;
566        }
567        srchNextEntryPtr = tablePtr.buckets[srchNextIndex];
568        srchNextIndex++;
569    }
570    hPtr = srchNextEntryPtr;
571    srchNextEntryPtr = hPtr->nextPtr;
572
573    return hPtr;
574}
575
576/**************************************************************************
577 *
578 * RpDict & clear()
579 *  iterate through the table and call erase on each element
580 *
581 * Results:
582 *  empty hash table
583 *
584 * Side Effects:
585 *  every element of the hash table will be erased.
586 *
587 *
588 *************************************************************************/
589template <typename KeyType, typename ValType>
590RpDict<KeyType,ValType>&
591RpDict<KeyType,ValType>::clear()
592{
593    RpDictEntry<KeyType,ValType> *hPtr;
594    RpDictIterator<KeyType,ValType> iter((RpDict&)*this);
595
596    hPtr = iter.first();
597
598    while (hPtr) {
599        hPtr->erase();
600        hPtr = iter.next();
601    }
602
603    return *this;
604}
605
606/**************************************************************************
607 *
608 * RpDict & getNullEntry()
609 *  get the nullEntry hash entry for initialization of references
610 *
611 *
612 * Results:
613 *  nullEntry RpDictEntry related to this dictionary is returned
614 *
615 * Side Effects:
616 *  none
617 *
618 *
619 *************************************************************************/
620template <typename KeyType, typename ValType>
621RpDictEntry<KeyType,ValType>&
622RpDict<KeyType,ValType>::getNullEntry()
623{
624    return *nullEntry;
625}
626
627
628/*
629 *----------------------------------------------------------------------
630 *
631 * void RpDictEntry::erase()
632 *
633 *  Remove a single entry from a hash table.
634 *
635 * Results:
636 *  None.
637 *
638 * Side effects:
639 *  The entry given by entryPtr is deleted from its table and
640 *  should never again be used by the caller.  It is up to the
641 *  caller to free the clientData field of the entry, if that
642 *  is relevant.
643 *
644 *----------------------------------------------------------------------
645 */
646
647template <typename KeyType, typename ValType>
648void
649RpDictEntry<KeyType,ValType>::erase()
650{
651    RpDictEntry<KeyType,ValType> *prevPtr;
652    RpDictEntry<KeyType,ValType> **bucketPtr;
653    int index = 0;
654
655    // check to see if the object is associated with a table
656    // if object is not associated with a table, there is no
657    // need to try to remove it from the table.
658    if (tablePtr) {
659
660        index = tablePtr->randomIndex(hash);
661
662        // calculate which bucket the entry should be in.
663        bucketPtr = &(tablePtr->buckets[index]);
664
665        // remove the entry from the buckets
666        //
667        // if entry is the first entry in the bucket
668        // move the bucket to point to the next entry
669        if ((*bucketPtr)->key == this->key) {
670            *bucketPtr = nextPtr;
671        }
672        else {
673            // if the entry is not the first entry in the bucket
674            // search for the entry
675            for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) {
676
677                // printf("malformed bucket chain in RpDictEntry::erase()");
678                assert(prevPtr != NULL);
679
680                if (prevPtr->nextPtr == this) {
681                    prevPtr->nextPtr = nextPtr;
682                    break;
683                }
684            } // end for loop
685        } // end else
686
687        // update our table's information
688        tablePtr->numEntries--;
689
690    } // end if tablePtr
691
692    // invalidate the object
693    nextPtr = NULL;
694    tablePtr = NULL;
695    hash = 0;
696    // clientData = NULL;
697    // key = NULL;
698
699    // delete the object.
700    delete this;
701
702}
703
704
705/*
706 *----------------------------------------------------------------------
707 *
708 * const char* RpDictEntry::getKey() const
709 *
710 *  retrieve the key of the current object
711 *
712 * Results:
713 *  the key is returned to the caller
714 *
715 * Side effects:
716 *  None.
717 *
718 *----------------------------------------------------------------------
719 */
720
721template <typename KeyType, typename ValType>
722const KeyType*
723RpDictEntry<KeyType,ValType>::getKey() const
724{
725    return (const KeyType*) &key;
726}
727
728/*
729 *----------------------------------------------------------------------
730 *
731 * const char* RpDictEntry::getValue() const
732 *
733 *  retrieve the value of the current object
734 *
735 * Results:
736 *  the value is returned to the caller
737 *
738 * Side effects:
739 *  None.
740 *
741 *----------------------------------------------------------------------
742 */
743
744template <typename KeyType, typename ValType>
745const ValType*
746RpDictEntry<KeyType,ValType>::getValue() const
747{
748    return (const ValType*) &clientData;
749}
750
751/*
752 *----------------------------------------------------------------------
753 *
754 * const void* RpDictEntry::setValue()
755 *
756 *  retrieve the value of the current object
757 *
758 * Results:
759 *  the value is returned to the caller
760 *
761 * Side effects:
762 *  None.
763 *
764 *----------------------------------------------------------------------
765 */
766
767template <typename KeyType, typename ValType>
768const ValType*
769RpDictEntry<KeyType,ValType>::setValue(const ValType& value)
770{
771    clientData = value;
772    return (const ValType*) &clientData;
773}
774
775template <typename KeyType, typename ValType>
776RpDictEntry<KeyType,ValType>::operator int() const
777{
778
779    if (!tablePtr && hash == 0)
780        return 0;
781    else
782        return 1;
783
784//    return (key);
785}
786
787
788/*************************************************************************/
789/*************************************************************************/
790
791// private member functions
792
793/*
794 *----------------------------------------------------------------------
795 *
796 * RebuildTable --
797 *
798 *  This procedure is invoked when the ratio of entries to hash
799 *  buckets becomes too large.  It creates a new table with a
800 *  larger bucket array and moves all of the entries into the
801 *  new table.
802 *
803 * Results:
804 *  None.
805 *
806 * Side effects:
807 *  Memory gets reallocated and entries get re-hashed to new
808 *  buckets.
809 *
810 *----------------------------------------------------------------------
811 */
812
813template <typename KeyType, typename ValType>
814void
815RpDict<KeyType,ValType>::RebuildTable()
816{
817    int oldSize=0, count=0, index=0;
818    RpDictEntry<KeyType,ValType> **oldBuckets;
819    RpDictEntry<KeyType,ValType> **oldChainPtr, **newChainPtr;
820    RpDictEntry<KeyType,ValType> *hPtr;
821
822    void *key;
823
824    oldSize = numBuckets;
825    oldBuckets = buckets;
826
827    /*
828     * Allocate and initialize the new bucket array, and set up
829     * hashing constants for new array size.
830     */
831
832
833    numBuckets *= 4;
834
835    buckets = (RpDictEntry<KeyType,ValType> **) malloc((unsigned)
836        (numBuckets * sizeof(RpDictEntry<KeyType,ValType> *)));
837
838    for (count = numBuckets, newChainPtr = buckets;
839        count > 0;
840        count--, newChainPtr++) {
841
842        *newChainPtr = NULL;
843    }
844
845    rebuildSize *= 4;
846    downShift -= 2;
847    mask = (mask << 2) + 3;
848
849    /*
850     * Rehash all of the existing entries into the new bucket array.
851     */
852
853    for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
854        for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
855            *oldChainPtr = hPtr->nextPtr;
856
857            key = (void *) hPtr->getKey();
858
859            index = randomIndex(hPtr->hash);
860
861            hPtr->nextPtr = buckets[index];
862            buckets[index] = hPtr;
863        }
864    }
865
866    /*
867     * Free up the old bucket array, if it was dynamically allocated.
868     */
869
870    if (oldBuckets != staticBuckets) {
871        free((char *) oldBuckets);
872    }
873}
874
875/*
876 *----------------------------------------------------------------------
877 *
878 * hashFxn --
879 *
880 *  Compute a one-word summary of a text string, which can be
881 *  used to generate a hash index.
882 *
883 * Results:
884 *  The return value is a one-word summary of the information in
885 *  string.
886 *
887 * Side effects:
888 *  None.
889 *
890 *----------------------------------------------------------------------
891 */
892
893template <typename KeyType, typename ValType>
894unsigned int
895RpDict<KeyType,ValType>::hashFxn(const void *keyPtr) const
896{
897    const char *stopAddr = (const char *) keyPtr + sizeof(&keyPtr) - 1 ;
898    const char *str = (const char *) keyPtr;
899    unsigned int result;
900    int c;
901
902    result = 0;
903
904    while (str != stopAddr) {
905        c = *str;
906        result += (result<<3) + c;
907        str++;
908    }
909
910    return result;
911}
912
913/*
914 * Quote from Tcl's hash table code
915 * I tried a zillion different hash functions and asked many other
916 * people for advice.  Many people had their own favorite functions,
917 * all different, but no-one had much idea why they were good ones.
918 * I chose the one below (multiply by 9 and add new character)
919 * because of the following reasons:
920 *
921 * 1. Multiplying by 10 is perfect for keys that are decimal strings,
922 *    and multiplying by 9 is just about as good.
923 * 2. Times-9 is (shift-left-3) plus (old).  This means that each
924 *    character's bits hang around in the low-order bits of the
925 *    hash value for ever, plus they spread fairly rapidly up to
926 *    the high-order bits to fill out the hash value.  This seems
927 *    works well both for decimal and non-decimal strings.
928 */
929
930
931template <typename KeyType, typename ValType>
932unsigned int
933RpDict<KeyType,ValType>::hashFxn(std::string* keyPtr) const
934{
935    const char *str = (const char *) (keyPtr->c_str());
936    unsigned int result;
937    int c;
938
939    result = 0;
940
941    while (1) {
942        c = *str;
943        if (c == 0) {
944            break;
945        }
946        result += (result<<3) + c;
947        str++;
948    }
949
950    return result;
951}
952
953template <typename KeyType, typename ValType>
954unsigned int
955RpDict<KeyType,ValType>::hashFxn(char* keyPtr) const
956{
957    const char *str = (const char *) (keyPtr);
958    unsigned int result;
959    int c;
960
961    result = 0;
962
963    while (1) {
964        c = *str;
965        if (c == 0) {
966            break;
967        }
968        result += (result<<3) + c;
969        str++;
970    }
971
972    return result;
973}
974
975/*
976 * ---------------------------------------------------------------------
977 *
978 * int RpDict::randomIndex(hash)
979 *
980 * The following macro takes a preliminary integer hash value and
981 * produces an index into a hash tables bucket list.  The idea is
982 * to make it so that preliminary values that are arbitrarily similar
983 * will end up in different buckets.  The hash function was taken
984 * from a random-number generator.
985 *
986 * ---------------------------------------------------------------------
987 */
988
989template <typename KeyType, typename ValType>
990int
991RpDict<KeyType,ValType>::randomIndex(unsigned int hash)
992{
993    return (((((long) (hash))*1103515245) >> downShift) & mask);
994}
995
996
997
998#endif
Note: See TracBrowser for help on using the repository browser.