diff options
Diffstat (limited to 'src/emu/devdelegate.h')
-rw-r--r-- | src/emu/devdelegate.h | 262 |
1 files changed, 213 insertions, 49 deletions
diff --git a/src/emu/devdelegate.h b/src/emu/devdelegate.h index 8bdef60f880..bbb94930d43 100644 --- a/src/emu/devdelegate.h +++ b/src/emu/devdelegate.h @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles, Vas Crabb /*************************************************************************** devdelegate.h @@ -7,7 +7,6 @@ Delegates that are late-bound to MAME devices. ***************************************************************************/ - #ifndef MAME_EMU_DEVDELEGATE_H #define MAME_EMU_DEVDELEGATE_H @@ -15,28 +14,59 @@ #include "delegate.h" +#include <array> +#include <functional> +#include <type_traits> +#include <utility> + + +namespace emu { + +//************************************************************************** +// FORWARD DECLARATIONS +//************************************************************************** + +template <typename Signature, unsigned Count> class device_delegate_array; + + //************************************************************************** // TYPE DEFINITIONS //************************************************************************** +namespace detail { + // ======================> device_delegate_helper // device_delegate_helper does non-template work class device_delegate_helper { +public: + // accessors + char const *finder_tag() const { return m_tag; } + std::pair<device_t &, char const *> finder_target() const { return std::make_pair(m_base, m_tag); } + protected: - // constructor - device_delegate_helper(const char *devname) : m_device_name(devname) { } + // construct/assign + device_delegate_helper(device_t &owner, char const *tag = nullptr) : m_base(owner), m_tag(tag) { } + template <class DeviceClass, bool Required> device_delegate_helper(device_finder<DeviceClass, Required> const &finder); + device_delegate_helper(device_delegate_helper const &) = default; + device_delegate_helper &operator=(device_delegate_helper const &) = default; // internal helpers - delegate_late_bind &bound_object(device_t &search_root) const; - static const char *safe_tag(device_t *object); + delegate_late_bind &bound_object() const; + void set_tag(device_t &object) { m_base = object; m_tag = nullptr; } + void set_tag(device_t &base, char const *tag) { m_base = base; m_tag = tag; } + void set_tag(char const *tag); + template <class DeviceClass, bool Required> void set_tag(device_finder<DeviceClass, Required> const &finder); - // internal state - const char *m_device_name; +private: + std::reference_wrapper<device_t> m_base; + char const *m_tag; }; +} // namespace detail + // ======================> named_delegate template <typename Signature> @@ -45,7 +75,7 @@ class named_delegate : public delegate<Signature> private: using basetype = delegate<Signature>; - const char * m_name; // name string + char const *m_name = nullptr; // name string protected: template <class FunctionClass> using member_func_type = typename basetype::template member_func_type<FunctionClass>; @@ -54,59 +84,193 @@ protected: public: // create a standard set of constructors - named_delegate() : basetype(), m_name(nullptr) { } - explicit named_delegate(const basetype &src) : basetype(src), m_name(src.m_name) { } - named_delegate(const basetype &src, delegate_late_bind &object) : basetype(src, object), m_name(src.m_name) { } - template <class FunctionClass> named_delegate(member_func_type<FunctionClass> funcptr, const char *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { } - template <class FunctionClass> named_delegate(const_member_func_type<FunctionClass> funcptr, const char *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { } - explicit named_delegate(std::function<Signature> funcptr, const char *name) : basetype(funcptr), m_name(name) { } - template <class FunctionClass> named_delegate(static_ref_func_type<FunctionClass> funcptr, const char *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { } - named_delegate &operator=(const basetype &src) { basetype::operator=(src); m_name = src.m_name; return *this; } - - const char *name() const { return m_name; } + named_delegate() = default; + named_delegate(named_delegate const &) = default; + named_delegate(named_delegate const &src, delegate_late_bind &object) : basetype(src, object), m_name(src.m_name) { } + 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) { } + + // allow assignment + named_delegate &operator=(named_delegate const &src) = default; + + char const *name() const { return m_name; } }; // ======================> device_delegate // device_delegate is a delegate that wraps with a device tag and can be easily // late bound without replicating logic everywhere -template <typename Signature> -class device_delegate : public named_delegate<Signature>, public device_delegate_helper +template <typename Signature> class device_delegate; + +template <typename ReturnType, typename... Params> +class device_delegate<ReturnType (Params...)> : protected named_delegate<ReturnType (Params...)>, public detail::device_delegate_helper { - using thistype = device_delegate<Signature>; - using basetype = named_delegate<Signature>; - template <class FunctionClass> using member_func_type = typename basetype::template member_func_type<FunctionClass>; - 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>; +private: + using basetype = named_delegate<ReturnType (Params...)>; + + template <class T, class U> struct is_related_device_implementation + { static constexpr bool value = std::is_base_of<T, U>::value && std::is_base_of<device_t, U>::value; }; + template <class T, class U> struct is_related_device_interface + { static constexpr bool value = std::is_base_of<T, U>::value && std::is_base_of<device_interface, U>::value && !std::is_base_of<device_t, U>::value; }; + template <class T, class U> struct is_related_device + { static constexpr bool value = is_related_device_implementation<T, U>::value || is_related_device_interface<T, U>::value; }; + + template <class T> static std::enable_if_t<is_related_device_implementation<T, T>::value, device_t &> get_device(T &object) { return object; } + template <class T> static std::enable_if_t<is_related_device_interface<T, T>::value, device_t &> get_device(T &object) { return object.device(); } public: - // provide the same constructors as the base class - device_delegate() : basetype(), device_delegate_helper(nullptr) { } - device_delegate(const basetype &src) : basetype(src), device_delegate_helper(src.m_device_name) { } - device_delegate(const basetype &src, delegate_late_bind &object) : basetype(src, object), device_delegate_helper(src.m_device_name) { } - template <class FunctionClass> device_delegate(member_func_type<FunctionClass> funcptr, const char *name, FunctionClass *object) : basetype(funcptr, name, object), device_delegate_helper(safe_tag(dynamic_cast<device_t *>(object))) { } - template <class FunctionClass> device_delegate(const_member_func_type<FunctionClass> funcptr, const char *name, FunctionClass *object) : basetype(funcptr, name, object), device_delegate_helper(safe_tag(dynamic_cast<device_t *>(object))) { } - template <class FunctionClass> device_delegate(static_ref_func_type<FunctionClass> funcptr, const char *name, FunctionClass *object) : basetype(funcptr, name, object), device_delegate_helper(safe_tag(dynamic_cast<device_t *>(object))) { } - device_delegate(std::function<Signature> funcptr, const char *name) : basetype(funcptr, name), device_delegate_helper(nullptr) { } - device_delegate &operator=(const thistype &src) { basetype::operator=(src); m_device_name = src.m_device_name; return *this; } - - // provide additional constructors that take a device name string - template <class FunctionClass> device_delegate(member_func_type<FunctionClass> funcptr, const char *name, const char *devname) : basetype(funcptr, name, static_cast<FunctionClass *>(nullptr)), device_delegate_helper(devname) { } - template <class FunctionClass> device_delegate(member_func_type<FunctionClass> funcptr, const char *name, const char *devname, FunctionClass *) : basetype(funcptr, name, static_cast<FunctionClass *>(nullptr)), device_delegate_helper(devname) { } - template <class FunctionClass> device_delegate(const_member_func_type<FunctionClass> funcptr, const char *name, const char *devname) : basetype(funcptr, name, static_cast<FunctionClass *>(nullptr)), device_delegate_helper(devname) { } - template <class FunctionClass> device_delegate(const_member_func_type<FunctionClass> funcptr, const char *name, const char *devname, FunctionClass *) : basetype(funcptr, name, static_cast<FunctionClass *>(nullptr)), device_delegate_helper(devname) { } - template <class FunctionClass> device_delegate(static_ref_func_type<FunctionClass> funcptr, const char *name, const char *devname, FunctionClass *) : basetype(funcptr, name, static_cast<FunctionClass *>(nullptr)), device_delegate_helper(devname) { } - device_delegate(static_ref_func_type<device_t> funcptr, const char *name) : basetype(funcptr, name, static_cast<device_t *>(nullptr)), device_delegate_helper(nullptr) { } - - // and constructors that provide a search root - device_delegate(const thistype &src, device_t &search_root) : basetype(src), device_delegate_helper(src.m_device_name) { bind_relative_to(search_root); } + template <unsigned Count> using array = device_delegate_array<ReturnType (Params...), Count>; + + template <typename T> struct supports_callback + { static constexpr bool value = std::is_constructible<device_delegate, device_t &, char const *, T, char const *>::value; }; + + // construct/assign + explicit device_delegate(device_t &owner) : basetype(), detail::device_delegate_helper(owner) { } + device_delegate(device_delegate const &) = default; + device_delegate &operator=(device_delegate const &) = default; + + // construct with prototype and target + device_delegate(basetype const &proto, device_t &object) : basetype(proto, object), detail::device_delegate_helper(object) { } + device_delegate(device_delegate const &proto, device_t &object) : basetype(proto, object), detail::device_delegate_helper(object) { } + + // construct with base and tag + template <class D> + device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...), char const *name) + : basetype(funcptr, name, static_cast<D *>(nullptr)) + , detail::device_delegate_helper(base, tag) + { } + template <class D> + device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...) const, char const *name) + : basetype(funcptr, name, static_cast<D *>(nullptr)) + , detail::device_delegate_helper(base, tag) + { } + template <class D> + device_delegate(device_t &base, char const *tag, ReturnType (*funcptr)(D &, Params...), char const *name) + : basetype(funcptr, name, static_cast<D *>(nullptr)) + , detail::device_delegate_helper(base, tag) + { } + + // construct with device finder + template <class D, bool R, class E> + device_delegate(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...), char const *name) + : basetype(funcptr, name, static_cast<E *>(nullptr)) + , detail::device_delegate_helper(finder) + { } + template <class D, bool R, class E> + device_delegate(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...) const, char const *name) + : basetype(funcptr, name, static_cast<E *>(nullptr)) + , detail::device_delegate_helper(finder) + { } + template <class D, bool R, class E> + device_delegate(device_finder<D, R> const &finder, ReturnType (*funcptr)(E &, Params...), char const *name) + : basetype(funcptr, name, static_cast<E *>(nullptr)) + , detail::device_delegate_helper(finder) + { } + + // construct with target object + template <class T, class D> + device_delegate(T &object, ReturnType (D::*funcptr)(Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name) + : basetype(funcptr, name, static_cast<D *>(&object)) + , detail::device_delegate_helper(get_device(object)) + { } + template <class T, class D> + device_delegate(T &object, ReturnType (D::*funcptr)(Params...) const, std::enable_if_t<is_related_device<D, T>::value, char const *> name) + : basetype(funcptr, name, static_cast<D *>(&object)) + , detail::device_delegate_helper(get_device(object)) + { } + template <class T, class D> + device_delegate(T &object, ReturnType (*funcptr)(D &, Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name) + : basetype(funcptr, name, static_cast<D *>(&object)) + , detail::device_delegate_helper(get_device(object)) + { } + + // 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) + : basetype(std::forward<T>(funcptr), name) + , detail::device_delegate_helper(owner) + { basetype::operator=(basetype(std::forward<T>(funcptr), name)); } + + // setters that implicitly bind to the current device + template <class D> void set(ReturnType (D::*funcptr)(Params...), char const *name) + { basetype::operator=(basetype(funcptr, name, static_cast<D *>(nullptr))); set_tag(nullptr); } + template <class D> void set(ReturnType (D::*funcptr)(Params...) const, char const *name) + { basetype::operator=(basetype(funcptr, name, static_cast<D *>(nullptr))); set_tag(nullptr); } + template <class D> void set(ReturnType (*funcptr)(D &, Params...), char const *name) + { basetype::operator=(basetype(funcptr, name, static_cast<D *>(nullptr))); set_tag(nullptr); } + + // setters that take a tag-like object specifying the target + template <typename T, class D> void set(T &&tag, ReturnType (D::*funcptr)(Params...), char const *name) + { basetype::operator=(basetype(funcptr, name, static_cast<D *>(nullptr))); set_tag(std::forward<T>(tag)); } + template <typename T, class D> void set(T &&tag, ReturnType (D::*funcptr)(Params...) const, char const *name) + { basetype::operator=(basetype(funcptr, name, static_cast<D *>(nullptr))); set_tag(std::forward<T>(tag)); } + template <typename T, class D> void set(T &&tag, ReturnType (*funcptr)(D &, Params...), char const *name) + { basetype::operator=(basetype(funcptr, name, static_cast<D *>(nullptr))); set_tag(std::forward<T>(tag)); } + + // setters that take a target object + template <class T, class D> std::enable_if_t<std::is_base_of<D, T>::value> set(T &object, ReturnType (D::*funcptr)(Params...), char const *name) + { basetype::operator=(basetype(funcptr, name, static_cast<D *>(&object))); set_tag(finder_target().first); } + template <class T, class D> std::enable_if_t<std::is_base_of<D, T>::value> set(T &object, ReturnType (D::*funcptr)(Params...) const, char const *name) + { basetype::operator=(basetype(funcptr, name, static_cast<D *>(&object))); set_tag(finder_target().first); } + template <class T, class D> std::enable_if_t<std::is_base_of<D, T>::value> set(T &object, ReturnType (*funcptr)(D &, Params...), char const *name) + { 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) + { basetype::operator=(basetype(std::forward<T>(funcptr), name)); } + + // unsetter + void set(std::nullptr_t) + { basetype::operator=(basetype()); set_tag(finder_target().first); } // perform the binding - void bind_relative_to(device_t &search_root) { if (!basetype::isnull()) basetype::late_bind(bound_object(search_root)); } + void resolve() { if (!basetype::isnull() && !basetype::has_object()) basetype::late_bind(bound_object()); } - // getter (for validation purposes) - const char *device_name() const { return m_device_name; } + // accessors + using basetype::operator(); + using basetype::isnull; + using basetype::has_object; + using basetype::name; }; +// simplifies constructing an array of delegates with a single owner +template <typename Signature, unsigned Count> +class device_delegate_array : public std::array<device_delegate<Signature>, Count> +{ +private: + template <unsigned... V> + device_delegate_array(device_t &owner, std::integer_sequence<unsigned, V...> const &) + : std::array<device_delegate<Signature>, Count>{ make_one<V>(owner)... } + { + } + + template <unsigned N> device_delegate<Signature> make_one(device_t &owner) + { + return device_delegate<Signature>(owner); + } + +public: + using std::array<device_delegate<Signature>, Count>::array; + + device_delegate_array(device_t &owner) + : device_delegate_array(owner, std::make_integer_sequence<unsigned, Count>()) + { + } + + void resolve_all() + { + for (device_delegate<Signature> &elem : *this) + elem.resolve(); + } +}; + +} // namespace emu + + +using emu::named_delegate; +using emu::device_delegate; + #endif // MAME_EMU_DEVDELEGATE_H |