Skip to content

Commit

Permalink
Add support for accessing the underlying pointer type via a dispatch (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mingxwa authored Apr 16, 2024
1 parent e650e70 commit c8f0b6b
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 7 deletions.
27 changes: 20 additions & 7 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ template <class D, class T, bool NE, class R, class... Args>
concept invocable_dispatch = requires { typename D::template invoker<T>; } &&
is_invoker_well_formed<
typename D::template invoker<T>, T, NE, R, Args...>();
template <class D, class P, bool NE, class R, class... Args>
concept invocable_dispatch_ptr = invocable_dispatch<
D, typename ptr_traits<P>::target_type, NE, R, Args...> ||
invocable_dispatch<D, const P, NE, R, Args...> ||
invocable_dispatch<D, void, NE, R, Args...>;

template <bool NE, class R, class... Args>
using func_ptr_t = std::conditional_t<
Expand All @@ -166,14 +171,20 @@ R invoke_dispatch(Args&&... args) {
}
}
template <class P, class F, class R, class... Args>
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<P>::target_type, true, R, Args...>()) {
return invoke_dispatch<F, R>(ptr_traits<P>::dereference(*std::launder(
reinterpret_cast<const P*>(self))), std::forward<Args>(args)...);
}
template <class P, class F, class R, class... Args>
R invocation_dispatcher_ptr(const char* self, Args... args)
noexcept(is_invoker_well_formed<F, const P, true, R, Args...>()) {
return invoke_dispatch<F, R>(*std::launder(reinterpret_cast<const P*>(self)),
std::forward<Args>(args)...);
}
template <class F, class R, class... Args>
R invocation_default_dispatcher(const char*, Args... args)
R invocation_dispatcher_void(const char*, Args... args)
noexcept(is_invoker_well_formed<F, void, true, R, Args...>())
{ return invoke_dispatch<F, R>(std::forward<Args>(args)...); }
template <class P>
Expand Down Expand Up @@ -208,19 +219,21 @@ struct overload_traits_impl : applicable_traits {
static constexpr func_ptr_t<NE, R, const char*, Args...> get() {
if constexpr (invocable_dispatch<
D, typename ptr_traits<P>::target_type, NE, R, Args...>) {
return &invocation_dispatcher<P, typename D::template invoker<
return &invocation_dispatcher_ref<P, typename D::template invoker<
typename ptr_traits<P>::target_type>, R, Args...>;
} else if constexpr (invocable_dispatch<D, const P, NE, R, Args...>) {
return &invocation_dispatcher_ptr<
P, typename D::template invoker<const P>, R, Args...>;
} else {
return &invocation_default_dispatcher<
return &invocation_dispatcher_void<
typename D::template invoker<void>, R, Args...>;
}
}
};
struct resolver { func_ptr_t<NE, R, Args...> operator()(Args...); };
template <class D, class P>
static constexpr bool applicable_ptr = invocable_dispatch<
D, typename ptr_traits<P>::target_type, NE, R, Args...> ||
invocable_dispatch<D, void, NE, R, Args...>;
static constexpr bool applicable_ptr =
invocable_dispatch_ptr<D, P, NE, R, Args...>;
static constexpr bool is_noexcept = NE;
};
template <class O> struct overload_traits : inapplicable_traits {};
Expand Down
37 changes: 37 additions & 0 deletions tests/proxy_invocation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <typeinfo>
#include <vector>
#include "proxy.h"
#include "utils.h"

namespace {

Expand Down Expand Up @@ -50,6 +51,25 @@ PRO_DEF_FREE_DISPATCH(Append, AppendImpl, pro::proxy<Container<T>>(T));
PRO_DEF_MEMBER_DISPATCH_WITH_DEFAULT(WeakAt, at, NotImplemented<std::string>, std::string(int));
PRO_DEF_FACADE(ResourceDictionary, WeakAt);

template <class F, class T>
pro::proxy<F> LockImpl(const std::weak_ptr<T>& p) {
auto result = p.lock();
if (static_cast<bool>(result)) {
return result;
}
return nullptr;
}
template <class F>
PRO_DEF_FREE_DISPATCH(Lock, LockImpl<F>, pro::proxy<F>());
template <class F>
PRO_DEF_FACADE(Weak, Lock<F>, pro::copyable_ptr_constraints);
template <class F, class T>
auto GetWeakImpl(const std::shared_ptr<T>& p) { return pro::make_proxy<Weak<F>, std::weak_ptr<T>>(p); }
template <class F>
PRO_DEF_FREE_DISPATCH_WITH_DEFAULT(GetWeak, GetWeakImpl<F>, std::nullptr_t, pro::proxy<Weak<F>>());

PRO_DEF_FACADE(SharedStringable, PRO_MAKE_DISPATCH_PACK(utils::spec::ToString, GetWeak<SharedStringable>), pro::copyable_ptr_constraints);

} // namespace spec

template <class F, class D, bool NE, class... Args>
Expand Down Expand Up @@ -237,3 +257,20 @@ TEST(ProxyInvocationTests, TestFreeDispatchDefault) {
ASSERT_TRUE(exception_thrown);
}
}

TEST(ProxyInvocationTests, TestObserverDispatch) {
int test_val = 123;
pro::proxy<spec::SharedStringable> p{std::make_shared<int>(test_val)};
auto weak = p.invoke<spec::GetWeak<spec::SharedStringable>>();
ASSERT_TRUE(weak.has_value());
{
auto locked = weak();
ASSERT_TRUE(locked.has_value());
ASSERT_EQ(locked.invoke<utils::spec::ToString>(), "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<spec::GetWeak<spec::SharedStringable>>().has_value());
ASSERT_EQ(p.invoke<utils::spec::ToString>(), "123");
}

0 comments on commit c8f0b6b

Please sign in to comment.