From c8f0b6bbb16f149e441892cd32914d7c226ba934 Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Tue, 16 Apr 2024 09:03:27 +0800 Subject: [PATCH] Add support for accessing the underlying pointer type via a dispatch (#85) --- proxy.h | 27 +++++++++++++++++------ tests/proxy_invocation_tests.cpp | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/proxy.h b/proxy.h index 1ee1bda..11e0aa1 100644 --- a/proxy.h +++ b/proxy.h @@ -152,6 +152,11 @@ template concept invocable_dispatch = requires { typename D::template invoker; } && is_invoker_well_formed< typename D::template invoker, T, NE, R, Args...>(); +template +concept invocable_dispatch_ptr = invocable_dispatch< + D, typename ptr_traits

::target_type, NE, R, Args...> || + invocable_dispatch || + invocable_dispatch; template using func_ptr_t = std::conditional_t< @@ -166,14 +171,20 @@ R invoke_dispatch(Args&&... args) { } } template -R invocation_dispatcher(const char* self, Args... args) +R invocation_dispatcher_ref(const char* self, Args... args) noexcept(is_invoker_well_formed< F, typename ptr_traits

::target_type, true, R, Args...>()) { return invoke_dispatch(ptr_traits

::dereference(*std::launder( reinterpret_cast(self))), std::forward(args)...); } +template +R invocation_dispatcher_ptr(const char* self, Args... args) + noexcept(is_invoker_well_formed()) { + return invoke_dispatch(*std::launder(reinterpret_cast(self)), + std::forward(args)...); +} template -R invocation_default_dispatcher(const char*, Args... args) +R invocation_dispatcher_void(const char*, Args... args) noexcept(is_invoker_well_formed()) { return invoke_dispatch(std::forward(args)...); } template @@ -208,19 +219,21 @@ struct overload_traits_impl : applicable_traits { static constexpr func_ptr_t get() { if constexpr (invocable_dispatch< D, typename ptr_traits

::target_type, NE, R, Args...>) { - return &invocation_dispatcher::target_type>, R, Args...>; + } else if constexpr (invocable_dispatch) { + return &invocation_dispatcher_ptr< + P, typename D::template invoker, R, Args...>; } else { - return &invocation_default_dispatcher< + return &invocation_dispatcher_void< typename D::template invoker, R, Args...>; } } }; struct resolver { func_ptr_t operator()(Args...); }; template - static constexpr bool applicable_ptr = invocable_dispatch< - D, typename ptr_traits

::target_type, NE, R, Args...> || - invocable_dispatch; + static constexpr bool applicable_ptr = + invocable_dispatch_ptr; static constexpr bool is_noexcept = NE; }; template struct overload_traits : inapplicable_traits {}; diff --git a/tests/proxy_invocation_tests.cpp b/tests/proxy_invocation_tests.cpp index 455af24..199169c 100644 --- a/tests/proxy_invocation_tests.cpp +++ b/tests/proxy_invocation_tests.cpp @@ -11,6 +11,7 @@ #include #include #include "proxy.h" +#include "utils.h" namespace { @@ -50,6 +51,25 @@ PRO_DEF_FREE_DISPATCH(Append, AppendImpl, pro::proxy>(T)); PRO_DEF_MEMBER_DISPATCH_WITH_DEFAULT(WeakAt, at, NotImplemented, std::string(int)); PRO_DEF_FACADE(ResourceDictionary, WeakAt); +template +pro::proxy LockImpl(const std::weak_ptr& p) { + auto result = p.lock(); + if (static_cast(result)) { + return result; + } + return nullptr; +} +template +PRO_DEF_FREE_DISPATCH(Lock, LockImpl, pro::proxy()); +template +PRO_DEF_FACADE(Weak, Lock, pro::copyable_ptr_constraints); +template +auto GetWeakImpl(const std::shared_ptr& p) { return pro::make_proxy, std::weak_ptr>(p); } +template +PRO_DEF_FREE_DISPATCH_WITH_DEFAULT(GetWeak, GetWeakImpl, std::nullptr_t, pro::proxy>()); + +PRO_DEF_FACADE(SharedStringable, PRO_MAKE_DISPATCH_PACK(utils::spec::ToString, GetWeak), pro::copyable_ptr_constraints); + } // namespace spec template @@ -237,3 +257,20 @@ TEST(ProxyInvocationTests, TestFreeDispatchDefault) { ASSERT_TRUE(exception_thrown); } } + +TEST(ProxyInvocationTests, TestObserverDispatch) { + int test_val = 123; + pro::proxy p{std::make_shared(test_val)}; + auto weak = p.invoke>(); + ASSERT_TRUE(weak.has_value()); + { + auto locked = weak(); + ASSERT_TRUE(locked.has_value()); + ASSERT_EQ(locked.invoke(), "123"); + } + p = &test_val; // The underlying std::shared_ptr will be destroyed + ASSERT_TRUE(weak.has_value()); + ASSERT_FALSE(weak().has_value()); + ASSERT_FALSE(p.invoke>().has_value()); + ASSERT_EQ(p.invoke(), "123"); +}