Skip to content

Commit

Permalink
Replace macro PRO_DEF_WEAK_DISPATCH with class template `weak_dispa…
Browse files Browse the repository at this point in the history
…tch` (#224)
  • Loading branch information
mingxwa authored Dec 26, 2024
1 parent 248e8cf commit 1f2037f
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 35 deletions.
55 changes: 43 additions & 12 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <bit>
#include <concepts>
#include <exception>
#include <initializer_list>
#include <limits>
#include <memory>
Expand All @@ -16,9 +18,6 @@
#include <utility>

#ifdef __cpp_rtti
#ifndef __cpp_exceptions
#include <cstdlib> // For std::abort() when "throw" is not available
#endif // __cpp_exceptions
#include <optional>
#include <typeinfo>
#endif // __cpp_rtti
Expand All @@ -31,6 +30,12 @@
#error "Proxy requires C++20 attribute no_unique_address"
#endif

#ifdef __cpp_exceptions
#define ___PRO_THROW(...) throw __VA_ARGS__
#else
#define ___PRO_THROW(...) std::abort()
#endif // __cpp_exceptions

#ifdef _MSC_VER
#define ___PRO_ENFORCE_EBO __declspec(empty_bases)
#else
Expand Down Expand Up @@ -1256,7 +1261,11 @@ using proxy_view = proxy<observer_facade<F>>;
accessor() noexcept { ::std::ignore = &accessor::__VA_ARGS__; })

#ifdef __cpp_rtti
struct bad_proxy_cast : std::bad_cast {};
class bad_proxy_cast : public std::bad_cast {
public:
bad_proxy_cast() noexcept = default;
char const* what() const noexcept override { return "pro::bad_proxy_cast"; }
};
#endif // __cpp_rtti

