From 583f1ae9c285f67646691402fcd07f09573c0ad1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Nov 2013 13:00:46 +0100 Subject: [PATCH] fixed info record ordering and performance problems by determining topic ranges in the record collection instead of in the index collection --- apps/opencs/model/world/collection.hpp | 8 +++ apps/opencs/model/world/infocollection.cpp | 64 +++++++++++----------- apps/opencs/model/world/infocollection.hpp | 6 +- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 1eee36ae9..316e76c5f 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -55,6 +55,8 @@ namespace CSMWorld const std::map& getIdMap() const; + const std::vector >& getRecords() const; + public: Collection(); @@ -138,6 +140,12 @@ namespace CSMWorld return mIndex; } + template + const std::vector >& Collection::getRecords() const + { + return mRecords; + } + template Collection::Collection() {} diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 8e7b6cf01..b5c1872a1 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -39,20 +39,9 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) if (index==-1) { - std::pair range = getTopicRange (topic); + Range range = getTopicRange (topic); - if (range.first==range.second) - index = getIdMap().size(); - else - { - for (; range.first!=range.second; ++range.first) - { - if (range.first->second>index) - index = range.first->second; - } - - ++index; - } + index = std::distance (getRecords().begin(), range.second); } insertRecord (record2, index); @@ -75,11 +64,11 @@ int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string { std::string fullId = Misc::StringUtils::lowerCase (topic) + "#" + id; - std::pair range = getTopicRange (topic); + std::pair range = getTopicRange (topic); for (; range.first!=range.second; ++range.first) - if (range.first->first==fullId) - return std::distance (getIdMap().begin(), range.first); + if (Misc::StringUtils::lowerCase (range.first->get().mId)==fullId) + return std::distance (getRecords().begin(), range.first); return -1; } @@ -91,18 +80,12 @@ int CSMWorld::InfoCollection::getAppendIndex (const std::string& id, UniversalId if (separator==std::string::npos) throw std::runtime_error ("invalid info ID: " + id); - std::pair range = getTopicRange (id.substr (0, separator)); + std::pair range = getTopicRange (id.substr (0, separator)); if (range.first==range.second) return Collection >::getAppendIndex (id, type); - int index = 0; - - for (; range.first!=range.second; ++range.first) - if (range.first->second>index) - index = range.first->second; - - return index+1; + return std::distance (getRecords().begin(), range.second); } void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue) @@ -146,25 +129,40 @@ void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ES } } -std::pair - CSMWorld::InfoCollection::getTopicRange (const std::string& topic) const +CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const std::string& topic) + const { std::string topic2 = Misc::StringUtils::lowerCase (topic); - MapConstIterator begin = getIdMap().lower_bound (topic2); + std::map::const_iterator iter = getIdMap().lower_bound (topic2); // Skip invalid records: The beginning of a topic string could be identical to another topic // string. - for (; begin!=getIdMap().end(); ++begin) - if (Misc::StringUtils::lowerCase (getRecord (begin->second).get().mTopicId)==topic2) + for (; iter!=getIdMap().end(); ++iter) + { + std::string testTopicId = + Misc::StringUtils::lowerCase (getRecord (iter->second).get().mTopicId); + + if (testTopicId==topic2) break; + std::size_t size = topic2.size(); + + if (testTopicId.size()second; + // Find end - MapConstIterator end = begin; + RecordConstIterator end = begin; - for (; end!=getIdMap().end(); ++end) - if (Misc::StringUtils::lowerCase (getRecord (end->second).get().mTopicId)!=topic2) + for (; end!=getRecords().end(); ++end) + if (Misc::StringUtils::lowerCase (end->get().mTopicId)!=topic2) break; - return std::make_pair (begin, end); + return Range (begin, end); } \ No newline at end of file diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index 398f9becc..1bccbb4ae 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -15,7 +15,8 @@ namespace CSMWorld { public: - typedef std::map::const_iterator MapConstIterator; + typedef std::vector >::const_iterator RecordConstIterator; + typedef std::pair Range; private: @@ -34,8 +35,7 @@ namespace CSMWorld void load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue); - std::pair getTopicRange (const std::string& topic) - const; + Range getTopicRange (const std::string& topic) const; ///< Return iterators that point to the beginning and past the end of the range for /// the given topic. };