summaryrefslogtreecommitdiff
path: root/src/saveload/linkgraph_sl.cpp
diff options
context:
space:
mode:
authorMichael Lutz <michi@icosahedron.de>2020-12-14 00:14:37 +0100
committerMichael Lutz <michi@icosahedron.de>2021-02-13 20:08:53 +0100
commit7845434270524d4c777a6711d2e17ac89eeeeb89 (patch)
tree161cb867662f70f6f242699b811929936c290938 /src/saveload/linkgraph_sl.cpp
parent9c9292949fa4d699c58d40abcac563a86df239dd (diff)
downloadopenttd-7845434270524d4c777a6711d2e17ac89eeeeb89.tar.xz
Codechange: Don't use cpp_offsetof in the save/load code.
Many of the member variables that are used in save/load are inside types that are not standard layout types. Using pointer arithmetics to determine addresses of members inside types that are not standard layout is generally undefined behaviour. If we'd use C++17, it is conditionally supported, which means each compiler may or may not support it. And even then using it for individual array elements is syntactically not supported the the standard offsetof function. Unfortunately, the trickery employed for saving linkgraph settings causes quite some clutter in the settings ini files.
Diffstat (limited to 'src/saveload/linkgraph_sl.cpp')
-rw-r--r--src/saveload/linkgraph_sl.cpp28
1 files changed, 16 insertions, 12 deletions
diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp
index aa3a2ff4b..a597edfc4 100644
--- a/src/saveload/linkgraph_sl.cpp
+++ b/src/saveload/linkgraph_sl.cpp
@@ -53,11 +53,23 @@ const SaveLoad *GetLinkGraphJobDesc()
static std::vector<SaveLoad> saveloads;
static const char *prefix = "linkgraph.";
+ static const SaveLoad job_desc[] = {
+ SLE_VAR(LinkGraphJob, join_date, SLE_INT32),
+ SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16),
+ SLE_END()
+ };
+
+ /* The member offset arithmetic below is only valid if the types in question
+ * are standard layout types. Otherwise, it would be undefined behaviour. */
+ static_assert(std::is_standard_layout<LinkGraphSettings>::value, "LinkGraphSettings needs to be a standard layout type");
+
+ /* We store the offset of each member of the #LinkGraphSettings in the
+ * extra data of the saveload struct. Use it together with the address
+ * of the settings struct inside the job to find the final memory address. */
+ static SaveLoadAddrProc * const proc = [](void *b, size_t extra) -> void * { return const_cast<void *>(static_cast<const void *>(reinterpret_cast<const char *>(std::addressof(static_cast<LinkGraphJob *>(b)->settings)) + extra)); };
+
/* Build the SaveLoad array on first call and don't touch it later on */
if (saveloads.size() == 0) {
- size_t offset_gamesettings = cpp_offsetof(GameSettings, linkgraph);
- size_t offset_component = cpp_offsetof(LinkGraphJob, settings);
-
size_t prefixlen = strlen(prefix);
int setting = 0;
@@ -65,20 +77,12 @@ const SaveLoad *GetLinkGraphJobDesc()
while (desc->save.cmd != SL_END) {
if (desc->desc.name != nullptr && strncmp(desc->desc.name, prefix, prefixlen) == 0) {
SaveLoad sl = desc->save;
- char *&address = reinterpret_cast<char *&>(sl.address);
- address -= offset_gamesettings;
- address += offset_component;
+ sl.address_proc = proc;
saveloads.push_back(sl);
}
desc = GetSettingDescription(++setting);
}
- const SaveLoad job_desc[] = {
- SLE_VAR(LinkGraphJob, join_date, SLE_INT32),
- SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16),
- SLE_END()
- };
-
int i = 0;
do {
saveloads.push_back(job_desc[i++]);