diff --git a/JNI_BIND_VERSION.inc b/JNI_BIND_VERSION.inc index 7dea76ed..9084fa2f 100644 --- a/JNI_BIND_VERSION.inc +++ b/JNI_BIND_VERSION.inc @@ -1 +1 @@ -1.0.1 +1.1.0 diff --git a/MODULE.bazel b/MODULE.bazel index ef714099..a7c9e7ac 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "jni_bind", - version = "1.0.0", + version = "1.1.0", compatibility_level = 1, ) diff --git a/README.md b/README.md index c7f710fb..c2987463 100644 --- a/README.md +++ b/README.md @@ -90,8 +90,8 @@ If you're already using Bazel add the following to your WORKSPACE: ```starlark http_archive( name = "jni-bind", - urls = ["https://github.com/google/jni-bind/archive/refs/tags/Release-1.0.1-beta.zip"], - strip_prefix = "jni-bind-Release-1.0.1-beta", + urls = ["https://github.com/google/jni-bind/archive/refs/tags/Release-1.1.0-beta.zip"], + strip_prefix = "jni-bind-Release-1.1.0-beta", ) ``` diff --git a/jni_bind_release.h b/jni_bind_release.h index 11906ae3..da0d9457 100644 --- a/jni_bind_release.h +++ b/jni_bind_release.h @@ -117,7 +117,6 @@ using ExtractTupleFromType_t = } // namespace jni::metaprogramming - namespace jni::metaprogramming { // Metafunction to forward all args in a tuple on to a metafunction. @@ -136,7 +135,6 @@ static constexpr auto Unwrap_v = Unwrap_t::value; } // namespace jni::metaprogramming - #include #include @@ -169,7 +167,6 @@ using TypeOfNthTupleElement_t = Unwrap_t, TupType>; } // namespace jni::metaprogramming - #include namespace jni::metaprogramming { @@ -199,6 +196,31 @@ using PerElement_t = typename PerElement::template type; } // namespace jni::metaprogramming +#include + +namespace jni::metaprogramming { + +// Takes two tuples and collapses them into a single tuple. +struct Combine { + template + struct CombineHelper { + static_assert(std::is_same_v && std::is_same_v, + "Combine requires tuples."); + }; + + template + struct CombineHelper, std::tuple> { + using type = std::tuple; + }; + + template + using type = typename CombineHelper::type; +}; + +template +using Combine_t = typename Combine::template type; + +} // namespace jni::metaprogramming #include #include @@ -224,6 +246,58 @@ struct Same { namespace jni::metaprogramming { +// Metafunction for a left fold reduction of a sequence of types with an +// operation. Single element sequences return the input type with no use of +// Operation. +template +struct Reduce { + template + struct SequenceGenerator {}; + + template + using Operation_t = typename Operation::template type; + + template + using SequenceGenerator_t = typename SequenceGenerator::type; + + // Used for single element sequence. + template + struct SequenceGenerator { + using type = T1; + }; + + // Terminal element in sequence. + template + struct SequenceGenerator { + using type = Operation_t; + }; + + template + struct SequenceGenerator { + using type = SequenceGenerator_t, Ts...>; + }; + + template + using type = typename SequenceGenerator::type; +}; + +template +using Reduce_t = typename Reduce::template type; + +template +using ReduceAsPack_t = TupleUnroller_t, TupleOfTs>; + +template +static constexpr auto ReduceAsPack_v = + TupleUnroller_t, TupleOfTs>::val; + +} // namespace jni::metaprogramming + +#include +#include + +namespace jni::metaprogramming { + // "Invokes" a metafunction (i.e. a type alias for Func::type). // Handles both variadic or non-variadic args for a consistent syntax. template @@ -268,33 +342,6 @@ using InvokePerTupArgAsPack_t = } // namespace jni::metaprogramming -#include - -namespace jni::metaprogramming { - -// Takes two tuples and collapses them into a single tuple. -struct Combine { - template - struct CombineHelper { - static_assert(std::is_same_v && std::is_same_v, - "Combine requires tuples."); - }; - - template - struct CombineHelper, std::tuple> { - using type = std::tuple; - }; - - template - using type = typename CombineHelper::type; -}; - -template -using Combine_t = typename Combine::template type; - -} // namespace jni::metaprogramming - - #include #include @@ -321,59 +368,36 @@ static constexpr bool Any_Tup_v = TupleUnroller_t, Ts>::value; } // namespace jni::metaprogramming +namespace jni { -#include -#include - -namespace jni::metaprogramming { - -// Metafunction for a left fold reduction of a sequence of types with an -// operation. Single element sequences return the input type with no use of -// Operation. -template -struct Reduce { - template - struct SequenceGenerator {}; - - template - using Operation_t = typename Operation::template type; - - template - using SequenceGenerator_t = typename SequenceGenerator::type; - - // Used for single element sequence. - template - struct SequenceGenerator { - using type = T1; - }; - - // Terminal element in sequence. - template - struct SequenceGenerator { - using type = Operation_t; - }; +// Single type that be used as a value when expressing void. +struct Void { + using Raw = void; +}; - template - struct SequenceGenerator { - using type = SequenceGenerator_t, Ts...>; - }; +template +struct VoidIfVoid { + using type = T; +}; - template - using type = typename SequenceGenerator::type; +template <> +struct VoidIfVoid { + using type = void; }; -template -using Reduce_t = typename Reduce::template type; +template +using VoidIfVoid_t = typename VoidIfVoid::type; -template -using ReduceAsPack_t = TupleUnroller_t, TupleOfTs>; +} // namespace jni -template -static constexpr auto ReduceAsPack_v = - TupleUnroller_t, TupleOfTs>::val; +namespace jni { -} // namespace jni::metaprogramming +struct Object { + const char* name_; + constexpr explicit Object(const char* name) : name_(name) {} +}; +} // namespace jni #include #include @@ -400,6 +424,126 @@ constexpr bool ContainsValue(const SoughtType& sought_value, Ts&&... ts) { } // namespace jni::metaprogramming +#include + +namespace jni::metaprogramming { + +// Metafunction to generate a concatenation of variadic args. +struct Concatenate { + template + using type = std::tuple; +}; + +template +using Concatenate_t = typename Concatenate::template type; + +// Metafunction to concatenate tuples into a single tuple. +template +struct ConcatenateTup { + static_assert(sizeof...(Ts) != 0, "ConcatenateTup must only take tuples."); +}; + +template +struct ConcatenateTup> { + using type = std::tuple; +}; + +template +using ConcatenateTup_t = Reduce_t; + +} // namespace jni::metaprogramming + +#include + +namespace jni { + +struct ReturnBase {}; + +template +struct Return : ReturnBase { + const Raw_ raw_ = {}; + + using Raw = Raw_; + + constexpr Return() = default; + + template + constexpr explicit Return(Raw raw) : raw_(raw) {} +}; + +template <> +struct Return : ReturnBase { + using Raw = void; + const Void raw_{}; + + constexpr Return() = default; +}; + +Return() -> Return; + +template +Return(Raw) -> Return; + +template +using Raw_t = typename T::Raw; + +} // namespace jni + +#include +#include +#include +#include + +namespace jni { + +struct ParamsBase {}; + +// Represents a sequence of parameters for a method in a compile time +// definition. +// +// These may be in their native type (e.g. int, float, etc) or they may have +// some minimal type wrapping such as Object (see JniTProxy). +template +struct Params : ParamsBase { + public: + using ParamsRawTup = std::tuple; + + const std::tuple values_ = {}; + + // Zero args constructor. + template ::type = 0> + constexpr explicit Params() {} + + // CTAD constructor, fully defined args (e.g. Params{class_value}). + template < + std::size_t N = sizeof...(ValuesRaw_), typename... Args, + typename std::enable_if<(N > 0 && sizeof...(Args) == N), int>::type = 0> + constexpr explicit Params(Args... args) : values_(args...) {} + + // Constructor for explicit templatizing, no args (e.g. Params{}). + template < + std::size_t N = sizeof...(ValuesRaw_), typename... Args, + typename std::enable_if<(N > 0 && sizeof...(Args) == 0), int>::type = 0> + constexpr explicit Params() {} +}; + +template +Params(Ts...) -> Params; + +template +constexpr bool operator==(const Params& lhs, + const Params& rhs) { + return lhs.values_ == rhs.values_; +} + +//============================================================================== + +template +using ParamsRawTup_t = typename T::ParamsRawTup; + +} // namespace jni + #include #include #include @@ -443,35 +587,6 @@ using LambdaStringToType = decltype(LambdaToStr(std::declval())); } // namespace jni::metaprogramming -#include - -namespace jni::metaprogramming { - -// Metafunction to generate a concatenation of variadic args. -struct Concatenate { - template - using type = std::tuple; -}; - -template -using Concatenate_t = typename Concatenate::template type; - -// Metafunction to concatenate tuples into a single tuple. -template -struct ConcatenateTup { - static_assert(sizeof...(Ts) != 0, "ConcatenateTup must only take tuples."); -}; - -template -struct ConcatenateTup> { - using type = std::tuple; -}; - -template -using ConcatenateTup_t = Reduce_t; - -} // namespace jni::metaprogramming - #include #include @@ -528,6 +643,54 @@ inline std::string Colorize(std::string_view colour, std::string_view str, } // namespace jni::metaprogramming +#include +#include + +namespace jni::metaprogramming { + +// Returns all elements derived from DesiredBase. +// +// Note, if no values found, this will be std::tuple<>. If you'd like a default +// value use BaseFilterWithDefault. +template > +struct BaseFilter { + static_assert(std::is_same_v>); + using type = std::tuple<>; +}; + +template +using BaseFilter_t = + typename BaseFilter>::type; + +template +struct BaseFilter, void>, + std::tuple> { + using type = + ConcatenateTup_t, BaseFilter_t>; +}; + +template +struct BaseFilter, void>, + std::tuple> { + using type = BaseFilter_t; +}; + +//============================================================================== +template +using DefaultIfEmpty_Tup = + std::conditional_t>, + DefaultValue, PostFilterValue>; + +template +using BaseFilterWithDefault_t = + DefaultIfEmpty_Tup, + std::tuple>; + +} // namespace jni::metaprogramming + #include namespace jni::metaprogramming { @@ -558,7 +721,6 @@ constexpr bool AllUniqueValues(const T1&& t1, const Ts&&... ts) { } // namespace jni::metaprogramming - namespace jni { // Convenience struct for returning results from pinning array. @@ -626,35 +788,116 @@ struct ArgStringify { } // namespace jni +#include +#include + namespace jni { -// Single type that be used as a value when expressing void. -struct Void { - using Raw = void; -}; +struct OverloadBase {}; +struct MethodBase {}; -template -struct VoidIfVoid { - using type = T; +// Represents a single overload of a given method. +template +struct Overload : OverloadBase { + const ReturnT_ return_; + const Params_ params_; + + // `Return`, no `Params`. + constexpr Overload(ReturnT_ return_type) + : return_(return_type), params_(Params{}) {} + + // `Return` and `Params`. + constexpr Overload(ReturnT_ return_type, Params_ params) + : return_(return_type), params_(params) {} }; -template <> -struct VoidIfVoid { - using type = void; +template +Overload(ReturnT_) -> Overload>; + +template +Overload(ReturnT_, Params_) -> Overload; + +template +struct Method {}; + +template +struct Method, std::tuple> + : public MethodBase { + public: + const char* name_; + const std::tuple...> invocations_; + + // `Return`, no `Params`. + template , int> = 0> + constexpr Method(const char* name, ReturnT_ return_type) + : name_(name), invocations_(Overload{return_type}) {} + + // `Return` and `Params`. + template , int> = 0> + constexpr Method(const char* name, ReturnT_ return_type, ParamsT_ params) + : name_(name), invocations_(Overload{return_type, params}) {} + + // `Overload` Set. + constexpr Method(const char* name, Overload... invocations) + : name_(name), invocations_(invocations...) {} }; -template -using VoidIfVoid_t = typename VoidIfVoid::type; +// CTAD for Non-overloaded form, no Params. +template >> +Method(const char*, + ReturnT) -> Method, std::tuple>>; + +// CTAD for Non-overloaded form. +template < + typename ReturnT, typename ParamsT, + typename = std::enable_if_t && + !std::is_base_of_v>> +Method(const char*, ReturnT, + ParamsT) -> Method, std::tuple>; + +// CTAD for Overloaded form. +template +Method(const char*, Overload...) + -> Method, std::tuple>; + +template +constexpr bool operator==(const Method& lhs, + const Method& rhs) { + return std::string_view(lhs.name_) == std::string_view(rhs.name_); +} } // namespace jni +#include + namespace jni { -struct Object { +struct FieldBase {}; + +template +struct Field : public FieldBase { + public: + using Raw = Raw_; + const char* name_; - constexpr explicit Object(const char* name) : name_(name) {} + + const Raw_ raw_ = {}; + + constexpr Field(const char* name) : name_(name) {} + constexpr Field(const char* name, Raw_ value_raw) + : name_(name), raw_(value_raw) {} }; +template +Field(const char*, Raw_) -> Field; + +template +using Raw_t = typename T::Raw; + } // namespace jni using jclass = jclass; @@ -746,7 +989,6 @@ static constexpr std::size_t FindIdxOfValInTup_idx = } // namespace jni::metaprogramming - #include namespace jni::metaprogramming { @@ -1125,98 +1367,36 @@ struct FakeImpl { } // namespace jni -#include - -namespace jni { - -struct ReturnBase {}; - -template -struct Return : ReturnBase { - const Raw_ raw_ = {}; - - using Raw = Raw_; - - constexpr Return() = default; - - template - constexpr explicit Return(Raw raw) : raw_(raw) {} -}; - -template <> -struct Return : ReturnBase { - using Raw = void; - const Void raw_{}; - - constexpr Return() = default; -}; - -Return() -> Return; - -template -Return(Raw) -> Return; - -template -using Raw_t = typename T::Raw; - -} // namespace jni - -#include #include #include -#include namespace jni { -struct ParamsBase {}; - -// Represents a sequence of parameters for a method in a compile time -// definition. -// -// These may be in their native type (e.g. int, float, etc) or they may have -// some minimal type wrapping such as Object (see JniTProxy). -template -struct Params : ParamsBase { - public: - using ParamsRawTup = std::tuple; - - const std::tuple values_ = {}; +class StaticBase {}; - // Zero args constructor. - template ::type = 0> - constexpr explicit Params() {} +template +class Static; - // CTAD constructor, fully defined args (e.g. Params{class_value}). - template < - std::size_t N = sizeof...(ValuesRaw_), typename... Args, - typename std::enable_if<(N > 0 && sizeof...(Args) == N), int>::type = 0> - constexpr explicit Params(Args... args) : values_(args...) {} +template +class Static, std::tuple> + : public StaticBase { + public: + const std::tuple methods_; + const std::tuple fields_; - // Constructor for explicit templatizing, no args (e.g. Params{}). - template < - std::size_t N = sizeof...(ValuesRaw_), typename... Args, - typename std::enable_if<(N > 0 && sizeof...(Args) == 0), int>::type = 0> - constexpr explicit Params() {} + constexpr Static(Methods_... methods, Fields_... fields) + : methods_(methods...), fields_(fields...) {} }; -template -Params(Ts...) -> Params; - -template -constexpr bool operator==(const Params& lhs, - const Params& rhs) { - return lhs.values_ == rhs.values_; -} - -//============================================================================== +Static() -> Static, std::tuple<>>; -template -using ParamsRawTup_t = typename T::ParamsRawTup; +template +Static(Params...) + -> Static, + metaprogramming::BaseFilter_t>; } // namespace jni - #include namespace jni::metaprogramming { @@ -1271,54 +1451,6 @@ using TypeToTypeMapFromKeyValuesTup_t = } // namespace jni::metaprogramming -#include -#include - -namespace jni::metaprogramming { - -// Returns all elements derived from DesiredBase. -// -// Note, if no values found, this will be std::tuple<>. If you'd like a default -// value use BaseFilterWithDefault. -template > -struct BaseFilter { - static_assert(std::is_same_v>); - using type = std::tuple<>; -}; - -template -using BaseFilter_t = - typename BaseFilter>::type; - -template -struct BaseFilter, void>, - std::tuple> { - using type = - ConcatenateTup_t, BaseFilter_t>; -}; - -template -struct BaseFilter, void>, - std::tuple> { - using type = BaseFilter_t; -}; - -//============================================================================== -template -using DefaultIfEmpty_Tup = - std::conditional_t>, - DefaultValue, PostFilterValue>; - -template -using BaseFilterWithDefault_t = - DefaultIfEmpty_Tup, - std::tuple>; - -} // namespace jni::metaprogramming - #include namespace jni { @@ -1436,192 +1568,103 @@ jfieldID JniHelper::GetFieldID(jclass clazz, const char* name, #endif // DRY_RUN } -jfieldID JniHelper::GetStaticFieldID(jclass clazz, const char* name, - const char* signature) { - Trace(metaprogramming::LambdaToStr(STR("GetStaticFieldID")), clazz, name, - signature); - -#ifdef DRY_RUN - return Fake(); -#else - return jni::JniEnv::GetEnv()->GetStaticFieldID(clazz, name, signature); -#endif // DRY_RUN -} - -inline const char* JniHelper::GetStringUTFChars(jstring str) { - Trace(metaprogramming::LambdaToStr(STR("GetStringUTFChars")), str); - -#ifdef DRY_RUN - return "DEAD_BEEF"; -#else - // If is_copy is an address of bool it will be set to true or false if a copy - // is made. That said, this seems to be of no consequence, as the API still - // requires you to release the string at the end. There's no discernible - // reason you would ever be able to meaningfully act differently based on - // this parameter of the API (except to do the wrong thing). - return jni::JniEnv::GetEnv()->GetStringUTFChars(str, /*isCopy=*/nullptr); -#endif // DRY_RUN -} - -inline void JniHelper::ReleaseStringUTFChars(jstring str, const char* chars) { - Trace(metaprogramming::LambdaToStr(STR("ReleaseStringUTFChars")), str, chars); - -#ifdef DRY_RUN -#else - jni::JniEnv::GetEnv()->ReleaseStringUTFChars(str, chars); -#endif // DRY_RUN -} - -} // namespace jni - -#include -#include - -namespace jni { - -struct OverloadBase {}; -struct MethodBase {}; - -// Represents a single overload of a given method. -template -struct Overload : OverloadBase { - const ReturnT_ return_; - const Params_ params_; - - // `Return`, no `Params`. - constexpr Overload(ReturnT_ return_type) - : return_(return_type), params_(Params{}) {} - - // `Return` and `Params`. - constexpr Overload(ReturnT_ return_type, Params_ params) - : return_(return_type), params_(params) {} -}; - -template -Overload(ReturnT_) -> Overload>; - -template -Overload(ReturnT_, Params_) -> Overload; - -template -struct Method {}; - -template -struct Method, std::tuple> - : public MethodBase { - public: - const char* name_; - const std::tuple...> invocations_; - - // `Return`, no `Params`. - template , int> = 0> - constexpr Method(const char* name, ReturnT_ return_type) - : name_(name), invocations_(Overload{return_type}) {} - - // `Return` and `Params`. - template , int> = 0> - constexpr Method(const char* name, ReturnT_ return_type, ParamsT_ params) - : name_(name), invocations_(Overload{return_type, params}) {} +jfieldID JniHelper::GetStaticFieldID(jclass clazz, const char* name, + const char* signature) { + Trace(metaprogramming::LambdaToStr(STR("GetStaticFieldID")), clazz, name, + signature); - // `Overload` Set. - constexpr Method(const char* name, Overload... invocations) - : name_(name), invocations_(invocations...) {} -}; +#ifdef DRY_RUN + return Fake(); +#else + return jni::JniEnv::GetEnv()->GetStaticFieldID(clazz, name, signature); +#endif // DRY_RUN +} -// CTAD for Non-overloaded form, no Params. -template >> -Method(const char*, - ReturnT) -> Method, std::tuple>>; +inline const char* JniHelper::GetStringUTFChars(jstring str) { + Trace(metaprogramming::LambdaToStr(STR("GetStringUTFChars")), str); -// CTAD for Non-overloaded form. -template < - typename ReturnT, typename ParamsT, - typename = std::enable_if_t && - !std::is_base_of_v>> -Method(const char*, ReturnT, ParamsT) - -> Method, std::tuple>; +#ifdef DRY_RUN + return "DEAD_BEEF"; +#else + // If is_copy is an address of bool it will be set to true or false if a copy + // is made. That said, this seems to be of no consequence, as the API still + // requires you to release the string at the end. There's no discernible + // reason you would ever be able to meaningfully act differently based on + // this parameter of the API (except to do the wrong thing). + return jni::JniEnv::GetEnv()->GetStringUTFChars(str, /*isCopy=*/nullptr); +#endif // DRY_RUN +} -// CTAD for Overloaded form. -template -Method(const char*, Overload...) - -> Method, std::tuple>; +inline void JniHelper::ReleaseStringUTFChars(jstring str, const char* chars) { + Trace(metaprogramming::LambdaToStr(STR("ReleaseStringUTFChars")), str, chars); -template -constexpr bool operator==(const Method& lhs, - const Method& rhs) { - return std::string_view(lhs.name_) == std::string_view(rhs.name_); +#ifdef DRY_RUN +#else + jni::JniEnv::GetEnv()->ReleaseStringUTFChars(str, chars); +#endif // DRY_RUN } } // namespace jni -#include +#include namespace jni { -struct FieldBase {}; - -template -struct Field : public FieldBase { - public: - using Raw = Raw_; +struct ExtendsBase {}; - const char* name_; +struct RootObject { + constexpr RootObject() = default; +}; - const Raw_ raw_ = {}; +static constexpr RootObject kObject{}; - constexpr Field(const char* name) : name_(name) {} - constexpr Field(const char* name, Raw_ value_raw) - : name_(name), raw_(value_raw) {} -}; +static constexpr struct NoClass { + constexpr NoClass() {} -template -Field(const char*, Raw_) -> Field; + const char* name_ = "__JNI_BIND__NO_CLASS__"; + const RootObject parent_; + const Static, std::tuple<>> static_{}; + const std::tuple<> methods_{}; + const std::tuple<> fields_{}; -template -using Raw_t = typename T::Raw; + constexpr bool operator==(const NoClass&) const { return true; } + constexpr bool operator!=(const NoClass&) const { return true; } +} kNoClassSpecified; } // namespace jni -#include -#include - namespace jni { -class StaticBase {}; - -template -class Static; - -template -class Static, std::tuple> - : public StaticBase { - public: - const std::tuple methods_; - const std::tuple fields_; +// Metafunction for helping strip the type for input Extends params. +struct ExtendsStrip { + template + struct Helper { + // Input is in a tuple of 1 element. + using StripOuterTuple = metaprogramming::TypeOfNthTupleElement_t<0, T>; + // Steal the outer Extends parameter pack into a tuple. + // e.g. Extends => std::tuple. + using ExtendsToTuple = + metaprogramming::ExtractTupleFromType_t; + // Extracts the single element. + using type = metaprogramming::TypeOfNthTupleElement_t<0, ExtendsToTuple>; + }; - constexpr Static(Methods_... methods, Fields_... fields) - : methods_(methods...), fields_(fields...) {} + template + using type = typename Helper::type; }; -Static()->Static, std::tuple<>>; - -template -Static(Params...) - -> Static, - metaprogramming::BaseFilter_t>; - -} // namespace jni +template +using ExtendsStrip_t = typename ExtendsStrip::template type; -#include -#include +template +struct Extends : public ExtendsBase { + constexpr Extends(ParentT parent) : parent_(parent) {} -namespace jni { + const ParentT parent_; +}; -static constexpr std::size_t kNoIdx{std::numeric_limits::max()}; +template +Extends(T) -> Extends; } // namespace jni @@ -1814,41 +1857,70 @@ constexpr std::size_t ModifiedMax( } // namespace jni::metaprogramming +namespace jni { + +// Tag to indicate you are referring to the enclosing class. +// Useful for builder patterns where the decorated object returned is identical. +struct Self {}; + +} // namespace jni + +#include #include -#include -#include -#include namespace jni { -static constexpr struct NoClass { - const char* name_ = "__JNI_BIND__NO_CLASS__"; - const Static, std::tuple<>> static_{}; - const std::tuple<> methods_{}; - const std::tuple<> fields_{}; +static constexpr std::size_t kNoIdx{std::numeric_limits::max()}; - constexpr bool operator==(const NoClass&) const { return true; } - constexpr bool operator!=(const NoClass&) const { return true; } -} kNoClassSpecified; +} // namespace jni + +#include +#include -template +namespace jni { + +template struct Class {}; -template -struct Class, +template +struct Class, std::tuple, std::tuple>>, std::tuple, std::tuple> : public Object { public: + // Filtering outputs a std::tuple, the caller will use just T in ctor. + using ExtendsArgT = metaprogramming::TypeOfNthTupleElement_t<0, Extends_>; + + // The type of the parent class (default `RootObject`). + const ExtendsStrip_t parent_; + const std::tuple constructors_; const Static, std::tuple> static_; const std::tuple methods_; const std::tuple fields_; - // Ctors + static. + //////////////////////////////////////////////////////////////////////////////// + // Constructors can pass any correctly ordered permutation of: + // - Extends (parent declaration) + // - Constructors + // - Statics + // - Methods + // - Fields + // + // For types that are not packs (e.g. Statics), they must have permutations + // provided where they are and aren't present. + //////////////////////////////////////////////////////////////////////////////// + + // Methods + Fields. + explicit constexpr Class(const char* class_name, Methods_... methods, + Fields_... fields) + : Class(class_name, Constructor<>{}, Static{}, methods..., fields...) {} + + // Constructors + Statics + Methods + Fields. explicit constexpr Class( const char* class_name, Constructors_... constructors, Static, std::tuple> @@ -1860,7 +1932,7 @@ struct Class, methods_(methods...), fields_(fields...) {} - // No ctors, static. + // Statics + Methods + Fields. explicit constexpr Class( const char* class_name, Static, std::tuple> @@ -1872,7 +1944,7 @@ struct Class, methods_(methods...), fields_(fields...) {} - // Ctors, no static. + // Constructors only + Methods + Fields. explicit constexpr Class(const char* class_name, Constructors_... constructors, Methods_... methods, Fields_... fields) @@ -1882,16 +1954,62 @@ struct Class, methods_(methods...), fields_(fields...) {} - // No ctors, no static. - explicit constexpr Class(const char* class_name, Methods_... methods, + //////////////////////////////////////////////////////////////////////////////// + // Constructors with `Extends`. + //////////////////////////////////////////////////////////////////////////////// + + // Extends + Methods + Fields. + explicit constexpr Class(const char* class_name, ExtendsArgT extends, + Methods_... methods, Fields_... fields) + : parent_(extends.parent_), + Object(class_name), + methods_(methods...), + fields_(fields...) {} + + // Extends + Statics + Methods + Fields. + explicit constexpr Class( + const char* class_name, ExtendsArgT extends, + Static, std::tuple> + statik, + Methods_... methods, Fields_... fields) + : Object(class_name), + parent_(extends.parent_), + static_(statik), + methods_(methods...), + fields_(fields...) {} + + // Extends + Constructors + Methods + Fields. + explicit constexpr Class(const char* class_name, ExtendsArgT extends, + Constructors_... constructors, Methods_... methods, Fields_... fields) - : Class(class_name, Constructor<>{}, Static{}, methods..., fields...) {} + : Object(class_name), + parent_(extends.parent_), + constructors_(constructors...), + methods_(methods...), + fields_(fields...) {} + + // Extends + Statics + Constructor + Methods + Fields. + explicit constexpr Class( + const char* class_name, ExtendsArgT extends, + Constructors_... constructors, + Static, std::tuple> + statik, + Methods_... methods, Fields_... fields) + : Object(class_name), + parent_(extends.parent_), + constructors_(constructors...), + static_(statik), + methods_(methods...), + fields_(fields...) {} - template constexpr bool operator==( - const Class, + const Class, std::tuple, std::tuple>>, std::tuple, std::tuple>& rhs) const { @@ -1906,20 +2024,22 @@ struct Class, template Class(const char*, Params...) - -> Class Class, Params...>, + metaprogramming::BaseFilterWithDefault_t, Params...>, metaprogramming::BaseFilterWithDefault_t< StaticBase, Static, std::tuple<>>, Params...>, metaprogramming::BaseFilter_t, metaprogramming::BaseFilter_t>; -Class(const char*) -> Class>, - std::tuple, std::tuple<>>>, - std::tuple<>, std::tuple<>>; +Class(const char*) + -> Class>, std::tuple>, + std::tuple, std::tuple<>>>, std::tuple<>, + std::tuple<>>; } // namespace jni - #include namespace jni { @@ -2071,7 +2191,6 @@ constexpr auto FullArrayStripV(const T& val) { } // namespace jni - #include namespace jni { @@ -2095,7 +2214,6 @@ SupportedClassSet(Classes...) -> SupportedClassSet; } // namespace jni - #include namespace jni { @@ -2192,11 +2310,9 @@ static constexpr auto kShadowDefaultClassLoader = kDefaultClassLoader; } // namespace jni - namespace jni { // clang-format off - inline constexpr Class kJavaLangClass{ "java/lang/Class", Method{"getClassLoader", Return{ Class { "java/lang/ClassLoader" } }}, @@ -2209,6 +2325,9 @@ inline constexpr Class kJavaLangObject{ inline constexpr Class kJavaLangClassLoader{ "java/lang/ClassLoader", + Static { + Method{"getSystemClassLoader", Return{Self{}}}, + }, Method{"loadClass", Return{kJavaLangClass}, Params{}}, Method{"toString", Return{jstring{}}, Params<>{}}, }; @@ -2221,6 +2340,14 @@ static constexpr Class kJavaLangString{ Method{"toString", Return{jstring{}}, Params<>{}}, }; + +static constexpr Class kJavaLangException{ + "java/lang/Exception", + Method{"getMessage", Return{jstring{}}, Params<>{}}, + Method{"printStackTrace", Return{}, Params<>{}}, + Method{"toString", Return{jstring{}}, Params<>{}}, +}; + // clang-format on } // namespace jni @@ -2353,7 +2480,6 @@ struct LifecycleHelper } // namespace jni - #include #include #include @@ -2504,7 +2630,6 @@ constexpr const auto& ParentLoaderForClass() { } // namespace jni - namespace jni::metaprogramming { template @@ -2600,7 +2725,6 @@ struct Constants { } // namespace jni::metaprogramming - namespace jni { // jobject. @@ -2739,14 +2863,6 @@ constexpr std::string_view JavaTypeToString() { } // namespace jni -namespace jni { - -// Tag to indicate you are referring to the enclosing class. -// Useful for builder patterns where the decorated object returned is identical. -struct Self {}; - -} // namespace jni - #include #include @@ -2939,7 +3055,6 @@ struct NBit { } // namespace jni::metaprogramming - #include #include @@ -2968,6 +3083,7 @@ using Increment_t = typename Increment::template type; } // namespace jni::metaprogramming +#include #include namespace jni { @@ -2982,6 +3098,22 @@ struct ParentIfSelf { using type = typename T::template ChangeIdType; }; +template +using ParentIfSelf_t = typename ParentIfSelf::type; + +template +struct Ancestor { + using type = typename Ancestor::type; +}; + +template +struct Ancestor { + using type = IdT; +}; + +template +using Ancestor_t = typename Ancestor::type; + // Helper to generate full signature information for a "selected" value, and // possibly some container information. Here, |Selector| is |MethodSelection|, // |FieldSelection|, etc. @@ -2995,7 +3127,8 @@ template struct SelectorStaticInfo { static constexpr inline bool kIsSelf = std::is_same_v; - using Selector = typename ParentIfSelf::type; + using Selector = + ParentIfSelf_t>; template struct IthRawTypeMember { @@ -3138,7 +3271,8 @@ struct ArrayViewHelper; // Id. template + std::size_t secondary_idx, std::size_t tertiary_idx, + std::size_t ancestry_idx> struct Id; // Scope. @@ -3472,9 +3606,12 @@ template struct Signature {}; template -struct Signature> { - using IdT = Id; + std::size_t secondary_idx, std::size_t tertiary_idx, + std::size_t ancestry_idx> +struct Signature< + Id> { + using IdT = + Id; static constexpr IdType kChildIdType = kIdType_ == IdType::OVERLOAD ? IdType::OVERLOAD_PARAM @@ -3487,8 +3624,8 @@ struct Signature> { struct Helper> { template struct Val { - static constexpr std::string_view val = - Signature>::val; + static constexpr std::string_view val = Signature< + Id>::val; }; static constexpr std::string_view val = @@ -3496,8 +3633,8 @@ struct Signature> { }; struct ReturnHelper { - static constexpr std::string_view val = - Signature>::val; + static constexpr std::string_view val = Signature< + Id>::val; }; // For methods and ctors generates the signature, e.g. "(II)LClass1;". @@ -3594,7 +3731,6 @@ constexpr auto StripClassLoaderFromLoadedBy(T val) { } // namespace jni - namespace jni::metaprogramming { // Builds a stable (i.e. first unique type is preserved) set of unique types @@ -3636,7 +3772,6 @@ using UniqueSet_Tup = TupleUnroller_t; } // namespace jni::metaprogramming - #include namespace jni::metaprogramming { @@ -3911,6 +4046,10 @@ struct JniT { static constexpr std::size_t kRank = kRank_; static_assert(kRank != -1); + static constexpr auto kParent = class_v_.parent_; + using ParentT = JniT; + // Same as this type, except uses rank-1. using RankLess1 = JniT; @@ -4080,19 +4219,19 @@ struct RawProxy { // Helper to generate signatures for objects at rank-1 but span types at rank. // Used in static selection signature generation (for types like LocalArray). -template +template struct JniTSelector { using RawProxyT = RawProxy; using RawValT = typename RawProxyT::RawValT; static constexpr std::size_t kRank = RawProxyT::kRank; + static constexpr std::size_t kAncestorIdx = ancestor_idx; static constexpr auto Val() { return RawProxyT{}; } }; } // namespace jni - #include #include @@ -4153,7 +4292,6 @@ struct Interleaved, std::tuple> { } // namespace jni::metaprogramming - namespace jni { template <> @@ -4711,7 +4849,6 @@ struct InvokeHelper 1), jobject>, kRank, false> { } // namespace jni - #include #include #include @@ -4802,7 +4939,6 @@ struct ProxyBase { } // namespace jni - #include #include #include @@ -4811,7 +4947,8 @@ struct ProxyBase { namespace jni { template + std::size_t secondary_idx = kNoIdx, std::size_t tertiary_idx = kNoIdx, + std::size_t ancestry_idx = 0> struct Id { using JniT = JniT_; static constexpr IdType kIdType = kIdType_; @@ -4821,6 +4958,7 @@ struct Id { static constexpr std::size_t kIdx = idx; static constexpr std::size_t kSecondaryIdx = secondary_idx; static constexpr std::size_t kTertiaryIdx = tertiary_idx; + static constexpr std::size_t kAncestorIdx = ancestry_idx; static constexpr bool kIsConstructor = (kIdType == IdType::OVERLOAD || kIdType == IdType::OVERLOAD_PARAM || @@ -4840,7 +4978,7 @@ struct Id { (kIdxToChange == 1 ? kNewValue : secondary_idx), (kIdxToChange == 2 ? kNewValue : tertiary_idx)>; - static constexpr auto Val() { + static constexpr auto ValWhenAncestryIs0() { if constexpr (kIdType == IdType::CLASS) { return Class(); } else if constexpr (kIdType == IdType::STATIC_FIELD) { @@ -4922,6 +5060,17 @@ struct Id { } } + using ParentIdT = Id; + + static constexpr auto Val() { + if constexpr (ancestry_idx > 0) { + return ParentIdT::Val(); + } else { + return ValWhenAncestryIs0(); + } + } + // Returns root for constructor, else return's "raw_" member. static constexpr auto Materialize() { if constexpr (kIdType == IdType::STATIC_OVERLOAD) { @@ -5004,6 +5153,19 @@ struct Id { } // namespace jni +namespace jni { + +struct Configuration { + // Release jclassID on JVM teardown (needed in test to balance global IDs). + bool release_class_ids_on_teardown_ = false; + + // Release jmethodID on JVM teardown (needed in test to balance global IDs). + bool release_method_ids_on_teardown_ = false; +}; + +static inline Configuration kConfiguration = {}; + +} // namespace jni #include #include @@ -5131,7 +5293,6 @@ class InvocableMap } // namespace jni::metaprogramming - #include #include @@ -6467,7 +6628,6 @@ struct AdoptGlobal {}; } // namespace jni - #include #include @@ -6499,7 +6659,9 @@ class ClassRef { if constexpr (JniT::GetClassLoader() == kDefaultClassLoader) { static auto get_lambda = [](metaprogramming::DoubleLockedValue* storage) { - DefaultRefs().push_back(storage); + if (kConfiguration.release_class_ids_on_teardown_) { + DefaultRefs().push_back(storage); + } // FindClass uses plain name (e.g. "kClass") for rank 0, qualified // class names when used in arrays (e.g. "[LkClass;"). This doesn't @@ -6519,14 +6681,14 @@ class ClassRef { LifecycleHelper::Promote( JniHelper::FindClass( SelectorStaticInfo< - JniTSelector>::TypeName() + JniTSelector>::TypeName() .data()))); } }; return RefStorage< decltype(get_lambda), - SelectorStaticInfo>>::Get(get_lambda); + SelectorStaticInfo>>::Get(get_lambda); } else { // For non default classloader, storage in class member. return class_ref_.LoadAndMaybeInit([=]() { @@ -7236,7 +7398,9 @@ struct OverloadRef { static jmethodID GetMethodID(jclass clazz) { static auto get_lambda = [clazz](metaprogramming::DoubleLockedValue* storage) { - DefaultRefs().push_back(storage); + if (kConfiguration.release_method_ids_on_teardown_) { + DefaultRefs().push_back(storage); + } if constexpr (IdT::kIsStatic) { return jni::JniHelper::GetStaticMethodID(clazz, IdT::Name(), @@ -7287,7 +7451,6 @@ struct OverloadRef { } // namespace jni - namespace jni { template @@ -7503,6 +7666,7 @@ struct OverloadSelector { #include #include #include +#include #include namespace jni { @@ -7524,6 +7688,8 @@ class FieldRef { using IdT = Id; using FieldSelectionT = FieldSelection; + using SelfIdT = typename IdT::template ChangeIdType; + explicit FieldRef(jclass class_ref, jobject object_ref) : class_ref_(class_ref), object_ref_(object_ref) {} @@ -7550,7 +7716,10 @@ class FieldRef { }); } - using ReturnProxied = Return_t; + using ReturnProxied = + std::conditional_t, + Return_t>; const auto& SelfVal() { if constexpr (IdT::kIsStatic) { @@ -8676,7 +8845,11 @@ class JvmRefBase { friend class ThreadGuard; friend class ThreadLocalGuardDestructor; - JvmRefBase(JavaVM* vm) { process_level_jvm_.store(vm); } + JvmRefBase(JavaVM* vm, const Configuration& configuration) { + process_level_jvm_.store(vm); + kConfiguration = configuration; + } + ~JvmRefBase() { process_level_jvm_.store(nullptr); } static JavaVM* GetJavaVm() { return process_level_jvm_.load(); } @@ -9304,9 +9477,9 @@ LocalArray( -> LocalArray; template -LocalArray(std::size_t, SpanType) - -> LocalArray; +LocalArray(std::size_t, + SpanType) -> LocalArray; template LocalArray(std::size_t, LocalArray) @@ -9384,8 +9557,10 @@ class JvmRef : public JvmRefBase { } } - explicit JvmRef(JNIEnv* env) : JvmRefBase(BuildJavaVMFromEnv(env)) {} - explicit JvmRef(JavaVM* vm) : JvmRefBase(vm) {} + explicit JvmRef(JNIEnv* env, const Configuration& configuration = {}) + : JvmRefBase(BuildJavaVMFromEnv(env), configuration) {} + explicit JvmRef(JavaVM* vm, const Configuration& configuration = {}) + : JvmRefBase(vm, configuration) {} ~JvmRef() { TeardownClassloadersHelper( @@ -9650,7 +9825,6 @@ inline jclass FindClassFallback(const char* class_name) { } // namespace jni - namespace jni { inline constexpr Class kJavaUtilList{ @@ -9663,4 +9837,17 @@ inline constexpr Class kJavaUtilList{ } // namespace jni +namespace jni { + +static constexpr ::jni::Class kJavaUtilArrayList{ + "java/util/ArrayList", + Constructor{}, + Constructor{kJavaLangObject}, + Constructor{int{}}, + + Method{"add", Return{}, Params{kJavaLangObject}}, +}; + +} // namespace jni + #endif // JNI_BIND_RELEASE_