From 5e623a2a1d06d5679f214cad95123a1d3bd88b34 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 14 Jul 2015 16:18:33 +0300 Subject: [PATCH] Rework RefIdData code. Update the index map when a new record is loaded --- apps/opencs/model/world/refiddata.cpp | 30 +++++++++-- apps/opencs/model/world/refiddata.hpp | 73 +++++++++++---------------- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 68f3fc4ad6..e7b36015e3 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -3,10 +3,20 @@ #include -#include - CSMWorld::RefIdDataContainerBase::~RefIdDataContainerBase() {} + +std::string CSMWorld::RefIdData::getRecordId(const CSMWorld::RefIdData::LocalIndex &index) const +{ + std::map::const_iterator found = + mRecordContainers.find (index.second); + + if (found == mRecordContainers.end()) + throw std::logic_error ("invalid local index type"); + + return found->second->getId(index.first); +} + CSMWorld::RefIdData::RefIdData() { mRecordContainers.insert (std::make_pair (UniversalId::Type_Activator, &mActivators)); @@ -167,9 +177,21 @@ void CSMWorld::RefIdData::load (ESM::ESMReader& reader, bool base, CSMWorld::Uni mRecordContainers.find (type); if (found == mRecordContainers.end()) - throw std::logic_error ("Invalid type for an Object (Reference ID)"); + throw std::logic_error ("Invalid Referenceable ID type"); - found->second->load(reader, base); + int index = found->second->load(reader, base); + if (index != -1) + { + LocalIndex localIndex = LocalIndex(index, type); + if (base && getRecord(localIndex).mState == RecordBase::State_Deleted) + { + erase(localIndex, 1); + } + else + { + mIndex[Misc::StringUtils::lowerCase(getRecordId(localIndex))] = localIndex; + } + } } void CSMWorld::RefIdData::erase (const LocalIndex& index, int count) diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 17d9139115..195244ba89 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -25,6 +25,8 @@ #include #include +#include + #include "record.hpp" #include "universalid.hpp" @@ -49,7 +51,8 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record) = 0; - virtual void load (ESM::ESMReader& reader, bool base) = 0; + virtual int load (ESM::ESMReader& reader, bool base) = 0; + ///< \return index of a loaded record or -1 if no record was loaded virtual void erase (int index, int count) = 0; @@ -73,7 +76,8 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record); - virtual void load (ESM::ESMReader& reader, bool base); + virtual int load (ESM::ESMReader& reader, bool base); + ///< \return index of a loaded record or -1 if no record was loaded virtual void erase (int index, int count); @@ -122,15 +126,16 @@ namespace CSMWorld } template - void RefIdDataContainer::load (ESM::ESMReader& reader, bool base) + int RefIdDataContainer::load (ESM::ESMReader& reader, bool base) { RecordT record; record.load(reader); - typename std::vector >::iterator found = mContainer.begin(); - for (; found != mContainer.end(); ++found) + int index = 0; + int numRecords = static_cast(mContainer.size()); + for (; index < numRecords; ++index) { - if (found->get().mId == record.mId) + if (Misc::StringUtils::ciEqual(mContainer[index].get().mId, record.mId)) { break; } @@ -138,26 +143,21 @@ namespace CSMWorld if (record.mIsDeleted) { - if (found == mContainer.end()) + if (index == numRecords) { // deleting a record that does not exist // ignore it for now /// \todo report the problem to the user - return; + return -1; } - if (base) - { - mContainer.erase(found); - } - else - { - found->mState = RecordBase::State_Deleted; - } + // Flag the record as Deleted even for a base content file. + // RefIdData is responsible for its erasure. + mContainer[index].mState = RecordBase::State_Deleted; } else { - if (found == mContainer.end()) + if (index == numRecords) { appendRecord(record.mId, base); if (base) @@ -169,20 +169,13 @@ namespace CSMWorld mContainer.back().mModified = record; } } - else + else if (!base) { - if (!base) - { - if (found->mState == RecordBase::State_Erased) - { - throw std::logic_error("Attempt to access a deleted record"); - } - - found->mState = RecordBase::State_Modified; - found->mModified = record; - } + mContainer[index].setModified(record); } } + + return index; } template @@ -204,25 +197,15 @@ namespace CSMWorld void RefIdDataContainer::save (int index, ESM::ESMWriter& writer) const { Record record = mContainer.at(index); - RecordT esmRecord; + RecordT esmRecord = record.get(); - switch (record.mState) + if (record.isModified() || record.mState == RecordBase::State_Deleted) { - case RecordBase::State_Modified: - case RecordBase::State_ModifiedOnly: - esmRecord = record.mModified; - break; - case RecordBase::State_Deleted: - esmRecord = record.mBase; - esmRecord.mIsDeleted = true; - break; - default: - break; + esmRecord.mIsDeleted = (record.mState == RecordBase::State_Deleted); + writer.startRecord(esmRecord.sRecordId); + esmRecord.save(writer); + writer.endRecord(esmRecord.sRecordId); } - - writer.startRecord(esmRecord.sRecordId); - esmRecord.save(writer); - writer.endRecord(esmRecord.sRecordId); } @@ -262,6 +245,8 @@ namespace CSMWorld void erase (const LocalIndex& index, int count); ///< Must not spill over into another type. + std::string getRecordId(const LocalIndex &index) const; + public: RefIdData();