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

Revise pointer requirements #47

Merged
merged 1 commit into from
Dec 1, 2023
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
41 changes: 22 additions & 19 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <concepts>
#include <initializer_list>
#include <memory>
#include <new>
#include <tuple>
#include <type_traits>
Expand Down Expand Up @@ -58,10 +59,12 @@ consteval bool has_destructibility(constraint_level level) {
}
}

template <class P> struct pointer_traits : inapplicable_traits {};
template <class P> requires(requires(const P& ptr) { { *ptr }; })
struct pointer_traits<P> : applicable_traits
{ using value_type = decltype(*std::declval<const P&>()); };
// As per std::to_address() wording in [pointer.conversion]
template <class P>
concept is_address_deducible =
(std::is_pointer_v<P> && !std::is_function_v<std::remove_pointer_t<P>>) ||
requires(P p) { std::pointer_traits<P>::to_address(p); } ||
requires(P p) { p.operator->(); };

template <class T, class... Us> struct contains_traits : inapplicable_traits {};
template <class T, class... Us>
Expand Down Expand Up @@ -96,15 +99,16 @@ struct overload_traits<R(Args...)> : applicable_traits {
using dispatcher_type = R (*)(const char*, Args...);
template <class T> struct resolver { T operator()(Args...); };

template <class D, class T>
static constexpr bool applicable_operand = requires(T operand, Args... args)
{ { D{}(std::forward<T>(operand), std::forward<Args>(args)...) }; };
template <class D, class P>
static R dispatcher(const char* p, Args... args) {
static constexpr bool applicable_pointer = requires(const P& p, Args... args)
{ { D{}(*std::to_address(p), std::forward<Args>(args)...) }; };
template <class D, class P>
static R dispatcher(const char* erased, Args... args) {
const P& p = *reinterpret_cast<const P*>(erased);
if constexpr (std::is_void_v<R>) {
D{}(**reinterpret_cast<const P*>(p), std::forward<Args>(args)...);
D{}(*std::to_address(p), std::forward<Args>(args)...);
} else {
return D{}(**reinterpret_cast<const P*>(p), std::forward<Args>(args)...);
return D{}(*std::to_address(p), std::forward<Args>(args)...);
}
}
};
Expand Down Expand Up @@ -137,9 +141,9 @@ struct dispatch_traits_impl<D, std::tuple<Os...>> : applicable_traits,
using dispatcher_types =
std::tuple<typename overload_traits<Os>::dispatcher_type...>;

template <class T>
static constexpr bool applicable_operand =
(overload_traits<Os>::template applicable_operand<D, T> && ...);
template <class P>
static constexpr bool applicable_pointer =
(overload_traits<Os>::template applicable_pointer<D, P> && ...);
template <class P>
static constexpr dispatcher_types dispatchers{
overload_traits<Os>::template dispatcher<D, P>...};
Expand Down Expand Up @@ -254,8 +258,7 @@ struct facade_traits_impl<F, std::tuple<Ds...>> : applicable_traits {
has_copyability<P>(F::minimum_copyability) &&
has_relocatability<P>(F::minimum_relocatability) &&
has_destructibility<P>(F::minimum_destructibility) &&
(dispatch_traits<Ds>::template applicable_operand<
typename pointer_traits<P>::value_type> && ...) &&
(dispatch_traits<Ds>::template applicable_pointer<P> && ...) &&
(std::is_void_v<typename F::reflection_type> || std::is_constructible_v<
typename F::reflection_type, std::in_place_type_t<P>>);
template <class P> static constexpr meta_type meta{std::in_place_type<P>};
Expand All @@ -270,7 +273,7 @@ using dependent_t = typename dependent_traits<T, Us...>::type;
} // namespace details

template <class P, class F>
concept proxiable = details::pointer_traits<P>::applicable &&
concept proxiable = details::is_address_deducible<const P> &&
details::basic_facade_traits<F>::applicable &&
details::facade_traits<F>::applicable &&
details::facade_traits<F>::template applicable_pointer<P>;
Expand Down Expand Up @@ -505,7 +508,7 @@ class sbo_ptr {
sbo_ptr(sbo_ptr&&) noexcept(std::is_nothrow_move_constructible_v<T>)
= default;

T& operator*() const { return value_; }
T* operator->() const noexcept { return &value_; }

private:
mutable T value_;
Expand All @@ -518,11 +521,11 @@ class deep_ptr {
deep_ptr(Args&&... args) requires(std::is_constructible_v<T, Args...>)
: ptr_(new T(std::forward<Args>(args)...)) {}
deep_ptr(const deep_ptr& rhs) requires(std::is_copy_constructible_v<T>)
: ptr_(rhs.ptr_ == nullptr ? nullptr : new T(*rhs)) {}
: ptr_(rhs.ptr_ == nullptr ? nullptr : new T(*rhs.ptr_)) {}
deep_ptr(deep_ptr&& rhs) noexcept : ptr_(rhs.ptr_) { rhs.ptr_ = nullptr; }
~deep_ptr() noexcept { delete ptr_; }

T& operator*() const { return *ptr_; }
T* operator->() const noexcept { return ptr_; }

private:
T* ptr_;
Expand Down
2 changes: 1 addition & 1 deletion tests/proxy_traits_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct MockPtr {
MockPtr(const MockPtr&) noexcept requires(kTrivial) = default;
MockPtr(MockPtr&&) noexcept requires(kNothrowRelocatable && !kTrivial) {}
MockPtr(MockPtr&&) noexcept requires(kTrivial) = default;
const MockPtr& operator*() const noexcept { return *this; }
const MockPtr* operator->() const noexcept { return this; }

alignas(kAlignment) char dummy_[kSize];
};
Expand Down
2 changes: 1 addition & 1 deletion tests/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class LifetimeTracker {
id_(rhs.host_->AllocateId(LifetimeOperationType::kMoveConstruction)),
host_(rhs.host_) {}
~Session() { host_->ops_.emplace_back(id_, LifetimeOperationType::kDestruction); }
const Session& operator*() const { return *this; }
const Session* operator->() const { return this; }
friend std::string to_string(const Session& self) { return "Session " + std::to_string(self.id_); }

private:
Expand Down