mirror of
https://github.com/mamedev/mame.git
synced 2024-11-16 07:48:32 +01:00
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.
This commit is contained in:
parent
da6f1fd6fc
commit
de28f087ff
4 changed files with 99 additions and 34 deletions
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
111
src/emu/save.h
111
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
|
||||
|
|
Loading…
Reference in a new issue