mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
-util/delegate.cpp: One less level of indirection for functoid delegates.
* If a delegate is set to a functoid (e.g. a lambda) with a signature that is an exact match for the delegate's signature, it will be bound directly. If arguments or the return value need conversion, a static adaptor will be generated. This removes unnecessary indirection through std::function::operator(). -Added a few more documentation comments.
This commit is contained in:
parent
4a39d895af
commit
d334586156
@ -127,7 +127,6 @@ files{
|
||||
MAME_DIR .. "src/mame/includes/exidy.h",
|
||||
MAME_DIR .. "src/mame/audio/exidy.cpp",
|
||||
MAME_DIR .. "src/mame/audio/exidy.h",
|
||||
MAME_DIR .. "src/mame/video/exidy.cpp",
|
||||
MAME_DIR .. "src/mame/audio/exidy440.cpp",
|
||||
MAME_DIR .. "src/mame/audio/exidy440.h",
|
||||
MAME_DIR .. "src/mame/audio/nl_fireone.h",
|
||||
|
@ -83,6 +83,8 @@ protected:
|
||||
template <class FunctionClass> using const_member_func_type = typename basetype::template const_member_func_type<FunctionClass>;
|
||||
template <class FunctionClass> using static_ref_func_type = typename basetype::template static_ref_func_type<FunctionClass>;
|
||||
|
||||
template <typename T> using suitable_functoid = typename basetype::template suitable_functoid<T>;
|
||||
|
||||
public:
|
||||
// create a standard set of constructors
|
||||
named_delegate() = default;
|
||||
@ -91,12 +93,18 @@ public:
|
||||
template <class FunctionClass> named_delegate(member_func_type<FunctionClass> funcptr, char const *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { }
|
||||
template <class FunctionClass> named_delegate(const_member_func_type<FunctionClass> funcptr, char const *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { }
|
||||
template <class FunctionClass> named_delegate(static_ref_func_type<FunctionClass> funcptr, char const *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { }
|
||||
template <typename T> named_delegate(T &&funcptr, std::enable_if_t<std::is_constructible<std::function<Signature>, T>::value, char const *> name) : basetype(std::forward<T>(funcptr)), m_name(name) { }
|
||||
template <typename T> named_delegate(T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name) : basetype(std::forward<T>(funcptr)), m_name(name) { }
|
||||
|
||||
// allow assignment
|
||||
named_delegate &operator=(named_delegate const &src) = default;
|
||||
named_delegate &operator=(named_delegate &&src) = default;
|
||||
named_delegate &operator=(std::nullptr_t) noexcept { reset(); return *this; }
|
||||
|
||||
// getters
|
||||
char const *name() const { return m_name; }
|
||||
|
||||
// unsetter
|
||||
void reset() noexcept { basetype::reset(); m_name = nullptr; }
|
||||
};
|
||||
|
||||
// ======================> device_delegate
|
||||
@ -111,6 +119,9 @@ class device_delegate<ReturnType (Params...)> : protected named_delegate<ReturnT
|
||||
private:
|
||||
using basetype = named_delegate<ReturnType (Params...)>;
|
||||
|
||||
template <typename T>
|
||||
using suitable_functoid = typename basetype::template suitable_functoid<T>;
|
||||
|
||||
template <class T, class U>
|
||||
using is_related_device_implementation = std::bool_constant<std::is_base_of_v<T, U> && std::is_base_of_v<device_t, U> >;
|
||||
template <class T, class U>
|
||||
@ -189,7 +200,7 @@ public:
|
||||
|
||||
// construct with callable object
|
||||
template <typename T>
|
||||
device_delegate(device_t &owner, T &&funcptr, std::enable_if_t<std::is_constructible<std::function<ReturnType (Params...)>, T>::value, char const *> name)
|
||||
device_delegate(device_t &owner, T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name)
|
||||
: basetype(std::forward<T>(funcptr), name)
|
||||
, detail::device_delegate_helper(owner)
|
||||
{ basetype::operator=(basetype(std::forward<T>(funcptr), name)); }
|
||||
@ -219,12 +230,14 @@ public:
|
||||
{ basetype::operator=(basetype(funcptr, name, static_cast<D *>(&object))); set_tag(finder_target().first); }
|
||||
|
||||
// setter that takes a functoid
|
||||
template <typename T> std::enable_if_t<std::is_constructible<std::function<ReturnType (Params...)>, T>::value> set(T &&funcptr, char const *name)
|
||||
template <typename T> std::enable_if_t<suitable_functoid<T>::value> set(T &&funcptr, char const *name)
|
||||
{ basetype::operator=(basetype(std::forward<T>(funcptr), name)); }
|
||||
|
||||
// unsetter
|
||||
void set(std::nullptr_t)
|
||||
{ basetype::operator=(basetype()); set_tag(finder_target().first); }
|
||||
{ reset(); }
|
||||
void reset()
|
||||
{ basetype::reset(); set_tag(finder_target().first); }
|
||||
|
||||
// perform the binding
|
||||
void resolve() { if (!basetype::isnull() && !basetype::has_object()) basetype::late_bind(bound_object()); }
|
||||
|
183
src/emu/device.h
183
src/emu/device.h
@ -353,7 +353,7 @@ constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass
|
||||
/// letters and underscores.
|
||||
/// \param Class The exposed device class name. Must be the device
|
||||
/// implementation class, or a public base of it, and must be derived
|
||||
/// from #device_t.
|
||||
/// from #device_t or #device_interface.
|
||||
/// \sa DECLARE_DEVICE_TYPE_NS DEFINE_DEVICE_TYPE
|
||||
/// DEFINE_DEVICE_TYPE_PRIVATE
|
||||
#define DECLARE_DEVICE_TYPE(Type, Class) \
|
||||
@ -379,7 +379,8 @@ constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass
|
||||
/// containing the exposed device class.
|
||||
/// \param Class The exposed device class name, without namespace
|
||||
/// qualifiers. Must be the device implementation class, or a public
|
||||
/// base of it, and must be derived from #device_t.
|
||||
/// base of it, and must be derived from #device_t or
|
||||
/// #device_interface.
|
||||
/// \sa DECLARE_DEVICE_TYPE DEFINE_DEVICE_TYPE
|
||||
/// DEFINE_DEVICE_TYPE_PRIVATE
|
||||
#define DECLARE_DEVICE_TYPE_NS(Type, Namespace, Class) \
|
||||
@ -435,7 +436,7 @@ constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass
|
||||
/// letters and underscores.
|
||||
/// \param Base The fully-qualified exposed device class name. Must be
|
||||
/// a public base of the device implementation class, and must be
|
||||
/// derived from #device_t.
|
||||
/// derived from #device_t or #device_interface.
|
||||
/// \param Class The fully-qualified device implementation class name.
|
||||
/// Must be derived from the exposed device class, and indirectly from
|
||||
/// #device_t.
|
||||
@ -457,16 +458,24 @@ constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass
|
||||
/// \}
|
||||
|
||||
|
||||
// exception classes
|
||||
/// \brief Start order dependencies not satisfied exception
|
||||
///
|
||||
/// May be thrown from the start member functions of #device_t and
|
||||
/// #device_interface implementations if start order dependencies have
|
||||
/// not been satisfied. MAME will start additional devices before
|
||||
/// reattempting to start the device that threw the exception.
|
||||
/// \sa device_t::device_start device_interface::interface_pre_start
|
||||
class device_missing_dependencies : public emu_exception { };
|
||||
|
||||
|
||||
// timer IDs for devices
|
||||
typedef u32 device_timer_id;
|
||||
|
||||
// ======================> device_t
|
||||
|
||||
// device_t represents a device
|
||||
/// \brief Base class for devices
|
||||
///
|
||||
/// The base class for all device implementations in MAME's modular
|
||||
/// architecture.
|
||||
class device_t : public delegate_late_bind
|
||||
{
|
||||
DISABLE_COPYING(device_t);
|
||||
@ -701,25 +710,102 @@ public:
|
||||
void synchronize(device_timer_id id = 0, int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, id, param, ptr); }
|
||||
void timer_expired(emu_timer &timer, device_timer_id id, int param, void *ptr) { device_timer(timer, id, param, ptr); }
|
||||
|
||||
// state saving interfaces
|
||||
template<typename ItemType>
|
||||
/// \brief Register data for save states
|
||||
///
|
||||
/// Registers data to be automatically saved/restored. Can be used
|
||||
/// with fixed-sized integer types, enumerated types marked safe for
|
||||
/// saving (see #ALLOW_SAVE_TYPE and #ALLOW_SAVE_TYPE_AND_VECTOR).
|
||||
/// Supports C arrays, \c std::array and \c std::vector. Note that
|
||||
/// \c std::vector instances must not be resized after being
|
||||
/// registered to be saved/restored.
|
||||
/// \param value Reference to the data to be saved/restored. The
|
||||
/// \c NAME macro can be used to simplify specifying the
|
||||
/// \p valname argument at the same time.
|
||||
/// \param [in] valname The name of the saved item. The combination
|
||||
/// of the \p valname and \p index arguments must be unique across
|
||||
/// saved items for a device.
|
||||
/// \param [in] index A numeric value to distinguish between saved
|
||||
/// items with the same name.
|
||||
template <typename ItemType>
|
||||
void ATTR_COLD save_item(ItemType &value, const char *valname, int index = 0)
|
||||
{
|
||||
assert(m_save);
|
||||
m_save->save_item(this, name(), tag(), index, value, valname);
|
||||
}
|
||||
template<typename ItemType, typename StructType, typename ElementType>
|
||||
|
||||
/// \brief Register a member of a structure in an array for save
|
||||
/// states
|
||||
///
|
||||
/// Registers data to be automatically saved/restored. Can be used
|
||||
/// with fixed-sized integer types, enumerated types marked safe for
|
||||
/// saving (see #ALLOW_SAVE_TYPE and #ALLOW_SAVE_TYPE_AND_VECTOR).
|
||||
/// Used to allow saving/restoring members of structures in C arrays
|
||||
/// or \c std::array instances.
|
||||
/// \param value Reference to the array of structures containing the
|
||||
/// member to be saved/restored. The #STRUCT_MEMBER macro can be
|
||||
/// used to simplify specifying the \p element and \p valname
|
||||
/// arguments at the same time.
|
||||
/// \param [in] element Pointer to the member of the structure to
|
||||
/// save/restore.
|
||||
/// \param [in] valname The name of the saved item. The combination
|
||||
/// of the \p valname and \p index arguments must be unique across
|
||||
/// saved items for a device.
|
||||
/// \param [in] index A numeric value to distinguish between saved
|
||||
/// items with the same name.
|
||||
template <typename ItemType, typename StructType, typename ElementType>
|
||||
void ATTR_COLD save_item(ItemType &value, ElementType StructType::*element, const char *valname, int index = 0)
|
||||
{
|
||||
assert(m_save);
|
||||
m_save->save_item(this, name(), tag(), index, value, element, valname);
|
||||
}
|
||||
|
||||
/// \brief Register an array of indeterminate for save states
|
||||
///
|
||||
/// Registers data to be automatically saved/restored when the
|
||||
/// length of the outermost array cannot be automatically determined
|
||||
/// at compile time. Can be used with C arrays of indeterminate
|
||||
/// length, pointers, and \c std::unique_ptr instances pointing to
|
||||
/// arrays. Use #save_item if length of the array can be determined
|
||||
/// at compile time.
|
||||
/// \param value Pointer to the array containing the data to be
|
||||
/// saved/restored. The \c NAME macro can be used to simplify
|
||||
/// specifying the \p valname argument at the same time.
|
||||
/// \param [in] valname The name of the saved item. The combination
|
||||
/// of the \p valname and \p index arguments must be unique across
|
||||
/// saved items for a device.
|
||||
/// \param [in] count The number of elements in the outermost array.
|
||||
/// \param [in] index A numeric value to distinguish between saved
|
||||
/// items with the same name.
|
||||
/// \sa save_item
|
||||
template<typename ItemType>
|
||||
void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0)
|
||||
{
|
||||
assert(m_save);
|
||||
m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), valname, count);
|
||||
}
|
||||
|
||||
/// \brief Register a member of a structure in an array of
|
||||
/// indeterminate for save states
|
||||
///
|
||||
/// Registers data to be automatically saved/restored when the
|
||||
/// length of the outermost array cannot be automatically determined
|
||||
/// at compile time. Can be used with C arrays of indeterminate
|
||||
/// length, pointers, and \c std::unique_ptr instances pointing to
|
||||
/// arrays. Use #save_item if length of the array can be determined
|
||||
/// at compile time.
|
||||
/// \param value Pointer to the array of structures containing the
|
||||
/// member to be saved/restored. The #STRUCT_MEMBER macro can be
|
||||
/// used to simplify specifying the \p element and \p valname
|
||||
/// arguments at the same time.
|
||||
/// \param [in] element Pointer to the member of the structure to
|
||||
/// save/restore.
|
||||
/// \param [in] valname The name of the saved item. The combination
|
||||
/// of the \p valname and \p index arguments must be unique across
|
||||
/// saved items for a device.
|
||||
/// \param [in] count The number of elements in the outermost array.
|
||||
/// \param [in] index A numeric value to distinguish between saved
|
||||
/// items with the same name.
|
||||
/// \sa save_item
|
||||
template<typename ItemType, typename StructType, typename ElementType>
|
||||
void ATTR_COLD save_pointer(ItemType &&value, ElementType StructType::*element, const char *valname, u32 count, int index = 0)
|
||||
{
|
||||
@ -763,8 +849,8 @@ protected:
|
||||
///
|
||||
/// Perform any final configuration tasks after all devices in the
|
||||
/// system have added machine configuration. This is called after
|
||||
/// any #device_interface mix-in interface_config_complete members
|
||||
/// have completed.
|
||||
/// any #device_interface mix-in \c interface_config_complete
|
||||
/// members have completed.
|
||||
///
|
||||
/// Note that automatic object finders will not have been resolved
|
||||
/// at the time this member is called.
|
||||
@ -793,29 +879,29 @@ protected:
|
||||
/// Implement this member to complete object resolution before any
|
||||
/// devices are started. For example it may be necessary to resolve
|
||||
/// callbacks before any devices start so initial input conditions
|
||||
/// can be set. This is called after all registerd automatic object
|
||||
/// finders are resolved.
|
||||
/// can be set. This is called after all registered automatic
|
||||
/// object finders are resolved.
|
||||
virtual void device_resolve_objects() ATTR_COLD;
|
||||
|
||||
/// \brief Device start handler
|
||||
///
|
||||
/// Implement this member to set up the initial state of the device
|
||||
/// on start. This will be called after all #device_interface
|
||||
// /mix-in interface_pre_start members have completed successfully.
|
||||
/// If the device can't start until another device has completed
|
||||
/// starting, throw a #device_missing_dependencies exception.
|
||||
/// Starting will be postponed until additional devices have been
|
||||
/// started.
|
||||
/// mix-in \c interface_pre_start members have completed
|
||||
/// successfully. If the device can't start until another device
|
||||
/// has completed starting, throw a #device_missing_dependencies
|
||||
/// exception. Starting will be postponed until additional devices
|
||||
/// have started.
|
||||
///
|
||||
/// If a device's base class is not device_t, it's good practice to
|
||||
/// check start order dependencies (and throw
|
||||
/// If a device's direct base class is not #device_t, it's good
|
||||
/// practice to check start order dependencies (and throw
|
||||
/// #device_missing_dependencies if necessary) before calling the
|
||||
/// base implementation. This will ensure that the base
|
||||
/// implementation won't be called twice if starting needs to be
|
||||
/// postponed.
|
||||
///
|
||||
/// This is the correct place to register for save states.
|
||||
/// \sa device_reset device_stop
|
||||
/// \sa device_reset device_stop save_item save_pointer
|
||||
/// device_interface::interface_pre_start
|
||||
/// device_interface::interface_post_start
|
||||
virtual void device_start() ATTR_COLD = 0;
|
||||
@ -824,8 +910,8 @@ protected:
|
||||
///
|
||||
/// Implement this member to perform additional tasks on ending an
|
||||
/// emulation session. You may deallocate memory here. This is
|
||||
/// called after interface_pre_stop is called for all
|
||||
/// #device_interface mix-ins, and before interface_post_stop is
|
||||
/// called after \c interface_pre_stop is called for all
|
||||
/// #device_interface mix-ins, and before \c interface_post_stop is
|
||||
/// called for any #device_interface mix-ins.
|
||||
/// \sa device_interface::interface_pre_stop
|
||||
/// device_interface::interface_post_stop
|
||||
@ -834,7 +920,7 @@ protected:
|
||||
/// \brief Device reset handler
|
||||
///
|
||||
/// Implement this member to provide reset behaviour. This is
|
||||
/// called after all #device_interface mix-in interface_pre_reset
|
||||
/// called after all #device_interface mix-in \c interface_pre_reset
|
||||
/// members have completed, and before any child devices are reset.
|
||||
/// All devices are reset at the beginning of an emulation session
|
||||
/// (after all devices have been started), and also when the user
|
||||
@ -859,7 +945,7 @@ protected:
|
||||
/// after child devices are reset. This is called when resetting a
|
||||
/// device after #device_reset has been called and all child devices
|
||||
/// have been reset, and before any #device_interface mix-in
|
||||
/// interface_post_reset members are called.
|
||||
/// \c interface_post_reset members are called.
|
||||
/// \sa device_reset device_interface::interface_pre_reset
|
||||
/// device_interface::interface_post_reset
|
||||
virtual void device_reset_after_children() ATTR_COLD;
|
||||
@ -870,8 +956,10 @@ protected:
|
||||
/// registered save state items are recorded. For example it may be
|
||||
/// necessary to flush caches, serialise self-referencing members or
|
||||
/// pointers into data structures. This is called after all
|
||||
/// #device_interface mix-in interface_pre_save members are called.
|
||||
/// \sa device_post_load device_interface::interface_pre_save
|
||||
/// #device_interface mix-in \c interface_pre_save members are
|
||||
/// called.
|
||||
/// \sa device_post_load save_item save_pointer
|
||||
/// device_interface::interface_pre_save
|
||||
virtual void device_pre_save() ATTR_COLD;
|
||||
|
||||
/// \brief Complete save state loading
|
||||
@ -880,8 +968,10 @@ protected:
|
||||
/// registered save state items are loaded. For example it may be
|
||||
/// necessary to update or invalidate caches, or de-serialise
|
||||
/// pointers into data structures. This is called after all
|
||||
/// #device_interface mix-in interface_post_load members are called.
|
||||
/// \sa device_pre_save device_interface::interface_post_load
|
||||
/// #device_interface mix-in \c interface_post_load members are
|
||||
/// called.
|
||||
/// \sa device_pre_save save_item save_pointer
|
||||
/// device_interface::interface_post_load
|
||||
virtual void device_post_load() ATTR_COLD;
|
||||
|
||||
virtual void device_clock_changed();
|
||||
@ -968,7 +1058,7 @@ public:
|
||||
///
|
||||
/// Perform any final configuration tasks after all devices in the
|
||||
/// system have added machine configuration. This is called before
|
||||
/// device_config_complete is called for the device.
|
||||
/// \c device_config_complete is called for the device.
|
||||
///
|
||||
/// Note that automatic object finders will not have been resolved
|
||||
/// at this time.
|
||||
@ -1003,12 +1093,12 @@ public:
|
||||
/// have been started.
|
||||
///
|
||||
/// Note that this member may be called multiple times if another
|
||||
/// device_interface mix-in throws a #device_missing_dependencies
|
||||
/// exception from its interface_pre_start member, or if the device
|
||||
/// throws a #device_missing_dependencies exception from its
|
||||
/// device_start member. You must check to ensure that operations
|
||||
/// like resource allocation are not performed multiple times, or
|
||||
/// postpone them until #interface_post_start is called.
|
||||
/// \c device_interface mix-in throws a #device_missing_dependencies
|
||||
/// exception from its \c interface_pre_start member, or if the
|
||||
/// device throws a #device_missing_dependencies exception from its
|
||||
/// \c device_start member. You must check to ensure that
|
||||
/// operations like resource allocation are not performed multiple
|
||||
/// times, or postpone them until #interface_post_start is called.
|
||||
///
|
||||
/// It's simpler to register for save states when
|
||||
/// #interface_post_start is called.
|
||||
@ -1019,22 +1109,23 @@ public:
|
||||
///
|
||||
/// Implement this member to complete mix-in start-up. This is
|
||||
/// called after #interface_pre_start is called for all
|
||||
/// device_interface mix-ins, and after device_start is called for
|
||||
/// the device. This member will only be called once, it will not
|
||||
/// be called multiple times if device starting is postponed.
|
||||
/// device_interface mix-ins, and after \c device_start is called
|
||||
/// for the device. This member will only be called once, it will
|
||||
/// not be called multiple times if device starting is postponed.
|
||||
///
|
||||
/// This member must not throw #device_missing_dependencies (start
|
||||
/// order dependencies should be checked in #interface_pre_start).
|
||||
/// This is the appropriate place to allocate resources like
|
||||
/// timers and register for save states.
|
||||
/// \sa interface_pre_start device_t::device_start
|
||||
/// device_t::save_item device_t::save_pointer
|
||||
virtual void interface_post_start() ATTR_COLD;
|
||||
|
||||
/// \brief Mix-in reset handler
|
||||
///
|
||||
/// Implement this member to provide reset behaviour. This is
|
||||
/// called before device_reset is called for the device, and before
|
||||
/// any child devices are reset. Only implement warm reset
|
||||
/// called before \c device_reset is called for the device, and
|
||||
/// before any child devices are reset. Only implement warm reset
|
||||
/// behaviour in this member. Initial cold reset conditions should
|
||||
/// be set up in #interface_pre_start and/or #interface_post_start.
|
||||
/// If you need to provide additional behaviour after child devices
|
||||
@ -1046,7 +1137,7 @@ public:
|
||||
///
|
||||
/// Implement this member to provide additional reset behaviour
|
||||
/// after child devices are reset. This is called after
|
||||
/// device_reset_after_children has been called for the device.
|
||||
/// \c device_reset_after_children has been called for the device.
|
||||
/// \sa interface_pre_reset device_t::device_reset
|
||||
/// device_t::device_reset_after_children
|
||||
virtual void interface_post_reset() ATTR_COLD;
|
||||
@ -1056,7 +1147,7 @@ public:
|
||||
/// Implement this member to perform additional tasks on ending an
|
||||
/// emulation session. Do not deallocate anything that may need to
|
||||
/// be referenced from another device_interface mix-in's
|
||||
/// interface_pre_stop member or from the device's device_stop
|
||||
/// \c interface_pre_stop member or from the device's \c device_stop
|
||||
/// member. This is called before device_stop is called for the
|
||||
/// device.
|
||||
/// \sa interface_post_stop device_t::device_stop
|
||||
@ -1066,7 +1157,7 @@ public:
|
||||
///
|
||||
/// Implement this member to perform additional tasks on ending an
|
||||
/// emulation session after the device is stopped. You can
|
||||
/// deallocate memory here. This is called after device_stop is
|
||||
/// deallocate memory here. This is called after \c device_stop is
|
||||
/// called for the device.
|
||||
/// \sa interface_pre_stop device_t::device_stop
|
||||
virtual void interface_post_stop() ATTR_COLD;
|
||||
@ -1077,7 +1168,7 @@ public:
|
||||
/// registered save state items are recorded. For example it may be
|
||||
/// necessary to flush caches, serialise self-referencing members or
|
||||
/// pointers into data structures. This is called before
|
||||
/// device_pre_save is called for the device.
|
||||
/// \c device_pre_save is called for the device.
|
||||
/// \sa interface_post_load device_t::device_pre_save
|
||||
virtual void interface_pre_save() ATTR_COLD;
|
||||
|
||||
@ -1087,7 +1178,7 @@ public:
|
||||
/// registered save state items are loaded. For example it may be
|
||||
/// necessary to update or invalidate caches, or de-serialise
|
||||
/// pointers into data structures. This is called before
|
||||
/// device_post_load is called for the device.
|
||||
/// \c device_post_load is called for the device.
|
||||
/// \sa interface_pre_save device_t::device_post_load
|
||||
virtual void interface_post_load() ATTR_COLD;
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define MAME_EMU_EMUMEM_H
|
||||
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
|
||||
using s8 = std::int8_t;
|
||||
@ -476,7 +477,6 @@ template<int Width, int AddrShift> class memory_units_descriptor;
|
||||
// =====================-> The root class of all handlers
|
||||
|
||||
// Handlers the refcounting as part of the interface
|
||||
#include <set>
|
||||
class handler_entry
|
||||
{
|
||||
DISABLE_COPYING(handler_entry);
|
||||
|
@ -392,7 +392,7 @@ extern game_driver const GAME_NAME(NAME) \
|
||||
/// avoid repetition. Screen orientation flags may be included here.
|
||||
/// \sa GAME GAMEL COMP SYST
|
||||
#define CONS(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
|
||||
GAME_DRIVER_TRAITS(NAME,FULLNAME) \
|
||||
GAME_DRIVER_TRAITS(NAME, FULLNAME) \
|
||||
extern game_driver const GAME_NAME(NAME) \
|
||||
{ \
|
||||
GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \
|
||||
@ -457,8 +457,8 @@ extern game_driver const GAME_NAME(NAME) \
|
||||
/// all systems implemented using the class in the class itself to
|
||||
/// avoid repetition. Screen orientation flags may be included here.
|
||||
/// \sa GAME GAMEL CONS SYST
|
||||
#define COMP(YEAR,NAME,PARENT,COMPAT,MACHINE,INPUT,CLASS,INIT,COMPANY,FULLNAME,FLAGS) \
|
||||
GAME_DRIVER_TRAITS(NAME,FULLNAME) \
|
||||
#define COMP(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
|
||||
GAME_DRIVER_TRAITS(NAME, FULLNAME) \
|
||||
extern game_driver const GAME_NAME(NAME) \
|
||||
{ \
|
||||
GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \
|
||||
@ -523,8 +523,8 @@ extern game_driver const GAME_NAME(NAME) \
|
||||
/// all systems implemented using the class in the class itself to
|
||||
/// avoid repetition. Screen orientation flags may be included here.
|
||||
/// \sa GAME GAMEL CONS COMP
|
||||
#define SYST(YEAR,NAME,PARENT,COMPAT,MACHINE,INPUT,CLASS,INIT,COMPANY,FULLNAME,FLAGS) \
|
||||
GAME_DRIVER_TRAITS(NAME,FULLNAME) \
|
||||
#define SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
|
||||
GAME_DRIVER_TRAITS(NAME, FULLNAME) \
|
||||
extern game_driver const GAME_NAME(NAME) \
|
||||
{ \
|
||||
GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \
|
||||
|
@ -51,18 +51,36 @@ enum save_error
|
||||
typedef named_delegate<void ()> save_prepost_delegate;
|
||||
|
||||
|
||||
// use this to declare a given type is a simple, non-pointer type that can be
|
||||
// saved; in general, this is intended only to be used for specific enum types
|
||||
// defined by your device
|
||||
/// \brief Declare a type as safe to automatically save/restore
|
||||
///
|
||||
/// Use this to declare that a given type is a simple, non-pointer type
|
||||
/// that can be saved and restored. In general, this should only be
|
||||
/// be used for specific enum types that have fixed width integer types
|
||||
/// as their storage classes.
|
||||
/// \param TYPE The name of the type to declare safe to save.
|
||||
/// \sa ALLOW_SAVE_TYPE_AND_VECTOR
|
||||
#define ALLOW_SAVE_TYPE(TYPE) \
|
||||
template <> struct save_manager::is_atom<TYPE> : public std::true_type { };
|
||||
|
||||
// use this as above, but also to declare that std::vector<TYPE> is safe as well
|
||||
/// \brief Declare a type as safe to automatically save/restore,
|
||||
/// including in \c std::vector instances
|
||||
///
|
||||
/// Used the same way as #ALLOW_SAVE_TYPE, but also declares that
|
||||
/// \c std::vector instances containing the type are safe to save.
|
||||
/// that can be saved and restored. This must not be used if
|
||||
/// \c std::vector is specialised in an incompatible way.
|
||||
/// \param TYPE The name of the type to declare safe to save.
|
||||
/// \sa ALLOW_SAVE_TYPE
|
||||
#define ALLOW_SAVE_TYPE_AND_VECTOR(TYPE) \
|
||||
ALLOW_SAVE_TYPE(TYPE) \
|
||||
template <> struct save_manager::is_vector_safe<TYPE> : public std::true_type { };
|
||||
|
||||
// use this for saving members of structures in arrays
|
||||
/// \brief Helper for referring to members of structures in arrays
|
||||
///
|
||||
/// Expands to the necessary reference, pointer to member and name to
|
||||
/// refer to a structure member.
|
||||
/// \param s Reference to a C array or \c std::array of structures.
|
||||
/// \param m Name of the structure member to refer to.
|
||||
#define STRUCT_MEMBER(s, m) s, &save_manager::pointer_unwrap<decltype(s)>::underlying_type::m, #s "." #m
|
||||
|
||||
|
||||
|
@ -2,17 +2,28 @@
|
||||
// copyright-holders:Aaron Giles
|
||||
/***************************************************************************
|
||||
|
||||
delegate.c
|
||||
delegate.cpp
|
||||
|
||||
Templates and classes to enable delegates for callbacks.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include "delegate.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#if defined(LOG_DELEGATES)
|
||||
#define LOG(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define LOG(...) do { if (false) printf(__VA_ARGS__); } while (false)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
@ -20,7 +31,7 @@
|
||||
|
||||
#if (USE_DELEGATE_TYPE == DELEGATE_TYPE_COMPATIBLE)
|
||||
|
||||
delegate_mfp::raw_mfp_data delegate_mfp::s_null_mfp = { {0 }};
|
||||
delegate_mfp::raw_mfp_data delegate_mfp::s_null_mfp = { { 0 } };
|
||||
|
||||
#endif
|
||||
|
||||
@ -40,10 +51,9 @@ delegate_mfp::raw_mfp_data delegate_mfp::s_null_mfp = { {0 }};
|
||||
delegate_generic_function delegate_mfp::convert_to_generic(delegate_generic_class *&object) const
|
||||
{
|
||||
#if defined(__arm__) || defined(__ARMEL__) || defined(__aarch64__) || defined(__MIPSEL__) || defined(__mips_isa_rev) || defined(__mips64) || defined(__EMSCRIPTEN__)
|
||||
if ((m_this_delta & 1) == 0) {
|
||||
#if defined(LOG_DELEGATES)
|
||||
printf("Calculated Addr = %08x\n", (uintptr_t)(void*)(m_function));
|
||||
#endif
|
||||
if ((m_this_delta & 1) == 0)
|
||||
{
|
||||
LOG("Calculated Addr = %p\n", reinterpret_cast<void const *>(uintptr_t(m_function)));
|
||||
object = reinterpret_cast<delegate_generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
|
||||
return reinterpret_cast<delegate_generic_function>(m_function);
|
||||
}
|
||||
@ -51,27 +61,22 @@ delegate_generic_function delegate_mfp::convert_to_generic(delegate_generic_clas
|
||||
|
||||
// otherwise, it is the byte index into the vtable where the actual function lives
|
||||
std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(object);
|
||||
#if defined(LOG_DELEGATES)
|
||||
printf("Calculated Addr = %08x (VTAB)\n", (uintptr_t)(void*)(*reinterpret_cast<delegate_generic_function *>(vtable_base + m_function + m_this_delta - 1)));
|
||||
#endif
|
||||
LOG("Calculated Addr = %p (VTAB)\n", reinterpret_cast<void const *>(uintptr_t(*reinterpret_cast<delegate_generic_function *>(vtable_base + m_function + m_this_delta - 1))));
|
||||
return *reinterpret_cast<delegate_generic_function *>(vtable_base + m_function + m_this_delta - 1);
|
||||
#else
|
||||
// apply the "this" delta to the object first
|
||||
object = reinterpret_cast<delegate_generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
|
||||
|
||||
// if the low bit of the vtable index is clear, then it is just a raw function pointer
|
||||
if (!(m_function & 1)) {
|
||||
#if defined(LOG_DELEGATES)
|
||||
printf("Calculated Addr = %08x\n", (uintptr_t)(void*)(m_function));
|
||||
#endif
|
||||
if (!(m_function & 1))
|
||||
{
|
||||
LOG("Calculated Addr = %p\n", reinterpret_cast<void const *>(uintptr_t(m_function)));
|
||||
return reinterpret_cast<delegate_generic_function>(m_function);
|
||||
}
|
||||
|
||||
// otherwise, it is the byte index into the vtable where the actual function lives
|
||||
std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(object);
|
||||
#if defined(LOG_DELEGATES)
|
||||
printf("Calculated Addr = %08x (VTAB)\n", (uintptr_t)(void*)(*reinterpret_cast<delegate_generic_function *>(vtable_base + m_function - 1)));
|
||||
#endif
|
||||
LOG("Calculated Addr = %p (VTAB)\n", reinterpret_cast<void *>(uintptr_t(*reinterpret_cast<delegate_generic_function *>(vtable_base + m_function - 1))));
|
||||
return *reinterpret_cast<delegate_generic_function *>(vtable_base + m_function - 1);
|
||||
#endif
|
||||
}
|
||||
|
@ -77,9 +77,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// standard C++ includes
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <exception>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
@ -571,9 +574,54 @@ class delegate<ReturnType (Params...)> : public delegate_base<ReturnType, Params
|
||||
{
|
||||
private:
|
||||
using basetype = delegate_base<ReturnType, Params...>;
|
||||
using functional_type = std::function<ReturnType (Params...)>;
|
||||
using functoid_setter = void (*)(delegate &);
|
||||
|
||||
functional_type m_std_func;
|
||||
template <typename T> static constexpr bool matching_non_const_call(T &&) { return false; }
|
||||
template <typename T> static constexpr bool matching_non_const_call(ReturnType (T::*)(Params...)) { return true; }
|
||||
template <typename T> static constexpr bool matching_const_call(T &&) { return false; }
|
||||
template <typename T> static constexpr bool matching_const_call(ReturnType (T::*)(Params...) const) { return true; }
|
||||
|
||||
template <typename T>
|
||||
static functoid_setter make_functoid_setter()
|
||||
{
|
||||
using unwrapped_type = std::remove_cv_t<std::remove_reference_t<T> >;
|
||||
if constexpr (matching_non_const_call(&T::operator()))
|
||||
{
|
||||
return
|
||||
[] (delegate &obj)
|
||||
{
|
||||
obj.basetype::operator=(
|
||||
basetype(
|
||||
static_cast<ReturnType (unwrapped_type::*)(Params...)>(&unwrapped_type::operator()),
|
||||
std::any_cast<unwrapped_type>(&obj.m_functoid)));
|
||||
};
|
||||
}
|
||||
else if constexpr (matching_const_call(&T::operator()))
|
||||
{
|
||||
return
|
||||
[] (delegate &obj)
|
||||
{
|
||||
obj.basetype::operator=(
|
||||
basetype(
|
||||
static_cast<ReturnType (unwrapped_type::*)(Params...) const>(&unwrapped_type::operator()),
|
||||
std::any_cast<unwrapped_type>(&obj.m_functoid)));
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return
|
||||
[] (delegate &obj)
|
||||
{
|
||||
obj.basetype::operator=(
|
||||
basetype(
|
||||
[] (unwrapped_type &f, Params... args) { return ReturnType(f(std::forward<Params>(args)...)); },
|
||||
std::any_cast<unwrapped_type>(&obj.m_functoid)));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
std::any m_functoid;
|
||||
functoid_setter m_set_functoid = nullptr;
|
||||
|
||||
protected:
|
||||
template <class FunctionClass> using traits = typename basetype::template traits<FunctionClass>;
|
||||
@ -581,35 +629,85 @@ protected:
|
||||
template <class FunctionClass> using const_member_func_type = typename traits<FunctionClass>::const_member_func_type;
|
||||
template <class FunctionClass> using static_ref_func_type = typename traits<FunctionClass>::static_ref_func_type;
|
||||
|
||||
template <typename T> using suitable_functoid = std::is_convertible<std::invoke_result_t<T, Params...>, ReturnType>;
|
||||
|
||||
public:
|
||||
// create a standard set of constructors
|
||||
delegate() : basetype() { }
|
||||
delegate(delegate const &src) : basetype(src.m_std_func ? basetype(&functional_type::operator(), &m_std_func) : static_cast<basetype const &>(src)), m_std_func(src.m_std_func) { }
|
||||
delegate(delegate &&src) : basetype(src.m_std_func ? basetype(&functional_type::operator(), &m_std_func) : std::move(static_cast<basetype &>(src))), m_std_func(std::move(src.m_std_func)) { }
|
||||
delegate(delegate const &src, delegate_late_bind &object) : basetype(src.m_std_func ? basetype(&functional_type::operator(), &m_std_func) : basetype(src, object)), m_std_func(src.m_std_func) { }
|
||||
|
||||
delegate(delegate const &src)
|
||||
: basetype(src.m_functoid.has_value() ? static_cast<const basetype &>(basetype()) : src)
|
||||
, m_functoid(src.m_functoid)
|
||||
, m_set_functoid(src.m_set_functoid)
|
||||
{
|
||||
if (m_functoid.has_value())
|
||||
m_set_functoid(*this);
|
||||
}
|
||||
|
||||
delegate(delegate &&src)
|
||||
: basetype(src.m_functoid.has_value() ? basetype() : std::move(src))
|
||||
, m_functoid(std::move(src.m_functoid))
|
||||
, m_set_functoid(std::move(src.m_set_functoid))
|
||||
{
|
||||
if (m_functoid.has_value())
|
||||
m_set_functoid(*this);
|
||||
}
|
||||
|
||||
delegate(delegate const &src, delegate_late_bind &object)
|
||||
: basetype(src.m_functoid.has_value() ? basetype() : basetype(src, object))
|
||||
, m_functoid(src.m_functoid)
|
||||
, m_set_functoid(src.m_set_functoid)
|
||||
{
|
||||
if (m_functoid.has_value())
|
||||
m_set_functoid(*this);
|
||||
}
|
||||
|
||||
template <class FunctionClass> delegate(member_func_type<FunctionClass> funcptr, FunctionClass *object) : basetype(funcptr, object) { }
|
||||
template <class FunctionClass> delegate(const_member_func_type<FunctionClass> funcptr, FunctionClass *object) : basetype(funcptr, object) { }
|
||||
explicit delegate(functional_type &&functoid) : basetype(&functional_type::operator(), &m_std_func), m_std_func(std::move(functoid)) { }
|
||||
template <class FunctionClass> delegate(static_ref_func_type<FunctionClass> funcptr, FunctionClass *object) : basetype(funcptr, object) { }
|
||||
|
||||
template <typename T>
|
||||
explicit delegate(T &&functoid, std::enable_if_t<suitable_functoid<T>::value, int> = 0)
|
||||
: basetype()
|
||||
, m_functoid(std::forward<T>(functoid))
|
||||
, m_set_functoid(make_functoid_setter<T>())
|
||||
{
|
||||
m_set_functoid(*this);
|
||||
}
|
||||
|
||||
delegate &operator=(std::nullptr_t) noexcept
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
delegate &operator=(delegate const &src)
|
||||
{
|
||||
if (src.m_std_func)
|
||||
basetype::operator=(basetype(&functional_type::operator(), &m_std_func));
|
||||
m_functoid = src.m_functoid;
|
||||
m_set_functoid = src.m_set_functoid;
|
||||
if (m_functoid.has_value())
|
||||
m_set_functoid(*this);
|
||||
else
|
||||
basetype::operator=(src);
|
||||
m_std_func = src.m_std_func;
|
||||
return *this;
|
||||
}
|
||||
|
||||
delegate &operator=(delegate &&src)
|
||||
{
|
||||
if (src.m_std_func)
|
||||
basetype::operator=(basetype(&functional_type::operator(), &m_std_func));
|
||||
m_functoid = std::move(src.m_functoid);
|
||||
m_set_functoid = std::move(src.m_set_functoid);
|
||||
if (m_functoid.has_value())
|
||||
m_set_functoid(*this);
|
||||
else
|
||||
basetype::operator=(std::move(src));
|
||||
m_std_func = std::move(src.m_std_func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
basetype::operator=(basetype());
|
||||
m_functoid.reset();
|
||||
m_set_functoid = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MAME_UTIL_DELEGATE_H
|
||||
|
Loading…
Reference in New Issue
Block a user