mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-21 13:23:52 +00:00
split record comparator from store
This commit is contained in:
parent
558e0557d0
commit
9995fd324d
2 changed files with 132 additions and 148 deletions
84
apps/openmw/mwworld/storedevel/recordcmp.hpp
Normal file
84
apps/openmw/mwworld/storedevel/recordcmp.hpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
#ifndef OPENMW_MWWORLD_RECORDCMP_H
|
||||
#define OPENMW_MWWORLD_RECORDCMP_H
|
||||
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
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 <class T>
|
||||
bool operator()(const T &x, const T& y) const {
|
||||
return x.mId < y.mId;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
bool RecordCmp::operator()<ESM::Dialogue>(const ESM::Dialogue &x, const ESM::Dialogue &y) const {
|
||||
return StringUtils::ciLess(x.mId, y.mId);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool RecordCmp::operator()<ESM::Cell>(const ESM::Cell &x, const ESM::Cell &y) const {
|
||||
return StringUtils::ciLess(x.mName, y.mName);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool RecordCmp::operator()<ESM::Pathgrid>(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const {
|
||||
return StringUtils::ciLess(x.mCell, y.mCell);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
#endif
|
|
@ -1,97 +1,16 @@
|
|||
#ifndef OPENMW_MWWORLD_STORE_H
|
||||
#define OPENMW_MWWORLD_STORE_H
|
||||
|
||||
#include <cctype>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#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<class T>
|
||||
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()<ESM::Cell>(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()<ESM::Pathgrid>(const ESM::Pathgrid &x, const ESM::Pathgrid &y) {
|
||||
if (mCaseInsensitive) {
|
||||
return CICompareString()(x.mCell, y.mCell);
|
||||
}
|
||||
return x.mCell < y.mCell;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class SharedIterator
|
||||
{
|
||||
|
@ -179,33 +82,27 @@ namespace MWWorld
|
|||
template <class T>
|
||||
class Store : public StoreBase
|
||||
{
|
||||
Compare mComp;
|
||||
std::vector<T> mData;
|
||||
std::vector<T *> mShared;
|
||||
|
||||
public:
|
||||
Store()
|
||||
: mComp(false)
|
||||
{}
|
||||
|
||||
Store(bool ci)
|
||||
: mComp(ci)
|
||||
{}
|
||||
|
||||
Store(const Store<T> &orig)
|
||||
: mComp(orig.mComp), mData(orig.mData)
|
||||
: mData(orig.mData)
|
||||
{}
|
||||
|
||||
typedef SharedIterator<T> iterator;
|
||||
|
||||
const T* search(const std::string &id) const {
|
||||
T item;
|
||||
item.mId = lowerCase(id);
|
||||
item.mId = StringUtils::lowerCase(id);
|
||||
|
||||
typename std::vector<T>::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<T>::iterator it = mData.begin();
|
||||
|
@ -277,6 +155,34 @@ namespace MWWorld
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
void Store<ESM::Dialogue>::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<ESM::Dialogue>::search(const std::string &id) const {
|
||||
ESM::Dialogue item;
|
||||
item.mId = id;
|
||||
|
||||
std::vector<ESM::Dialogue>::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<ESM::Script>::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<ESM::LandTexture> : public StoreBase
|
||||
{
|
||||
|
@ -402,6 +308,7 @@ namespace MWWorld
|
|||
typedef std::vector<ESM::Cell>::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<ESM::Cell> mData;
|
||||
std::vector<ESM::Cell>::iterator mIntBegin, mIntEnd, mExtBegin, mExtEnd;
|
||||
|
||||
public:
|
||||
Store<ESM::Cell>()
|
||||
: 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<ESM::Pathgrid>::const_iterator iterator;
|
||||
|
||||
private:
|
||||
Compare mIntCmp;
|
||||
std::vector<ESM::Pathgrid> mData;
|
||||
|
||||
std::vector<ESM::Pathgrid>::iterator mIntBegin, mIntEnd, mExtBegin, mExtEnd;
|
||||
|
@ -595,9 +498,6 @@ namespace MWWorld
|
|||
};
|
||||
|
||||
public:
|
||||
Store<ESM::Pathgrid>()
|
||||
: 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;
|
||||
|
|
Loading…
Reference in a new issue