diff --git a/apps/openmw/mwworld/storedevel/recordcmp.hpp b/apps/openmw/mwworld/storedevel/recordcmp.hpp new file mode 100644 index 000000000..0e2871ba5 --- /dev/null +++ b/apps/openmw/mwworld/storedevel/recordcmp.hpp @@ -0,0 +1,84 @@ +#ifndef OPENMW_MWWORLD_RECORDCMP_H +#define OPENMW_MWWORLD_RECORDCMP_H + +#include +#include +#include + +#include + +namespace MWWorld +{ + /// \todo move this to another location + class StringUtils + { + struct ci + { + bool operator()(int x, int y) const { + return std::tolower(x) < std::tolower(y); + } + }; + + public: + static bool ciLess(const std::string &x, const std::string &y) { + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); + } + + static bool ciEqual(const std::string &x, const std::string &y) { + if (x.size() != y.size()) { + return false; + } + std::string::const_iterator xit = x.begin(); + std::string::const_iterator yit = y.begin(); + for (; xit != x.end(); ++xit, ++yit) { + if (std::tolower(*xit) != std::tolower(*yit)) { + return false; + } + } + return true; + } + + /// Transforms input string to lower case w/o copy + static std::string &toLower(std::string &inout) { + std::transform( + inout.begin(), + inout.end(), + inout.begin(), + (int (*)(int)) std::tolower + ); + return inout; + } + + /// Returns lower case copy of input string + static std::string lowerCase(const std::string &in) + { + std::string out = in; + return toLower(out); + } + }; + + struct RecordCmp + { + template + bool operator()(const T &x, const T& y) const { + return x.mId < y.mId; + } + }; + + template <> + bool RecordCmp::operator()(const ESM::Dialogue &x, const ESM::Dialogue &y) const { + return StringUtils::ciLess(x.mId, y.mId); + } + + template <> + bool RecordCmp::operator()(const ESM::Cell &x, const ESM::Cell &y) const { + return StringUtils::ciLess(x.mName, y.mName); + } + + template <> + bool RecordCmp::operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { + return StringUtils::ciLess(x.mCell, y.mCell); + } + +} // end namespace +#endif diff --git a/apps/openmw/mwworld/storedevel/store.hpp b/apps/openmw/mwworld/storedevel/store.hpp index 14ff11e8a..3a4a7960a 100644 --- a/apps/openmw/mwworld/storedevel/store.hpp +++ b/apps/openmw/mwworld/storedevel/store.hpp @@ -1,97 +1,16 @@ #ifndef OPENMW_MWWORLD_STORE_H #define OPENMW_MWWORLD_STORE_H -#include -#include #include #include -#include #include +#include "recordcmp.hpp" + namespace MWWorld { - std::string lowerCase(const std::string &in) - { - std::string out = in; - std::transform( - in.begin(), - in.end(), - out.begin(), - (int (*)(int)) std::tolower - ); - - return out; - } - - struct CICompareString - { - struct ci - { - bool operator()(int x, int y) { - return std::tolower(x) < std::tolower(y); - } - }; - - bool operator()(const std::string &x, const std::string &y) { - return std::lexicographical_compare( - x.begin(), - x.end(), - y.begin(), - y.end(), - ci() - ); - } - }; - struct StoreBase { - class Compare - { - bool mCaseInsensitive; - - public: - Compare() - : mCaseInsensitive(false) - {} - - Compare(bool ci) - : mCaseInsensitive(ci) - {} - - Compare(const Compare &orig) - : mCaseInsensitive(orig.mCaseInsensitive) - {} - - template - bool operator()(const T &x, const T &y) { - if (mCaseInsensitive) { - return CICompareString()(x.mId, y.mId); - } - return x.mId < y.mId; - } - - bool isCaseInsensitive() const { - return mCaseInsensitive; - } - - bool equalString(const std::string &x, const std::string &y) const { - if (!mCaseInsensitive) { - return x == y; - } - if (x.length() != y.length()) { - return false; - } - std::string::const_iterator xit = x.begin(); - std::string::const_iterator yit = y.begin(); - for (; xit != x.end(); ++xit, ++yit) { - if (std::tolower(*xit) != std::tolower(*yit)) { - return false; - } - } - return true; - } - }; - virtual ~StoreBase() {} virtual void setUp() {} @@ -101,22 +20,6 @@ namespace MWWorld virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; }; - template <> - bool StoreBase::Compare::operator()(const ESM::Cell &x, const ESM::Cell &y) { - if (mCaseInsensitive) { - return CICompareString()(x.mName, y.mName); - } - return x.mName < y.mName; - } - - template <> - bool StoreBase::Compare::operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) { - if (mCaseInsensitive) { - return CICompareString()(x.mCell, y.mCell); - } - return x.mCell < y.mCell; - } - template class SharedIterator { @@ -179,33 +82,27 @@ namespace MWWorld template class Store : public StoreBase { - Compare mComp; std::vector mData; std::vector mShared; public: Store() - : mComp(false) - {} - - Store(bool ci) - : mComp(ci) {} Store(const Store &orig) - : mComp(orig.mComp), mData(orig.mData) + : mData(orig.mData) {} typedef SharedIterator iterator; const T* search(const std::string &id) const { T item; - item.mId = lowerCase(id); + item.mId = StringUtils::lowerCase(id); typename std::vector::const_iterator it = - std::lower_bound(mData.begin(), mData.end(), item, mComp); + std::lower_bound(mData.begin(), mData.end(), item, RecordCmp()); - if (it != mData.end() && mComp.equalString(it->mId, item.mId)) { + if (it != mData.end() && it->mId == item.mId) { return &(*it); } return 0; @@ -222,32 +119,13 @@ namespace MWWorld } void load(ESM::ESMReader &esm, const std::string &id) { - // reduce size of allocated memory to copy mData.push_back(T()); - - // some records requires id before loading - // make sure that string case is the same across container - if (mComp.isCaseInsensitive()) { - mData.back().mId = id; - } else { - mData.back().mId = lowerCase(id); - } + mData.back().mId = StringUtils::lowerCase(id); mData.back().load(esm); - - // allow records to overwrite id on loading - if (!mComp.isCaseInsensitive()) { - std::string &s = mData.back().mId; - std::transform( - s.begin(), - s.end(), - s.begin(), - (int (*)(int)) std::tolower - ); - } } void setUp() { - std::sort(mData.begin(), mData.end(), mComp); + std::sort(mData.begin(), mData.end(), RecordCmp()); mShared.reserve(mData.size()); typename std::vector::iterator it = mData.begin(); @@ -277,6 +155,34 @@ namespace MWWorld } }; + template <> + void Store::load(ESM::ESMReader &esm, const std::string &id) { + mData.push_back(ESM::Dialogue()); + mData.back().mId = id; + mData.back().load(esm); + } + + template <> + const ESM::Dialogue *Store::search(const std::string &id) const { + ESM::Dialogue item; + item.mId = id; + + std::vector::const_iterator it = + std::lower_bound(mData.begin(), mData.end(), item, RecordCmp()); + + if (it != mData.end() && StringUtils::ciEqual(it->mId, id)) { + return &(*it); + } + return 0; + } + + template <> + void Store::load(ESM::ESMReader &esm, const std::string &id) { + mData.push_back(ESM::Script()); + mData.back().load(esm); + StringUtils::toLower(mData.back().mId); + } + template <> class Store : public StoreBase { @@ -402,6 +308,7 @@ namespace MWWorld typedef std::vector::const_iterator iterator; private: + struct ExtCompare { bool operator()(const ESM::Cell &x, const ESM::Cell &y) { @@ -425,24 +332,21 @@ namespace MWWorld } }; - Compare mIntCmp; std::vector mData; std::vector::iterator mIntBegin, mIntEnd, mExtBegin, mExtEnd; public: Store() - : mIntCmp(true) {} - const ESM::Cell *search(const std::string &id) const { ESM::Cell cell; cell.mName = id; iterator it = - std::lower_bound(mIntBegin, mIntEnd, cell, mIntCmp); + std::lower_bound(mIntBegin, mIntEnd, cell, RecordCmp()); - if (it != mIntEnd && mIntCmp.equalString(it->mName, id)) { + if (it != mIntEnd && StringUtils::ciEqual(it->mName, id)) { return &(*it); } return 0; @@ -494,7 +398,7 @@ namespace MWWorld mIntBegin = mData.begin(); mIntEnd = mExtBegin; - std::sort(mIntBegin, mIntEnd, mIntCmp); + std::sort(mIntBegin, mIntEnd, RecordCmp()); std::sort(mExtBegin, mExtEnd, ExtCompare()); } @@ -531,7 +435,7 @@ namespace MWWorld /// \todo implement appropriate index const ESM::Cell *searchExteriorByName(const std::string &id) const { for (iterator it = mExtBegin; it != mExtEnd; ++it) { - if (mIntCmp.equalString(it->mName, id)) { + if (StringUtils::ciEqual(it->mName, id)) { return &(*it); } } @@ -541,7 +445,7 @@ namespace MWWorld /// \todo implement appropriate index const ESM::Cell *searchExteriorByRegion(const std::string &id) const { for (iterator it = mExtBegin; it != mExtEnd; ++it) { - if (mIntCmp.equalString(it->mRegion, id)) { + if (StringUtils::ciEqual(it->mRegion, id)) { return &(*it); } } @@ -567,7 +471,6 @@ namespace MWWorld typedef std::vector::const_iterator iterator; private: - Compare mIntCmp; std::vector mData; std::vector::iterator mIntBegin, mIntEnd, mExtBegin, mExtEnd; @@ -595,9 +498,6 @@ namespace MWWorld }; public: - Store() - : mIntCmp(true) - {} void load(ESM::ESMReader &esm, const std::string &id) { mData.push_back(ESM::Pathgrid()); @@ -621,7 +521,7 @@ namespace MWWorld mIntBegin = mData.begin(); mIntEnd = mExtBegin; - std::sort(mIntBegin, mIntEnd, mIntCmp); + std::sort(mIntBegin, mIntEnd, RecordCmp()); std::sort(mExtBegin, mExtEnd, ExtCompare()); } @@ -652,8 +552,8 @@ namespace MWWorld ESM::Pathgrid pg; pg.mCell = name; - iterator it = std::lower_bound(mIntBegin, mIntEnd, pg, mIntCmp); - if (it != mIntEnd && mIntCmp.equalString(it->mCell, name)) { + iterator it = std::lower_bound(mIntBegin, mIntEnd, pg, RecordCmp()); + if (it != mIntEnd && StringUtils::ciEqual(it->mCell, name)) { return &(*it); } return 0; @@ -804,14 +704,14 @@ namespace MWWorld mData.reserve(ESM::Attribute::Length); } - const ESM::Attribute *search(int index) const { - if (index < 0 || index >= mData.size()) { + const ESM::Attribute *search(size_t index) const { + if (index >= mData.size()) { return 0; } return &mData.at(index); } - const ESM::Attribute *find(int index) const { + const ESM::Attribute *find(size_t index) const { const ESM::Attribute *ptr = search(index); if (ptr == 0) { std::ostringstream msg;