Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce semantics of proxy_invoke #167

Merged
merged 1 commit into from
Oct 1, 2024
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
2 changes: 1 addition & 1 deletion docs/PRO_DEF_FREE_DISPATCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct dispatch_name {
template <class F, class C, class R, class... Args>
struct accessor<F, C, R(Args...) cv ref noex> {
friend R accessibility_func_name(accessor cv ref self, Args... args) noex {
return pro::proxy_invoke<C>(pro::access_proxy<F>(SELF), std::forward<Args>(args)...);
return pro::proxy_invoke<C, R(Args...) cv ref noex>(pro::access_proxy<F>(SELF), std::forward<Args>(args)...);
}
};
};
Expand Down
2 changes: 1 addition & 1 deletion docs/PRO_DEF_MEM_DISPATCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct dispatch_name {
template <class F, class C, class R, class... Args>
struct accessor<F, C, R(Args...) cv ref noex> {
R accessibility_func_name(Args... args) cv ref noex {
return pro::proxy_invoke<C>(pro::access_proxy<F>(SELF), std::forward<Args>(args)...);
return pro::proxy_invoke<C, R(Args...) cv ref noex>(pro::access_proxy<F>(SELF), std::forward<Args>(args)...);
}
};
};
Expand Down
2 changes: 1 addition & 1 deletion docs/access_proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ int main() {
pro::proxy<Stringable>& p2 = pro::access_proxy<Stringable>(a);
std::cout << std::boolalpha << (&p == &p2) << "\n"; // Prints: "true" because access_proxy converts
// an accessor back to the original proxy
auto result = pro::proxy_invoke<Convention>(p2);
auto result = pro::proxy_invoke<Convention, std::string()>(p2);
std::cout << result << "\n"; // Prints: "123"
}
```
Expand Down
2 changes: 1 addition & 1 deletion docs/conversion_dispatch/accessor.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ Let `SELF` be `std::forward<accessor cv ref>(*this)`.

`(2)` When `sizeof...(Os)` is greater than `1`, and `accessor<F, C, Os>...` are trivial types, inherits all `accessor<F, C, Os>...` types and `using` their `operator T`.

`(3)` When `sizeof...(Os)` is `1` and the only type `O` in `Os` is `T() cv ref noex`, provides an explicit (when `Expl` is `true`) or implicit (when `Expl` is `false`) `operator T()` with the same *cv ref noex* specifiers. `accessor::operator T()` is equivalent to `return proxy_invoke<C>(access_proxy<F>(SELF))`.
`(3)` When `sizeof...(Os)` is `1` and the only type `O` in `Os` is `T() cv ref noex`, provides an explicit (when `Expl` is `true`) or implicit (when `Expl` is `false`) `operator T()` with the same *cv ref noex* specifiers. `accessor::operator T()` is equivalent to `return proxy_invoke<C, T() cv ref noex>(access_proxy<F>(SELF))`.
10 changes: 5 additions & 5 deletions docs/operator_dispatch/accessor.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct accessor<F, C, R(Args...) cv ref noex> {
}
```

`(3)` Provides an `operator sop(Args...)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Args...)` is equivalent to `return proxy_invoke<C>(access_proxy<F>(SELF), std::forward<Args>(args)...)`.
`(3)` Provides an `operator sop(Args...)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Args...)` is equivalent to `return proxy_invoke<C, R(Args...) cv ref noex>(access_proxy<F>(SELF), std::forward<Args>(args)...)`.

### `!` and `~`

Expand All @@ -53,7 +53,7 @@ struct accessor<F, C, R() cv ref noex> {
}
```

`(4)` Provides an `operator sop()` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop()` is equivalent to `return proxy_invoke<C>(access_proxy<F>(SELF))`.
`(4)` Provides an `operator sop()` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop()` is equivalent to `return proxy_invoke<C, R() cv ref noex>(access_proxy<F>(SELF))`.

### Assignment SOPs

Expand All @@ -67,7 +67,7 @@ struct accessor<F, C, R(Arg) cv ref noex> {
}
```

`(4)` Provides an `operator sop(Arg)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Arg)` calls `proxy_invoke<C>(access_proxy<F>(SELF), std::forward<Arg>(arg))` and returns `access_proxy<F>(SELF)` when `C::is_direct` is `true`, or otherwise, returns `*access_proxy<F>(SELF)` when `C::is_direct` is `false`.
`(4)` Provides an `operator sop(Arg)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Arg)` calls `proxy_invoke<C, R(Arg) cv ref noex>(access_proxy<F>(SELF), std::forward<Arg>(arg))` and returns `access_proxy<F>(SELF)` when `C::is_direct` is `true`, or otherwise, returns `*access_proxy<F>(SELF)` when `C::is_direct` is `false`.

