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.h284
1 files changed, 208 insertions, 76 deletions
diff --git a/src/emu/devdelegate.h b/src/emu/devdelegate.h
index 5f7af89383b..3a63c874d92 100644
--- a/src/emu/devdelegate.h
+++ b/src/emu/devdelegate.h
@@ -43,41 +43,6 @@ 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:
- // 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() 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);
-
-private:
- std::reference_wrapper<device_t> m_base;
- char const *m_tag;
-};
-
-} // namespace detail
-
-
-// ======================> named_delegate
template <typename Signature>
class named_delegate : public delegate<Signature>
{
@@ -104,8 +69,8 @@ public:
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=(named_delegate const &) = default;
+ named_delegate &operator=(named_delegate &&) = default;
named_delegate &operator=(std::nullptr_t) noexcept { reset(); return *this; }
// getters
@@ -115,14 +80,53 @@ public:
void reset() noexcept { basetype::reset(); m_name = nullptr; }
};
-// ======================> device_delegate
+template <class FunctionClass, typename ReturnType, typename... Params>
+named_delegate(ReturnType (FunctionClass::*)(Params...), char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>;
-// 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;
+template <class FunctionClass, typename ReturnType, typename... Params>
+named_delegate(ReturnType (FunctionClass::*)(Params...) const, char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>;
+
+template <class FunctionClass, typename ReturnType, typename... Params>
+named_delegate(ReturnType (*)(FunctionClass &, Params...), char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>;
+
+
+namespace detail {
+
+// 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:
+ // 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() 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);
+
+private:
+ std::reference_wrapper<device_t> m_base;
+ char const *m_tag;
+};
+
+
+// device_delegate_base doesn't need to be specialised on return type
+
+template <typename Signature> class device_delegate_base;
template <typename ReturnType, typename... Params>
-class device_delegate<ReturnType (Params...)> : protected named_delegate<ReturnType (Params...)>, public detail::device_delegate_helper
+class device_delegate_base<ReturnType (Params...)> : protected named_delegate<ReturnType (Params...)>, public device_delegate_helper
{
private:
using basetype = named_delegate<ReturnType (Params...)>;
@@ -141,77 +145,72 @@ private:
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:
- template <unsigned Count> using array = device_delegate_array<ReturnType (Params...), Count>;
-
- template <typename T>
- using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >;
-
// 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;
+ explicit device_delegate_base(device_t &owner) : basetype(), device_delegate_helper(owner) { }
+ device_delegate_base(device_delegate_base const &) = default;
+ device_delegate_base &operator=(device_delegate_base 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) { }
+ device_delegate_base(basetype const &proto, device_t &object) : basetype(proto, object), device_delegate_helper(object) { }
+ device_delegate_base(device_delegate_base const &proto, device_t &object) : basetype(proto, object), 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)
+ device_delegate_base(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)
+ , device_delegate_helper(base, tag)
{ }
template <class D>
- device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...) const, char const *name)
+ device_delegate_base(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)
+ , device_delegate_helper(base, tag)
{ }
template <class D>
- device_delegate(device_t &base, char const *tag, ReturnType (*funcptr)(D &, Params...), char const *name)
+ device_delegate_base(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)
+ , 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)
+ device_delegate_base(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)
+ , 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)
+ device_delegate_base(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)
+ , 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)
+ device_delegate_base(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)
+ , 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)
+ device_delegate_base(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))
+ , 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)
+ device_delegate_base(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))
+ , 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)
+ device_delegate_base(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))
+ , device_delegate_helper(get_device(object))
{ }
// construct with callable object
template <typename T>
- device_delegate(device_t &owner, T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name)
+ device_delegate_base(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)); }
+ , device_delegate_helper(owner)
+ { }
// setters that implicitly bind to the current device
template <class D> void set(ReturnType (D::*funcptr)(Params...), char const *name)
@@ -247,18 +246,117 @@ public:
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()); }
-
// accessors
using basetype::operator();
using basetype::isnull;
using basetype::has_object;
using basetype::name;
+
+ // perform the binding
+ void resolve()
+ {
+ if (!this->isnull() && !this->has_object())
+ this->late_bind(bound_object());
+ }
+};
+
+} // namespace detail
+
+
+// device_delegate is a delegate that can be late bound to a device specification
+
+template <typename Signature> class device_delegate;
+
+template <typename ReturnType, typename... Params>
+class device_delegate<ReturnType (Params...)> : protected detail::device_delegate_base<ReturnType (Params...)>
+{
+public:
+ template <unsigned Count> using array = device_delegate_array<ReturnType (Params...), Count>;
+
+ template <typename T>
+ using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >;
+
+ // constructors
+ using detail::device_delegate_base<ReturnType (Params...)>::device_delegate_base;
+ device_delegate(device_delegate const &) = default;
+ device_delegate(device_delegate const &proto, device_t &object) : detail::device_delegate_base<ReturnType (Params...)>(proto, object) { }
+
+ // assignment
+ device_delegate &operator=(device_delegate const &) = default;
+ device_delegate &operator=(std::nullptr_t) { this->reset(); }
+
+ // setters/unsetters
+ void set(device_delegate const &src) { operator=(src); }
+ using detail::device_delegate_base<ReturnType (Params...)>::set;
+ using detail::device_delegate_base<ReturnType (Params...)>::reset;
+
+ // accessors
+ using detail::device_delegate_base<ReturnType (Params...)>::operator();
+ using detail::device_delegate_base<ReturnType (Params...)>::isnull;
+ using detail::device_delegate_base<ReturnType (Params...)>::has_object;
+ using detail::device_delegate_base<ReturnType (Params...)>::name;
+ using detail::device_delegate_base<ReturnType (Params...)>::finder_tag;
+ using detail::device_delegate_base<ReturnType (Params...)>::finder_target;
+
+ // perform the binding
+ using detail::device_delegate_base<ReturnType (Params...)>::resolve;
+
+ template <typename T>
+ void resolve_safe(T &&dflt)
+ {
+ if (this->isnull())
+ this->set([result = std::decay_t<T>(std::forward<T>(dflt))] (Params...) { return ReturnType(result); }, "default");
+ else if (!this->has_object())
+ this->late_bind(this->bound_object());
+ }
+};
+
+template <typename... Params>
+class device_delegate<void (Params...)> : protected detail::device_delegate_base<void (Params...)>
+{
+public:
+ template <unsigned Count> using array = device_delegate_array<void (Params...), Count>;
+
+ template <typename T>
+ using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >;
+
+ // constructors
+ using detail::device_delegate_base<void (Params...)>::device_delegate_base;
+ device_delegate(device_delegate const &) = default;
+ device_delegate(device_delegate const &proto, device_t &object) : detail::device_delegate_base<void (Params...)>(proto, object) { }
+
+ // assignment
+ device_delegate &operator=(device_delegate const &) = default;
+ device_delegate &operator=(std::nullptr_t) { this->reset(); }
+
+ // setters/unsetters
+ void set(device_delegate const &src) { operator=(src); }
+ using detail::device_delegate_base<void (Params...)>::set;
+ using detail::device_delegate_base<void (Params...)>::reset;
+
+ // accessors
+ using detail::device_delegate_base<void (Params...)>::operator();
+ using detail::device_delegate_base<void (Params...)>::isnull;
+ using detail::device_delegate_base<void (Params...)>::has_object;
+ using detail::device_delegate_base<void (Params...)>::name;
+ using detail::device_delegate_base<void (Params...)>::finder_tag;
+ using detail::device_delegate_base<void (Params...)>::finder_target;
+
+ // perform the binding
+ using detail::device_delegate_base<void (Params...)>::resolve;
+
+ void resolve_safe()
+ {
+ if (this->isnull())
+ this->set([] (Params...) { }, "default");
+ else if (!this->has_object())
+ this->late_bind(this->bound_object());
+ }
};
// 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>
{
@@ -288,8 +386,42 @@ public:
for (device_delegate<Signature> &elem : *this)
elem.resolve();
}
+
+ template <typename... T>
+ void resolve_all_safe(T &&... args)
+ {
+ for (device_delegate<Signature> &elem : *this)
+ elem.resolve_safe(args...);
+ }
};
+template <class D, typename ReturnType, typename... Params>
+device_delegate(device_t &, char const *, ReturnType (D::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, typename ReturnType, typename... Params>
+device_delegate(device_t &, char const *, ReturnType (D::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, typename ReturnType, typename... Params>
+device_delegate(device_t &, char const *, ReturnType (*)(D &, Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, bool R, class E, typename ReturnType, typename... Params>
+device_delegate(device_finder<D, R> const &, ReturnType (E::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, bool R, class E, typename ReturnType, typename... Params>
+device_delegate(device_finder<D, R> const &, ReturnType (E::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, bool R, class E, typename ReturnType, typename... Params>
+device_delegate(device_finder<D, R> const &, ReturnType (*)(E &, Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class T, class D, typename ReturnType, typename... Params>
+device_delegate(T &, ReturnType (D::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class T, class D, typename ReturnType, typename... Params>
+device_delegate(T &, ReturnType (D::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class T, class D, typename ReturnType, typename... Params>
+device_delegate(T &, ReturnType (*)(D &, Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
} // namespace emu