Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions cppwinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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> %(com_ptr<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;
};
)";
Expand All @@ -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,
bind<write_consume_params>(signature));
}

Expand Down Expand Up @@ -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...); } })
{
}
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
{%
check_hresult((*(impl::abi_t<%<%>>**)this)->Invoke(%));%
Expand Down Expand Up @@ -2562,6 +2574,16 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
bind<write_generic_typenames>(generics),
type_name,
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_return_type>(signature, true),
type_name,
Expand Down Expand Up @@ -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...); } })
{
}
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
{%
check_hresult((*(impl::abi_t<%>**)this)->Invoke(%));%
Expand All @@ -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,
bind<write_consume_params>(signature),
bind<write_consume_return_type>(signature, true),
type_name,
Expand Down
10 changes: 10 additions & 0 deletions strings/base_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
return (*(variadic_delegate_abi<R, Args...> * *)this)->invoke(args...);
Expand Down
85 changes: 82 additions & 3 deletions test/old_tests/UnitTests/delegate_weak_strong.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
{
~ReturnObject()
Expand All @@ -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>
void test_delegate()
void test_delegate_winrt()
{
auto object = make_self<Object<Sender, Args>>();

Expand Down Expand Up @@ -81,6 +113,51 @@ namespace
weak({}, {});
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")
Expand Down Expand Up @@ -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.

auto object = make_self<ReturnObject>();

Component::TwoArgDelegateReturn strong{ object->get_strong(), &ReturnObject::Handler };

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));
}
52 changes: 52 additions & 0 deletions test/test/variadic_delegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ namespace
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")
Expand Down Expand Up @@ -100,6 +114,44 @@ TEST_CASE("variadic_delegate")
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
{
int count{};
Expand Down