mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 05:51:20 +00:00
fix Dictionary and DictionaryIterator memory leaks
This commit is contained in:
parent
70f9b649aa
commit
3607ffaf66
6 changed files with 200 additions and 75 deletions
|
@ -843,21 +843,6 @@ void InitThingdef()
|
||||||
wbplayerstruct->Size = sizeof(wbplayerstruct_t);
|
wbplayerstruct->Size = sizeof(wbplayerstruct_t);
|
||||||
wbplayerstruct->Align = alignof(wbplayerstruct_t);
|
wbplayerstruct->Align = alignof(wbplayerstruct_t);
|
||||||
|
|
||||||
auto dictionarystruct = NewStruct("Dictionary", nullptr, true);
|
|
||||||
dictionarystruct->Size = sizeof(Dictionary);
|
|
||||||
dictionarystruct->Align = alignof(Dictionary);
|
|
||||||
NewPointer(dictionarystruct, false)->InstallHandlers(
|
|
||||||
[](FSerializer &ar, const char *key, const void *addr)
|
|
||||||
{
|
|
||||||
ar(key, *(Dictionary **)addr);
|
|
||||||
},
|
|
||||||
[](FSerializer &ar, const char *key, void *addr)
|
|
||||||
{
|
|
||||||
Serialize<Dictionary>(ar, key, *(Dictionary **)addr, nullptr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
FAutoSegIterator probe(CRegHead, CRegTail);
|
FAutoSegIterator probe(CRegHead, CRegTail);
|
||||||
|
|
||||||
while (*++probe != NULL)
|
while (*++probe != NULL)
|
||||||
|
|
|
@ -2190,7 +2190,7 @@ Dictionary *DictionaryFromString(const FString &string)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary *const dict = new Dictionary;
|
Dictionary *const dict = Create<Dictionary>();
|
||||||
|
|
||||||
if (string.IsEmpty())
|
if (string.IsEmpty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,20 +3,87 @@
|
||||||
#include "scripting/vm/vm.h"
|
#include "scripting/vm/vm.h"
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
//=====================================================================================
|
||||||
|
//
|
||||||
|
// DObject implementations for Dictionary and DictionaryIterator
|
||||||
|
//
|
||||||
|
//=====================================================================================
|
||||||
|
|
||||||
|
IMPLEMENT_CLASS(Dictionary, false, false);
|
||||||
|
|
||||||
|
IMPLEMENT_CLASS(DictionaryIterator, false, true);
|
||||||
|
|
||||||
|
IMPLEMENT_POINTERS_START(DictionaryIterator)
|
||||||
|
IMPLEMENT_POINTER(Dict)
|
||||||
|
IMPLEMENT_POINTERS_END
|
||||||
|
|
||||||
|
//=====================================================================================
|
||||||
|
//
|
||||||
|
// Dictionary functions
|
||||||
|
//
|
||||||
|
//=====================================================================================
|
||||||
|
|
||||||
|
void Dictionary::Serialize(FSerializer &arc)
|
||||||
|
{
|
||||||
|
Super::Serialize(arc);
|
||||||
|
|
||||||
|
constexpr char key[] { "dictionary" };
|
||||||
|
|
||||||
|
if (arc.isWriting())
|
||||||
|
{
|
||||||
|
// Pass this instance to serializer.
|
||||||
|
Dictionary *pointerToThis = this;
|
||||||
|
arc(key, pointerToThis);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Receive new Dictionary, copy contents, clean up.
|
||||||
|
Dictionary *pointerToDeserializedDictionary;
|
||||||
|
arc(key, pointerToDeserializedDictionary);
|
||||||
|
TransferFrom(*pointerToDeserializedDictionary);
|
||||||
|
delete pointerToDeserializedDictionary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Dictionary *DictCreate()
|
||||||
|
{
|
||||||
|
Dictionary *dict { Create<Dictionary>() };
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DictInsert(Dictionary *dict, const FString &key, const FString &value)
|
||||||
|
{
|
||||||
|
dict->Insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DictAt(const Dictionary *dict, const FString &key, FString *result)
|
||||||
|
{
|
||||||
|
const FString *value = dict->CheckKey(key);
|
||||||
|
*result = value ? *value : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DictToString(const Dictionary *dict, FString *result)
|
||||||
|
{
|
||||||
|
*result = DictionaryToString(*dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DictRemove(Dictionary *dict, const FString &key)
|
||||||
|
{
|
||||||
|
dict->Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
//=====================================================================================
|
//=====================================================================================
|
||||||
//
|
//
|
||||||
// Dictionary exports
|
// Dictionary exports
|
||||||
//
|
//
|
||||||
//=====================================================================================
|
//=====================================================================================
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(_Dictionary, Create)
|
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Create, DictCreate)
|
||||||
{
|
{
|
||||||
ACTION_RETURN_POINTER(new Dictionary);
|
ACTION_RETURN_POINTER(DictCreate());
|
||||||
}
|
|
||||||
|
|
||||||
static void DictInsert(Dictionary *dict, const FString &key, const FString &value)
|
|
||||||
{
|
|
||||||
dict->Insert(key, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Insert, DictInsert)
|
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Insert, DictInsert)
|
||||||
|
@ -28,12 +95,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Insert, DictInsert)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DictAt(const Dictionary *dict, const FString &key, FString *result)
|
|
||||||
{
|
|
||||||
const FString *value = dict->CheckKey(key);
|
|
||||||
*result = value ? *value : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, At, DictAt)
|
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, At, DictAt)
|
||||||
{
|
{
|
||||||
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
||||||
|
@ -43,11 +104,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, At, DictAt)
|
||||||
ACTION_RETURN_STRING(result);
|
ACTION_RETURN_STRING(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DictToString(const Dictionary *dict, FString *result)
|
|
||||||
{
|
|
||||||
*result = DictionaryToString(*dict);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, ToString, DictToString)
|
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, ToString, DictToString)
|
||||||
{
|
{
|
||||||
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
||||||
|
@ -56,21 +112,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, ToString, DictToString)
|
||||||
ACTION_RETURN_STRING(result);
|
ACTION_RETURN_STRING(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Dictionary *DictFromString(const FString& string)
|
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, FromString, DictionaryFromString)
|
||||||
{
|
|
||||||
return DictionaryFromString(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, FromString, DictFromString)
|
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
PARAM_STRING(string);
|
PARAM_STRING(string);
|
||||||
ACTION_RETURN_POINTER(DictFromString(string));
|
ACTION_RETURN_POINTER(DictionaryFromString(string));
|
||||||
}
|
|
||||||
|
|
||||||
static void DictRemove(Dictionary *dict, const FString &key)
|
|
||||||
{
|
|
||||||
dict->Remove(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Remove, DictRemove)
|
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Remove, DictRemove)
|
||||||
|
@ -83,21 +129,65 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Remove, DictRemove)
|
||||||
|
|
||||||
//=====================================================================================
|
//=====================================================================================
|
||||||
//
|
//
|
||||||
// DictionaryIterator exports
|
// DictionaryIterator functions
|
||||||
//
|
//
|
||||||
//=====================================================================================
|
//=====================================================================================
|
||||||
|
|
||||||
DictionaryIterator::DictionaryIterator(const Dictionary &dict)
|
DictionaryIterator::DictionaryIterator()
|
||||||
: Iterator(dict)
|
: Iterator(nullptr)
|
||||||
, Pair(nullptr)
|
, Pair(nullptr)
|
||||||
|
, Dict(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static DictionaryIterator *DictIteratorCreate(const Dictionary *dict)
|
void DictionaryIterator::Serialize(FSerializer &arc)
|
||||||
{
|
{
|
||||||
return new DictionaryIterator(*dict);
|
if (arc.isWriting())
|
||||||
|
{
|
||||||
|
I_Error("Attempt to save pointer to unhandled type DictionaryIterator");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DictionaryIterator::init(Dictionary *dict)
|
||||||
|
{
|
||||||
|
Iterator = std::make_unique<Dictionary::ConstIterator>(*dict);
|
||||||
|
Dict = dict;
|
||||||
|
|
||||||
|
GC::WriteBarrier(this, Dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DictionaryIterator *DictIteratorCreate(Dictionary *dict)
|
||||||
|
{
|
||||||
|
DictionaryIterator *iterator = Create<DictionaryIterator>();
|
||||||
|
iterator->init(dict);
|
||||||
|
|
||||||
|
return iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DictIteratorNext(DictionaryIterator *self)
|
||||||
|
{
|
||||||
|
assert(self->Iterator != nullptr);
|
||||||
|
|
||||||
|
const bool hasNext { self->Iterator->NextPair(self->Pair) };
|
||||||
|
return hasNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DictIteratorKey(const DictionaryIterator *self, FString *result)
|
||||||
|
{
|
||||||
|
*result = self->Pair ? self->Pair->Key : FString {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DictIteratorValue(const DictionaryIterator *self, FString *result)
|
||||||
|
{
|
||||||
|
*result = self->Pair ? self->Pair->Value : FString {};
|
||||||
|
}
|
||||||
|
|
||||||
|
//=====================================================================================
|
||||||
|
//
|
||||||
|
// DictionaryIterator exports
|
||||||
|
//
|
||||||
|
//=====================================================================================
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Create, DictIteratorCreate)
|
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Create, DictIteratorCreate)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
|
@ -105,22 +195,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Create, DictIteratorCreate)
|
||||||
ACTION_RETURN_POINTER(DictIteratorCreate(dict));
|
ACTION_RETURN_POINTER(DictIteratorCreate(dict));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DictIteratorNext(DictionaryIterator *self)
|
|
||||||
{
|
|
||||||
return self->Iterator.NextPair(self->Pair);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Next, DictIteratorNext)
|
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Next, DictIteratorNext)
|
||||||
{
|
{
|
||||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||||
ACTION_RETURN_BOOL(DictIteratorNext(self));
|
ACTION_RETURN_BOOL(DictIteratorNext(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DictIteratorKey(const DictionaryIterator *self, FString *result)
|
|
||||||
{
|
|
||||||
*result = self->Pair ? self->Pair->Key : FString {};
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Key, DictIteratorKey)
|
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Key, DictIteratorKey)
|
||||||
{
|
{
|
||||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||||
|
@ -129,11 +209,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Key, DictIteratorKey)
|
||||||
ACTION_RETURN_STRING(result);
|
ACTION_RETURN_STRING(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DictIteratorValue(const DictionaryIterator *self, FString *result)
|
|
||||||
{
|
|
||||||
*result = self->Pair ? self->Pair->Value : FString {};
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Value, DictIteratorValue)
|
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Value, DictIteratorValue)
|
||||||
{
|
{
|
||||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||||
|
|
|
@ -2,13 +2,63 @@
|
||||||
|
|
||||||
#include "tarray.h"
|
#include "tarray.h"
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
|
#include "dobject.h"
|
||||||
|
|
||||||
using Dictionary = TMap<FString, FString>;
|
#include <memory>
|
||||||
|
|
||||||
struct DictionaryIterator
|
/**
|
||||||
|
* @brief The Dictionary class exists to be exported to ZScript.
|
||||||
|
*
|
||||||
|
* It is a string-to-string map.
|
||||||
|
*
|
||||||
|
* It is derived from DObject to be a part of normal GC process.
|
||||||
|
*/
|
||||||
|
class Dictionary final : public DObject, public TMap<FString, FString>
|
||||||
{
|
{
|
||||||
explicit DictionaryIterator(const Dictionary &dict);
|
DECLARE_CLASS(Dictionary, DObject)
|
||||||
|
|
||||||
Dictionary::ConstIterator Iterator;
|
public:
|
||||||
Dictionary::ConstPair *Pair;
|
|
||||||
|
void Serialize(FSerializer &arc) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The DictionaryIterator class exists to be exported to ZScript.
|
||||||
|
*
|
||||||
|
* It provides iterating over a Dictionary. The order is not specified.
|
||||||
|
*
|
||||||
|
* It is derived from DObject to be a part of normal GC process.
|
||||||
|
*/
|
||||||
|
class DictionaryIterator final : public DObject
|
||||||
|
{
|
||||||
|
DECLARE_CLASS(DictionaryIterator, DObject)
|
||||||
|
HAS_OBJECT_POINTERS
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
~DictionaryIterator() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMPLEMENT_CLASS macro needs a constructor without parameters.
|
||||||
|
*
|
||||||
|
* @see init().
|
||||||
|
*/
|
||||||
|
DictionaryIterator();
|
||||||
|
|
||||||
|
void Serialize(FSerializer &arc) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief init function complements constructor.
|
||||||
|
* @attention always call init after constructing DictionaryIterator.
|
||||||
|
*/
|
||||||
|
void init(Dictionary *dict);
|
||||||
|
|
||||||
|
std::unique_ptr<Dictionary::ConstIterator> Iterator;
|
||||||
|
Dictionary::ConstPair *Pair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dictionary attribute exists for holding a pointer to iterated
|
||||||
|
* dictionary, so it is known by GC.
|
||||||
|
*/
|
||||||
|
Dictionary *Dict;
|
||||||
};
|
};
|
||||||
|
|
|
@ -84,11 +84,11 @@ const char *GetVersionString();
|
||||||
#define SAVEGAME_EXT "zds"
|
#define SAVEGAME_EXT "zds"
|
||||||
|
|
||||||
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
||||||
#define MINSAVEVER 4556
|
#define MINSAVEVER 4558
|
||||||
|
|
||||||
// Use 4500 as the base git save version, since it's higher than the
|
// Use 4500 as the base git save version, since it's higher than the
|
||||||
// SVN revision ever got.
|
// SVN revision ever got.
|
||||||
#define SAVEVER 4557
|
#define SAVEVER 4558
|
||||||
|
|
||||||
// This is so that derivates can use the same savegame versions without worrying about engine compatibility
|
// This is so that derivates can use the same savegame versions without worrying about engine compatibility
|
||||||
#define GAMESIG "GZDOOM"
|
#define GAMESIG "GZDOOM"
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
struct Dictionary native
|
/**
|
||||||
|
* Dictionary provides key-value storage.
|
||||||
|
*
|
||||||
|
* Both keys and values are strings.
|
||||||
|
*
|
||||||
|
* @note keys are case-sensitive.
|
||||||
|
*/
|
||||||
|
class Dictionary
|
||||||
{
|
{
|
||||||
native static Dictionary Create();
|
native static Dictionary Create();
|
||||||
|
|
||||||
|
@ -23,7 +30,15 @@ struct Dictionary native
|
||||||
native String ToString() const;
|
native String ToString() const;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DictionaryIterator native
|
/**
|
||||||
|
* Provides iterating over a Dictionary.
|
||||||
|
*
|
||||||
|
* Order is not specified.
|
||||||
|
*
|
||||||
|
* DictionaryIterator is not serializable. To make DictionaryIterator a class
|
||||||
|
* member, use `transient` keyword.
|
||||||
|
*/
|
||||||
|
class DictionaryIterator
|
||||||
{
|
{
|
||||||
native static DictionaryIterator Create(Dictionary dict);
|
native static DictionaryIterator Create(Dictionary dict);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue