Skip to content
This repository was archived by the owner on Jan 29, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
124 changes: 72 additions & 52 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,20 @@ struct recursive_reduction<R, O, I, Is...>
template <template <class, class> class R, class O, class... Is>
using recursive_reduction_t = typename recursive_reduction<R, O, Is...>::type;

template <template <class...> class R, class... Args>
struct reduction_traits {
template <class O, class I>
using type = typename R<Args..., O, I>::type;
};

template <template <class...> class T, class... Args>
using traits_t = typename T<Args...>::type;

template <auto V> struct nontype_t; // For compatibility before C++26

template <class Expr>
consteval bool is_consteval(Expr)
{ return requires { typename std::bool_constant<(Expr{}(), false)>; }; }
{ return requires { typename nontype_t<(Expr{}(), 0)>; }; }

template <class T, std::size_t I>
concept has_tuple_element = requires { typename std::tuple_element_t<I, T>; };
Expand Down Expand Up @@ -283,7 +294,6 @@ template <class O> struct overload_traits : inapplicable_traits {};
template <qualifier_type Q, bool NE, class R, class... Args>
struct overload_traits_impl : applicable_traits {
using return_type = R;
using view_type = R(Args...) const noexcept(NE);
template <class F>
using dispatcher_type =
R (*)(add_qualifier_t<proxy<F>, Q>, Args...) noexcept(NE);
Expand Down Expand Up @@ -392,11 +402,9 @@ struct meta_reduction<composite_meta_impl<Ms...>, I>
template <class... Ms1, class... Ms2>
struct meta_reduction<composite_meta_impl<Ms1...>, composite_meta_impl<Ms2...>>
: std::type_identity<composite_meta_impl<Ms1..., Ms2...>> {};
template <class O, class I>
using meta_reduction_t = typename meta_reduction<O, I>::type;
template <class... Ms>
using composite_meta =
recursive_reduction_t<meta_reduction_t, composite_meta_impl<>, Ms...>;
using composite_meta = recursive_reduction_t<reduction_traits<
meta_reduction>::template type, composite_meta_impl<>, Ms...>;

template <class T>
consteval bool is_is_direct_well_formed() {
Expand Down Expand Up @@ -553,32 +561,24 @@ struct accessor_traits<std::void_t<typename T::template accessor<F>>, T, F>
template <class T, class F>
using accessor_t = typename accessor_traits<void, T, F>::type;

template <bool IsDirect, class F, class O, class I>
template <class NTIsDirect, class F, class O, class I>
struct composite_accessor_reduction : std::type_identity<O> {};
template <bool IsDirect, class F, class... As, class I>
requires(IsDirect == I::is_direct && !std::is_void_v<accessor_t<I, F>>)
template <class NTIsDirect, class F, class... As, class I>
requires(std::is_same_v<NTIsDirect, nontype_t<I::is_direct>> &&
!std::is_void_v<accessor_t<I, F>>)
struct composite_accessor_reduction<
IsDirect, F, composite_accessor_impl<As...>, I>
NTIsDirect, F, composite_accessor_impl<As...>, I>
: std::type_identity<composite_accessor_impl<As..., accessor_t<I, F>>> {};
template <bool IsDirect, class F>
struct composite_accessor_helper {
template <class O, class I>
using reduction_t =
typename composite_accessor_reduction<IsDirect, F, O, I>::type;
};
template <bool IsDirect, class F, class... Ts>
using composite_accessor = recursive_reduction_t<
composite_accessor_helper<IsDirect, F>::template reduction_t,
composite_accessor_impl<>, Ts...>;
using composite_accessor = recursive_reduction_t<reduction_traits<
composite_accessor_reduction, nontype_t<IsDirect>, F>::template type,
composite_accessor_impl<>, Ts...>;

template <class A1, class A2> struct composite_accessor_merge_traits;
template <class... A1, class... A2>
struct composite_accessor_merge_traits<
composite_accessor_impl<A1...>, composite_accessor_impl<A2...>>
: std::type_identity<composite_accessor_impl<A1..., A2...>> {};
template <class A1, class A2>
using merged_composite_accessor =
typename composite_accessor_merge_traits<A1, A2>::type;

template <class P> struct ptr_traits : inapplicable_traits {};
template <class P>
Expand Down Expand Up @@ -705,10 +705,10 @@ struct facade_traits<F>
lifetime_meta_t<F, destroy_dispatch, void() noexcept, void(),
F::constraints.destructibility>, typename facade_traits::conv_meta,
typename facade_traits::refl_meta>;
using indirect_accessor = merged_composite_accessor<
using indirect_accessor = traits_t<composite_accessor_merge_traits,
typename facade_traits::conv_indirect_accessor,
typename facade_traits::refl_indirect_accessor>;
using direct_accessor = merged_composite_accessor<
using direct_accessor = traits_t<composite_accessor_merge_traits,
typename facade_traits::conv_direct_accessor,
typename facade_traits::refl_direct_accessor>;

Expand Down Expand Up @@ -779,8 +779,7 @@ template <class M>
std::is_nothrow_default_constructible_v<M> &&
std::is_trivially_copyable_v<M>)
struct meta_ptr_traits<M> : meta_ptr_traits_impl<M> {};
template <class M>
using meta_ptr = typename meta_ptr_traits<M>::type;
template <class M> using meta_ptr = traits_t<meta_ptr_traits, M>;

template <class T>
class inplace_ptr {
Expand Down Expand Up @@ -1848,7 +1847,6 @@ using merge_facade_conv_t = typename add_upward_conversion_conv<
template <class O>
using observer_upward_conversion_overload = proxy_view<
typename overload_traits<O>::return_type::facade_type>() const noexcept;

template <class O, class I>
struct observer_upward_conversion_conv_reduction : std::type_identity<O> {};
template <class... Os, class O>
Expand All @@ -1857,13 +1855,10 @@ struct observer_upward_conversion_conv_reduction<
conv_impl<true, upward_conversion_dispatch, Os...>, O>
: std::type_identity<conv_impl<true, upward_conversion_dispatch, Os...,
observer_upward_conversion_overload<O>>> {};
template <class O, class I>
using observer_upward_conversion_conv_reduction_t =
typename observer_upward_conversion_conv_reduction<O, I>::type;
template <class... Os>
using observer_upward_conversion_conv =
recursive_reduction_t<observer_upward_conversion_conv_reduction_t,
conv_impl<true, upward_conversion_dispatch>, Os...>;
using observer_upward_conversion_conv = recursive_reduction_t<
reduction_traits<observer_upward_conversion_conv_reduction>::template type,
conv_impl<true, upward_conversion_dispatch>, Os...>;

template <class D, class F, class... Os>
using observer_indirect_conv =
Expand All @@ -1890,29 +1885,23 @@ template <class F, class... Cs, class I>
struct observer_conv_reduction<F, std::tuple<Cs...>, I>
: std::type_identity<
std::tuple<Cs..., typename observer_conv_traits<I, F>::type>> {};
template <class F>
struct observer_conv_reduction_helper {
template <class O, class I>
using type = typename observer_conv_reduction<F, O, I>::type;
template <class F, class... Cs>
struct observer_facade_conv_impl {
using convention_types = recursive_reduction_t<
reduction_traits<observer_conv_reduction, F>::template type,
std::tuple<>, Cs...>;
};

template <class O, class I>
struct observer_refl_reduction : std::type_identity<O> {};
template <class... Rs, class R> requires(!R::is_direct)
struct observer_refl_reduction<std::tuple<Rs...>, R>
: std::type_identity<std::tuple<Rs..., R>> {};
template <class O, class I>
using observer_refl_reduction_t = typename observer_refl_reduction<O, I>::type;

template <class F, class... Cs>
struct observer_facade_conv_impl {
using convention_types = recursive_reduction_t<
observer_conv_reduction_helper<F>::template type, std::tuple<>, Cs...>;
};
template <class... Rs>
struct observer_facade_refl_impl {
using reflection_types = recursive_reduction_t<
observer_refl_reduction_t, std::tuple<>, Rs...>;
reduction_traits<observer_refl_reduction>::template type,
std::tuple<>, Rs...>;
};

template <class P>
Expand All @@ -1938,6 +1927,41 @@ auto weak_lock_impl(const P& self) noexcept
{ return nullable_ptr_adapter{self.lock()}; }
PRO_DEF_FREE_AS_MEM_DISPATCH(weak_mem_lock, weak_lock_impl, lock);

template <class O> struct weak_upward_conversion_overload_traits;
template <class F>
struct weak_upward_conversion_overload_traits<proxy<F>() const&>
: std::type_identity<weak_proxy<F>() const&> {};
template <class F>
struct weak_upward_conversion_overload_traits<proxy<F>() const& noexcept>
: std::type_identity<weak_proxy<F>() const& noexcept> {};
template <class F>
struct weak_upward_conversion_overload_traits<proxy<F>() &&>
: std::type_identity<weak_proxy<F>() &&> {};
template <class F>
struct weak_upward_conversion_overload_traits<proxy<F>() && noexcept>
: std::type_identity<weak_proxy<F>() && noexcept> {};
template <class... Os>
using weak_upward_conversion_conv = conv_impl<true, upward_conversion_dispatch,
typename weak_upward_conversion_overload_traits<Os>::type...>;

template <class O, class I>
struct weak_conv_reduction : std::type_identity<O> {};
template <class... Cs, class I>
requires(I::is_direct &&
std::is_same_v<typename I::dispatch_type, upward_conversion_dispatch>)
struct weak_conv_reduction<std::tuple<Cs...>, I>
: std::type_identity<std::tuple<Cs..., instantiated_t<
weak_upward_conversion_conv, typename I::overload_types>>> {};
template <class F, class... Cs>
struct weak_facade_impl {
using convention_types = recursive_reduction_t<
reduction_traits<weak_conv_reduction>::template type,
std::tuple<conv_impl<true, weak_mem_lock, proxy<F>() const noexcept>>,
Cs...>;
using reflection_types = std::tuple<>;
static constexpr auto constraints = F::constraints;
};

} // namespace details

template <facade F>
Expand All @@ -1954,12 +1978,8 @@ struct observer_facade
};

template <facade F>
struct weak_facade {
using convention_types = std::tuple<details::conv_impl<
true, details::weak_mem_lock, proxy<F>() const noexcept>>;
using reflection_types = std::tuple<>;
static constexpr auto constraints = F::constraints;
};
struct weak_facade : details::instantiated_t<
details::weak_facade_impl, typename F::convention_types, F> {};

template <class Cs, class Rs, proxiable_ptr_constraints C>
struct basic_facade_builder {
Expand Down
27 changes: 26 additions & 1 deletion tests/proxy_creation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ struct TestSharedStringable : pro::facade_builder
::build {};

struct TestWeakSharedStringable: pro::facade_builder
::add_facade<TestSharedStringable>
::add_facade<TestSharedStringable, true>
::support<pro::skills::as_weak>
::build {};

Expand Down Expand Up @@ -954,6 +954,31 @@ TEST(ProxyCreationTests, TestMakeProxyShared_StrongCompact_Lifetime_WeakAccess)
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}

TEST(ProxyCreationTests, TestMakeProxyShared_StrongCompact_Lifetime_WeakConversion) {
utils::LifetimeTracker tracker;
std::vector<utils::LifetimeOperation> expected_ops;
{
auto p1 = pro::make_proxy_shared<details::TestWeakSharedStringable, utils::LifetimeTracker::Session>(&tracker);
expected_ops.emplace_back(1, utils::LifetimeOperationType::kValueConstruction);
pro::weak_proxy<details::TestWeakSharedStringable> p2 = p1;
pro::weak_proxy<details::TestSharedStringable> p3 = std::move(p2);
ASSERT_TRUE(p1.has_value());
ASSERT_FALSE(p2.has_value());
ASSERT_TRUE(p3.has_value());
auto p4 = p3.lock();
ASSERT_TRUE(p4.has_value());
ASSERT_EQ(ToString(*p4), "Session 1");
ASSERT_EQ(p4.GetLifetimeType(), details::LifetimeModelType::kStrongCompact);
p4.reset();
p1.reset();
expected_ops.emplace_back(1, utils::LifetimeOperationType::kDestruction);
auto p5 = p3.lock();
ASSERT_FALSE(p5.has_value());
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}

TEST(ProxyCreationTests, TestStdWeakPtrCompatibility) {
utils::LifetimeTracker tracker;
std::vector<utils::LifetimeOperation> expected_ops;
Expand Down