1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-11-30 11:34:32 +00:00

Check Nif::RecordPtrT in debug builds

To verify class invariant.
This commit is contained in:
elsid 2025-09-20 12:42:32 +02:00
parent 0c2164330b
commit 434f450778
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40

View file

@ -19,6 +19,16 @@ namespace Nif
template <class X>
class RecordPtrT
{
#ifndef NDEBUG
enum class State
{
Index,
Ptr,
};
State mState;
#endif
union
{
intptr_t mIndex;
@ -27,12 +37,22 @@ namespace Nif
public:
RecordPtrT()
: mIndex(-2)
:
#ifndef NDEBUG
mState(State::Index)
,
#endif
mIndex(-2)
{
}
RecordPtrT(X* ptr)
: mPtr(ptr)
:
#ifndef NDEBUG
mState(State::Ptr)
,
#endif
mPtr(ptr)
{
}
@ -40,6 +60,9 @@ namespace Nif
void read(NIFStream* nif)
{
// Can only read the index once
#ifndef NDEBUG
assert(mState == State::Index);
#endif
assert(mIndex == -2);
// Store the index for later
@ -53,6 +76,10 @@ namespace Nif
/// Resolve index to pointer
void post(Reader& nif)
{
#ifndef NDEBUG
assert(mState == State::Index);
#endif
if (mIndex < 0)
mPtr = nullptr;
else
@ -61,34 +88,66 @@ namespace Nif
if (r == nullptr)
throw std::runtime_error(std::format("Record at {} is nullptr", mIndex));
// And cast it
mPtr = dynamic_cast<X*>(r);
if (mPtr == nullptr)
X* const ptr = dynamic_cast<X*>(r);
if (ptr == nullptr)
throw std::runtime_error(std::format("Failed to cast record pointer to {}", typeid(X).name()));
mPtr = ptr;
}
#ifndef NDEBUG
mState = State::Ptr;
#endif
}
/// Look up the actual object from the index
const X* getPtr() const
{
#ifndef NDEBUG
assert(mState == State::Ptr);
#endif
assert(mPtr != nullptr);
return mPtr;
}
X* getPtr()
{
#ifndef NDEBUG
assert(mState == State::Ptr);
#endif
assert(mPtr != nullptr);
return mPtr;
}
const X& get() const { return *getPtr(); }
X& get() { return *getPtr(); }
const X& get() const
{
return *getPtr();
}
X& get()
{
return *getPtr();
}
/// Syntactic sugar
const X* operator->() const { return getPtr(); }
X* operator->() { return getPtr(); }
const X* operator->() const
{
return getPtr();
}
X* operator->()
{
return getPtr();
}
/// Pointers are allowed to be empty
bool empty() const { return mPtr == nullptr; }
bool empty() const
{
#ifndef NDEBUG
assert(mState == State::Ptr);
#endif
return mPtr == nullptr;
}
};
/** A list of references to other records. These are read as a list,