// license:BSD-3-Clause // copyright-holders:Aaron Giles, Vas Crabb /*************************************************************************** devdelegate.h Delegates that are late-bound to MAME devices. ***************************************************************************/ #ifndef MAME_EMU_DEVDELEGATE_H #define MAME_EMU_DEVDELEGATE_H #pragma once #include "delegate.h" #include #include #include #include namespace emu { //************************************************************************** // FORWARD DECLARATIONS //************************************************************************** template 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 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 device_delegate_helper(device_finder 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 void set_tag(device_finder const &finder); private: std::reference_wrapper m_base; char const *m_tag; }; } // namespace detail // ======================> named_delegate template class named_delegate : public delegate { private: using basetype = delegate; char const *m_name = nullptr; // name string protected: template using member_func_type = typename basetype::template member_func_type; template using const_member_func_type = typename basetype::template const_member_func_type; template using static_ref_func_type = typename basetype::template static_ref_func_type; public: // create a standard set of constructors 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 named_delegate(member_func_type funcptr, char const *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { } template named_delegate(const_member_func_type funcptr, char const *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { } template named_delegate(static_ref_func_type funcptr, char const *name, FunctionClass *object) : basetype(funcptr, object), m_name(name) { } template named_delegate(T &&funcptr, std::enable_if_t, T>::value, char const *> name) : basetype(std::forward(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 class device_delegate; template class device_delegate : protected named_delegate, public detail::device_delegate_helper { private: using basetype = named_delegate; template struct is_related_device_implementation { static constexpr bool value = std::is_base_of::value && std::is_base_of::value; }; template struct is_related_device_interface { static constexpr bool value = std::is_base_of::value && std::is_base_of::value && !std::is_base_of::value; }; template struct is_related_device { static constexpr bool value = is_related_device_implementation::value || is_related_device_interface::value; }; template static std::enable_if_t::value, device_t &> get_device(T &object) { return object; } template static std::enable_if_t::value, device_t &> get_device(T &object) { return object.device(); } public: template using array = device_delegate_array; template struct supports_callback { static constexpr bool value = std::is_constructible::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 device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...), char const *name) : basetype(funcptr, name, static_cast(nullptr)) , detail::device_delegate_helper(base, tag) { } template device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...) const, char const *name) : basetype(funcptr, name, static_cast(nullptr)) , detail::device_delegate_helper(base, tag) { } template device_delegate(device_t &base, char const *tag, ReturnType (*funcptr)(D &, Params...), char const *name) : basetype(funcptr, name, static_cast(nullptr)) , detail::device_delegate_helper(base, tag) { } // construct with device finder template device_delegate(device_finder const &finder, ReturnType (E::*funcptr)(Params...), char const *name) : basetype(funcptr, name, static_cast(nullptr)) , detail::device_delegate_helper(finder) { } template device_delegate(device_finder const &finder, ReturnType (E::*funcptr)(Params...) const, char const *name) : basetype(funcptr, name, static_cast(nullptr)) , detail::device_delegate_helper(finder) { } template device_delegate(device_finder const &finder, ReturnType (*funcptr)(E &, Params...), char const *name) : basetype(funcptr, name, static_cast(nullptr)) , detail::device_delegate_helper(finder) { } // construct with target object template device_delegate(T &object, ReturnType (D::*funcptr)(Params...), std::enable_if_t::value, char const *> name) : basetype(funcptr, name, static_cast(&object)) , detail::device_delegate_helper(get_device(object)) { } template device_delegate(T &object, ReturnType (D::*funcptr)(Params...) const, std::enable_if_t::value, char const *> name) : basetype(funcptr, name, static_cast(&object)) , detail::device_delegate_helper(get_device(object)) { } template device_delegate(T &object, ReturnType (*funcptr)(D &, Params...), std::enable_if_t::value, char const *> name) : basetype(funcptr, name, static_cast(&object)) , detail::device_delegate_helper(get_device(object)) { } // construct with callable object template device_delegate(device_t &owner, T &&funcptr, std::enable_if_t, T>::value, char const *> name) : basetype(std::forward(funcptr), name) , detail::device_delegate_helper(owner) { basetype::operator=(basetype(std::forward(funcptr), name)); } // setters that implicitly bind to the current device template void set(ReturnType (D::*funcptr)(Params...), char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(nullptr))); set_tag(nullptr); } template void set(ReturnType (D::*funcptr)(Params...) const, char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(nullptr))); set_tag(nullptr); } template void set(ReturnType (*funcptr)(D &, Params...), char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(nullptr))); set_tag(nullptr); } // setters that take a tag-like object specifying the target template void set(T &&tag, ReturnType (D::*funcptr)(Params...), char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(nullptr))); set_tag(std::forward(tag)); } template void set(T &&tag, ReturnType (D::*funcptr)(Params...) const, char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(nullptr))); set_tag(std::forward(tag)); } template void set(T &&tag, ReturnType (*funcptr)(D &, Params...), char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(nullptr))); set_tag(std::forward(tag)); } // setters that take a target object template std::enable_if_t::value> set(T &object, ReturnType (D::*funcptr)(Params...), char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(&object))); set_tag(finder_target().first); } template std::enable_if_t::value> set(T &object, ReturnType (D::*funcptr)(Params...) const, char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(&object))); set_tag(finder_target().first); } template std::enable_if_t::value> set(T &object, ReturnType (*funcptr)(D &, Params...), char const *name) { basetype::operator=(basetype(funcptr, name, static_cast(&object))); set_tag(finder_target().first); } // setter that takes a functoid template std::enable_if_t, T>::value> set(T &&funcptr, char const *name) { basetype::operator=(basetype(std::forward(funcptr), name)); } // unsetter void set(std::nullptr_t) { basetype::operator=(basetype()); 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; }; // simplifies constructing an array of delegates with a single owner template class device_delegate_array : public std::array, Count> { private: template device_delegate_array(device_t &owner, std::integer_sequence const &) : std::array, Count>{{ make_one(owner)... }} { } template device_delegate make_one(device_t &owner) { return device_delegate(owner); } public: using std::array, Count>::array; device_delegate_array(device_t &owner) : device_delegate_array(owner, std::make_integer_sequence()) { } void resolve_all() { for (device_delegate &elem : *this) elem.resolve(); } }; } // namespace emu using emu::named_delegate; using emu::device_delegate; #endif // MAME_EMU_DEVDELEGATE_H