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