Saveload: Refactor interface for memory dumper raw write functions

This commit is contained in:
Jonathan G Rennison 2024-08-08 21:36:30 +01:00
parent d0cbc48f7d
commit 22a6dc642d
4 changed files with 141 additions and 99 deletions

View File

@ -261,23 +261,27 @@ static void Save_WMAP()
dumper->CopyBytes((uint8_t *) _m, size * 8);
dumper->CopyBytes((uint8_t *) _me, size * 4);
#else
for (TileIndex i = 0; i != size; i++) {
dumper->CheckBytes(8);
dumper->RawWriteByte(_m[i].type);
dumper->RawWriteByte(_m[i].height);
dumper->RawWriteByte(GB(_m[i].m2, 0, 8));
dumper->RawWriteByte(GB(_m[i].m2, 8, 8));
dumper->RawWriteByte(_m[i].m1);
dumper->RawWriteByte(_m[i].m3);
dumper->RawWriteByte(_m[i].m4);
dumper->RawWriteByte(_m[i].m5);
Tile *m_start = _m;
Tile *m_end = _m + size;
for (Tile *m = m_start; m != m_end; m++) {
RawMemoryDumper dump = dumper->RawWriteBytes(8);
dump.RawWriteByte(m->type);
dump.RawWriteByte(m->height);
dump.RawWriteByte(GB(m->m2, 0, 8));
dump.RawWriteByte(GB(m->m2, 8, 8));
dump.RawWriteByte(m->m1);
dump.RawWriteByte(m->m3);
dump.RawWriteByte(m->m4);
dump.RawWriteByte(m->m5);
}
for (TileIndex i = 0; i != size; i++) {
dumper->CheckBytes(4);
dumper->RawWriteByte(_me[i].m6);
dumper->RawWriteByte(_me[i].m7);
dumper->RawWriteByte(GB(_me[i].m8, 0, 8));
dumper->RawWriteByte(GB(_me[i].m8, 8, 8));
TileExtended *me_start = _me;
TileExtended *me_end = _me + size;
for (TileExtended *me = me_start; me != me_end; me++) {
RawMemoryDumper dump = dumper->RawWriteBytes(4);
dump.RawWriteByte(me->m6);
dump.RawWriteByte(me->m7);
dump.RawWriteByte(GB(me->m8, 0, 8));
dump.RawWriteByte(GB(me->m8, 8, 8));
}
#endif
}

View File

@ -643,20 +643,17 @@ void SlWriteByte(uint8_t b)
void SlWriteUint16(uint16_t v)
{
_sl.dumper->CheckBytes(2);
_sl.dumper->RawWriteUint16(v);
_sl.dumper->RawWriteBytes(2).RawWriteUint16(v);
}
void SlWriteUint32(uint32_t v)
{
_sl.dumper->CheckBytes(4);
_sl.dumper->RawWriteUint32(v);
_sl.dumper->RawWriteBytes(4).RawWriteUint32(v);
}
void SlWriteUint64(uint64_t v)
{
_sl.dumper->CheckBytes(8);
_sl.dumper->RawWriteUint64(v);
_sl.dumper->RawWriteBytes(8).RawWriteUint64(v);
}
/**
@ -731,27 +728,35 @@ uint SlReadSimpleGamma()
*/
void SlWriteSimpleGamma(size_t i)
{
MemoryDumper *dumper = MemoryDumper::GetCurrent();
RawMemoryDumper raw_dumper = dumper->BorrowRawWriteBytes(SlGetMaxGammaLength());
raw_dumper.RawWriteSimpleGamma(i);
dumper->ReturnRawWriteBytes(raw_dumper);
}
void RawMemoryDumper::RawWriteSimpleGamma(size_t i)
{
if (i >= (1 << 7)) {
if (i >= (1 << 14)) {
if (i >= (1 << 21)) {
if (i >= (1 << 28)) {
assert(i <= UINT32_MAX); // We can only support 32 bits for now.
SlWriteByte((uint8_t)(0xF0));
SlWriteByte((uint8_t)(i >> 24));
*this->buf++ = ((uint8_t)(0xF0));
*this->buf++ = ((uint8_t)(i >> 24));
} else {
SlWriteByte((uint8_t)(0xE0 | (i >> 24)));
*this->buf++ = ((uint8_t)(0xE0 | (i >> 24)));
}
SlWriteByte((uint8_t)(i >> 16));
*this->buf++ = ((uint8_t)(i >> 16));
} else {
SlWriteByte((uint8_t)(0xC0 | (i >> 16)));
*this->buf++ = ((uint8_t)(0xC0 | (i >> 16)));
}
SlWriteByte((uint8_t)(i >> 8));
*this->buf++ = ((uint8_t)(i >> 8));
} else {
SlWriteByte((uint8_t)(0x80 | (i >> 8)));
*this->buf++ = ((uint8_t)(0x80 | (i >> 8)));
}
}
SlWriteByte((uint8_t)i);
*this->buf++ = ((uint8_t)i);
}
/** Return how many bytes used to encode a gamma value */
@ -2076,8 +2081,7 @@ bool SlObjectMemberGeneric(void *object, const SaveLoad &sld)
sld.struct_handler->Save(object);
if (offset == _sl.dumper->GetWriteOffsetGeneric()) {
/* Nothing was actaully written, so it's safe to change the 1 above to 0 */
_sl.dumper->UnWriteByte(); // This is fine iff nothing has been written since the WriteByte(1)
_sl.dumper->RawWriteByte(0);
_sl.dumper->ReplaceLastWrittenByte(0); // This is fine iff nothing has been written since the WriteByte(1)
}
} else {
sld.struct_handler->Save(object);

View File

@ -213,6 +213,77 @@ struct ReadBuffer {
};
namespace SlSerialise {
inline void RawWriteUint16At(uint8_t *b, uint16_t v)
{
#if OTTD_ALIGNMENT == 0
*((unaligned_uint16 *)b) = TO_BE16(v);
#else
b[0] = GB(v, 8, 8);
b[1] = GB(v, 0, 8);
#endif
}
inline void RawWriteUint32At(uint8_t *b, uint32_t v)
{
#if OTTD_ALIGNMENT == 0
*((unaligned_uint32 *)b) = TO_BE32(v);
#else
b[0] = GB(v, 24, 8);
b[1] = GB(v, 16, 8);
b[2] = GB(v, 8, 8);
b[3] = GB(v, 0, 8);
#endif
}
inline void RawWriteUint64At(uint8_t *b, uint64_t v)
{
#if OTTD_ALIGNMENT == 0
*((unaligned_uint64 *)b) = TO_BE64(v);
#else
b[0] = GB(v, 56, 8);
b[1] = GB(v, 48, 8);
b[2] = GB(v, 40, 8);
b[3] = GB(v, 32, 8);
b[4] = GB(v, 24, 8);
b[5] = GB(v, 16, 8);
b[6] = GB(v, 8, 8);
b[7] = GB(v, 0, 8);
#endif
}
}
struct RawMemoryDumper {
uint8_t *buf; ///< Buffer we're going to write to.
RawMemoryDumper(uint8_t *b) : buf(b) {}
inline void RawWriteByte(uint8_t b)
{
*this->buf++ = b;
}
inline void RawWriteUint16(uint16_t v)
{
SlSerialise::RawWriteUint16At(this->buf, v);
this->buf += 2;
}
inline void RawWriteUint32(uint32_t v)
{
SlSerialise::RawWriteUint32At(this->buf, v);
this->buf += 4;
}
inline void RawWriteUint64(uint64_t v)
{
SlSerialise::RawWriteUint64At(this->buf, v);
this->buf += 8;
}
void RawWriteSimpleGamma(size_t i);
};
/** Container for dumping the savegame (quickly) to memory. */
struct MemoryDumper {
struct BufferInfo {
@ -236,44 +307,6 @@ struct MemoryDumper {
uint8_t *saved_buf = nullptr;
uint8_t *saved_bufe = nullptr;
static inline void RawWriteUint16At(uint8_t *b, uint16_t v)
{
#if OTTD_ALIGNMENT == 0
*((unaligned_uint16 *)b) = TO_BE16(v);
#else
b[0] = GB(v, 8, 8);
b[1] = GB(v, 0, 8);
#endif
}
static inline void RawWriteUint32At(uint8_t *b, uint32_t v)
{
#if OTTD_ALIGNMENT == 0
*((unaligned_uint32 *)b) = TO_BE32(v);
#else
b[0] = GB(v, 24, 8);
b[1] = GB(v, 16, 8);
b[2] = GB(v, 8, 8);
b[3] = GB(v, 0, 8);
#endif
}
static inline void RawWriteUint64At(uint8_t *b, uint64_t v)
{
#if OTTD_ALIGNMENT == 0
*((unaligned_uint64 *)b) = TO_BE64(v);
#else
b[0] = GB(v, 56, 8);
b[1] = GB(v, 48, 8);
b[2] = GB(v, 40, 8);
b[3] = GB(v, 32, 8);
b[4] = GB(v, 24, 8);
b[5] = GB(v, 16, 8);
b[6] = GB(v, 8, 8);
b[7] = GB(v, 0, 8);
#endif
}
MemoryDumper()
{
const size_t size = 8192;
@ -330,32 +363,28 @@ struct MemoryDumper {
}
/** For limited/special purposes only */
inline void UnWriteByte()
inline void ReplaceLastWrittenByte(uint8_t b)
{
this->buf--;
*(this->buf - 1) = b;
}
inline void RawWriteByte(uint8_t b)
inline RawMemoryDumper RawWriteBytes(size_t bytes)
{
*this->buf++ = b;
this->CheckBytes(bytes);
RawMemoryDumper raw_dumper(this->buf);
this->buf += bytes;
return raw_dumper;
}
inline void RawWriteUint16(uint16_t v)
inline RawMemoryDumper BorrowRawWriteBytes(size_t bytes)
{
RawWriteUint16At(this->buf, v);
this->buf += 2;
this->CheckBytes(bytes);
return RawMemoryDumper(this->buf);
}
inline void RawWriteUint32(uint32_t v)
inline void ReturnRawWriteBytes(RawMemoryDumper raw_dumper)
{
RawWriteUint32At(this->buf, v);
this->buf += 4;
}
inline void RawWriteUint64(uint64_t v)
{
RawWriteUint64At(this->buf, v);
this->buf += 8;
this->buf = raw_dumper.buf;
}
template <typename F>
@ -382,7 +411,7 @@ struct MemoryDumper {
size_t to_copy = std::min<size_t>((this->bufe - this->buf) / 2, length);
uint8_t *b = this->buf;
for (size_t i = 0; i < to_copy; i++) {
RawWriteUint16At(b, handler());
SlSerialise::RawWriteUint16At(b, handler());
b += 2;
}
this->buf = b;

View File

@ -304,10 +304,13 @@ struct StationGoodsFlowStructHandler final : public TypedSaveLoadStructHandler<S
for (const FlowStat &stat : ged->flows) {
uint32_t sum_shares = 0;
dumper->CheckBytes(2 + 2);
dumper->RawWriteUint16(stat.GetOrigin());
dumper->RawWriteUint16(stat.GetRawFlags());
SlWriteSimpleGamma(stat.size());
RawMemoryDumper dump = dumper->BorrowRawWriteBytes(2 + 2 + SlGetMaxGammaLength());
dump.RawWriteUint16(stat.GetOrigin());
dump.RawWriteUint16(stat.GetRawFlags());
dump.RawWriteSimpleGamma(stat.size());
dumper->ReturnRawWriteBytes(dump);
for (const auto &it : stat) {
StationID via = it.second;
uint32_t share = it.first - sum_shares;
@ -316,10 +319,10 @@ struct StationGoodsFlowStructHandler final : public TypedSaveLoadStructHandler<S
dbg_assert(share > 0);
/* This is performance-sensitive, manually unroll */
dumper->CheckBytes(2 + 4 + 1);
dumper->RawWriteUint16(via);
dumper->RawWriteUint32(share);
dumper->RawWriteByte(restricted ? 1 : 0);
dump = dumper->RawWriteBytes(2 + 4 + 1);
dump.RawWriteUint16(via);
dump.RawWriteUint32(share);
dump.RawWriteByte(restricted ? 1 : 0);
}
}
}
@ -670,18 +673,20 @@ struct StationCargoHistoryStructHandler final : public TypedSaveLoadStructHandle
void Save(Station *st) const override
{
MemoryDumper *dumper = MemoryDumper::GetCurrent();
SlWriteUint64(st->station_cargo_history_cargoes);
SlWriteSimpleGamma(st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS);
RawMemoryDumper dump = dumper->BorrowRawWriteBytes(8 + SlGetMaxGammaLength() + (st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS * 2));
dump.RawWriteUint64(st->station_cargo_history_cargoes);
dump.RawWriteSimpleGamma(st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS);
dumper->CheckBytes(st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS * 2);
for (const auto &history : st->station_cargo_history) {
uint i = st->station_cargo_history_offset;
do {
dumper->RawWriteUint16(history[i]);
dump.RawWriteUint16(history[i]);
i++;
if (i == MAX_STATION_CARGO_HISTORY_DAYS) i = 0;
} while (i != st->station_cargo_history_offset);
}
dumper->ReturnRawWriteBytes(dump);
}
void Load(Station *st) const override