1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-04 00:15:53 +02:00

Implemented string deduplication for serializer

Every unique string will now be serialized only once.
Reduces save size by ~20%
This commit is contained in:
Ivan Savenko 2024-05-07 14:50:21 +00:00
parent 5b182c31df
commit 87eac164e6
4 changed files with 67 additions and 6 deletions

View File

@ -156,6 +156,7 @@ public:
bool reverseEndianness; //if source has different endianness than us, we reverse bytes
Version version;
std::vector<std::string> loadedStrings;
std::map<ui32, void*> loadedPointers;
std::map<const void*, std::shared_ptr<void>> loadedSharedPointers;
IGameCallback * cb = nullptr;
@ -451,9 +452,33 @@ public:
}
void load(std::string &data)
{
ui32 length = readAndCheckLength();
data.resize(length);
this->read(static_cast<void *>(data.data()), length, false);
if (hasFeature(Version::COMPACT_STRING_SERIALIZATION))
{
int32_t length;
load(length);
if (length < 0)
{
int32_t stringID = -length - 1; // -1, -2 ... -> 0, 1 ...
data = loadedStrings[stringID];
}
if (length == 0)
{
data = {};
}
if (length > 0)
{
data.resize(length);
this->read(static_cast<void *>(data.data()), length, false);
loadedStrings.push_back(data);
}
}
else
{
ui32 length = readAndCheckLength();
data.resize(length);
this->read(static_cast<void *>(data.data()), length, false);
}
}
template<typename... TN>

View File

@ -113,6 +113,7 @@ class DLL_LINKAGE BinarySerializer : public CSaverBase
public:
using Version = ESerializationVersion;
std::map<std::string, uint32_t> savedStrings;
std::map<const void*, ui32> savedPointers;
const Version version = Version::CURRENT;
@ -322,11 +323,42 @@ public:
for(auto i = d.begin(); i != d.end(); i++)
save(*i);
}
void save(const std::string &data)
{
save(ui32(data.length()));
this->write(static_cast<const void *>(data.data()), data.size());
if (hasFeature(Version::COMPACT_STRING_SERIALIZATION))
{
if (data.empty())
{
save(ui32(0));
return;
}
auto it = savedStrings.find(data);
if (it == savedStrings.end())
{
save(ui32(data.length()));
this->write(static_cast<const void *>(data.data()), data.size());
// -1, -2...
int32_t newStringID = -1 - savedStrings.size();
savedStrings[data] = newStringID;
}
else
{
int32_t index = it->second;
save(index);
}
}
else
{
save(ui32(data.length()));
this->write(static_cast<const void *>(data.data()), data.size());
}
}
template <typename T1, typename T2>
void save(const std::pair<T1,T2> &data)
{

View File

@ -73,6 +73,7 @@ void CConnection::sendPack(const CPack * pack)
boost::mutex::scoped_lock lock(writeMutex);
auto connectionPtr = networkConnection.lock();
serializer->savedStrings.clear();
if (!connectionPtr)
throw std::runtime_error("Attempt to send packet on a closed connection!");
@ -91,6 +92,7 @@ CPack * CConnection::retrievePack(const std::vector<std::byte> & data)
packReader->buffer = &data;
packReader->position = 0;
deserializer->loadedStrings.clear();
*deserializer & result;

View File

@ -44,5 +44,7 @@ enum class ESerializationVersion : int32_t
RELEASE_150 = ARTIFACT_COSTUMES, // for convenience
CURRENT = ARTIFACT_COSTUMES
COMPACT_STRING_SERIALIZATION,
CURRENT = COMPACT_STRING_SERIALIZATION
};