Ignore:
Timestamp:
Oct 10, 2005 9:00:37 PM (17 years ago)
Author:
dkearney
Message:

adding initial matlab bindings
few minor changes with other listed files

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/core/RpDict.h

    r38 r97  
    1010
    1111/**************************************************************************/
    12 
    13 
    1412/**************************************************************************/
    1513
     
    183181
    184182
    185        
     183
    186184};
    187185
     
    191189    public:
    192190
    193        
     191
    194192        // functionality for the user to access/adjust data members
    195        
     193
    196194        // checks table size
    197195        /*virtual*/ const int size() const;
     
    250248
    251249        }
    252        
     250
    253251        // copy constructor
    254252        // RpDict (const RpDict& dict);
     
    270268        const int SMALL_RP_DICT_SIZE;
    271269        const int REBUILD_MULTIPLIER;
    272        
     270
    273271        RpDictEntry<KeyType,ValType>
    274272                    **buckets;        /* Pointer to bucket array.  Each
     
    312310/*--------------------------------------------------------------------------*/
    313311
    314 #include "../../src/core/RpDict.cc"
     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
    315997
    316998#endif
Note: See TracChangeset for help on using the changeset viewer.