// database tracking which resources use which other resources #include "usageDatabase.h" #include "resourceDatabase.h" #include "common.h" #include "minorGems/util/log/AppLog.h" #include "minorGems/util/SimpleVector.h" #include "Scene.h" #include "StateObject.h" #include "SpriteResource.h" #include "Room.h" #include "Tile.h" #include "Song.h" #include "Scale.h" #include "Music.h" #include "TimbreResource.h" // for platform-independent ptr -> unsigned int casting #include typedef struct usageRecord { uniqueID id; SimpleVector usedByList; SimpleVector usesList; } usageRecord; #define B 2000 class UsageRecordHashTable { public: ~UsageRecordHashTable(); void insert( usageRecord *inRecord ); // does not destroy record void remove( usageRecord *inRecord ); usageRecord *lookup( uniqueID inID ); protected: SimpleVector mBins[B]; }; UsageRecordHashTable::~UsageRecordHashTable() { for( int b=0; b *v = &( mBins[b] ); int numHits = v->size(); for( int i=0; igetElementFast( i ) ); } } } // use first 4 ID bytes as an int #define getHashBin( id ) \ (uintptr_t)( id.bytes[0] | \ id.bytes[1] << 8 | \ id.bytes[2] << 16 | \ id.bytes[3] << 24 ) % B void UsageRecordHashTable::insert( usageRecord *inRecord ) { int b = getHashBin( inRecord->id ); mBins[b].push_back( inRecord ); } void UsageRecordHashTable::remove( usageRecord *inRecord ) { int b = getHashBin( inRecord->id ); mBins[b].deleteElementEqualTo( inRecord ); } usageRecord *UsageRecordHashTable::lookup( uniqueID inID ) { int b = getHashBin( inID ); SimpleVector *v = &( mBins[b] ); int numHits = v->size(); for( int i=0; igetElementFast( i ) ); if( equal( record->id, inID ) ) { return record; } } return NULL; } static usageRecord *addUsage( uniqueID inID, uniqueID inUsesID, usageRecord *inIDRecord ); static UsageRecordHashTable *table; void initUsageDatabase() { table = new UsageRecordHashTable(); printf( "Building usage database\n" ); int addUsageCalls = 0; // scenes use objects and rooms int numScenes = countSearchResults( "scene", "" ); uniqueID *scenes = new uniqueID[ numScenes ]; int numGotten = getSearchResults( "scene", "", 0, numScenes, scenes ); numScenes = numGotten; for( int i=0; ilookup( inID ); } if( r == NULL ) { //printf( "Adding new record\n" ); r = new usageRecord; r->id = inID; table->insert( r ); } r->usesList.push_back( inUsesID ); // allow duplicates, because checking for them is too slow /* else { // record exists. Make sure this usage not already tracked //printf( "Record exists\n" ); int numUses = r->usesList.size(); char found = false; for( int i=0; iusesList.getElementFast( i ) ) ) ) { found = true; } } if( !found ) { // new addition r->usesList.push_back( inUsesID ); } } */ usageRecord *returnValue = r; r = table->lookup( inUsesID ); if( r == NULL ) { r = new usageRecord; r->id = inUsesID; table->insert( r ); } r->usedByList.push_back( inID ); // allow duplicates, because checking for them is too slow /* else { // record exists. Make sure this usage not already tracked int numUsedBy = r->usedByList.size(); char found = false; for( int i=0; iusedByList.getElementFast( i ) ) ) ) { found = true; } } if( !found ) { // new addition r->usedByList.push_back( inID ); } } */ return returnValue; } void addUsage( uniqueID inID, uniqueID inUsesID ) { addUsage( inID, inUsesID, NULL ); } // remove all usages associated with inID // note that because inID is a hash of the using object, removing one // usage from that object means that the ID of the object will change // Thus, we would never be removing a usage from inID unless we were deleting // inID entirely, which means we'd want to remove ALL usages from inID void removeUsages( uniqueID inID ) { // first, make sure it's not used by anything usageRecord *r = table->lookup( inID ); if( r != NULL ) { if( r->usedByList.size() == 0 ) { // walk over all resources that inID uses int numUses = r->usesList.size(); for( int i=0; iusesList.getElementFast( i ); // remove inID from each of these IDs' usedBy lists usageRecord *r2 = table->lookup( *usesID ); if( r2 != NULL ) { // might contain duplicates, so check all for( int j=0; jusedByList.size(); j++ ) { if( equal( inID, *( r2->usedByList.getElementFast( j ) ) ) ) { r2->usedByList.deleteElement( j ); j--; } } } } table->remove( r ); delete r; } else { AppLog::error( "Error: Trying to remove a resource that is " "still used" ); } } } char isUsed( uniqueID inID ) { usageRecord *r = table->lookup( inID ); if( r != NULL ) { if( r->usedByList.size() > 0 ) { return true; } } return false; } uniqueID getUser( uniqueID inID ) { usageRecord *r = table->lookup( inID ); if( r != NULL ) { if( r->usedByList.size() > 0 ) { return *( r->usedByList.getElement( 0 ) ); } } return defaultID; }