Skip to content

Commit

Permalink
Add support for custom accessors (#93)
Browse files Browse the repository at this point in the history
* Add support for optional base classes

* Fix build

* Workaround warning in GCC

* Workaround GCC rejection

* Formatting

* Refactor

* Update sample code
  • Loading branch information
mingxwa authored May 8, 2024
1 parent aa384eb commit dc44c4a
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 83 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ class Rectangle {
std::string PrintDrawableToString(pro::proxy<spec::Drawable> p) {
std::stringstream result;
result << "shape = ";
p.invoke<spec::Draw>(result);
result << ", area = " << p.invoke<spec::Area>();
p.Draw(result);
result << ", area = " << p.Area();
return std::move(result).str();
}

Expand Down
56 changes: 42 additions & 14 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@ struct proxiable_ptr_constraints {
constraint_level destructibility;
};

template <class F> class proxy;

namespace details {

struct applicable_traits { static constexpr bool applicable = true; };
struct inapplicable_traits { static constexpr bool applicable = false; };

template <template <class, class> class R, class O, class... Is>
struct recursive_reduction : std::type_identity<O> {};
template <template <class, class> class R, class O, class I, class... Is>
struct recursive_reduction<R, O, I, Is...>
: recursive_reduction<R, typename R<O, I>::type, 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> class R, class O, class I, class... Is>
struct recursive_reduction<R, O, I, Is...>
{ using type = recursive_reduction_t<R, typename R<O, I>::type, Is...>; };

template <template <class> class T, class... Is>
struct first_applicable {};
Expand Down Expand Up @@ -359,6 +361,18 @@ template <class... Ms, class I> requires(!std::is_void_v<I>)
struct facade_meta_reduction<composite_meta<Ms...>, I>
: std::type_identity<composite_meta<Ms..., I>> {};

template <class... As> struct composite_accessor : As... {};
template <class T>
struct accessor_helper {
template <class D> using accessor = typename D::template accessor<T>;
template <class O, class I> struct reduction : std::type_identity<O> {};
template <class... As, class I>
requires(requires { typename accessor<I>; } &&
std::is_nothrow_default_constructible_v<accessor<I>>)
struct reduction<composite_accessor<As...>, I>
: std::type_identity<composite_accessor<As..., accessor<I>>> {};
};

template <class F>
consteval bool is_facade_constraints_well_formed() {
if constexpr (is_consteval([] { return F::constraints; })) {
Expand Down Expand Up @@ -395,6 +409,8 @@ struct facade_traits_impl<F, Ds...>
composite_meta<>, copyability_meta, relocatability_meta,
destructibility_meta, typename dispatch_traits<Ds>::meta...,
typename F::reflection_type>;
using base = recursive_reduction_t<accessor_helper<proxy<F>>
::template reduction, composite_accessor<>, Ds...>;

template <class D>
static constexpr bool has_dispatch = (std::is_same_v<D, Ds> || ...);
Expand Down Expand Up @@ -454,7 +470,7 @@ concept proxiable = facade<F> && details::ptr_traits<P>::applicable &&
details::facade_traits<F>::template applicable_ptr<P>;

template <class F>
class proxy {
class proxy : public details::facade_traits<F>::base {
using Traits = details::facade_traits<F>;
static_assert(Traits::applicable);
using DefaultDispatch = typename Traits::default_dispatch;
Expand Down Expand Up @@ -871,6 +887,9 @@ proxy<F> make_proxy(T&& value) {
namespace details {

template <class... Args> void invalid_call(Args&&...) = delete;
template <class T, class...> struct dependent : std::type_identity<T> {};
template <class T, class... U>
using dependent_t = typename dependent<T, U...>::type;

template <class O, class I> struct flat_reduction : std::type_identity<O> {};
template <class O, class... Is>
Expand All @@ -894,42 +913,51 @@ struct facade_prototype {

} // namespace pro

#define ___PRO_DIRECT_FUNC_IMPL(__EXPR) \
noexcept(noexcept(__EXPR)) requires(requires { __EXPR; }) { return __EXPR; }
#define ___PRO_DEF_DISPATCH_IMPL(__NAME, __EXPR, __DEFEXPR, __OVERLOADS) \
struct __NAME { \
private: \
using __Name = __NAME; \
struct __FT { \
template <class __T, class... __Args> \
decltype(auto) operator()(__T& __self, __Args&&... __args) \
noexcept(noexcept(__EXPR)) requires(requires { __EXPR; }) \
{ return __EXPR; } \
___PRO_DIRECT_FUNC_IMPL(__EXPR) \
}; \
struct __FV { \
template <class... __Args> \
decltype(auto) operator()(__Args&&... __args) \
noexcept(noexcept(__DEFEXPR)) requires(requires { __DEFEXPR; }) \
{ return __DEFEXPR; } \
___PRO_DIRECT_FUNC_IMPL(__DEFEXPR) \
}; \
\
public: \
using overload_types = __OVERLOADS; \
template <class __T> \
using invoker = std::conditional_t<std::is_void_v<__T>, __FV, __FT>; \
using invoker = ::std::conditional_t<::std::is_void_v<__T>, __FV, __FT>; \
template <class __P> \
struct accessor { \
template <class... __Args> \
decltype(auto) __NAME(__Args&&... __args) const \
___PRO_DIRECT_FUNC_IMPL((static_cast<::pro::details::dependent_t< \
const __P*, __Args...>>(this)->template invoke<__Name>( \
::std::forward<__Args>(__args)...))) \
}; \
}
#define PRO_DEF_MEMBER_DISPATCH_WITH_DEFAULT(__NAME, __FUNC, __DEFFUNC, ...) \
___PRO_DEF_DISPATCH_IMPL(__NAME, \
__self.__FUNC(std::forward<__Args>(__args)...), \
__DEFFUNC(std::forward<__Args>(__args)...), std::tuple<__VA_ARGS__>)
__self.__FUNC(::std::forward<__Args>(__args)...), \
__DEFFUNC(::std::forward<__Args>(__args)...), ::std::tuple<__VA_ARGS__>)
#define PRO_DEF_FREE_DISPATCH_WITH_DEFAULT(__NAME, __FUNC, __DEFFUNC, ...) \
___PRO_DEF_DISPATCH_IMPL(__NAME, \
__FUNC(__self, std::forward<__Args>(__args)...), \
__DEFFUNC(std::forward<__Args>(__args)...), std::tuple<__VA_ARGS__>)
__FUNC(__self, ::std::forward<__Args>(__args)...), \
__DEFFUNC(::std::forward<__Args>(__args)...), ::std::tuple<__VA_ARGS__>)
#define PRO_DEF_MEMBER_DISPATCH(__NAME, ...) \
PRO_DEF_MEMBER_DISPATCH_WITH_DEFAULT( \
__NAME, __NAME, ::pro::details::invalid_call, __VA_ARGS__)
#define PRO_DEF_FREE_DISPATCH(__NAME, __FUNC, ...) \
PRO_DEF_FREE_DISPATCH_WITH_DEFAULT( \
__NAME, __FUNC, ::pro::details::invalid_call, __VA_ARGS__)
#define PRO_MAKE_DISPATCH_PACK(...) std::tuple<__VA_ARGS__>
#define PRO_MAKE_DISPATCH_PACK(...) ::std::tuple<__VA_ARGS__>
#define PRO_DEF_FACADE(__NAME, ...) \
struct __NAME : ::pro::details::facade_prototype<__VA_ARGS__> {}

Expand Down
2 changes: 1 addition & 1 deletion samples/resource_dictionary/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ PRO_DEF_FACADE(Dictionary, at);
} // namespace spec

void demo_print(pro::proxy<spec::Dictionary> dictionary) {
std::cout << dictionary(1) << std::endl;
std::cout << dictionary.at(1) << std::endl;
}

int main() {
Expand Down
8 changes: 4 additions & 4 deletions tests/freestanding/proxy_freestanding_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ extern "C" int main() {
std::tuple<int, double> t{11, 22};
pro::proxy<spec::Hashable> p;
p = &i;
if (p() != GetHash(i)) {
if (p.GetHash() != GetHash(i)) {
return 1;
}
p = &d;
if (p() != GetHash(d)) {
if (p.GetHash() != GetHash(d)) {
return 1;
}
p = pro::make_proxy_inplace<spec::Hashable>(s);
if (p() != GetHash(s)) {
if (p.GetHash() != GetHash(s)) {
return 1;
}
p = &t;
if (p() != GetDefaultHash()) {
if (p.GetHash() != GetDefaultHash()) {
return 1;
}
return 0;
Expand Down
Loading

0 comments on commit dc44c4a

Please sign in to comment.