summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/devdelegate.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/devdelegate.h')
-rw-r--r--src/emu/devdelegate.h262
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