- started reorganizing SW's memory management.

Need to get rid of all those unmanaged allocations and present game data in an easily serializable form.
This adds a managed TPointer class that replicates the useful parts of std::unique_pointer but steers clear of its properties that often render it useless.
This commit is contained in:
Christoph Oelckers 2021-04-02 10:28:18 +02:00
parent 588fa5ffe2
commit dcb393bc44
5 changed files with 175 additions and 17 deletions

View file

@ -269,6 +269,32 @@ FSerializer &Serialize(FSerializer &arc, const char *key, TArray<T, TT> &value,
return arc; return arc;
} }
template<class T, class TT>
FSerializer& Serialize(FSerializer& arc, const char* key, TPointer<T>& value, TPointer<T>* def)
{
if (arc.isWriting())
{
if (value.Data() == nullptr && key) return arc;
}
bool res = arc.BeginArray(key);
if (arc.isReading())
{
if (!res || arc.ArraySize() == 0)
{
value.Clear();
return arc;
}
value.Alloc();
}
if (value.Data())
{
Serialize(arc, nullptr, *value, def ? def->Data() : nullptr);
}
arc.EndArray();
return arc;
}
template<int size> template<int size>
FSerializer& Serialize(FSerializer& arc, const char* key, FixedBitArray<size>& value, FixedBitArray<size>* def) FSerializer& Serialize(FSerializer& arc, const char* key, FixedBitArray<size>& value, FixedBitArray<size>* def)
{ {

View file

@ -1368,6 +1368,128 @@ protected:
}; };
// Pointer wrapper without the unpleasant side effects of std::unique_ptr, mainly the inability to copy it.
// This class owns the object with no means to release it, and copying the pointer copies the object.
template <class T>
class TPointer
{
public:
////////
TPointer()
{
Ptr = nullptr;
}
TPointer(const T& other)
{
Alloc();
*Ptr = other;
}
TPointer(T&& other)
{
Alloc();
*Ptr = other;
}
TPointer(const TPointer<T>& other)
{
DoCopy(other);
}
TPointer(TPointer<T>&& other)
{
Ptr = other.Ptr;
other.Ptr = nullptr;
}
TPointer<T>& operator= (const T& other)
{
if (&other != this)
{
Alloc();
*Ptr = other;
}
return *this;
}
TPointer<T>& operator= (const TPointer<T>& other)
{
if (&other != this)
{
DoCopy(other);
}
return *this;
}
TPointer<T>& operator= (TPointer<T>&& other)
{
if (&other != this)
{
if (Ptr) delete Ptr;
Ptr = other.Ptr;
other.Ptr = nullptr;
}
return *this;
}
~TPointer()
{
if (Ptr) delete Ptr;
Ptr = nullptr;
}
// Check equality of two pointers
bool operator==(const TPointer<T>& other) const
{
return *Ptr == *other.Ptr;
}
T& operator* () const
{
assert(Ptr);
return *Ptr;
}
T* operator->() { return Ptr; }
// returns raw pointer
T* Data() const
{
return Ptr;
}
operator T* () const
{
return Ptr;
}
void Alloc()
{
if (!Ptr) Ptr = new T;
}
void Clear()
{
if (Ptr) delete Ptr;
Ptr = nullptr;
}
void Swap(TPointer<T>& other)
{
std::swap(Ptr, other.Ptr);
}
private:
T* Ptr;
void DoCopy(const TPointer<T>& other)
{
if (other.Ptr == nullptr)
{
Clear();
}
else
{
Alloc();
*Ptr = *other.Ptr;
}
}
};
//========================================================================== //==========================================================================
// //

View file

