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

Last change on this file since 1006 was 962, checked in by dkearney, 17 years ago

code cleanups.
adjusted gague.tcl to check the length of the string it receives for integers and reals.
modified c, matlab, and octave's lib function to handle empty string for creation of empty library.
modified matlab and octave's lib result function to handle status as a parameter.
fixed core library code to deal with incorrect order of translating xml entity references.

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