зеркало из https://github.com/microsoft/cppwinrt.git
Register event handlers with `shared_ptr` and `weak_ptr` (#1330)
This commit is contained in:
Родитель
297454ee28
Коммит
953d65cc85
|
@ -2446,6 +2446,8 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
|
||||||
template <typename O, typename M> %(O* object, M method);
|
template <typename O, typename M> %(O* object, M method);
|
||||||
template <typename O, typename M> %(com_ptr<O>&& object, M method);
|
template <typename O, typename M> %(com_ptr<O>&& object, M method);
|
||||||
template <typename O, typename M> %(weak_ref<O>&& object, M method);
|
template <typename O, typename M> %(weak_ref<O>&& object, M method);
|
||||||
|
template <typename O, typename M> %(std::shared_ptr<O>&& object, M method);
|
||||||
|
template <typename O, typename M> %(std::weak_ptr<O>&& object, M method);
|
||||||
auto operator()(%) const;
|
auto operator()(%) const;
|
||||||
};
|
};
|
||||||
)";
|
)";
|
||||||
|
@ -2462,6 +2464,8 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
|
||||||
type_name,
|
type_name,
|
||||||
type_name,
|
type_name,
|
||||||
type_name,
|
type_name,
|
||||||
|
type_name,
|
||||||
|
type_name,
|
||||||
bind<write_consume_params>(signature));
|
bind<write_consume_params>(signature));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2523,6 +2527,14 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
|
||||||
%([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } })
|
%([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } })
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
template <%> template <typename O, typename M> %<%>::%(std::shared_ptr<O>&& object, M method) :
|
||||||
|
%([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); })
|
||||||
|
{
|
||||||
|
}
|
||||||
|
template <%> template <typename O, typename M> %<%>::%(std::weak_ptr<O>&& object, M method) :
|
||||||
|
%([o = std::move(object), method](auto&&... args) { if (auto s = o.lock()) { ((*s).*(method))(args...); } })
|
||||||
|
{
|
||||||
|
}
|
||||||
template <%> auto %<%>::operator()(%) const
|
template <%> auto %<%>::operator()(%) const
|
||||||
{%
|
{%
|
||||||
check_hresult((*(impl::abi_t<%<%>>**)this)->Invoke(%));%
|
check_hresult((*(impl::abi_t<%<%>>**)this)->Invoke(%));%
|
||||||
|
@ -2562,6 +2574,16 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
|
||||||
bind<write_generic_typenames>(generics),
|
bind<write_generic_typenames>(generics),
|
||||||
type_name,
|
type_name,
|
||||||
bind_list(", ", generics),
|
bind_list(", ", generics),
|
||||||
|
type_name,
|
||||||
|
type_name,
|
||||||
|
bind<write_generic_typenames>(generics),
|
||||||
|
type_name,
|
||||||
|
bind_list(", ", generics),
|
||||||
|
type_name,
|
||||||
|
type_name,
|
||||||
|
bind<write_generic_typenames>(generics),
|
||||||
|
type_name,
|
||||||
|
bind_list(", ", generics),
|
||||||
bind<write_consume_params>(signature),
|
bind<write_consume_params>(signature),
|
||||||
bind<write_consume_return_type>(signature, true),
|
bind<write_consume_return_type>(signature, true),
|
||||||
type_name,
|
type_name,
|
||||||
|
@ -2591,6 +2613,14 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
|
||||||
%([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } })
|
%([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } })
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
template <typename O, typename M> %::%(std::shared_ptr<O>&& object, M method) :
|
||||||
|
%([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); })
|
||||||
|
{
|
||||||
|
}
|
||||||
|
template <typename O, typename M> %::%(std::weak_ptr<O>&& object, M method) :
|
||||||
|
%([o = std::move(object), method](auto&&... args) { if (auto s = o.lock()) { ((*s).*(method))(args...); } })
|
||||||
|
{
|
||||||
|
}
|
||||||
inline auto %::operator()(%) const
|
inline auto %::operator()(%) const
|
||||||
{%
|
{%
|
||||||
check_hresult((*(impl::abi_t<%>**)this)->Invoke(%));%
|
check_hresult((*(impl::abi_t<%>**)this)->Invoke(%));%
|
||||||
|
@ -2615,6 +2645,12 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
|
||||||
type_name,
|
type_name,
|
||||||
type_name,
|
type_name,
|
||||||
type_name,
|
type_name,
|
||||||
|
type_name,
|
||||||
|
type_name,
|
||||||
|
type_name,
|
||||||
|
type_name,
|
||||||
|
type_name,
|
||||||
|
type_name,
|
||||||
bind<write_consume_params>(signature),
|
bind<write_consume_params>(signature),
|
||||||
bind<write_consume_return_type>(signature, true),
|
bind<write_consume_return_type>(signature, true),
|
||||||
type_name,
|
type_name,
|
||||||
|
|
|
@ -179,6 +179,16 @@ namespace winrt::impl
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename O, typename M> delegate_base(std::shared_ptr<O>&& object, M method) :
|
||||||
|
delegate_base([o = std::move(object), method](auto&& ... args) { return ((*o).*(method))(args...); })
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename O, typename M> delegate_base(std::weak_ptr<O>&& object, M method) :
|
||||||
|
delegate_base([o = std::move(object), method](auto&& ... args) { if (auto s = o.lock()) { ((*s).*(method))(args...); } })
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
auto operator()(Args const& ... args) const
|
auto operator()(Args const& ... args) const
|
||||||
{
|
{
|
||||||
return (*(variadic_delegate_abi<R, Args...> * *)this)->invoke(args...);
|
return (*(variadic_delegate_abi<R, Args...> * *)this)->invoke(args...);
|
||||||
|
|
|
@ -31,6 +31,25 @@ namespace
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Sender, typename Args>
|
||||||
|
struct ObjectStd : std::enable_shared_from_this<ObjectStd<Sender, Args>>
|
||||||
|
{
|
||||||
|
~ObjectStd()
|
||||||
|
{
|
||||||
|
destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StrongHandler(Sender const&, Args const&)
|
||||||
|
{
|
||||||
|
++strong_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WeakHandler(Sender const&, Args const&)
|
||||||
|
{
|
||||||
|
++weak_count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct ReturnObject : implements<ReturnObject, IInspectable>
|
struct ReturnObject : implements<ReturnObject, IInspectable>
|
||||||
{
|
{
|
||||||
~ReturnObject()
|
~ReturnObject()
|
||||||
|
@ -44,8 +63,21 @@ namespace
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ReturnObjectStd : std::enable_shared_from_this<ReturnObjectStd>
|
||||||
|
{
|
||||||
|
~ReturnObjectStd()
|
||||||
|
{
|
||||||
|
destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Handler(int a, int b)
|
||||||
|
{
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Delegate, typename Sender, typename Args>
|
template <typename Delegate, typename Sender, typename Args>
|
||||||
void test_delegate()
|
void test_delegate_winrt()
|
||||||
{
|
{
|
||||||
auto object = make_self<Object<Sender, Args>>();
|
auto object = make_self<Object<Sender, Args>>();
|
||||||
|
|
||||||
|
@ -81,6 +113,51 @@ namespace
|
||||||
weak({}, {});
|
weak({}, {});
|
||||||
REQUIRE(weak_count == 2);
|
REQUIRE(weak_count == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Delegate, typename Sender, typename Args>
|
||||||
|
void test_delegate_std()
|
||||||
|
{
|
||||||
|
auto object = std::make_shared<ObjectStd<Sender, Args>>();
|
||||||
|
|
||||||
|
Delegate strong{ object->shared_from_this(), &ObjectStd<Sender, Args>::StrongHandler };
|
||||||
|
Delegate weak{ object->weak_from_this(), &ObjectStd<Sender, Args>::WeakHandler };
|
||||||
|
|
||||||
|
destroyed = false;
|
||||||
|
strong_count = 0;
|
||||||
|
weak_count = 0;
|
||||||
|
|
||||||
|
// Both weak and strong handlers
|
||||||
|
strong({}, {});
|
||||||
|
weak({}, {});
|
||||||
|
REQUIRE(strong_count == 1);
|
||||||
|
REQUIRE(weak_count == 1);
|
||||||
|
|
||||||
|
// Local 'object' strong reference is released
|
||||||
|
object = nullptr;
|
||||||
|
|
||||||
|
// Still both since strong handler keeps object alive
|
||||||
|
strong({}, {});
|
||||||
|
weak({}, {});
|
||||||
|
REQUIRE(strong_count == 2);
|
||||||
|
REQUIRE(weak_count == 2);
|
||||||
|
|
||||||
|
// ~Object is called since the strong delegate is destroyed
|
||||||
|
REQUIRE(!destroyed);
|
||||||
|
strong = nullptr;
|
||||||
|
REQUIRE(destroyed);
|
||||||
|
|
||||||
|
// Weak delegate remains but no longer fires
|
||||||
|
REQUIRE(weak_count == 2);
|
||||||
|
weak({}, {});
|
||||||
|
REQUIRE(weak_count == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Delegate, typename Sender, typename Args>
|
||||||
|
void test_delegate()
|
||||||
|
{
|
||||||
|
test_delegate_winrt<Delegate, Sender, Args>();
|
||||||
|
test_delegate_std<Delegate, Sender, Args>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("delegate_weak_strong")
|
TEST_CASE("delegate_weak_strong")
|
||||||
|
@ -111,8 +188,10 @@ TEST_CASE("delegate_weak_strong")
|
||||||
// scenarios such as callbacks so weak support isn't interesting anyway, but it does work with get_strong.
|
// scenarios such as callbacks so weak support isn't interesting anyway, but it does work with get_strong.
|
||||||
|
|
||||||
auto object = make_self<ReturnObject>();
|
auto object = make_self<ReturnObject>();
|
||||||
|
|
||||||
Component::TwoArgDelegateReturn strong{ object->get_strong(), &ReturnObject::Handler };
|
Component::TwoArgDelegateReturn strong{ object->get_strong(), &ReturnObject::Handler };
|
||||||
|
|
||||||
REQUIRE(5 == strong(2, 3));
|
REQUIRE(5 == strong(2, 3));
|
||||||
|
|
||||||
|
auto objectStd = std::make_shared<ReturnObjectStd>();
|
||||||
|
Component::TwoArgDelegateReturn strongStd{ objectStd->shared_from_this(), &ReturnObjectStd::Handler };
|
||||||
|
REQUIRE(5 == strongStd(2, 3));
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,20 @@ namespace
|
||||||
return L"Object";
|
return L"Object";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ObjectStd : std::enable_shared_from_this<ObjectStd>
|
||||||
|
{
|
||||||
|
int& m_count;
|
||||||
|
|
||||||
|
ObjectStd(int& count) : m_count(count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Callback()
|
||||||
|
{
|
||||||
|
++m_count;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("variadic_delegate")
|
TEST_CASE("variadic_delegate")
|
||||||
|
@ -100,6 +114,44 @@ TEST_CASE("variadic_delegate")
|
||||||
REQUIRE(count == 2); // Unchanged
|
REQUIRE(count == 2); // Unchanged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shared_from_this
|
||||||
|
{
|
||||||
|
int count{};
|
||||||
|
auto object = std::make_shared<ObjectStd>(count);
|
||||||
|
|
||||||
|
delegate<> up{ object->shared_from_this(), &ObjectStd::Callback };
|
||||||
|
|
||||||
|
REQUIRE(count == 0);
|
||||||
|
up();
|
||||||
|
REQUIRE(count == 1);
|
||||||
|
up();
|
||||||
|
REQUIRE(count == 2);
|
||||||
|
|
||||||
|
object = nullptr;
|
||||||
|
|
||||||
|
up();
|
||||||
|
REQUIRE(count == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// weak_from_this
|
||||||
|
{
|
||||||
|
int count{};
|
||||||
|
auto object = std::make_shared<ObjectStd>(count);
|
||||||
|
|
||||||
|
delegate<> up{ object->weak_from_this(), &ObjectStd::Callback };
|
||||||
|
|
||||||
|
REQUIRE(count == 0);
|
||||||
|
up();
|
||||||
|
REQUIRE(count == 1);
|
||||||
|
up();
|
||||||
|
REQUIRE(count == 2);
|
||||||
|
|
||||||
|
object = nullptr;
|
||||||
|
|
||||||
|
up();
|
||||||
|
REQUIRE(count == 2); // Unchanged
|
||||||
|
}
|
||||||
|
|
||||||
// Mixed arguments
|
// Mixed arguments
|
||||||
{
|
{
|
||||||
int count{};
|
int count{};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче