Ticket #8912: kyra_resource_parent_cache_v6.diff

File kyra_resource_parent_cache_v6.diff, 8.8 KB (added by tramboi, 16 years ago)
  • resource.h

     
    4343
    4444struct ResFileEntry {
    4545        Common::String parent;
     46        mutable ResFileEntry *parentEntry; // Cache to avoid lookup by string in the map
     47                                                                           // No smart invalidation is needed because the map is cleared globally
     48                                                                           // or expanded but no element is ever removed
    4649        uint32 size;
    4750
    4851        bool preload;
     
    129132protected:
    130133        void checkFile(const Common::String &file);
    131134        bool isAccessable(const Common::String &file);
     135        bool isAccessable(const ResFileEntry *fileEntry);
    132136
    133137        void detectFileTypes();
     138        void detectFileType(const Common::String &filename, ResFileEntry *fileEntry);
    134139
    135140        void initializeLoaders();
    136141        const ResArchiveLoader *getLoader(ResFileEntry::kType type) const;
     
    140145        LoaderList _loaders;
    141146        ResFileMap _map;
    142147
     148        ResFileEntry *getParentEntry(const ResFileEntry *entry) const;
     149        ResFileEntry *getParentEntry(const Common::String &filename) const;
     150
    143151        typedef Common::List<Common::SharedPtr<CompArchiveLoader> > CompLoaderList;
    144152        typedef CompLoaderList::iterator CompLoaderIterator;
    145153        typedef CompLoaderList::const_iterator CCompLoaderIterator;
  • resource.cpp

     
    3434
    3535namespace Kyra {
    3636
     37static int sParentCacheHit  = 0;
     38static int sParentCacheMiss = 0;
     39
    3740Resource::Resource(KyraEngine_v1 *vm) : _loaders(), _map(), _vm(vm) {
    3841        initializeLoaders();
    3942}
     
    201204                                                // If the old parent is not protected we mark it as not preload anymore,
    202205                                                // since now no longer all of its embedded files are in the filemap.
    203206                                                oldParent->_value.preload = false;
    204                                                 _map[i->filename] = i->entry;
     207                                                iter->_value = i->entry;
    205208                                        }
    206209                                } else {
    207210                                        // Old parent not found? That's strange... But we just overwrite the old
    208211                                        // entry.
    209                                         _map[i->filename] = i->entry;
     212                                        iter->_value = i->entry;
    210213                                }
    211214                        } else {
    212215                                // The old parent has the same filenames as the new archive, we are sure and overwrite the
    213216                                // old file entry, could be afterall that the preload flag of the new archive was
    214217                                // just unflagged.
    215                                 _map[i->filename] = i->entry;
     218                                iter->_value = i->entry;
    216219                        }
    217220                }
    218221                // 'else' case would mean here overwriting an existing file entry in the map without parent.
     
    381384                Common::SeekableReadStream *parent = getFileStream(iter->_value.parent);
    382385                assert(parent);
    383386
    384                 ResFileMap::const_iterator parentIter = _map.find(iter->_value.parent);
    385                 const ResArchiveLoader *loader = getLoader(parentIter->_value.type);
     387                ResFileEntry* parentEntry = getParentEntry(&iter->_value);
     388                const ResArchiveLoader *loader = getLoader(parentEntry->type);
    386389                assert(loader);
    387390
    388391                return loader->loadFileFromArchive(file, parent, iter->_value);
     
    395398        checkFile(file);
    396399
    397400        ResFileMap::const_iterator iter = _map.find(file);
    398         while (iter != _map.end()) {
    399                 if (!iter->_value.parent.empty()) {
    400                         iter = _map.find(iter->_value.parent);
    401                         if (iter != _map.end()) {
    402                                 // parent can never be a non archive file
    403                                 if (iter->_value.type == ResFileEntry::kRaw)
    404                                         return false;
    405                                 // not mounted parent means not accessable
    406                                 else if (!iter->_value.mounted)
    407                                         return false;
    408                         }
    409                 } else {
    410                         return true;
     401        if (iter == _map.end())
     402                return false;
     403       
     404        return isAccessable(&iter->_value);
     405}
     406
     407bool Resource::isAccessable(const ResFileEntry *fileEntry) {
     408        assert(fileEntry);
     409       
     410        const ResFileEntry* currentEntry = fileEntry;
     411        while (not currentEntry->parent.empty()) {
     412                if (currentEntry->parentEntry) {
     413                        ++sParentCacheHit;
     414                        currentEntry = currentEntry->parentEntry;
    411415                }
     416                else {
     417                        ++sParentCacheMiss;
     418                        ResFileMap::iterator it = _map.find(currentEntry->parent);
     419                        if (it == _map.end())
     420                                return false;
     421                        else
     422                                currentEntry->parentEntry = &it->_value;
     423                }
     424                // parent can never be a non archive file
     425                if (currentEntry->type == ResFileEntry::kRaw)
     426                        return false;
     427                // not mounted parent means not accessable
     428                else if (!currentEntry->mounted)
     429                        return false;
    412430        }
    413         return false;
     431       
     432        return true;
    414433}
    415434
     435ResFileEntry *Resource::getParentEntry(const ResFileEntry *entry) const {
     436        assert(entry);
     437        if (entry->parent.empty())
     438                return NULL;
     439        else if (entry->parentEntry) {
     440                ++sParentCacheHit;
     441                //printf ("%d %d %d\n", sParentCacheHit, sParentCacheMiss, sParentCacheHit+sParentCacheMiss);
     442                assert(_map.find(entry->parent) != _map.end());
     443                assert(entry->parentEntry == &_map.find(entry->parent)->_value);
     444                return entry->parentEntry;
     445        }
     446        else {
     447                ++sParentCacheMiss;
     448                ResFileMap::iterator it = _map.find(entry->parent);
     449                if (it == _map.end())
     450                        return NULL; // If it happens often, the structure maybe deserves a flag to avoid rechecking the map
     451                else {
     452                        entry->parentEntry = &it->_value;
     453                        return entry->parentEntry;
     454                }
     455        }
     456}
     457
     458ResFileEntry *Resource::getParentEntry(const Common::String &filename) const {
     459        ResFileMap::iterator it = _map.find(filename);
     460        assert(it != _map.end());
     461        return getParentEntry(&it->_value);
     462}
     463
    416464void Resource::checkFile(const Common::String &file) {
    417465        if (_map.find(file) == _map.end()) {
    418466                CompFileMap::const_iterator iter;
    419467
    420468                if ((iter = _compFiles.find(file)) != _compFiles.end()) {
    421                         ResFileEntry entry;
     469                        ResFileEntry& entry = _map[file];
    422470                        entry.parent = "";
     471                        entry.parentEntry = NULL;
    423472                        entry.size = iter->_value.size;
    424473                        entry.mounted = false;
    425474                        entry.preload = false;
    426475                        entry.prot = false;
    427476                        entry.type = ResFileEntry::kAutoDetect;
    428477                        entry.offset = 0;
    429                         _map[file] = entry;
    430 
    431                         detectFileTypes();
     478                       
     479                        detectFileType(file, &entry);
    432480                } else if (Common::File::exists(file)) {
    433481                        Common::File temp;
    434482                        if (temp.open(file)) {
    435                                 ResFileEntry entry;
     483                                ResFileEntry& entry = _map[file];
    436484                                entry.parent = "";
     485                                entry.parentEntry = NULL;
    437486                                entry.size = temp.size();
    438487                                entry.mounted = file.compareToIgnoreCase(StaticResource::staticDataFilename()) != 0;
    439488                                entry.preload = false;
    440489                                entry.prot = false;
    441490                                entry.type = ResFileEntry::kAutoDetect;
    442491                                entry.offset = 0;
    443                                 _map[file] = entry;
    444492                                temp.close();
    445493
    446                                 detectFileTypes();
     494                                detectFileType(file, &entry);
    447495                        }
    448496                }
    449497        }
    450498}
    451499
    452 void Resource::detectFileTypes() {
    453         for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) {
    454                 if (!isAccessable(i->_key))
    455                         continue;
     500void Resource::detectFileType(const Common::String &filename, ResFileEntry *fileEntry) {
     501        assert(fileEntry);
     502       
     503        if (!isAccessable(fileEntry))
     504                return;
    456505
    457                 if (i->_value.type == ResFileEntry::kAutoDetect) {
    458                         Common::SeekableReadStream *stream = 0;
    459                         for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) {
    460                                 if (!(*l)->checkFilename(i->_key))
    461                                         continue;
    462                                
    463                                 if (!stream)
    464                                         stream = getFileStream(i->_key);
     506        if (fileEntry->type == ResFileEntry::kAutoDetect) {
     507                Common::SeekableReadStream *stream = 0;
     508                for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) {
     509                        if (!(*l)->checkFilename(filename))
     510                                continue;
     511                       
     512                        if (!stream)
     513                                stream = getFileStream(filename);
    465514
    466                                 if ((*l)->isLoadable(i->_key, *stream)) {
    467                                         i->_value.type = (*l)->getType();
    468                                         i->_value.mounted = false;
    469                                         i->_value.preload = false;
    470                                         break;
    471                                 }
     515                        if ((*l)->isLoadable(filename, *stream)) {
     516                                fileEntry->type = (*l)->getType();
     517                                fileEntry->mounted = false;
     518                                fileEntry->preload = false;
     519                                break;
    472520                        }
    473                         delete stream;
    474                         stream = 0;
     521                }
     522                delete stream;
     523                stream = 0;
    475524
    476                         if (i->_value.type == ResFileEntry::kAutoDetect)
    477                                 i->_value.type = ResFileEntry::kRaw;
    478                 }
     525                if (fileEntry->type == ResFileEntry::kAutoDetect)
     526                        fileEntry->type = ResFileEntry::kRaw;
    479527        }
    480528}
    481529
     530void Resource::detectFileTypes() {
     531        for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i)
     532                detectFileType(i->_key, &i->_value);
     533}
     534
    482535void Resource::tryLoadCompFiles() {
    483536        for (CCompLoaderIterator i = _compLoaders.begin(); i != _compLoaders.end(); ++i) {
    484537                if ((*i)->checkForFiles())
     
    620673                        entry.size = endoffset - startoffset;
    621674                        entry.offset = startoffset;
    622675                        entry.parent = filename;
     676                        entry.parentEntry = NULL;
    623677                        entry.type = ResFileEntry::kAutoDetect;
    624678                        entry.mounted = false;
    625679                        entry.prot = false;
     
    738792        for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {
    739793                ResFileEntry entry;
    740794                entry.parent = filename;
     795                entry.parentEntry = NULL;
    741796                entry.type = ResFileEntry::kAutoDetect;
    742797                entry.mounted = false;
    743798                entry.preload = false;
     
    807862        for (uint i = 0; i < entries; ++i) {
    808863                ResFileEntry entry;
    809864                entry.parent = filename;
     865                entry.parentEntry = NULL;
    810866                entry.type = ResFileEntry::kAutoDetect;
    811867                entry.mounted = false;
    812868                entry.preload = false;