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

Improve accessibility in debugging #200

Merged
merged 7 commits into from
Nov 19, 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/ProAccessible.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Given that `F` is a type meeting the [*ProBasicFacade* requirements](ProBasicFac

| Expressions | Semantics |
| ------------------------------------------- | ------------------------------------------------------------ |
| `typename T::template accessor<F, Args...>` | A type that provides accessibility to `proxy`. It shall be a trivial class type and not [final](https://en.cppreference.com/w/cpp/language/final). |
| `typename T::template accessor<F, Args...>` | A type that provides accessibility to `proxy`. It shall be a *nothrow-default-constructible*, *trivially-copyable* type, and shall not be [final](https://en.cppreference.com/w/cpp/language/final). |

## See Also

Expand Down
85 changes: 62 additions & 23 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,30 +450,37 @@ struct lifetime_meta_traits<MP, constraint_level::nontrivial>
template <template <bool> class MP, constraint_level C>
using lifetime_meta_t = typename lifetime_meta_traits<MP, C>::type;

template <class F> struct proxy_indirect_accessor;
template <class... As>
class ___PRO_ENFORCE_EBO composite_accessor_impl : public As... {
template <class> friend class pro::proxy;
template <class F> friend struct proxy_indirect_accessor;

composite_accessor_impl() noexcept = default;
composite_accessor_impl(const composite_accessor_impl&) noexcept = default;
composite_accessor_impl& operator=(const composite_accessor_impl&) noexcept
= default;
};

template <class T>
struct accessor_traits_impl : std::type_identity<void> {};
template <class T>
requires(std::is_nothrow_default_constructible_v<T> &&
std::is_trivially_copyable_v<T> && !std::is_final_v<T>)
struct accessor_traits_impl<T> : std::type_identity<T> {};
template <class SFINAE, class T, class... Args>
struct sfinae_accessor_traits : std::type_identity<void> {};
template <class T, class... Args>
struct sfinae_accessor_traits<
std::void_t<typename T::template accessor<Args...>>, T, Args...>
: std::type_identity<typename T::template accessor<Args...>> {};
: accessor_traits_impl<typename T::template accessor<Args...>> {};
template <class T, class... Args>
using accessor_t = typename sfinae_accessor_traits<void, T, Args...>::type;

template <bool IS_DIRECT, class F, class O, class I>
struct composite_accessor_reduction : std::type_identity<O> {};
template <bool IS_DIRECT, class F, class... As, class I>
requires(IS_DIRECT == I::is_direct && std::is_trivial_v<accessor_t<I, F>> &&
!std::is_final_v<accessor_t<I, F>>)
requires(IS_DIRECT == I::is_direct && !std::is_void_v<accessor_t<I, F>>)
struct composite_accessor_reduction<
IS_DIRECT, F, composite_accessor_impl<As...>, I>
{ using type = composite_accessor_impl<As..., accessor_t<I, F>>; };
Expand Down Expand Up @@ -508,7 +515,6 @@ consteval bool is_facade_constraints_well_formed() {
}
return false;
}
struct empty_proxy_base {};
template <class F, class... Cs>
struct facade_conv_traits_impl : inapplicable_traits {};
template <class F, class... Cs> requires(conv_traits<Cs>::applicable && ...)
Expand Down Expand Up @@ -563,12 +569,14 @@ struct facade_traits<F>
using direct_accessor = merged_composite_accessor<
typename facade_traits::conv_direct_accessor,
typename facade_traits::refl_direct_accessor>;
using base = std::conditional_t<std::is_same_v<direct_accessor,
composite_accessor_impl<>>, empty_proxy_base, direct_accessor>;
static constexpr bool has_indirection = !std::is_same_v<
typename facade_traits::indirect_accessor, composite_accessor_impl<>>;
};

template <class F> struct proxy_indirect_accessor {};
template <class F> requires(facade_traits<F>::has_indirection)
struct proxy_indirect_accessor<F> : facade_traits<F>::indirect_accessor {};

using ptr_prototype = void*[2];

template <class M>
Expand Down Expand Up @@ -672,14 +680,32 @@ concept proxiable = facade<F> && sizeof(P) <= F::constraints.max_size &&
details::facade_traits<F>::template refl_applicable_ptr<P>;

template <class F>
class proxy : public details::facade_traits<F>::base {
class proxy : public details::facade_traits<F>::direct_accessor {
static_assert(facade<F>);
friend struct details::proxy_helper<F>;
using _Traits = details::facade_traits<F>;
using _IA = details::proxy_indirect_accessor<F>;

public:
#ifdef NDEBUG
proxy() noexcept = default;
proxy(std::nullptr_t) noexcept {}
#else
proxy() noexcept {
if constexpr (_Traits::has_indirection) {
std::ignore = static_cast<_IA* (proxy::*)() noexcept>(&proxy::operator->);
std::ignore = static_cast<const _IA* (proxy::*)() const noexcept>(
&proxy::operator->);
std::ignore = static_cast<_IA& (proxy::*)() & noexcept>(&proxy::operator*);
std::ignore = static_cast<const _IA& (proxy::*)() const& noexcept>(
&proxy::operator*);
std::ignore = static_cast<_IA&& (proxy::*)() && noexcept>(
&proxy::operator*);
std::ignore = static_cast<const _IA&& (proxy::*)() const&& noexcept>(
&proxy::operator*);
}
}
#endif // NDEBUG
proxy(std::nullptr_t) noexcept : proxy() {}
proxy(const proxy&) noexcept requires(F::constraints.copyability ==
constraint_level::trivial) = default;
proxy(const proxy& rhs)
Expand Down Expand Up @@ -709,20 +735,20 @@ class proxy : public details::facade_traits<F>::base {
template <class P>
proxy(P&& ptr) noexcept(std::is_nothrow_constructible_v<std::decay_t<P>, P>)
requires(proxiable<std::decay_t<P>, F> &&
std::is_constructible_v<std::decay_t<P>, P>)
std::is_constructible_v<std::decay_t<P>, P>) : proxy()
{ initialize<std::decay_t<P>>(std::forward<P>(ptr)); }
template <proxiable<F> P, class... Args>
explicit proxy(std::in_place_type_t<P>, Args&&... args)
noexcept(std::is_nothrow_constructible_v<P, Args...>)
requires(std::is_constructible_v<P, Args...>)
requires(std::is_constructible_v<P, Args...>) : proxy()
{ initialize<P>(std::forward<Args>(args)...); }
template <proxiable<F> P, class U, class... Args>
explicit proxy(std::in_place_type_t<P>, std::initializer_list<U> il,
Args&&... args)
noexcept(std::is_nothrow_constructible_v<
P, std::initializer_list<U>&, Args...>)
requires(std::is_constructible_v<P, std::initializer_list<U>&, Args...>)
{ initialize<P>(il, std::forward<Args>(args)...); }
: proxy() { initialize<P>(il, std::forward<Args>(args)...); }
proxy& operator=(std::nullptr_t)
noexcept(F::constraints.destructibility >= constraint_level::nothrow)
requires(F::constraints.destructibility >= constraint_level::nontrivial)
Expand Down Expand Up @@ -826,18 +852,18 @@ class proxy : public details::facade_traits<F>::base {
requires(std::is_constructible_v<P, std::initializer_list<U>&, Args...> &&
F::constraints.destructibility >= constraint_level::nontrivial)
{ reset(); return initialize<P>(il, std::forward<Args>(args)...); }
auto operator->() noexcept requires(_Traits::has_indirection)
_IA* operator->() noexcept requires(_Traits::has_indirection)
{ return std::addressof(ia_); }
auto operator->() const noexcept requires(_Traits::has_indirection)
const _IA* operator->() const noexcept requires(_Traits::has_indirection)
{ return std::addressof(ia_); }
auto& operator*() & noexcept requires(_Traits::has_indirection)
_IA& operator*() & noexcept requires(_Traits::has_indirection)
{ return ia_; }
auto& operator*() const& noexcept requires(_Traits::has_indirection)
const _IA& operator*() const& noexcept requires(_Traits::has_indirection)
{ return ia_; }
auto&& operator*() && noexcept requires(_Traits::has_indirection)
{ return std::forward<typename _Traits::indirect_accessor>(ia_); }
auto&& operator*() const&& noexcept requires(_Traits::has_indirection)
{ return std::forward<const typename _Traits::indirect_accessor>(ia_); }
_IA&& operator*() && noexcept requires(_Traits::has_indirection)
{ return std::forward<_IA>(ia_); }
const _IA&& operator*() const&& noexcept requires(_Traits::has_indirection)
{ return std::forward<const _IA>(ia_); }

friend void swap(proxy& lhs, proxy& rhs) noexcept(noexcept(lhs.swap(rhs)))
{ lhs.swap(rhs); }
Expand All @@ -856,7 +882,7 @@ class proxy : public details::facade_traits<F>::base {
}

[[___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE]]
typename _Traits::indirect_accessor ia_;
_IA ia_;
details::meta_ptr<typename _Traits::meta> meta_;
alignas(F::constraints.max_align) std::byte ptr_[F::constraints.max_size];
};
Expand Down Expand Up @@ -1107,9 +1133,9 @@ proxy<F> make_proxy(T&& value) {
struct ___PRO_ENFORCE_EBO accessor { accessor() = delete; }; \
template <class __F, class __C, class... __Os> \
requires(sizeof...(__Os) > 1u && \
(::std::is_trivial_v<accessor<__F, __C, __Os>> && ...)) \
(::std::is_constructible_v<accessor<__F, __C, __Os>> && ...)) \
struct accessor<__F, __C, __Os...> : accessor<__F, __C, __Os>... \
{ using accessor<__F, __C, __Os>:: __VA_ARGS__ ...; }; \
{ using accessor<__F, __C, __Os>::__VA_ARGS__...; }; \
__MACRO(, *this, __VA_ARGS__); \
__MACRO(noexcept, *this, __VA_ARGS__); \
__MACRO(&, *this, __VA_ARGS__); \
Expand All @@ -1129,7 +1155,7 @@ proxy<F> make_proxy(T&& value) {
struct ___PRO_ENFORCE_EBO accessor { accessor() = delete; }; \
template <class __F, class __C, class... __Os> \
requires(sizeof...(__Os) > 1u && \
(::std::is_trivial_v<accessor<__F, __C, __Os>> && ...)) \
(::std::is_constructible_v<accessor<__F, __C, __Os>> && ...)) \
struct accessor<__F, __C, __Os...> : accessor<__F, __C, __Os>... {}; \
__MACRO(,, accessor& __self, __self, __VA_ARGS__); \
__MACRO(noexcept, noexcept, accessor& __self, __self, __VA_ARGS__); \
Expand All @@ -1150,6 +1176,13 @@ proxy<F> make_proxy(T&& value) {
__MACRO(const&& noexcept, noexcept, const accessor&& __self, \
::std::forward<const accessor>(__self), __VA_ARGS__);

#ifdef NDEBUG
#define ___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(...)
#else
#define ___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(...) \
accessor() noexcept { ::std::ignore = &accessor::__VA_ARGS__; }
#endif // NDEBUG

namespace details {

constexpr std::size_t invalid_size = std::numeric_limits<std::size_t>::max();
Expand Down Expand Up @@ -1227,6 +1260,7 @@ struct facade_impl {
#define ___PRO_DEF_UPWARD_CONVERSION_ACCESSOR(Q, SELF, ...) \
template <class F2, class C> \
struct accessor<F2, C, proxy<F>() Q> { \
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
__VA_ARGS__ () Q { \
if (access_proxy<F2>(SELF).has_value()) { \
return proxy_invoke<C, proxy<F>() Q>(access_proxy<F2>(SELF)); \
Expand Down Expand Up @@ -1389,12 +1423,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> { \
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
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> { \
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
R __VA_ARGS__ (Args... args) Q { \
return proxy_invoke<C, R(Args...) Q>( \
access_proxy<F>(SELF), std::forward<Args>(args)...); \
Expand Down Expand Up @@ -1460,6 +1496,7 @@ struct operator_dispatch;
#define ___PRO_DEF_LHS_ASSIGNMENT_OP_ACCESSOR(Q, SELF, ...) \
template <class F, class C, class R, class Arg> \
struct accessor<F, C, R(Arg) Q> { \
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
decltype(auto) __VA_ARGS__ (Arg arg) Q { \
proxy_invoke<C, R(Arg) Q>( \
access_proxy<F>(SELF), std::forward<Arg>(arg)); \
Expand Down Expand Up @@ -1577,6 +1614,7 @@ struct operator_dispatch<"[]", false> {
#define ___PRO_DEF_CONVERSION_ACCESSOR(Q, SELF, ...) \
template <class F, class C> \
struct accessor<F, C, T() Q> { \
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
explicit(Expl) __VA_ARGS__ () Q \
{ return proxy_invoke<C, T() Q>(access_proxy<F>(SELF)); } \
}
Expand Down Expand Up @@ -1604,6 +1642,7 @@ struct conversion_dispatch {
#define ___PRO_DEF_MEM_ACCESSOR(__Q, __SELF, ...) \
template <class __F, class __C, class __R, class... __Args> \
struct accessor<__F, __C, __R(__Args...) __Q> { \
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
__R __VA_ARGS__ (__Args... __args) __Q { \
return ::pro::proxy_invoke<__C, __R(__Args...) __Q>( \
::pro::access_proxy<__F>(__SELF), \
Expand Down