## Right-Hand-Side Operand Specializations

Expand All @@ -94,7 +94,7 @@ struct accessor<F, C, R(Arg) cv ref noex> {
}
```

`(7)` Provides a `friend operator sop(Arg arg, accessor cv ref)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, accessor cv ref)` is equivalent to `return proxy_invoke<C>(access_proxy<F>(SELF), std::forward<Arg>(arg))`.
`(7)` Provides a `friend operator sop(Arg arg, accessor cv ref)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, accessor cv ref)` is equivalent to `return proxy_invoke<C, R(Arg) cv ref noex>(access_proxy<F>(SELF), std::forward<Arg>(arg))`.

### Assignment SOPs

Expand All @@ -108,4 +108,4 @@ struct accessor<F, C, R(Arg) cv ref noex> {
}
```

`(8)` Provides a `friend operator sop(Arg arg, accessor cv ref)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, accessor cv ref)` calls `proxy_invoke<C>(access_proxy<F>(SELF), std::forward<Arg>(arg))` and returns `access_proxy<F>(SELF)` when `C::is_direct` is `true`, or otherwise, returns `*access_proxy<F>(SELF)` when `C::is_direct` is `false`.
`(8)` Provides a `friend operator sop(Arg arg, accessor cv ref)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, accessor cv ref)` calls `proxy_invoke<C, R(Arg) cv ref noex>(access_proxy<F>(SELF), std::forward<Arg>(arg))` and returns `access_proxy<F>(SELF)` when `C::is_direct` is `true`, or otherwise, returns `*access_proxy<F>(SELF)` when `C::is_direct` is `false`.
14 changes: 7 additions & 7 deletions docs/proxy_invoke.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# Function template `proxy_invoke`

```cpp
template <class C, class F, class... Args>
template <class C, class O, class F, class... Args>
/* see below */ proxy_invoke(proxy<F>& p, Args&&... args);

template <class C, class F, class... Args>
template <class C, class O, class F, class... Args>
/* see below */ proxy_invoke(const proxy<F>& p, Args&&... args);

template <class C, class F, class... Args>
template <class C, class O, class F, class... Args>
/* see below */ proxy_invoke(proxy<F>&& p, Args&&... args);

template <class C, class F, class... Args>
template <class C, class O, class F, class... Args>
/* see below */ proxy_invoke(const proxy<F>&& p, Args&&... args);
```

Invokes a `proxy` with a specified convention type and arguments. `C` is required to be defined in `typename F::convention_types`. Overload resolution is performed among the overload types defined in `typename C::overload_types`.
Invokes a `proxy` with a specified convention type, an overload type, and arguments. `C` is required to be defined in `typename F::convention_types`. `O` is required to be defined in `typename C::overload_types`.

Let `ptr` be the contained value of `p` with the same cv ref-qualifiers, `O` be the matched overload type among the overload types defined in `typename C::overload_types`, `Args2...` be the argument types of `O`, `R` be the return type of `O`,
Let `ptr` be the contained value of `p` with the same cv ref-qualifiers, `Args2...` be the argument types of `O`, `R` be the return type of `O`,

