Codechange: Add compile-time check that variable size matches saveload entry.

This commit is contained in:
Peter Nelson 2023-12-07 18:39:54 +00:00 committed by Peter Nelson
parent cb53fed229
commit 9f853c10b0
1 changed files with 60 additions and 2 deletions

View File

@ -741,6 +741,54 @@ static inline constexpr bool IsNumericType(VarType conv)
return GetVarMemType(conv) <= SLE_VAR_U64;
}
/**
* Return expect size in bytes of a VarType
* @param type VarType to get size of.
* @return size of type in bytes.
*/
static inline constexpr size_t SlVarSize(VarType type)
{
switch (GetVarMemType(type)) {
case SLE_VAR_BL: return sizeof(bool);
case SLE_VAR_I8: return sizeof(int8_t);
case SLE_VAR_U8: return sizeof(uint8_t);
case SLE_VAR_I16: return sizeof(int16_t);
case SLE_VAR_U16: return sizeof(uint16_t);
case SLE_VAR_I32: return sizeof(int32_t);
case SLE_VAR_U32: return sizeof(uint32_t);
case SLE_VAR_I64: return sizeof(int64_t);
case SLE_VAR_U64: return sizeof(uint64_t);
case SLE_VAR_NULL: return sizeof(void *);
case SLE_VAR_STR: return sizeof(std::string);
case SLE_VAR_STRQ: return sizeof(std::string);
case SLE_VAR_NAME: return sizeof(std::string);
default: NOT_REACHED();
}
}
/**
* Check if a saveload cmd/type/length entry matches the size of the variable.
* @param cmd SaveLoadType of entry.
* @param type VarType of entry.
* @param length Array length of entry.
* @param size Actual size of variable.
* @return true iff the sizes match.
*/
static inline constexpr bool SlCheckVarSize(SaveLoadType cmd, VarType type, size_t length, size_t size)
{
switch (cmd) {
case SL_VAR: return SlVarSize(type) == size;
case SL_REF: return sizeof(void *) == size;
case SL_STDSTR: return SlVarSize(type) == size;
case SL_ARR: return SlVarSize(type) * length <= size; // Partial load of array is permitted.
case SL_DEQUE: return sizeof(std::deque<void *>) == size;
case SL_VECTOR: return sizeof(std::vector<void *>) == size;
case SL_REFLIST: return sizeof(std::list<void *>) == size;
case SL_SAVEBYTE: return true;
default: NOT_REACHED();
}
}
/**
* Storage of simple variables, references (pointers), and arrays.
* @param cmd Load/save type. @see SaveLoadType
@ -748,12 +796,18 @@ static inline constexpr bool IsNumericType(VarType conv)
* @param base Name of the class or struct containing the variable.
* @param variable Name of the variable in the class or struct referenced by \a base.
* @param type Storage of the data in memory and in the savegame.
* @param length Number of elements in the array.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
* @param extra Extra data to pass to the address callback function.
* @note In general, it is better to use one of the SLE_* macros below.
*/
#define SLE_GENERAL_NAME(cmd, name, base, variable, type, length, from, to, extra) SaveLoad {name, cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { assert(b != nullptr); return const_cast<void *>(static_cast<const void *>(std::addressof(static_cast<base *>(b)->variable))); }, extra, nullptr}
#define SLE_GENERAL_NAME(cmd, name, base, variable, type, length, from, to, extra) \
SaveLoad {name, cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { \
static_assert(SlCheckVarSize(cmd, type, length, sizeof(static_cast<base *>(b)->variable))); \
assert(b != nullptr); \
return const_cast<void *>(static_cast<const void *>(std::addressof(static_cast<base *>(b)->variable))); \
}, extra, nullptr}
/**
* Storage of simple variables, references (pointers), and arrays with a custom name.
@ -761,6 +815,7 @@ static inline constexpr bool IsNumericType(VarType conv)
* @param base Name of the class or struct containing the variable.
* @param variable Name of the variable in the class or struct referenced by \a base.
* @param type Storage of the data in memory and in the savegame.
* @param length Number of elements in the array.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
* @param extra Extra data to pass to the address callback function.
@ -966,7 +1021,10 @@ static inline constexpr bool IsNumericType(VarType conv)
* @param extra Extra data to pass to the address callback function.
* @note In general, it is better to use one of the SLEG_* macros below.
*/
#define SLEG_GENERAL(name, cmd, variable, type, length, from, to, extra) SaveLoad {name, cmd, type, length, from, to, sizeof(variable), [] (void *, size_t) -> void * { return static_cast<void *>(std::addressof(variable)); }, extra, nullptr}
#define SLEG_GENERAL(name, cmd, variable, type, length, from, to, extra) \
SaveLoad {name, cmd, type, length, from, to, sizeof(variable), [] (void *, size_t) -> void * { \
static_assert(SlCheckVarSize(cmd, type, length, sizeof(variable))); \
return static_cast<void *>(std::addressof(variable)); }, extra, nullptr}
/**
* Storage of a global variable in some savegame versions.