namespace details {
Expand Down Expand Up @@ -1554,12 +1563,6 @@ template <std::size_t N>
sign(const char (&str)[N]) -> sign<N>;

#ifdef __cpp_rtti
#ifdef __cpp_exceptions
#define ___PRO_THROW(...) throw __VA_ARGS__
#else
#define ___PRO_THROW(...) std::abort()
#endif // __cpp_exceptions

struct proxy_cast_context {
const std::type_info* type_ptr;
bool is_ref;
Expand Down Expand Up @@ -1657,9 +1660,21 @@ ___PRO_DEBUG(

const std::type_info* info;
};
#undef ___PRO_THROW
#endif // __cpp_rtti

struct wildcard {
wildcard() = delete;

template <class T>
[[noreturn]] operator T() {
#ifdef __cpp_lib_unreachable
std::unreachable();
#else
std::abort();
#endif // __cpp_lib_unreachable
}
};

} // namespace details

template <class Cs, class Rs, proxiable_ptr_constraints C>
Expand Down Expand Up @@ -1969,6 +1984,20 @@ struct explicit_conversion_dispatch : details::cast_dispatch_base<true, false> {
};
using conversion_dispatch = explicit_conversion_dispatch;

class not_implemented : public std::exception {
public:
not_implemented() noexcept = default;
char const* what() const noexcept override { return "pro::not_implemented"; }
};

template <class D>
struct weak_dispatch : D {
using D::operator();
template <class... Args>
[[noreturn]] details::wildcard operator()(std::nullptr_t, Args&&...)
{ ___PRO_THROW(not_implemented{}); }
};

#define ___PRO_EXPAND_IMPL(__X) __X
#define ___PRO_EXPAND_MACRO_IMPL( \
__MACRO, __1, __2, __3, __NAME, ...) \
Expand Down Expand Up @@ -2049,7 +2078,8 @@ ___PRO_DEBUG( \
___PRO_EXPAND_MACRO(___PRO_DEF_FREE_AS_MEM_DISPATCH, __NAME, __VA_ARGS__)

#define PRO_DEF_WEAK_DISPATCH(__NAME, __D, __FUNC) \
struct __NAME : __D { \
struct [[deprecated("'PRO_DEF_WEAK_DISPATCH' is deprecated. " \
"Use pro::weak_dispatch<" #__D "> instead.")]] __NAME : __D { \
using __D::operator(); \
template <class... __Args> \
decltype(auto) operator()(::std::nullptr_t, __Args&&... __args) \
Expand All @@ -2058,6 +2088,7 @@ ___PRO_DEBUG( \

} // namespace pro

#undef ___PRO_THROW
#undef ___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE

#endif // _MSFT_PROXY_
8 changes: 4 additions & 4 deletions tests/freestanding/proxy_freestanding_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "proxy.h"

constexpr unsigned DefaultHash = -1;
unsigned GetHash(int v) { return static_cast<unsigned>(v + 3) * 31; }
unsigned GetHash(double v) { return static_cast<unsigned>(v * v + 5) * 87; }
unsigned GetHash(const char* v) {
Expand All @@ -13,12 +14,11 @@ unsigned GetHash(const char* v) {
}
return result;
}
unsigned GetDefaultHash() { return -1; }
unsigned GetHash(std::nullptr_t) { return DefaultHash; }

PRO_DEF_FREE_DISPATCH(FreeGetHash, GetHash);
PRO_DEF_WEAK_DISPATCH(WeakFreeGetHash, FreeGetHash, GetDefaultHash);
struct Hashable : pro::facade_builder
::add_convention<WeakFreeGetHash, unsigned()>
::add_convention<FreeGetHash, unsigned()>
::build {};

extern "C" int main() {
Expand All @@ -40,7 +40,7 @@ extern "C" int main() {
return 1;
}
p = &t;
if (GetHash(*p) != GetDefaultHash()) {
if (GetHash(*p) != DefaultHash) {
return 1;
}
return 0;
Expand Down
27 changes: 8 additions & 19 deletions tests/proxy_invocation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,10 @@ struct Callable : pro::facade_builder
::add_facade<MovableCallable<Os...>>
::build {};

struct Wildcard {
template <class T>
operator T() const noexcept { std::terminate(); }
};

Wildcard NotImplemented(auto&&...) { throw std::runtime_error{ "Not implemented!" }; }

PRO_DEF_WEAK_DISPATCH(WeakOpCall, pro::operator_dispatch<"()">, NotImplemented);
template <class... Os>
struct WeakCallable : pro::facade_builder
::support_copy<pro::constraint_level::nontrivial>
::add_convention<WeakOpCall, Os...>
::add_convention<pro::weak_dispatch<pro::operator_dispatch<"()">>, Os...>
::build {};

PRO_DEF_FREE_DISPATCH(FreeSize, std::ranges::size, Size);
Expand Down Expand Up @@ -77,10 +69,9 @@ struct Container : pro::facade_builder
::build {};

PRO_DEF_MEM_DISPATCH(MemAt, at, at);
PRO_DEF_WEAK_DISPATCH(MemAtWeak, MemAt, NotImplemented);

struct ResourceDictionary : pro::facade_builder
::add_convention<MemAtWeak, std::string(int)>
::add_convention<pro::weak_dispatch<MemAt>, std::string(int)>
::build {};

template <class F, class T>
Expand All @@ -101,12 +92,12 @@ struct Weak : pro::facade_builder
::build {};

template <class F, class T>
auto GetWeakImpl(const std::shared_ptr<T>& p) { return pro::make_proxy<Weak<F>, std::weak_ptr<T>>(p); }

pro::proxy<Weak<F>> GetWeakImpl(const std::shared_ptr<T>& p) { return pro::make_proxy<Weak<F>, std::weak_ptr<T>>(p); }
template <class F>
PRO_DEF_FREE_DISPATCH(FreeGetWeakImpl, GetWeakImpl<F>, GetWeak);
pro::proxy<Weak<F>> GetWeakImpl(std::nullptr_t) { return nullptr; }

template <class F>
PRO_DEF_WEAK_DISPATCH(FreeGetWeak, FreeGetWeakImpl<F>, std::nullptr_t);
PRO_DEF_FREE_DISPATCH(FreeGetWeak, GetWeakImpl<F>, GetWeak);

struct SharedStringable : pro::facade_builder
::add_facade<utils::spec::Stringable>
Expand Down Expand Up @@ -272,9 +263,8 @@ TEST(ProxyInvocationTests, TestMemberDispatchDefault) {
bool exception_thrown = false;
try {
p->at(0);
} catch (const std::runtime_error& e) {
} catch (const pro::not_implemented&) {
exception_thrown = true;
ASSERT_EQ(static_cast<std::string>(e.what()), "Not implemented!");
}
ASSERT_TRUE(exception_thrown);
}
Expand All @@ -292,9 +282,8 @@ TEST(ProxyInvocationTests, TestFreeDispatchDefault) {
auto p = pro::make_proxy<details::WeakCallable<void()>>(123);
try {
(*p)();
} catch (const std::runtime_error& e) {
} catch (const pro::not_implemented&) {
exception_thrown = true;
ASSERT_EQ(static_cast<std::string>(e.what()), "Not implemented!");
}
ASSERT_TRUE(exception_thrown);
}
Expand Down

0 comments on commit 1f2037f

Please sign in to comment.