- if `C::is_direct` is `true`, let `v` be `std::forward<decltype(ptr)>(ptr)`, or otherwise,
- if `C::is_direct` is `false`, let `v` be `*std::forward<decltype(ptr)>(ptr)`,
Expand Down Expand Up @@ -55,7 +55,7 @@ int main() {
std::cout << ToString(*p) << "\n"; // Invokes with accessor, prints: "123"

using C = std::tuple_element_t<0u, Stringable::convention_types>;
std::cout << pro::proxy_invoke<C>(p) << "\n"; // Invokes with proxy_invoke, also prints: "123"
std::cout << pro::proxy_invoke<C, std::string() const>(p) << "\n"; // Invokes with proxy_invoke, also prints: "123"
}
```

Expand Down
55 changes: 25 additions & 30 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,6 @@ struct overload_traits_impl : applicable_traits {
}
}
};
struct resolver {
overload_traits_impl operator()(add_qualifier_t<std::byte, Q>, Args...);
};

template <bool IS_DIRECT, class D, class P>
static constexpr bool applicable_ptr =
Expand Down Expand Up @@ -350,13 +347,8 @@ struct conv_traits_impl : inapplicable_traits {};
template <class C, class... Os>
requires(sizeof...(Os) > 0u && (overload_traits<Os>::applicable && ...))
struct conv_traits_impl<C, Os...> : applicable_traits {
struct overload_resolver : overload_traits<Os>::resolver...
{ using overload_traits<Os>::resolver::operator()...; };
using meta = composite_meta_impl<dispatcher_meta<typename overload_traits<Os>
::template meta_provider<C::is_direct, typename C::dispatch_type>>...>;
template <qualifier_type Q, class... Args>
using matched_overload_traits = std::invoke_result_t<
overload_resolver, add_qualifier_t<std::byte, Q>, Args...>;

template <class P>
static constexpr bool applicable_ptr =
Expand Down Expand Up @@ -575,15 +567,14 @@ template <class F>
struct proxy_helper {
static inline const auto& get_meta(const proxy<F>& p) noexcept
{ return *p.meta_.operator->(); }
template <class C, qualifier_type Q, class... Args>
template <class C, class O, qualifier_type Q, class... Args>
static decltype(auto) invoke(add_qualifier_t<proxy<F>, Q> p, Args&&... args) {
using OverloadTraits = typename conv_traits<C>
::template matched_overload_traits<Q, Args...>;
auto dispatcher = p.meta_->template dispatcher_meta<typename OverloadTraits
auto dispatcher = p.meta_
->template dispatcher_meta<typename overload_traits<O>
::template meta_provider<C::is_direct, typename C::dispatch_type>>
::dispatcher;
if constexpr (C::is_direct &&
OverloadTraits::qualifier == qualifier_type::rv) {
overload_traits<O>::qualifier == qualifier_type::rv) {
meta_ptr_reset_guard guard{p.meta_};
return dispatcher(std::forward<add_qualifier_t<std::byte, Q>>(*p.ptr_),
std::forward<Args>(args)...);
Expand Down Expand Up @@ -808,26 +799,26 @@ class proxy : public details::facade_traits<F>::direct_accessor {
alignas(F::constraints.max_align) std::byte ptr_[F::constraints.max_size];
};

template <class C, class F, class... Args>
template <class C, class O, class F, class... Args>
decltype(auto) proxy_invoke(proxy<F>& p, Args&&... args) {
return details::proxy_helper<F>::template invoke<
C, details::qualifier_type::lv>(p, std::forward<Args>(args)...);
C, O, details::qualifier_type::lv>(p, std::forward<Args>(args)...);
}
template <class C, class F, class... Args>
template <class C, class O, class F, class... Args>
decltype(auto) proxy_invoke(const proxy<F>& p, Args&&... args) {
return details::proxy_helper<F>::template invoke<
C, details::qualifier_type::const_lv>(p, std::forward<Args>(args)...);
C, O, details::qualifier_type::const_lv>(p, std::forward<Args>(args)...);
}
template <class C, class F, class... Args>
template <class C, class O, class F, class... Args>
decltype(auto) proxy_invoke(proxy<F>&& p, Args&&... args) {
return details::proxy_helper<F>::template invoke<
C, details::qualifier_type::rv>(
C, O, details::qualifier_type::rv>(
std::forward<proxy<F>>(p), std::forward<Args>(args)...);
}
template <class C, class F, class... Args>
template <class C, class O, class F, class... Args>
decltype(auto) proxy_invoke(const proxy<F>&& p, Args&&... args) {
return details::proxy_helper<F>::template invoke<
C, details::qualifier_type::const_rv>(
C, O, details::qualifier_type::const_rv>(
std::forward<const proxy<F>>(p), std::forward<Args>(args)...);
}

Expand Down Expand Up @@ -1167,7 +1158,7 @@ struct facade_impl {
struct accessor<F2, C, proxy<F>() Q> { \
__VA_ARGS__ () Q { \
if (access_proxy<F2>(SELF).has_value()) { \
return proxy_invoke<C>(access_proxy<F2>(SELF)); \
return proxy_invoke<C, proxy<F>() Q>(access_proxy<F2>(SELF)); \
} \
return nullptr; \
} \
Expand Down Expand Up @@ -1323,13 +1314,14 @@ struct operator_dispatch;
#define ___PRO_DEF_LHS_LEFT_OP_ACCESSOR(Q, SELF, ...) \
template <class F, class C, class R> \
struct accessor<F, C, R() Q> { \
R __VA_ARGS__ () Q { return proxy_invoke<C>(access_proxy<F>(SELF)); } \
R __VA_ARGS__ () Q \
{ return proxy_invoke<C, R() Q>(access_proxy<F>(SELF)); } \
}
#define ___PRO_DEF_LHS_ANY_OP_ACCESSOR(Q, SELF, ...) \
template <class F, class C, class R, class... Args> \
struct accessor<F, C, R(Args...) Q> { \
R __VA_ARGS__ (Args... args) Q { \
return proxy_invoke<C>( \
return proxy_invoke<C, R(Args...) Q>( \
access_proxy<F>(SELF), std::forward<Args>(args)...); \
} \
}
Expand Down Expand Up @@ -1367,7 +1359,7 @@ struct operator_dispatch;
template <class F, class C, class R, class Arg> \
struct accessor<F, C, R(Arg) Q> { \
friend R __VA_ARGS__ (Arg arg, SELF) NE { \
return proxy_invoke<C>( \
return proxy_invoke<C, R(Arg) Q>( \
access_proxy<F>(FW_SELF), std::forward<Arg>(arg)); \
} \
}
Expand All @@ -1394,7 +1386,8 @@ struct operator_dispatch;
template <class F, class C, class R, class Arg> \
struct accessor<F, C, R(Arg) Q> { \
decltype(auto) __VA_ARGS__ (Arg arg) Q { \
proxy_invoke<C>(access_proxy<F>(SELF), std::forward<Arg>(arg)); \
proxy_invoke<C, R(Arg) Q>( \
access_proxy<F>(SELF), std::forward<Arg>(arg)); \
if constexpr (C::is_direct) { \
return access_proxy<F>(SELF); \
} else { \
Expand All @@ -1406,7 +1399,7 @@ struct operator_dispatch;
template <class F, class C, class R, class Arg> \
struct accessor<F, C, R(Arg&) Q> { \
friend Arg& __VA_ARGS__ (Arg& arg, SELF) NE { \
proxy_invoke<C>(access_proxy<F>(FW_SELF), arg); \
proxy_invoke<C, R(Arg&) Q>(access_proxy<F>(FW_SELF), arg); \
return arg; \
} \
}
Expand Down Expand Up @@ -1510,7 +1503,7 @@ struct operator_dispatch<"[]", false> {
template <class F, class C> \
struct accessor<F, C, T() Q> { \
explicit(Expl) __VA_ARGS__ () Q \
{ return proxy_invoke<C>(access_proxy<F>(SELF)); } \
{ return proxy_invoke<C, T() Q>(access_proxy<F>(SELF)); } \
}
template <class T, bool Expl = true>
struct conversion_dispatch {
Expand All @@ -1537,7 +1530,8 @@ struct conversion_dispatch {
template <class __F, class __C, class __R, class... __Args> \
struct accessor<__F, __C, __R(__Args...) __Q> { \
__R __VA_ARGS__ (__Args... __args) __Q { \
return ::pro::proxy_invoke<__C>(::pro::access_proxy<__F>(__SELF), \
return ::pro::proxy_invoke<__C, __R(__Args...) __Q>( \
::pro::access_proxy<__F>(__SELF), \
::std::forward<__Args>(__args)...); \
} \
}
Expand All @@ -1560,7 +1554,8 @@ struct conversion_dispatch {
template <class __F, class __C, class __R, class... __Args> \
struct accessor<__F, __C, __R(__Args...) __Q> { \
friend __R __VA_ARGS__ (__SELF, __Args... __args) __NE { \
return ::pro::proxy_invoke<__C>(::pro::access_proxy<__F>(__FW_SELF), \
return ::pro::proxy_invoke<__C, __R(__Args...) __Q>( \
::pro::access_proxy<__F>(__FW_SELF), \
::std::forward<__Args>(__args)...); \
} \
}
Expand Down
2 changes: 1 addition & 1 deletion samples/access_proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ int main() {
pro::proxy<Stringable>& p2 = pro::access_proxy<Stringable>(a);
std::cout << std::boolalpha << (&p == &p2) << "\n"; // Prints: "true" because access_proxy converts
// an accessor back to the original proxy
auto result = pro::proxy_invoke<Convention>(p2);
auto result = pro::proxy_invoke<Convention, std::string()>(p2);
std::cout << result << "\n"; // Prints: "123"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// This file contains example code from __msft_lib_proxy.md.
// This file contains example code from msft_lib_proxy.md.

#include <cstdio>

Expand Down
2 changes: 1 addition & 1 deletion samples/proxy_invoke.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ int main() {
std::cout << ToString(*p) << "\n"; // Invokes with accessor, prints: "123"

using C = std::tuple_element_t<0u, Stringable::convention_types>;
std::cout << pro::proxy_invoke<C>(p) << "\n"; // Invokes with proxy_invoke, also prints: "123"
std::cout << pro::proxy_invoke<C, std::string() const>(p) << "\n"; // Invokes with proxy_invoke, also prints: "123"
}
Loading