source: trunk/src/core/RpDict.h @ 829

Last change on this file since 829 was 568, checked in by dkearney, 18 years ago

reworking of the Rappture Units code.
Rappture Units no longer creates an object for each metric extension of every
metric unit. Now the metric prefixes are kept in the dictionary as unit objects,
and when a unit is parsed out of the string received from the user, the unit
is checked to see if it acccepts metric prefixes, if so, a search is done for
the prefix. This allows Rappture Units code to more easily tackle case insensitive
unit name searches. Eventually the prefixes will be removed as direct Rappture Units objects and be turned into (possibly a derived object) rappture units prefix objects.

The find function of the core Rappture Units code now accepts
a "hints" function pointer. The function pointer is executed by the dictionary when
the dictionary thinks it found a matching object. This allows the user of the
dictionary to insert different objects with the same key. For Rappture Units,
multiple units objects with the same key can be inserted into the dictionary.
This is important for units like "A" which could stand for angstroms or amperes.

Additionally, the "make metric" functions were removed because the idea of being a
metric unit has been reduced to a flag inside the Rappture Units object and some
newly added logic. The role of setting the metric flag has been added to the define()
function as an additional function input. The fortran and c code has been updated to
reflect the removal of the function. No updates were made to the define function in
the fortran and c code.

The units.test file was also updated with new tests. Old tests were updated, removing
derived units from the list of compatible units. When searching for micro-meters (um),
compatible units of (A,in,m) will be provided instead of (A,in,m,um).

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