From ba99e90fa6fbb4ef2d25d959db0d90c9e96df41f Mon Sep 17 00:00:00 2001 From: Jamieson Pryor Date: Sun, 5 Jan 2025 12:09:29 -0800 Subject: [PATCH] `InvocableMap` and `QueryableMap` no longer deriver their pointer-to-member. This caused compatability issues with gcc on C++20. Also, rename usages of JniT to _JniT because of issues with gcc. https://github.com/google/jni-bind/issues/42 Tested: Compiled on Ubuntu and Mac platforms with C++20 using clang and gcc. PiperOrigin-RevId: 712293981 --- implementation/id.h | 14 ++++---- implementation/local_array.h | 6 ++-- implementation/method_selection.h | 11 +++--- implementation/object_ref.h | 25 +++++++------ implementation/proxy_definitions.h | 4 +-- implementation/signature_method_test.cc | 2 +- implementation/static_ref.h | 46 +++++++++++++----------- metaprogramming/invocable_map.h | 37 +++++++++---------- metaprogramming/invocable_map_20.h | 12 +++---- metaprogramming/invocable_map_20_test.cc | 12 ++++--- metaprogramming/invocable_map_test.cc | 26 ++++++++++---- metaprogramming/queryable_map.h | 45 +++++++++++------------ metaprogramming/queryable_map_20.h | 12 +++---- metaprogramming/queryable_map_20_test.cc | 12 ++++--- metaprogramming/queryable_map_test.cc | 16 +++++++-- 15 files changed, 155 insertions(+), 125 deletions(-) diff --git a/implementation/id.h b/implementation/id.h index 22d8b8cd..d1688551 100644 --- a/implementation/id.h +++ b/implementation/id.h @@ -36,10 +36,10 @@ template struct Id { - using JniT = JniT_; + using _JniT = JniT_; static constexpr IdType kIdType = kIdType_; - static constexpr auto Class() { return JniT::GetClass(); } + static constexpr auto Class() { return _JniT::GetClass(); } static constexpr std::size_t kIdx = idx; static constexpr std::size_t kSecondaryIdx = secondary_idx; @@ -58,10 +58,10 @@ struct Id { template using ChangeIdType = - Id; + Id<_JniT, new_id_type, idx, secondary_idx, tertiary_idx, ancestry_idx>; template - using ChangeIdx = Id; @@ -148,7 +148,7 @@ struct Id { } } - using ParentIdT = Id; static constexpr auto Val() { @@ -199,7 +199,7 @@ struct Id { } else if constexpr (kIdType == IdType::STATIC_OVERLOAD_SET) { return Val().name_; } else if constexpr (kIdType == IdType::STATIC_OVERLOAD) { - return Id::Name(); } else if constexpr (kIdType == IdType::STATIC_FIELD) { return std::get(Class().static_.fields_).name_; @@ -208,7 +208,7 @@ struct Id { } else if constexpr (kIdType == IdType::OVERLOAD_SET) { return Val().name_; } else if constexpr (kIdType == IdType::OVERLOAD) { - return Id::Name(); } else if constexpr (kIdType == IdType::FIELD) { return std::get(Class().fields_).name_; diff --git a/implementation/local_array.h b/implementation/local_array.h index 5a291bfa..b6355d29 100644 --- a/implementation/local_array.h +++ b/implementation/local_array.h @@ -56,7 +56,7 @@ class LocalArray using RawValT = std::conditional_t, std::decay_t, SpanType>; - using JniT_ = JniT; + using _JniT = JniT; using Base = ArrayRef>; @@ -68,7 +68,7 @@ class LocalArray LocalArray(std::size_t size, RefTag arr) : Base(AdoptLocal{}, JniArrayHelper::NewArray( size, - ClassRef_t::GetAndMaybeLoadClassRef( + ClassRef_t<_JniT>::GetAndMaybeLoadClassRef( static_cast(arr)), arr)) {} @@ -103,7 +103,7 @@ class LocalArray const ObjectContainer& local_object) : Base(JniArrayHelper::NewArray( size, - ClassRef_t::GetAndMaybeLoadClassRef( + ClassRef_t<_JniT>::GetAndMaybeLoadClassRef( static_cast(local_object)), static_cast(local_object))) {} diff --git a/implementation/method_selection.h b/implementation/method_selection.h index 03157c56..976f474e 100644 --- a/implementation/method_selection.h +++ b/implementation/method_selection.h @@ -87,12 +87,12 @@ template struct MethodSelection { using IdT = IdT_; - using JniT = typename IdT::JniT; + using _JniT = typename IdT::_JniT; template struct Helper { using type = metaprogramming::Val_t, + Id<_JniT, kIDType, IdT::kIdx, I, kNoIdx, 0>, kReturnIDType>::template OverloadIdxIfViable()>; }; @@ -103,7 +103,8 @@ struct MethodSelection { template using FindOverloadSelection = OverloadSelection< - Id, kNoIdx, 0>, kReturnIDType>; + Id<_JniT, kIDType, IdT::kIdx, kIdxForTs, kNoIdx, 0>, + kReturnIDType>; template static constexpr bool ArgSetViable() { @@ -116,8 +117,8 @@ struct OverloadSelector { using OverloadSelectionForArgs = typename MethodSelection< IdT, kIDType, kReturnIDType>::template FindOverloadSelection; - using OverloadRef = - OverloadRef, kReturnIDType>; diff --git a/implementation/object_ref.h b/implementation/object_ref.h index 420ad6f9..2685d752 100644 --- a/implementation/object_ref.h +++ b/implementation/object_ref.h @@ -53,14 +53,17 @@ class ObjectRef // C++17 augmentations. : public metaprogramming::InvocableMap< ObjectRef, JniT::stripped_class_v, typename JniT::ClassT, - &JniT::ClassT::methods_>, + decltype(&JniT::ClassT::methods_), &JniT::ClassT::methods_>, public metaprogramming::QueryableMap_t< - ObjectRef, JniT::stripped_class_v, &JniT::ClassT::fields_>, + ObjectRef, JniT::stripped_class_v, + decltype(&JniT::ClassT::fields_), &JniT::ClassT::fields_>, // C++ 20 augmentations. - public metaprogramming::InvocableMap20_t< - ObjectRef, JniT::stripped_class_v, &JniT::ClassT::methods_>, - public metaprogramming::QueryableMap20_t< - ObjectRef, JniT::stripped_class_v, &JniT::ClassT::fields_>, + public metaprogramming::InvocableMap20< + ObjectRef, JniT::stripped_class_v, ObjectRef, + decltype(&JniT::ClassT::methods_), &JniT::ClassT::methods_>, + public metaprogramming::QueryableMap20< + ObjectRef, JniT::stripped_class_v, ObjectRef, + decltype(&JniT::ClassT::fields_), &JniT::ClassT::fields_>, public RefBase { protected: static_assert( @@ -109,7 +112,7 @@ class ObjectRef static_assert(MethodSelectionForArgs::kIsValidArgSet, "JNI Error: Invalid argument set."); - return MethodSelectionForArgs::OverloadRef::Invoke( + return MethodSelectionForArgs::_OverloadRef::Invoke( GetJClass(), RefBaseT::object_ref_, std::forward(args)...); } @@ -139,7 +142,7 @@ class ObjectRef static_assert(MethodSelectionForArgs::kIsValidArgSet, "JNI Error: Invalid argument set."); - return MethodSelectionForArgs::OverloadRef::Invoke( + return MethodSelectionForArgs::_OverloadRef::Invoke( GetJClass(), RefBaseT::object_ref_, std::forward(args)...); } @@ -187,7 +190,7 @@ class ConstructorValidator : public ObjectRef { int>::type = 0> ConstructorValidator(Args&&... args) : Base(static_cast( - Permutation_t::OverloadRef::Invoke( + Permutation_t::_OverloadRef::Invoke( Base::GetJClass(), Base::object_ref_, std::forward(args)...) .Release())) { @@ -196,8 +199,8 @@ class ConstructorValidator : public ObjectRef { } ConstructorValidator() - : Base(Permutation_t<>::OverloadRef::Invoke(Base::GetJClass(), - Base::object_ref_) + : Base(Permutation_t<>::_OverloadRef::Invoke(Base::GetJClass(), + Base::object_ref_) .Release()) {} }; diff --git a/implementation/proxy_definitions.h b/implementation/proxy_definitions.h index cd81c70b..9a5b0a1a 100644 --- a/implementation/proxy_definitions.h +++ b/implementation/proxy_definitions.h @@ -160,7 +160,7 @@ struct Proxy struct Helper { static constexpr auto kClass{Id::Val()}; - static constexpr auto kClassLoader{Id::JniT::GetClassLoader()}; + static constexpr auto kClassLoader{Id::_JniT::GetClassLoader()}; // TODO(b/174272629): Class loaders should also be enforced. using type = LocalObject; @@ -200,7 +200,7 @@ struct Proxy struct Helper { static constexpr auto kClass{Id::Val()}; - static constexpr auto kClassLoader{Id::JniT::GetClassLoader()}; + static constexpr auto kClassLoader{Id::_JniT::GetClassLoader()}; // TODO(b/174272629): Class loaders should also be enforced. using type = LocalObject; diff --git a/implementation/signature_method_test.cc b/implementation/signature_method_test.cc index f23f383d..c51164e5 100644 --- a/implementation/signature_method_test.cc +++ b/implementation/signature_method_test.cc @@ -81,7 +81,7 @@ static constexpr auto Sig_v = //////////////////////////////////////////////////////////////////////////////// using kSelf1 = Id; using JniSelfT = - JniTSelector::JniT_, -1, 0>; + JniTSelector::_JniT, -1, 0>; using StaticSelectorInfoSelf = SelectorStaticInfo; static_assert(std::string_view{"LkClass1;"} == diff --git a/implementation/static_ref.h b/implementation/static_ref.h index 3aa22f82..0b78ec3f 100644 --- a/implementation/static_ref.h +++ b/implementation/static_ref.h @@ -42,22 +42,28 @@ namespace jni { template struct StaticRefHelper { - using JniT = JniT; + using _JniT = JniT; // C++17 augmentations. - using MethodMapT = metaprogramming::InvocableMap; - using FieldMapT = metaprogramming::QueryableMap_t; + using MethodMapT = metaprogramming::InvocableMap< + CrtpBase_, _JniT::static_v, typename _JniT::StaticT, + decltype(&_JniT::StaticT::methods_), &_JniT::StaticT::methods_>; + using FieldMapT = + metaprogramming::QueryableMap_t; // C++ 20 augmentations. - using MethodMap20T = - metaprogramming::InvocableMap20_t; - using FieldMap20T = - metaprogramming::QueryableMap20_t; + using MethodMap20T = metaprogramming::InvocableMap20< + CrtpBase_, _JniT::static_v, + StaticRefHelper, + decltype(&_JniT::StaticT::methods_), &_JniT::StaticT::methods_>; + + using FieldMap20T = metaprogramming::QueryableMap20< + CrtpBase_, _JniT::static_v, + StaticRefHelper, + decltype(&_JniT::StaticT::fields_), &_JniT::StaticT::fields_>; }; // C++17 augmentations. @@ -100,10 +106,10 @@ struct StaticRef class_v_, class_loader_v_, jvm_v_>, StaticRefHelperFieldMap20_t, class_v_, class_loader_v_, jvm_v_> { - using JniT = JniT; + using _JniT = JniT; jclass GetJClass() const { - return ClassRef_t::GetAndMaybeLoadClassRef(nullptr); + return ClassRef_t<_JniT>::GetAndMaybeLoadClassRef(nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -114,7 +120,7 @@ struct StaticRef #if __clang__ template auto InvocableMapCall(const char* key, Args&&... args) const { - using IdT = Id; + using IdT = Id<_JniT, IdType::STATIC_OVERLOAD_SET, I, kNoIdx, kNoIdx, 0>; using MethodSelectionForArgs = OverloadSelector; @@ -122,13 +128,13 @@ struct StaticRef static_assert(MethodSelectionForArgs::kIsValidArgSet, "JNI Error: Invalid argument set."); - return MethodSelectionForArgs::OverloadRef::Invoke( + return MethodSelectionForArgs::_OverloadRef::Invoke( GetJClass(), nullptr, std::forward(args)...); } template auto QueryableMapCall(const char* key) const { - return FieldRef{GetJClass(), nullptr}; + return FieldRef<_JniT, IdType::STATIC_FIELD, I>{GetJClass(), nullptr}; } #endif // __clang__ @@ -137,7 +143,7 @@ struct StaticRef template auto InvocableMap20Call(Args&&... args) const { - using IdT = Id; + using IdT = Id<_JniT, IdType::STATIC_OVERLOAD_SET, I, kNoIdx, kNoIdx, 0>; using MethodSelectionForArgs = OverloadSelector; @@ -145,14 +151,14 @@ struct StaticRef static_assert(MethodSelectionForArgs::kIsValidArgSet, "JNI Error: Invalid argument set."); - return MethodSelectionForArgs::OverloadRef::Invoke( + return MethodSelectionForArgs::_OverloadRef::Invoke( GetJClass(), nullptr, std::forward(args)...); } // Invoked through CRTP from QueryableMap20, C++20 only. template auto QueryableMap20Call() const { - return FieldRef{GetJClass(), nullptr}; + return FieldRef<_JniT, IdType::STATIC_FIELD, I>{GetJClass(), nullptr}; } #endif // __cplusplus >= 202002L }; diff --git a/metaprogramming/invocable_map.h b/metaprogramming/invocable_map.h index 40badde6..831bd682 100644 --- a/metaprogramming/invocable_map.h +++ b/metaprogramming/invocable_map.h @@ -25,10 +25,6 @@ namespace jni::metaprogramming { -template -class InvocableMap; - // This is an interface that can be inherited from to expose an operator(...). // It provides compile time string index lookup with no macros although it is // dependent on a clang extension. @@ -54,36 +50,38 @@ class InvocableMap; // the the const char cannot be propagated without losing its constexpr-ness, // and so the clang extension can no longer restrict function candidates. template ::* nameable_member> -using InvocableMap_t = - InvocableMap, nameable_member>; + typename TupContainerT, typename MemberT, MemberT nameable_member> +class InvocableMap; template class InvocableMapEntry; template class InvocableMapBase {}; template -class InvocableMapBase> : public InvocableMapEntry... { + MemberT, nameable_member, idxs>... { public: - using InvocableMapEntry:: operator()...; +#endif // __clang__ }; template class InvocableMapEntry { public: @@ -109,18 +107,15 @@ class InvocableMapEntry { .template InvocableMapCall(key, std::forward(args)...); } -#else - static_assert(false, - "This container requires clang for compile time strings."); -#endif +#endif // __clang__ }; //============================================================================== template + typename TupContainerT, typename MemberT, MemberT nameable_member> class InvocableMap : public InvocableMapBase< - CrtpBase, tup_container_v, TupContainerT, nameable_member, + CrtpBase, tup_container_v, TupContainerT, MemberT, nameable_member, std::make_index_sequence>>> {}; diff --git a/metaprogramming/invocable_map_20.h b/metaprogramming/invocable_map_20.h index 4162b87c..2e280f47 100644 --- a/metaprogramming/invocable_map_20.h +++ b/metaprogramming/invocable_map_20.h @@ -50,12 +50,16 @@ namespace jni::metaprogramming { // |tup_container_v| is a static instance of an object whose |nameable_member| // contains a public field called name_. It might seem strange not to // directly pass a const auto&, however, this prevents accessing subobjects. +// |TupContainerT| is the type of the container for the member. +// |MemberT| is the type of a *pointer to member* in the container, *not* the +// actual type of the member itself. +// |nameable_member| is pointer to member of the nameable type. // // The motivation for using inheritance as opposed to a simple member is that // the the const char cannot be propagated without losing its constexpr-ness, // and so the clang extension can no longer restrict function candidates. template + typename TupContainerT, typename MemberT, MemberT nameable_member> class InvocableMap20 { #if __cplusplus >= 202002L public: @@ -89,12 +93,6 @@ class InvocableMap20 { #endif // __cplusplus >= 202002L }; -template ::* nameable_member> -using InvocableMap20_t = - InvocableMap20, nameable_member>; - } // namespace jni::metaprogramming #endif // JNI_BIND_METAPROGRAMMING_INVOCABLE_MAP_20_H diff --git a/metaprogramming/invocable_map_20_test.cc b/metaprogramming/invocable_map_20_test.cc index c8eb7856..703c662d 100644 --- a/metaprogramming/invocable_map_20_test.cc +++ b/metaprogramming/invocable_map_20_test.cc @@ -24,7 +24,7 @@ #include "string_literal.h" #include -using jni::metaprogramming::InvocableMap20_t; +using jni::metaprogramming::InvocableMap20; using jni::metaprogramming::StringLiteral; struct Str { @@ -44,11 +44,13 @@ constexpr NameContainer name_container{ //////////////////////////////////////////////////////////////////////////////// class SampleClassNowExposingCallOperator1 - : public InvocableMap20_t { + : public InvocableMap20< + SampleClassNowExposingCallOperator1, name_container, NameContainer, + decltype(&NameContainer::container1_), &NameContainer::container1_> { protected: - friend InvocableMap20_t; + friend InvocableMap20; template auto InvocableMap20Call(Args&&... ts) { diff --git a/metaprogramming/invocable_map_test.cc b/metaprogramming/invocable_map_test.cc index 792bfaf1..afd6eeae 100644 --- a/metaprogramming/invocable_map_test.cc +++ b/metaprogramming/invocable_map_test.cc @@ -16,6 +16,7 @@ #include "invocable_map.h" +#include #include #include #include @@ -24,7 +25,7 @@ namespace { -using ::jni::metaprogramming::InvocableMap_t; +using ::jni::metaprogramming::InvocableMap; struct Str { const char* name_; @@ -43,11 +44,12 @@ constexpr NameContainer name_container{ //////////////////////////////////////////////////////////////////////////////// class SampleClassNowExposingCallOperator1 - : public InvocableMap_t { + : public InvocableMap { protected: template friend class jni::metaprogramming::InvocableMapEntry; @@ -70,6 +72,8 @@ class SampleClassNowExposingCallOperator1 } }; +#if __clang__ + TEST(InvocableMapTest1, HasCorrectTypesAndForwardsCalls) { SampleClassNowExposingCallOperator1 val; val("Foo", 1); @@ -80,13 +84,17 @@ TEST(InvocableMapTest1, HasCorrectTypesAndForwardsCalls) { // val("BazNar", 7, 8, 9); } +#endif // __clang__ + //////////////////////////////////////////////////////////////////////////////// class SampleClassNowExposingCallOperator2 - : public InvocableMap_t { + : public InvocableMap { public: template friend class jni::metaprogramming::InvocableMapEntry; @@ -109,6 +117,8 @@ class SampleClassNowExposingCallOperator2 } }; +#if __clang__ + TEST(InvocableMapTest2, HasCorrectTypesAndForwardsCalls) { SampleClassNowExposingCallOperator2 val; val("Fizz", 1); @@ -119,4 +129,6 @@ TEST(InvocableMapTest2, HasCorrectTypesAndForwardsCalls) { // val("BazNar", 7, 8, 9); } +#endif // __clang__ + } // namespace diff --git a/metaprogramming/queryable_map.h b/metaprogramming/queryable_map.h index 9e38446c..fc55a3dc 100644 --- a/metaprogramming/queryable_map.h +++ b/metaprogramming/queryable_map.h @@ -26,7 +26,7 @@ namespace jni::metaprogramming { template class QueryableMapBase {}; @@ -50,46 +50,50 @@ class QueryableMapBase {}; // the the const char cannot be propagated without losing its constexpr-ness, // and so the clang extension can no longer restrict function candidates. template + std::size_t container_size, typename TupContainerT, typename MemberT, + MemberT nameable_member> class QueryableMap - : public QueryableMapBase> {}; -template ::*nameable_member> -using QueryableMap_t = - QueryableMap>, - std::decay_t, nameable_member>; +template +using QueryableMap_t = QueryableMap< + CrtpBase, tup_container_v, + std::tuple_size_v< + std::decay_t>, + std::decay_t, MemberT, nameable_member>; template class QueryableMapEntry; template -class QueryableMapBase> : public QueryableMapEntry... { + MemberT, nameable_member, idxs>... { public: +#if __clang__ using QueryableMapEntry::operator[]...; + + MemberT, nameable_member, idxs>::operator[]...; using QueryableMapEntry::Contains...; + + MemberT, nameable_member, idxs>::Contains...; +#endif // __clang__ // Will select subclass specialisations if present. constexpr bool Contains(const char* key) { return false; } }; template class QueryableMapEntry { public: @@ -119,10 +123,7 @@ class QueryableMapEntry { ""))) { return true; } -#else - static_assert(false, - "This container requires clang for compile time strings."); -#endif +#endif // __clang__ }; } // namespace jni::metaprogramming diff --git a/metaprogramming/queryable_map_20.h b/metaprogramming/queryable_map_20.h index ddf16743..db862668 100644 --- a/metaprogramming/queryable_map_20.h +++ b/metaprogramming/queryable_map_20.h @@ -43,12 +43,16 @@ namespace jni::metaprogramming { // |tup_container_v| is a static instance of an object whose |nameable_member| // contains a public field called name_. It might seem strange not to // directly pass a const auto&, however, this prevents accessing subobjects. +// |TupContainerT| is the type of the container for the member. +// |MemberT| is the type of a *pointer to member* in the container, *not* the +// actual type of the member itself. +// |nameable_member| is pointer to member of the nameable type. // // The motivation for using inheritance as opposed to a simple member is that // the the const char cannot be propagated without losing its constexpr-ness, // and so the clang extension can no longer restrict function candidates. template + typename TupContainerT, typename MemberT, MemberT nameable_member> class QueryableMap20 { #if __cplusplus >= 202002L private: @@ -81,12 +85,6 @@ class QueryableMap20 { #endif // __cplusplus >= 202002L }; -template ::* nameable_member> -using QueryableMap20_t = - QueryableMap20, nameable_member>; - } // namespace jni::metaprogramming #endif // JNI_BIND_METAPROGRAMMING_QUERYABLE_MAP_20_H diff --git a/metaprogramming/queryable_map_20_test.cc b/metaprogramming/queryable_map_20_test.cc index 8a06e5b4..270b4c04 100644 --- a/metaprogramming/queryable_map_20_test.cc +++ b/metaprogramming/queryable_map_20_test.cc @@ -26,7 +26,7 @@ #if __cplusplus >= 202002L -using jni::metaprogramming::QueryableMap20_t; +using jni::metaprogramming::QueryableMap20; using jni::metaprogramming::StringLiteral; struct Str { @@ -46,11 +46,13 @@ constexpr NameContainer name_container{ //////////////////////////////////////////////////////////////////////////////// class SampleClassNowExposingCallOperator1 - : public QueryableMap20_t { + : public QueryableMap20< + SampleClassNowExposingCallOperator1, name_container, NameContainer, + decltype(&NameContainer::container1_), &NameContainer::container1_> { protected: - friend QueryableMap20_t; + friend QueryableMap20; template auto QueryableMap20Call() { diff --git a/metaprogramming/queryable_map_test.cc b/metaprogramming/queryable_map_test.cc index d943092a..b8a0845c 100644 --- a/metaprogramming/queryable_map_test.cc +++ b/metaprogramming/queryable_map_test.cc @@ -50,10 +50,11 @@ using ValuesTup = std::tuple; class SampleClassNowExposingCallOperator1 : public QueryableMap_t { protected: template friend class jni::metaprogramming::QueryableMapEntry; @@ -79,8 +80,10 @@ constexpr SomeIndexerStruct kSomeKey{"Foo"}; template void FuncThatTrampolinesStaticValue(SampleClassNowExposingCallOperator1& map) { +#if __clang__ map["Foo"]; map[val.key_]; +#endif // __clang__ } template @@ -88,6 +91,8 @@ struct InSet { using type = std::false_type; }; +#if __clang__ + TEST(QueryableMapTest1, HasCorrectTypesAndForwardsCalls) { SampleClassNowExposingCallOperator1 val; val["Foo"]; @@ -107,12 +112,15 @@ TEST(QueryableMapTest1, HasCorrectTypesAndForwardsCalls) { // val["BazNar"]; } +#endif // __clang__ + class SampleClassNowExposingCallOperator2 : public QueryableMap_t { protected: template friend class jni::metaprogramming::QueryableMapEntry; @@ -130,6 +138,8 @@ class SampleClassNowExposingCallOperator2 } }; +#if __clang__ + TEST(QueryableMapTest2, HasCorrectTypesAndForwardsCalls) { SampleClassNowExposingCallOperator2 val; val["Fizz"]; @@ -140,4 +150,6 @@ TEST(QueryableMapTest2, HasCorrectTypesAndForwardsCalls) { // val("BazNar", 7, 8, 9); } +#endif // __clang__ + } // namespace