summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2021-09-15 11:06:58 -0700
committer Aaron Giles <aaron@aarongiles.com>2021-09-15 11:06:58 -0700
commitde28f087ffe26ece88ef416ca7080f8d10d08398 (patch)
treeb031f70d3ca93e81c818b587fb71dead4568420b /src
parentda6f1fd6fc9643902dea9e9737c70847fb380599 (diff)
Enable flexible structure saving.
This change introduces the ability to save arbitrary structures. To make a structure eligible for saving, it must implement a new method register_save(save_registrar &). Structs can then save their members directly via the provided save_registrar. Nested structs and arrays of structs are supported in this manner. Note that state registration is not done via a virtual method or mix-in interface because doing so would convert lightweight structures away from being POD, and lightweight structures are one of the most common situations where this system can be leveraged in MAME. As a first example, the attotime struct has been changed to support this mechanism for saving, allowing us to remove the special cases for attotimes currently in save_manager. (It would be tempting to do the same for bitmap_t, but bitmaps are defined in lib/util and can't take a dependency on save.h so those special cases will remain.) This is a prologue to full hierarchical save state support, which I am working on in another branch. The save_registrar class name and reg() signatures match current work on that branch, so any changes made to existing code to leverage struct saving in this way will port over cleanly.
Diffstat (limited to 'src')
-rw-r--r--src/emu/attotime.cpp17
-rw-r--r--src/emu/attotime.h2
-rw-r--r--src/emu/emufwd.h3
-rw-r--r--src/emu/save.h111
4 files changed, 99 insertions, 34 deletions
diff --git a/src/emu/attotime.cpp b/src/emu/attotime.cpp
index a1ba4d9ed61..3ba52c3157a 100644
--- a/src/emu/attotime.cpp
+++ b/src/emu/attotime.cpp
@@ -8,9 +8,8 @@
***************************************************************************/
-#include "emucore.h"
-#include "eminline.h"
-#include "attotime.h"
+#include "emu.h"
+
//**************************************************************************
// GLOBAL VARIABLES
@@ -170,3 +169,15 @@ std::string attotime::to_string() const
int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
return util::string_format("%s%04d.%03d,%03d,%03d", sign, int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
}
+
+
+//-------------------------------------------------
+// register_save - register for save states
+//-------------------------------------------------
+
+void attotime::register_save(save_registrar &save)
+{
+ // use names without m_ prefix for backwards compatibility
+ save.reg(m_attoseconds, "attoseconds");
+ save.reg(m_seconds, "seconds");
+}
diff --git a/src/emu/attotime.h b/src/emu/attotime.h
index c975bbde0d3..d17a5227967 100644
--- a/src/emu/attotime.h
+++ b/src/emu/attotime.h
@@ -164,6 +164,8 @@ public:
attotime &operator*=(u32 factor);
attotime &operator/=(u32 factor);
+ void register_save(save_registrar &save);
+
// members
seconds_t m_seconds;
attoseconds_t m_attoseconds;
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index b3969a8fc99..171b9f7c5fa 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -210,6 +210,9 @@ class rom_entry;
// declared in romload.h
class rom_load_manager;
+// declared in save.h
+class save_registrar;
+
// declared in schedule.h
class device_scheduler;
class emu_timer;
diff --git a/src/emu/save.h b/src/emu/save.h
index cfd674e738e..71e6679a36e 100644
--- a/src/emu/save.h
+++ b/src/emu/save.h
@@ -70,9 +70,43 @@ typedef named_delegate<void ()> save_prepost_delegate;
// TYPE DEFINITIONS
//**************************************************************************
+class save_manager;
class ram_state;
class rewinder;
+// helper class to provide pass-through interface for saving struct items
+class save_registrar
+{
+ friend class save_manager;
+
+public:
+ save_registrar(save_manager &manager, device_t *device, char const *module, char const *tag, int index, char const *valname) :
+ m_manager(manager),
+ m_device(device),
+ m_module(module),
+ m_tag(tag),
+ m_valname(valname),
+ m_inner_index(index),
+ m_outer_index(-1)
+ {
+ }
+
+ template <typename ItemType>
+ void reg(ItemType &value, const char *valname);
+
+ template <typename ItemType>
+ void reg(ItemType &value, const char *valname, int index);
+
+private:
+ save_manager &m_manager;
+ device_t *m_device;
+ char const *m_module;
+ char const *m_tag;
+ char const *m_valname;
+ int m_inner_index;
+ int m_outer_index;
+};
+
class save_manager
{
// stuff for working with arrays
@@ -102,6 +136,13 @@ class save_manager
template <typename ItemType> struct is_atom : public std::false_type { };
template <typename ItemType> struct is_vector_safe : public std::false_type { };
+ // template to query if a type is a struct/union that can be saved; note that bitmap_t is explicitly
+ // excluded because it is handled as a special case
+ template <typename ItemType> struct is_saveable_struct
+ {
+ static constexpr bool value = (std::is_class<ItemType>::value || std::is_union<ItemType>::value) && !std::is_base_of<bitmap_t, ItemType>::value && !is_atom<ItemType>::value;
+ };
+
class state_entry
{
public:
@@ -166,6 +207,23 @@ public:
save_memory(device, module, tag, index, valname, array_unwrap<ItemType>::ptr(value), array_unwrap<ItemType>::SIZE, array_unwrap<ItemType>::SAVE_COUNT);
}
+ // templatized wrappers for saving saveable structs
+ template<typename ItemType>
+ std::enable_if_t<is_saveable_struct<typename array_unwrap<ItemType>::underlying_type>::value && array_unwrap<ItemType>::SAVE_COUNT == 1>
+ save_item(device_t *device, const char *module, const char *tag, int index, ItemType &value, const char *valname)
+ {
+ save_registrar save(*this, device, module, tag, index, valname);
+ value.register_save(save);
+ }
+ template<typename ItemType>
+ std::enable_if_t<is_saveable_struct<typename array_unwrap<ItemType>::underlying_type>::value && array_unwrap<ItemType>::SAVE_COUNT != 1>
+ save_item(device_t *device, const char *module, const char *tag, int index, ItemType &value, const char *valname)
+ {
+ save_registrar save(*this, device, module, tag, index, valname);
+ for (save.m_outer_index = 0; save.m_outer_index < array_unwrap<ItemType>::SAVE_COUNT; save.m_outer_index++)
+ array_unwrap<ItemType>::ptr(value)[save.m_outer_index].register_save(save);
+ }
+
// templatized wrapper for structure members
template <typename ItemType, typename StructType, typename ElementType>
void save_item(device_t *device, const char *module, const char *tag, int index, ItemType &value, ElementType StructType::*element, const char *valname)
@@ -236,37 +294,6 @@ public:
save_memory(device, module, tag, index, valname, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height());
}
- // specializations for attotimes
- template <typename ItemType>
- std::enable_if_t<std::is_same<typename save_manager::array_unwrap<ItemType>::underlying_type, attotime>::value> save_item(device_t *device, const char *module, const char *tag, int index, ItemType &value, const char *valname)
- {
- std::string tempstr;
- tempstr.assign(valname).append(".attoseconds");
- save_item(device, module, tag, index, value, &attotime::m_attoseconds, tempstr.c_str());
- tempstr.assign(valname).append(".seconds");
- save_item(device, module, tag, index, value, &attotime::m_seconds, tempstr.c_str());
- }
-
- template <typename ItemType>
- std::enable_if_t<std::is_same<typename save_manager::array_unwrap<ItemType>::underlying_type, attotime>::value> save_pointer(device_t *device, const char *module, const char *tag, int index, ItemType *value, const char *valname, u32 count)
- {
- std::string tempstr;
- tempstr.assign(valname).append(".attoseconds");
- save_item(device, module, tag, index, value, &attotime::m_attoseconds, tempstr.c_str(), count);
- tempstr.assign(valname).append(".seconds");
- save_item(device, module, tag, index, value, &attotime::m_seconds, tempstr.c_str(), count);
- }
-
- template <typename ItemType>
- std::enable_if_t<std::is_same<typename save_manager::array_unwrap<ItemType>::underlying_type, attotime>::value> save_pointer(device_t *device, const char *module, const char *tag, int index, const std::unique_ptr<ItemType []> &value, const char *valname, u32 count)
- {
- std::string tempstr;
- tempstr.assign(valname).append(".attoseconds");
- save_item(device, module, tag, index, value, &attotime::m_attoseconds, tempstr.c_str(), count);
- tempstr.assign(valname).append(".seconds");
- save_item(device, module, tag, index, value, &attotime::m_seconds, tempstr.c_str(), count);
- }
-
// global memory registration
template <typename ItemType>
void save_item(ItemType &value, const char *valname, int index = 0)
@@ -377,6 +404,28 @@ public:
};
+template <typename ItemType>
+void save_registrar::reg(ItemType &value, const char *valname)
+{
+ std::string fullname;
+ if (m_outer_index == -1)
+ fullname = string_format("%s.%s", m_valname, valname);
+ else
+ fullname = string_format("%s[%d].%s", m_valname, m_outer_index, valname);
+ m_manager.save_item(m_device, m_module, m_tag, m_inner_index, value, fullname.c_str());
+}
+
+template <typename ItemType>
+void save_registrar::reg(ItemType &value, const char *valname, int index)
+{
+ std::string fullname;
+ if (m_outer_index == -1)
+ fullname = string_format("%s.%s[%d]", m_valname, valname, index);
+ else
+ fullname = string_format("%s[%d].%s[%d]", m_valname, m_outer_index, valname, index);
+ m_manager.save_item(m_device, m_module, m_tag, m_inner_index, value, fullname.c_str());
+}
+
// template specializations to enumerate the fundamental atomic types you are allowed to save
ALLOW_SAVE_TYPE_AND_VECTOR(char)
ALLOW_SAVE_TYPE (bool) // std::vector<bool> may be packed internally