Ticket #8912: kyra_resource_parent_cache_v3.diff

File kyra_resource_parent_cache_v3.diff, 5.8 KB (added by tramboi, 12 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();
    134138
     
    140144        LoaderList _loaders;
    141145        ResFileMap _map;
    142146
     147        ResFileEntry *getParentEntry(const ResFileEntry *entry) const;
     148        ResFileEntry *getParentEntry(const Common::String &filename) const;
     149
    143150        typedef Common::List<Common::SharedPtr<CompArchiveLoader> > CompLoaderList;
    144151        typedef CompLoaderList::iterator CompLoaderIterator;
    145152        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}
     
    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;
     
    420468                if ((iter = _compFiles.find(file)) != _compFiles.end()) {
    421469                        ResFileEntry entry;
    422470                        entry.parent = "";
     471                        entry.parentEntry = NULL;
    423472                        entry.size = iter->_value.size;
    424473                        entry.mounted = false;
    425474                        entry.preload = false;
     
    434483                        if (temp.open(file)) {
    435484                                ResFileEntry entry;
    436485                                entry.parent = "";
     486                                entry.parentEntry = NULL;
    437487                                entry.size = temp.size();
    438488                                entry.mounted = file.compareToIgnoreCase(StaticResource::staticDataFilename()) != 0;
    439489                                entry.preload = false;
     
    451501
    452502void Resource::detectFileTypes() {
    453503        for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) {
    454                 if (!isAccessable(i->_key))
     504                if (!isAccessable(&i->_value))
    455505                        continue;
    456506
    457507                if (i->_value.type == ResFileEntry::kAutoDetect) {
     
    620670                        entry.size = endoffset - startoffset;
    621671                        entry.offset = startoffset;
    622672                        entry.parent = filename;
     673                        entry.parentEntry = NULL;
    623674                        entry.type = ResFileEntry::kAutoDetect;
    624675                        entry.mounted = false;
    625676                        entry.prot = false;
     
    738789        for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {
    739790                ResFileEntry entry;
    740791                entry.parent = filename;
     792                entry.parentEntry = NULL;
    741793                entry.type = ResFileEntry::kAutoDetect;
    742794                entry.mounted = false;
    743795                entry.preload = false;
     
    807859        for (uint i = 0; i < entries; ++i) {
    808860                ResFileEntry entry;
    809861                entry.parent = filename;
     862                entry.parentEntry = NULL;
    810863                entry.type = ResFileEntry::kAutoDetect;
    811864                entry.mounted = false;
    812865                entry.preload = false;