home *** CD-ROM | disk | FTP | other *** search
- /********************************************************************
- CDictionary.c
-
- see header for information
-
- SUPERCLASS = CCollection
- ********************************************************************/
-
-
- #include "CDictionary.h"
- #include "CDataFile.h"
- #include "CApplication.h"
- #include "CError.h"
- #include "TBUtilities.h"
-
- #define kMintableSize 64L /* minimum table size */
-
- /* macro to calculate address of a bucket in the hash table
- can't use C arrays because entry size is determined
- at runtime */
-
- #define ASSOCIATION( bucketNum) \
- ((tAssociationPtr) (*table + ((Int32)bucketNum * slotSize)))
-
- #define EMPTY ((void*) 0L)
- #define DELETED ((void*) -1L)
- #define VACANT( assocPtr) \
- ((assocPtr->value == EMPTY)||(assocPtr->value == DELETED))
- #define NOT_FOUND (-1L)
-
- extern CApplication *gApplication;
- extern CError *gError;
-
-
- /********************************************************************/
- Boolean CDictionary::IDictionary( Int16 keySize, MapProc map, CompareProc compare,
- Int32 initialSize)
- /*
- initialize a Dictionary, return false if no error.
- */
- {
- Int32 sizeNeeded;
- register Int16 power2;
- register Int32 bits;
-
- CCollection::ICollection();
-
- /* get initial table size */
-
- this->map = map;
- this->compare = compare;
- this->keySize = keySize;
- this->slotSize = keySize + sizeof( CObject*);
-
- /* tableSize must be power of 2 >= kMinTableSize */
- initialSize = MAX( initialSize, kMintableSize);
-
- /* find greatest power of 2 <= initialSize */
- power2 = 0; bits = initialSize;
- while (bits >>= 1) power2++;
-
- /* if initialSize was power of 2 use it, else get next highest */
- tableSize = initialSize == 1 << power2 ? initialSize : 1 << (power2 + 1);
- slotsLeft = tableSize;
-
- /* calculate size of hash table and allocate the memory */
-
- sizeNeeded = tableSize * (Int32) slotSize;
-
- gApplication->RequestMemory( FALSE, TRUE);
- table = NewHandleClear( sizeNeeded);
- gApplication->RequestMemory( FALSE, FALSE);
-
- if (!table) return TRUE;
- MoveHHi( table);
-
- return FALSE;
-
- } /* CDictionary::IDictionary */
- /********************************************************************/
- void CDictionary::Add( void *key, CObject *value)
- {
- Int32 hash, curr;
-
- /* always leave at least one empty slot as sentinel */
-
- if (slotsLeft <= 1) MoreSlots();
-
- /* map key to value and do simple mod to get table index */
- curr = hash = map( key) & (tableSize -1);
-
- while( !VACANT(ASSOCIATION(curr)))
- {
- /* if the key is already present then replace its
- value and return */
- if(compare( key, (void*) ASSOCIATION(curr)->key) )
- {
- ASSOCIATION(curr)->value = value;
- return;
- }
- if (++curr == tableSize) curr = 0; /* linear probing with wraparound */
- }
- /* curr now points to a vacant slot */
-
- ASSOCIATION(curr)->value = value;
- BlockMove( key, ASSOCIATION(curr)->key, keySize);
- numItems++;
- slotsLeft--;
-
- } /* CDictionary::Add */
- /********************************************************************/
- /* iterator for dictionary to add */
- static void DICT_AddAssoc( tAssociationPtr anAssoc, Int32 targetDict)
- {
- ((CDictionary*) targetDict)->Add( anAssoc->key, anAssoc->value);
-
- } /* DICT_AddAssoc */
-
-
- void CDictionary::AddAll( CDictionary *aDictionary)
- {
- aDictionary->DoForEach1( DICT_AddAssoc, (Int32)this);
-
- } /* CDictionary::AddAll */
- /********************************************************************/
- void CDictionary::Remove( void *key)
- {
- Int32 index = _lookup( key);
-
- if (index != NOT_FOUND)
- {
- ASSOCIATION( index)->value = DELETED;
- numItems--;
- }
-
- } /* CDictionary::Remove */
- /********************************************************************/
- Boolean CDictionary::IncludesKey( void *key)
- {
- return (_lookup( key) != NOT_FOUND);
-
- } /* CDictionary::IncludesKey */
- /********************************************************************/
- Boolean CDictionary::IncludesValue( CObject *anObject)
- {
- Int32 i;
- tAssociationPtr assoc;
-
- for (i = 0; i < tableSize; i++)
- {
- assoc = ASSOCIATION(i);
- if (!VACANT( assoc))
- {
- if (anObject == assoc->value)
- return TRUE;
- }
- }
- return FALSE;
-
- } /* CDictionary::IncludesValue */
- /********************************************************************/
- void CDictionary::DoForEach( DictIterator actionProc)
- {
- Int32 i;
- tAssociationPtr assoc;
- SignedByte hState;
-
- /* since we pass the iterator a pointer to our data,
- it is safer to lock the table down so the pointer
- remains valid */
-
- MoveHHi( table);
- hState = HGetState( table);
- HLock( table);
- for (i = 0; i < tableSize; i++)
- {
- assoc = ASSOCIATION(i);
- if (!VACANT( assoc))
- actionProc( assoc);
- }
- HSetState( table, hState);
-
- } /* CDictionary::DoForEach */
- /********************************************************************/
- void CDictionary::DoForEach1( DictIterator1 actionProc, Int32 aParam)
- {
- Int32 i;
- tAssociationPtr assoc;
- SignedByte hState;
-
- MoveHHi( table);
- hState = HGetState( table);
- HLock( table);
- for (i = 0; i < tableSize; i++)
- {
- assoc = ASSOCIATION(i);
- if (!VACANT( assoc))
- actionProc( assoc, aParam);
- }
- HSetState( table, hState);
-
- } /* CDictionary::DoForEach1 */
- /********************************************************************/
- CObject *CDictionary::Lookup( void *key)
- {
- Int32 index = _lookup( key);
-
- return( index == NOT_FOUND? NIL : ASSOCIATION( index)->value);
-
- } /* CDictionary::Lookup */
- /********************************************************************/
- Int32 CDictionary::_lookup( void *key)
- /*
- private routine to lookup a key in the hash table.
- Given a key, either returns its index (a positive long),
- or NOT_FOUND.
- */
- { register Int32 curr;
-
- curr = map( key) & (tableSize -1);
-
- while(ASSOCIATION(curr)->value != EMPTY &&
- (ASSOCIATION(curr)->value == DELETED ? 1:!compare( key,ASSOCIATION(curr)->key)))
- {
- if (++curr == tableSize) curr = 0;
- }
- return (ASSOCIATION(curr)->value == EMPTY ? NOT_FOUND : curr);
-
- } /* CDictionary::_lookup */
- /********************************************************************/
- CObject *CDictionary::Copy( void)
- {
- CDictionary *newDict = (CDictionary *) inherited::Copy();
- Handle tableCopy = table;
-
- newDict->table = NIL;
- HandToHand( &tableCopy);
- if (!gError->CheckOSError( MemError()))
- {
- newDict->Dispose();
- return NIL;
- }
- MoveHHi( tableCopy);
- newDict->table = tableCopy;
- newDict->itsFile = NIL;
- return newDict;
-
- } /* CDictionary::Copy */
- /********************************************************************/
- void CDictionary::MoreSlots( void)
- /*
- called when we need to grow the table.
- */
- { CDictionary *tmpDict;
- Int32 newSize;
-
- tmpDict = (CDictionary*) Copy();/* make temporary copy of dictionary */
- if (tmpDict)
- {
- tableSize <<= 1;
- newSize = tableSize * slotSize;
- DisposHandle( table);
- gApplication->RequestMemory( FALSE, TRUE);
- table = NewHandleClear( newSize);
- gApplication->RequestMemory( FALSE, FALSE);
- if (!table) gError->SevereMacError( memFullErr);
- MoveHHi( table);
-
- numItems = 0;
- slotsLeft = tableSize;
- AddAll( tmpDict);
- tmpDict->Dispose();
- }
- else gError->SevereMacError( memFullErr);
-
- } /* CDictionary::MoreSlots */
- /********************************************************************/
- void CDictionary::Dispose( void)
- {
- if (table) DisposHandle( table);
- inherited::Dispose();
-
- } /* CDictionary::Dispose */
- /********************************************************************/
- void CDictionary::DisposeAll( void)
- {
- DisposeItems();
- Dispose();
-
- } /* CDictionary::DisposeAll */
- /********************************************************************/
- /* iterator for disposing items */
- static void DICT_DisposeItems( tAssociationPtr anAssoc)
- {
- if (anAssoc->value) anAssoc->value->Dispose();
-
- } /* DICT_DisposeItems */
-
- void CDictionary::DisposeItems( void)
- {
- DoForEach( DICT_DisposeItems);
- numItems = 0;
-
- } /* CDictionary::DisposeItems */
- /********************************************************************/
-