@ -1115,12 +1115,22 @@ typedef struct
// User Extension record // User Extension record
// //
typedef struct struct USER
{ {
// These are for easy zero-init of USERs without having to be on the lookout for non-trivial members.
void* operator new(size_t alloc)
{
return M_Calloc(alloc, 1);
}
void operator delete (void* mem)
{
M_Free(mem);
}
// //
// Variables that can be used by actors and Player // Variables that can be used by actors and Player
// //
ROTATORp rotator; TPointer<ROTATOR> rotator;
// wall vars for lighting // wall vars for lighting
int WallCount; int WallCount;
@ -1269,7 +1279,9 @@ typedef struct
int16_t oangdiff; // Used for interpolating sprite angles int16_t oangdiff; // Used for interpolating sprite angles
uint8_t filler; uint8_t filler;
} USER,*USERp; };
using USERp = USER*;
struct USERSAVE struct USERSAVE
{ {
@ -1440,21 +1452,15 @@ typedef struct
} RANGE,*RANGEp; } RANGE,*RANGEp;
inline void ClearUser(USER* user) #pragma message ("Remove NewUser/FreeUser!")
{
*user = {};
}
inline USER* NewUser() inline USER* NewUser()
{ {
auto u = (USER*)M_Calloc(sizeof(USER), 1);// new USER; return new USER;
ClearUser(u);
return u;
} }
inline void FreeUser(int num) inline void FreeUser(int num)
{ {
if (User[num]) M_Free(User[num]);// delete User[num]; if (User[num]) delete User[num];
User[num] = nullptr; User[num] = nullptr;
} }

View file

@ -747,7 +747,11 @@ bool GameInterface::LoadGame()
while (SpriteNum != -1) while (SpriteNum != -1)
{ {
User[SpriteNum] = u = NewUser(); User[SpriteNum] = u = NewUser();
// We need to be careful with allocated content in User when loading a binary save state.
// This needs to be refactored out ASAP.
u->rotator.Clear();
MREAD(u,sizeof(USER),1,fil); MREAD(u,sizeof(USER),1,fil);
memset((void*)&u->rotator, 0, sizeof(u->rotator));
if (u->WallShade) if (u->WallShade)
{ {
@ -757,7 +761,7 @@ bool GameInterface::LoadGame()
if (u->rotator) if (u->rotator)
{ {
u->rotator = (ROTATORp)CallocMem(sizeof(*u->rotator), 1); u->rotator.Alloc();
MREAD(u->rotator,sizeof(*u->rotator),1,fil); MREAD(u->rotator,sizeof(*u->rotator),1,fil);
if (u->rotator->origx) if (u->rotator->origx)

View file

@ -790,7 +790,8 @@ KillSprite(int16_t SpriteNum)
FreeMem(u->rotator->origx); FreeMem(u->rotator->origx);
if (u->rotator->origy) if (u->rotator->origy)
FreeMem(u->rotator->origy); FreeMem(u->rotator->origy);
FreeMem(u->rotator);
u->rotator.Clear();
} }
FreeUser(SpriteNum); FreeUser(SpriteNum);
@ -909,7 +910,6 @@ SpawnUser(short SpriteNum, short id, STATEp state)
u->WaitTics = 0; u->WaitTics = 0;
u->OverlapZ = Z(4); u->OverlapZ = Z(4);
u->WallShade = NULL; u->WallShade = NULL;
u->rotator = NULL;
u->bounce = 0; u->bounce = 0;
u->motion_blur_num = 0; u->motion_blur_num = 0;
@ -2404,7 +2404,7 @@ SpriteSetup(void)
for (w = startwall, wallcount = 0; w <= endwall; w++) for (w = startwall, wallcount = 0; w <= endwall; w++)
wallcount++; wallcount++;
u->rotator = (ROTATORp)CallocMem(sizeof(ROTATOR), 1); u->rotator.Alloc();
u->rotator->num_walls = wallcount; u->rotator->num_walls = wallcount;
u->rotator->open_dest = SP_TAG5(sp); u->rotator->open_dest = SP_TAG5(sp);
u->rotator->speed = SP_TAG7(sp); u->rotator->speed = SP_TAG7(sp);
@ -2460,7 +2460,7 @@ SpriteSetup(void)
u->WaitTics = time*15; // 1/8 of a sec u->WaitTics = time*15; // 1/8 of a sec
u->Tics = 0; u->Tics = 0;
u->rotator = (ROTATORp)CallocMem(sizeof(ROTATOR), 1); u->rotator.Alloc();
u->rotator->open_dest = SP_TAG5(sp); u->rotator->open_dest = SP_TAG5(sp);
u->rotator->speed = SP_TAG7(sp); u->rotator->speed = SP_TAG7(sp);
u->rotator->vel = SP_TAG8(sp); u->rotator->vel = SP_TAG8(sp);