Minor performance gains on loading cell references.

- Use integers where possible
- Unfortunately many functions are simply duplicated for now, but over time the deprecated ones will be removed
pull/1955/head
cc9cii 9 years ago
parent 003b0d48be
commit abe6904a94

@ -6,9 +6,9 @@
void ESM::RefNum::load (ESMReader& esm, bool wide)
{
if (wide)
esm.getHNT (*this, "FRMR", 8);
esm.getHNT (*this, SREC_FRMR, 8);
else
esm.getHNT (mIndex, "FRMR");
esm.getHNT (mIndex, SREC_FRMR);
}
void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const
@ -36,14 +36,14 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum)
// the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system.
// Its only purpose is a performance optimization for "immovable" things. We don't need this, and it's problematic anyway,
// because any item can theoretically be moved by a script.
if (esm.isNextSub ("NAM0"))
if (esm.isNextSub (SREC_NAM0))
esm.skipHSub();
blank();
mRefNum.load (esm, wideRefNum);
mRefID = esm.getHNString ("NAME");
esm.getHNString (SREC_NAME, mRefID);
}
void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted)
@ -180,7 +180,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool
void ESM::CellRef::blank()
{
mRefNum.unset();
mRefID.clear();
mRefID.clear();
mScale = 1;
mOwner.clear();
mGlobalVariable.clear();
@ -196,7 +196,7 @@ void ESM::CellRef::blank()
mTrap.clear();
mReferenceBlocked = -1;
mTeleport = false;
for (int i=0; i<3; ++i)
{
mDoorDest.pos[i] = 0;

@ -128,7 +128,9 @@ enum RecNameInts
enum SubRecNameInts
{
SREC_DELE = ESM::FourCC<'D','E','L','E'>::value,
SREC_NAME = ESM::FourCC<'N','A','M','E'>::value
SREC_NAME = ESM::FourCC<'N','A','M','E'>::value,
SREC_NAM0 = ESM::FourCC<'N','A','M','0'>::value,
SREC_FRMR = ESM::FourCC<'F','R','M','R'>::value
};
}

@ -109,6 +109,12 @@ std::string ESMReader::getHNString(const char* name)
return getHString();
}
void ESMReader::getHNString(const int name, std::string& str)
{
getSubNameIs(name);
getHString(str);
}
std::string ESMReader::getHString()
{
getSubHeader();
@ -130,6 +136,28 @@ std::string ESMReader::getHString()
return getString(mCtx.leftSub);
}
void ESMReader::getHString(std::string& str)
{
getSubHeader();
// Hack to make MultiMark.esp load. Zero-length strings do not
// occur in any of the official mods, but MultiMark makes use of
// them. For some reason, they break the rules, and contain a byte
// (value 0) even if the header says there is no data. If
// Morrowind accepts it, so should we.
if (mCtx.leftSub == 0)
{
// Skip the following zero byte
mCtx.leftRec--;
char c;
getExact(&c, 1);
str = "";
return;
}
getString(str, mCtx.leftSub);
}
void ESMReader::getHExact(void*p, int size)
{
getSubHeader();
@ -159,6 +187,24 @@ void ESMReader::getSubNameIs(const char* name)
+ mCtx.subName.toString());
}
void ESMReader::getSubNameIs(const int name)
{
getSubName();
if (mCtx.subName != name)
{
unsigned char typeName[4];
typeName[0] = name & 0xff;
typeName[1] = (name >> 8) & 0xff;
typeName[2] = (name >> 16) & 0xff;
typeName[3] = (name >> 24) & 0xff;
std::string subName = std::string((char*)typeName, 4);
fail("Expected subrecord " + subName + " but got "
+ mCtx.subName.toString());
}
}
bool ESMReader::isNextSub(const char* name)
{
if (!mCtx.leftRec)
@ -174,6 +220,21 @@ bool ESMReader::isNextSub(const char* name)
return !mCtx.subCached;
}
bool ESMReader::isNextSub(const int name)
{
if (!mCtx.leftRec)
return false;
getSubName();
// If the name didn't match, then mark the it as 'cached' so it's
// available for the next call to getSubName.
mCtx.subCached = (mCtx.subName != name);
// If subCached is false, then subName == name.
return !mCtx.subCached;
}
bool ESMReader::peekNextSub(const char *name)
{
if (!mCtx.leftRec)
@ -347,6 +408,26 @@ std::string ESMReader::getString(int size)
return std::string (ptr, size);
}
void ESMReader::getString(std::string& str, int size)
{
size_t s = size;
if (mBuffer.size() <= s)
// Add some extra padding to reduce the chance of having to resize again later.
mBuffer.resize(3*s);
mBuffer[s] = 0; // And make sure the string is zero terminated
char *ptr = &mBuffer[0];
getExact(ptr, size); // read ESM data
size = static_cast<int>(strnlen(ptr, size));
if (mEncoder)
str = mEncoder->getUtf8(ptr, size); // Convert to UTF8 and return
else
str = std::string (ptr, size);
}
void ESMReader::fail(const std::string &msg)
{
using namespace std;

@ -103,6 +103,13 @@ public:
getHT(x);
}
template <typename X>
void getHNT(X &x, const int name)
{
getSubNameIs(name);
getHT(x);
}
// Optional version of getHNT
template <typename X>
void getHNOT(X &x, const char* name)
@ -121,6 +128,14 @@ public:
getHT(x);
}
template <typename X>
void getHNT(X &x, const int name, int size)
{
assert(sizeof(X) == size);
getSubNameIs(name);
getHT(x);
}
template <typename X>
void getHNOT(X &x, const char* name, int size)
{
@ -159,9 +174,11 @@ public:
// Read a string with the given sub-record name
std::string getHNString(const char* name);
void getHNString(const int name, std::string& str);
// Read a string, including the sub-record header (but not the name)
std::string getHString();
void getHString(std::string& str);
// Read the given number of bytes from a subrecord
void getHExact(void*p, int size);
@ -177,6 +194,7 @@ public:
// Get the next subrecord name and check if it matches the parameter
void getSubNameIs(const char* name);
void getSubNameIs(const int name);
/** Checks if the next sub record name matches the parameter. If it
does, it is read into 'subName' just as if getSubName() was
@ -184,6 +202,7 @@ public:
calls to getSubName(), isNextSub() and getSubNameIs().
*/
bool isNextSub(const char* name);
bool isNextSub(const int name);
bool peekNextSub(const char* name);
@ -256,6 +275,7 @@ public:
// Read the next 'size' bytes and return them as a string. Converts
// them from native encoding to UTF8 in the process.
std::string getString(int size);
void getString(std::string& str, int size);
void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); }
uint64_t getOffset() { return mEsm->tell(); }

Loading…
Cancel
Save