From 1f2037ff984ee05944ed9b8f5d85adb3214cc2c4 Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Thu, 26 Dec 2024 19:32:16 +1000 Subject: [PATCH] Replace macro `PRO_DEF_WEAK_DISPATCH` with class template `weak_dispatch` (#224) --- proxy.h | 55 +++++++++++++++---- .../freestanding/proxy_freestanding_tests.cpp | 8 +-- tests/proxy_invocation_tests.cpp | 27 +++------ 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/proxy.h b/proxy.h index 6378f8e..1bb6ba9 100644 --- a/proxy.h +++ b/proxy.h @@ -6,8 +6,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -16,9 +18,6 @@ #include #ifdef __cpp_rtti -#ifndef __cpp_exceptions -#include // For std::abort() when "throw" is not available -#endif // __cpp_exceptions #include #include #endif // __cpp_rtti @@ -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 @@ -1256,7 +1261,11 @@ using proxy_view = proxy>; 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 { @@ -1554,12 +1563,6 @@ template sign(const char (&str)[N]) -> sign; #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; @@ -1657,9 +1660,21 @@ ___PRO_DEBUG( const std::type_info* info; }; -#undef ___PRO_THROW #endif // __cpp_rtti +struct wildcard { + wildcard() = delete; + + template + [[noreturn]] operator T() { +#ifdef __cpp_lib_unreachable + std::unreachable(); +#else + std::abort(); +#endif // __cpp_lib_unreachable + } +}; + } // namespace details template @@ -1969,6 +1984,20 @@ struct explicit_conversion_dispatch : details::cast_dispatch_base { }; 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 +struct weak_dispatch : D { + using D::operator(); + template + [[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, ...) \ @@ -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 \ decltype(auto) operator()(::std::nullptr_t, __Args&&... __args) \ @@ -2058,6 +2088,7 @@ ___PRO_DEBUG( \ } // namespace pro +#undef ___PRO_THROW #undef ___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE #endif // _MSFT_PROXY_ diff --git a/tests/freestanding/proxy_freestanding_tests.cpp b/tests/freestanding/proxy_freestanding_tests.cpp index 11eb8f9..fc584e5 100644 --- a/tests/freestanding/proxy_freestanding_tests.cpp +++ b/tests/freestanding/proxy_freestanding_tests.cpp @@ -4,6 +4,7 @@ #include "proxy.h" +constexpr unsigned DefaultHash = -1; unsigned GetHash(int v) { return static_cast(v + 3) * 31; } unsigned GetHash(double v) { return static_cast(v * v + 5) * 87; } unsigned GetHash(const char* v) { @@ -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 + ::add_convention ::build {}; extern "C" int main() { @@ -40,7 +40,7 @@ extern "C" int main() { return 1; } p = &t; - if (GetHash(*p) != GetDefaultHash()) { + if (GetHash(*p) != DefaultHash) { return 1; } return 0; diff --git a/tests/proxy_invocation_tests.cpp b/tests/proxy_invocation_tests.cpp index bd059a7..c56fa73 100644 --- a/tests/proxy_invocation_tests.cpp +++ b/tests/proxy_invocation_tests.cpp @@ -36,18 +36,10 @@ struct Callable : pro::facade_builder ::add_facade> ::build {}; -struct Wildcard { - template - 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 struct WeakCallable : pro::facade_builder ::support_copy - ::add_convention + ::add_convention>, Os...> ::build {}; PRO_DEF_FREE_DISPATCH(FreeSize, std::ranges::size, Size); @@ -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 + ::add_convention, std::string(int)> ::build {}; template @@ -101,12 +92,12 @@ struct Weak : pro::facade_builder ::build {}; template -auto GetWeakImpl(const std::shared_ptr& p) { return pro::make_proxy, std::weak_ptr>(p); } - +pro::proxy> GetWeakImpl(const std::shared_ptr& p) { return pro::make_proxy, std::weak_ptr>(p); } template -PRO_DEF_FREE_DISPATCH(FreeGetWeakImpl, GetWeakImpl, GetWeak); +pro::proxy> GetWeakImpl(std::nullptr_t) { return nullptr; } + template -PRO_DEF_WEAK_DISPATCH(FreeGetWeak, FreeGetWeakImpl, std::nullptr_t); +PRO_DEF_FREE_DISPATCH(FreeGetWeak, GetWeakImpl, GetWeak); struct SharedStringable : pro::facade_builder ::add_facade @@ -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(e.what()), "Not implemented!"); } ASSERT_TRUE(exception_thrown); } @@ -292,9 +282,8 @@ TEST(ProxyInvocationTests, TestFreeDispatchDefault) { auto p = pro::make_proxy>(123); try { (*p)(); - } catch (const std::runtime_error& e) { + } catch (const pro::not_implemented&) { exception_thrown = true; - ASSERT_EQ(static_cast(e.what()), "Not implemented!"); } ASSERT_TRUE(exception_thrown); }