split record comparator from store

actorid
greye 12 years ago
parent 558e0557d0
commit 9995fd324d

@ -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…
Cancel
Save