From ac0dea6e4d7c01155d56215fc6abcbac53e242f0 Mon Sep 17 00:00:00 2001 From: Jamieson Pryor Date: Tue, 29 Aug 2023 14:43:07 -0700 Subject: [PATCH] Rev JNI Bind release header to v 0.9.7. PiperOrigin-RevId: 561143131 --- README.md | 4 +- jni_bind_release.h | 5071 +++++++++++++++++++---------------- jni_bind_release_leader.inc | 2 +- 3 files changed, 2699 insertions(+), 2378 deletions(-) diff --git a/README.md b/README.md index 9881ec23..bd5e9fb4 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,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-0.9.6-alpha.zip"], - strip_prefix = "jni-bind-Release-0.9.6-alpha", + urls = ["https://github.com/google/jni-bind/archive/refs/tags/Release-0.9.7-alpha.zip"], + strip_prefix = "jni-bind-Release-0.9.7-alpha", ) ``` diff --git a/jni_bind_release.h b/jni_bind_release.h index 68bd68ae..6b427968 100644 --- a/jni_bind_release.h +++ b/jni_bind_release.h @@ -15,7 +15,7 @@ */ /******************************************************************************* - * JNI Bind Version 0.9.5. + * JNI Bind Version 0.9.7. * Alpha Public Release. ******************************************************************************** * This header is the single header version which you can use to quickly test or @@ -396,74 +396,6 @@ constexpr bool ContainsValue(const SoughtType& sought_value, Ts&&... ts) { } // namespace jni::metaprogramming -namespace jni { - -struct Object { - const char* name_; - constexpr explicit Object(const char* name) : name_(name) {} -}; - -} // namespace jni - -#include -#include - -namespace jni::metaprogramming { - -template -using T_ = T; - -template -auto TupleFromSize(std::index_sequence) { - return std::tuple...>{}; -} - -// Takes a type and returns a std::tuple of DefaultValues. -template -auto TupleFromSize() { - return TupleFromSize(std::make_index_sequence{}); -} - -template -using TupleFromSize_t = decltype(TupleFromSize()); - -} // namespace jni::metaprogramming - -#include -#include -#include - -namespace jni::metaprogramming { - -// Returns a null pointer of the type of the two input tuples interleaved. -template -auto Interleave(std::integer_sequence) - -> decltype(std::tuple_cat( - std::make_tuple(std::get(std::declval()), - std::get(std::declval()))...))* { - // This interleave is for *types only*, all values within the tuples are - // completely incidental. In the event there is no default constructor, it - // won't be possible to return a value, so, instead, return a pointer (which - // won't be used) and infer the type by stripping the pointer. - return nullptr; -} - -template -auto Interleave() { - return Interleave( - std::make_index_sequence::value>()); -} - -template -struct Interleaved; - -template -struct Interleaved, std::tuple> { - using type = std::remove_pointer_t< - decltype(Interleave, std::tuple>())>; -}; - -} // namespace jni::metaprogramming #include @@ -526,6 +458,143 @@ constexpr bool AllUniqueValues(const T1&& t1, const Ts&&... ts) { } // namespace jni::metaprogramming +namespace jni { + +struct Object { + const char* name_; + constexpr explicit Object(const char* name) : name_(name) {} +}; + +} // namespace jni + + +#include +#include + +namespace jni::metaprogramming { + +// Metafunction that binds a metafunction (e.g. Same), a query (e.g. "A"), a +// variadic pack as arguments, and returns the idx of the query. All members +// of the variadic pack must be unique. +// +// |Comparator| must express a static bool data member "value". +template +struct FindIdxOfVal { + template + struct FindIdxOfValHelper { + static_assert(sizeof...(Ts) == -1, "The sought element is not in the set"); + }; + + template + struct FindIdxOfValHelper { + template + static constexpr std::size_t GetIdxHelper() { + if constexpr (Comparator::template value) { + return idx; + } else { + return FindIdxOfValHelper::template GetIdxHelper(); + } + } + + static constexpr std::size_t GetIdx() { + return sizeof...(Ts) - GetIdxHelper(); + } + }; + + // Done once in a seperate struct for improved compilation time. + template + struct StaticAssertWrapper { + static_assert(AllUnique_v, + "FindIdxOfVal only operates on unique sets."); + static constexpr std::size_t value = FindIdxOfValHelper::GetIdx(); + }; + + template + static constexpr std::size_t value = StaticAssertWrapper::value; +}; + +template +static constexpr std::size_t FindIdxOfValWithComparator_idx = + FindIdxOfVal::template value; + +// Convenience alias with default of std::is_same Comparator (typical use case). +template +static constexpr std::size_t FindIdxOfVal_idx = + FindIdxOfValWithComparator_idx, Ts...>; + +template +static constexpr std::size_t FindIdxOfValInTupWithComparator_idx = + TupleUnroller_v, TupType>; + +// Convenience alias with default of std::is_same Comparator (typical use case). +template +static constexpr std::size_t FindIdxOfValInTup_idx = + FindIdxOfValInTupWithComparator_idx, TupType>; + +} // namespace jni::metaprogramming + + +#include + +namespace jni::metaprogramming { + +// Metafunction to return only even elements. +struct Even { + template + struct EvenHelper {}; + + template <> + struct EvenHelper> { + using type = std::tuple<>; + }; + + template + struct OddHelper {}; + + template <> + struct OddHelper> { + using type = std::tuple<>; + }; + + template + struct OddHelper> { + using type = typename EvenHelper>::type; + }; + + template + struct EvenHelper> { + using type = ConcatenateTup_t, + typename OddHelper>::type>; + }; + + template + using type = typename EvenHelper>::type; +}; + +template +using Even_t = typename Even::template type; + +// Metafunction to return only odd elements. +struct Odd { + template + struct OddHelper { + using type = std::tuple<>; + }; + + template + struct OddHelper> { + using type = Even_t; + }; + + template + using type = typename OddHelper>::type; +}; + +template +using Odd_t = typename Odd::template type; + +} // namespace jni::metaprogramming + namespace jni { template @@ -644,415 +713,151 @@ using ParamsRawTup_t = typename T::ParamsRawTup; } // namespace jni -#include +using jclass = jclass; +using jthrowable = jthrowable; +using jstring = jstring; +using jarray = jarray; +using jbooleanArray = jbooleanArray; +using jbyteArray = jbyteArray; +using jcharArray = jcharArray; +using jshortArray = jshortArray; +using jintArray = jintArray; +using jlongArray = jlongArray; +using jfloatArray = jfloatArray; +using jdoubleArray = jdoubleArray; +using jobjectArray = jobjectArray; + +using jweak = jweak; +using jvalue = jvalue; +using jfieldID = jfieldID; +using jmethodID = jmethodID; + +using JavaVM = JavaVM; +using JNIEnv = JNIEnv; + +// IWYU pragma: end_exports + #include -#include namespace jni::metaprogramming { -template -class QueryableMapBase {}; +// Maps types to other types. +// Keys do not need to be unique, although queries only return the first entry. +template +struct TypeToTypeMap {}; -// This is an interface that can be inherited from to expose an -// operator["name"]. It provides compile time string index lookup with no macros -// although it is dependent on a clang extension. -// -// To use this API, inherit from this class using template types as follows: -// -// |CrtpBase|: The name of the class inheriting from the map. This class -// will inherit an operator[]. It must implement this exact signature: -// -// template -// auto QueryableMapCall(const char* key); -// -// |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. -// -// 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 -class QueryableMap - : public QueryableMapBase> {}; +template +struct TypeToTypeMap, std::tuple> { + static_assert(sizeof...(Keys_) == sizeof...(Values_), + "Keys must be an equal size to the value."); -template ::*nameable_member> -using QueryableMap_t = - QueryableMap>, - std::decay_t, nameable_member>; + using Keys = std::tuple; + using Values = std::tuple; + using Invert = TypeToTypeMap, std::tuple>; -template -class QueryableMapEntry; + template + using type = + TypeOfNthElement_t, + Values_...>; +}; -template -class QueryableMapBase> - : public QueryableMapEntry... { - public: - using QueryableMapEntry::operator[]...; +template +using TypeToTypeMap_Keys_t = typename TypeToTypeMap::Keys; - using QueryableMapEntry::Contains...; +template +using TypeToTypeMap_Values_t = typename TypeToTypeMap::Values; - // Will select subclass specialisations if present. - constexpr bool Contains(const char* key) { return false; } -}; +// Metafunction to invert the map from keys->vals to vals->keys. +// Note, keys do not need to be unique. +template +using TypeToTypeMap_Invert = typename TypeToTypeMap::Invert; -template -class QueryableMapEntry { - public: -#if __clang__ - // This function blurs the distinction between type and value space. The - // clang extension allows the key to be wrapped in a constexpr way. This - // allows for string to string comparison based on the static value the class - // is templated by. - // - // The reason the TypeMap interface requires inheritance as opposed to simply - // holding an instance of this map (like you would with a regular hash map) is - // the constexpr-ness of the string can't be propagated. This essentially - // means you get one shot at defining the function. - constexpr auto operator[](const char* key) __attribute__(( - enable_if(std::string_view(key) == - std::get(tup_container_v.*nameable_member).name_, - ""))) { - static_assert(std::is_base_of_v, - "You must derive from the invocable map."); +template +using TypeToTypeMapQuery_t = typename TypeToTypeMap::template type>; - return (*static_cast(this)).template QueryableMapCall(key); - } +// Queries a type map using a custom comparator, +// If multiple keys satisfy, the first is returned. +template +using TypeToTypeMapQueryWithComparator_t = + typename TypeToTypeMap::template type; - constexpr bool Contains(const char* key) __attribute__(( - enable_if(std::string_view(key) == - std::get(tup_container_v.*nameable_member).name_, - ""))) { - return true; - } -#else - static_assert(false, - "This container requires clang for compile time strings."); -#endif -}; +// Builds a TypeToTypeMap from interleaved Keys and Values. +template +using TypeToTypeMapFromKeyValues_t = TypeToTypeMap, Odd_t>; + +template +using TypeToTypeMapFromKeyValuesTup_t = + TupleToType_t; } // namespace jni::metaprogramming -#include #include -#include +#include 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. -// -// To use this API, inherit from this class using template types as follows: -// -// |CrtpBase|: The name of the class inheriting from the map. This class -// will inherit an operator(). It must implement this exact signature: -// -// template -// auto InvocableMapCall(const char* key, Args&&... args); -// -// If i is the index where |tup_container_v.*nameable_member|.name_ == key, -// then InvocablemapCall will forward the args from operator() with the -// same args. Static memory can be used in this function call and it will -// be unique because of the I non-type template parameter. -// -// |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. +// Returns all elements derived from DesiredBase. // -// 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 ::*nameable_member> -using InvocableMap_t = - InvocableMap, nameable_member>; - -template -class InvocableMapEntry; +// 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 -class InvocableMapBase {}; +template +using BaseFilter_t = + typename BaseFilter>::type; -template -class InvocableMapBase> - : public InvocableMapEntry... { - public: - using InvocableMapEntry::operator()...; +template +struct BaseFilter, void>, + std::tuple> { + using type = + ConcatenateTup_t, BaseFilter_t>; }; -template -class InvocableMapEntry { - public: -#if __clang__ - // This function blurs the distinction between type and value space. The - // clang extension allows the key to be wrapped in a constexpr way. This - // allows for string to string comparison based on the static value the class - // is templated by. - // - // The reason the TypeMap interface requires inheritance as opposed to simply - // holding an instance of this map (like you would with a regular hash map) is - // the constexpr-ness of the string can't be propagated. This essentially - // means you get one shot at defining the function. - template - constexpr auto operator()(const char* key, Args&&... args) __attribute__(( - enable_if(std::string_view(key) == - std::get(tup_container_v.*nameable_member).name_, - ""))) { - static_assert(std::is_base_of_v, - "You must derive from the invocable map."); - - return (*static_cast(this)) - .template InvocableMapCall(key, - std::forward(args)...); - } -#else - static_assert(false, - "This container requires clang for compile time strings."); -#endif +template +struct BaseFilter, void>, + std::tuple> { + using type = BaseFilter_t; }; //============================================================================== -template -class InvocableMap - : public InvocableMapBase< - CrtpBase, tup_container_v, TupContainerT, nameable_member, - std::make_index_sequence>>> {}; +template +using DefaultIfEmpty_Tup = + std::conditional_t>, + DefaultValue, PostFilterValue>; -} // namespace jni::metaprogramming +template +using BaseFilterWithDefault_t = + DefaultIfEmpty_Tup, + std::tuple>; -#include -#include +} // namespace jni::metaprogramming -namespace jni::metaprogramming { +#include -// Metafunction that binds a metafunction (e.g. Same), a query (e.g. "A"), a -// variadic pack as arguments, and returns the idx of the query. All members -// of the variadic pack must be unique. -// -// |Comparator| must express a static bool data member "value". -template -struct FindIdxOfVal { - template - struct FindIdxOfValHelper { - static_assert(sizeof...(Ts) == -1, "The sought element is not in the set"); - }; +namespace jni { - template - struct FindIdxOfValHelper { - template - static constexpr std::size_t GetIdxHelper() { - if constexpr (Comparator::template value) { - return idx; - } else { - return FindIdxOfValHelper::template GetIdxHelper(); - } - } +// Helper JNI shim for object, method, class, etc. lookup. +class JniHelper { + public: + // Finds a class with "name". Note, the classloader used is whatever is + // present on the statck when this is caled. No caching is performed, + // returned jclass is a local. + static jclass FindClass(const char* name); - static constexpr std::size_t GetIdx() { - return sizeof...(Ts) - GetIdxHelper(); - } - }; + // Returns a local ref jclass for the given jobject. + // Note, if the object is polymorphic it may be a sub or superclass. + static jclass GetObjectClass(jobject object); - // Done once in a seperate struct for improved compilation time. - template - struct StaticAssertWrapper { - static_assert(AllUnique_v, - "FindIdxOfVal only operates on unique sets."); - static constexpr std::size_t value = FindIdxOfValHelper::GetIdx(); - }; - - template - static constexpr std::size_t value = StaticAssertWrapper::value; -}; - -template -static constexpr std::size_t FindIdxOfValWithComparator_idx = - FindIdxOfVal::template value; - -// Convenience alias with default of std::is_same Comparator (typical use case). -template -static constexpr std::size_t FindIdxOfVal_idx = - FindIdxOfValWithComparator_idx, Ts...>; - -template -static constexpr std::size_t FindIdxOfValInTupWithComparator_idx = - TupleUnroller_v, TupType>; - -// Convenience alias with default of std::is_same Comparator (typical use case). -template -static constexpr std::size_t FindIdxOfValInTup_idx = - FindIdxOfValInTupWithComparator_idx, TupType>; - -} // namespace jni::metaprogramming - - -#include - -namespace jni::metaprogramming { - -// Metafunction to return only even elements. -struct Even { - template - struct EvenHelper {}; - - template <> - struct EvenHelper> { - using type = std::tuple<>; - }; - - template - struct OddHelper {}; - - template <> - struct OddHelper> { - using type = std::tuple<>; - }; - - template - struct OddHelper> { - using type = typename EvenHelper>::type; - }; - - template - struct EvenHelper> { - using type = ConcatenateTup_t, - typename OddHelper>::type>; - }; - - template - using type = typename EvenHelper>::type; -}; - -template -using Even_t = typename Even::template type; - -// Metafunction to return only odd elements. -struct Odd { - template - struct OddHelper { - using type = std::tuple<>; - }; - - template - struct OddHelper> { - using type = Even_t; - }; - - template - using type = typename OddHelper>::type; -}; - -template -using Odd_t = typename Odd::template type; - -} // 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 { - -// Helper JNI shim for object, method, class, etc. lookup. -class JniHelper { - public: - // Finds a class with "name". Note, the classloader used is whatever is - // present on the statck when this is caled. No caching is performed, - // returned jclass is a local. - static jclass FindClass(const char* name); - - // Returns a local ref jclass for the given jobject. - // Note, if the object is polymorphic it may be a sub or superclass. - static jclass GetObjectClass(jobject object); - - // Gets a method for a signature (no caching is performed). - static inline jmethodID GetMethodID(jclass clazz, const char* method_name, - const char* method_signature); + // Gets a method for a signature (no caching is performed). + static inline jmethodID GetMethodID(jclass clazz, const char* method_name, + const char* method_signature); // Gets a static method for a signature (no caching is performed). static inline jmethodID GetStaticMethodID(jclass clazz, @@ -1244,60 +1049,6 @@ using Raw_t = typename T::Raw; } // namespace jni -#include - -namespace jni::metaprogramming { - -// Maps types to other types. -// Keys do not need to be unique, although queries only return the first entry. -template -struct TypeToTypeMap {}; - -template -struct TypeToTypeMap, std::tuple> { - static_assert(sizeof...(Keys_) == sizeof...(Values_), - "Keys must be an equal size to the value."); - - using Keys = std::tuple; - using Values = std::tuple; - using Invert = TypeToTypeMap, std::tuple>; - - template - using type = - TypeOfNthElement_t, - Values_...>; -}; - -template -using TypeToTypeMap_Keys_t = typename TypeToTypeMap::Keys; - -template -using TypeToTypeMap_Values_t = typename TypeToTypeMap::Values; - -// Metafunction to invert the map from keys->vals to vals->keys. -// Note, keys do not need to be unique. -template -using TypeToTypeMap_Invert = typename TypeToTypeMap::Invert; - -template -using TypeToTypeMapQuery_t = typename TypeToTypeMap::template type>; - -// Queries a type map using a custom comparator, -// If multiple keys satisfy, the first is returned. -template -using TypeToTypeMapQueryWithComparator_t = - typename TypeToTypeMap::template type; - -// Builds a TypeToTypeMap from interleaved Keys and Values. -template -using TypeToTypeMapFromKeyValues_t = TypeToTypeMap, Odd_t>; - -template -using TypeToTypeMapFromKeyValuesTup_t = - TupleToType_t; - -} // namespace jni::metaprogramming - #include #include @@ -1400,37 +1151,129 @@ class ConstructorRef : public ConstructorBase { } // namespace jni -#include -#include +namespace jni { -namespace jni::metaprogramming { +template +struct ArrayTag {}; -struct StringConcatenate { - template - struct Helper { - static constexpr auto BuildConcatenation() noexcept { - constexpr std::size_t len = (Vs.size() + ... + 0); - std::array arr{}; - auto append_single_string = - [i = 0, &arr](auto const& string_to_concatenate) mutable { - for (auto c : string_to_concatenate) arr[i++] = c; - }; - (append_single_string(Vs), ...); - arr[len] = 0; +template +static constexpr bool kIsArrayType = + std::is_base_of_v, T> || + std::is_base_of_v, T> || + std::is_base_of_v, T> || + std::is_base_of_v, T> || + std::is_base_of_v, T> || + std::is_base_of_v, T> || + std::is_base_of_v, T> || + std::is_base_of_v, T> || + std::is_base_of_v, T> || + std::is_base_of_v, T>; - return arr; - } +// Primitive Keys. +using PrimitiveKeys = + std::tuple; - static constexpr auto arr = BuildConcatenation(); - static constexpr std::string_view value{arr.data(), arr.size() - 1}; - }; +// Simple type for proxying types used in the API (e.g. jint) to their +// corresponding array type (e.g. jintarray). Only use the former type when +// using JNI Bind (e.g. LocalArray, not LocalArray). +using RegularToArrayTypeMap = metaprogramming::TypeToTypeMap< + std::tuple, + std::tuple>; - template - static constexpr std::string_view value = Helper::value; +// Given a type, returns the corresponding array type (e.g. jint => jintArray). +template +using RegularToArrayTypeMap_t = + metaprogramming::TypeToTypeMapQuery_t; + +// Array to CDecl type used for invocation. +// Defined separately since this map is not invertible (jobject, jstring => +// jobject). +using ArrayToRegularTypeMap = metaprogramming::TypeToTypeMap< + std::tuple, + std::tuple>; + +template +using ArrayToRegularTypeMap_t = + metaprogramming::TypeToTypeMapQuery_t; + +//////////////////////////////////////////////////////////////////////////////// +// Storage Helper Metafunction. +//////////////////////////////////////////////////////////////////////////////// + +// Figures out the underlying physical opaque handle used to store a type. +// e.g. A rank two int is a jobjectarray. +template +struct StorageHelper { + using type = jobjectArray; }; -template -static constexpr auto StringConcatenate_v = StringConcatenate::value; +// HACK: jstring has its own type despite just being a jobject. To make the +// lookup tables above function, this is handled separately. This will hopefully +// be removed in the future. +template <> +struct StorageHelper { + using type = jobjectArray; +}; + +template +struct StorageHelper { + using type = RegularToArrayTypeMap_t; +}; + +template +struct StorageHelper { + using type = T; +}; + +template +using StorageHelper_t = typename StorageHelper::type; + +} // namespace jni + +#include +#include +#include + +namespace jni::metaprogramming { + +constexpr std::size_t kNegativeOne = std::numeric_limits::max(); + +// This function returns a std::size_t with a symbolic -1 that will not be +// included. This can be useful for building masks of indexes. +// +// When passed an empty set, this function returns kNegativeOne. +// When passed n elements, this function returns the maximum value, or +// kNegativeOne if all elements are kNegativeOne. +constexpr std::size_t ModifiedMax( + std::initializer_list initializer_lister) { + if (initializer_lister.size() == 0) { + return kNegativeOne; + } + + // If all values -1, return -1. + bool non_trivial_value_found = false; + for (const std::size_t val : initializer_lister) { + non_trivial_value_found |= (val != kNegativeOne); + } + if (!non_trivial_value_found) { + return kNegativeOne; + } + + std::size_t max = 0; + for (const std::size_t val : initializer_lister) { + if (max < val && val != kNegativeOne) { + max = val; + } + } + + return max; +} } // namespace jni::metaprogramming @@ -1539,503 +1382,562 @@ Class(const char*) -> Class>, } // namespace jni -namespace jni { - -template -struct ArrayTag {}; - -template -static constexpr bool kIsArrayType = - std::is_base_of_v, T> || - std::is_base_of_v, T> || - std::is_base_of_v, T> || - std::is_base_of_v, T> || - std::is_base_of_v, T> || - std::is_base_of_v, T> || - std::is_base_of_v, T> || - std::is_base_of_v, T> || - std::is_base_of_v, T> || - std::is_base_of_v, T>; - -// Primitive Keys. -using PrimitiveKeys = - std::tuple; -// Simple type for proxying types used in the API (e.g. jint) to their -// corresponding array type (e.g. jintarray). Only use the former type when -// using JNI Bind (e.g. LocalArray, not LocalArray). -using RegularToArrayTypeMap = metaprogramming::TypeToTypeMap< - std::tuple, - std::tuple>; +#include -// Given a type, returns the corresponding array type (e.g. jint => jintArray). -template -using RegularToArrayTypeMap_t = - metaprogramming::TypeToTypeMapQuery_t; +namespace jni { -// Array to CDecl type used for invocation. -// Defined separately since this map is not invertible (jobject, jstring => -// jobject). -using ArrayToRegularTypeMap = metaprogramming::TypeToTypeMap< - std::tuple, - std::tuple>; +template +struct Array; -template -using ArrayToRegularTypeMap_t = - metaprogramming::TypeToTypeMapQuery_t; +template +struct Rank {}; //////////////////////////////////////////////////////////////////////////////// -// Storage Helper Metafunction. +// Array Non-Object Implementation. //////////////////////////////////////////////////////////////////////////////// +template +struct ArrayNonObjectTypeImpl { + RawType raw_; -// Figures out the underlying physical opaque handle used to store a type. -// e.g. A rank two int is a jobjectarray. -template -struct StorageHelper { - using type = jobjectArray; -}; + constexpr ArrayNonObjectTypeImpl(RawType raw) : raw_(raw) {} -// HACK: jstring has its own type despite just being a jobject. To make the -// lookup tables above function, this is handled separately. This will hopefully -// be removed in the future. -template <> -struct StorageHelper { - using type = jobjectArray; -}; + constexpr ArrayNonObjectTypeImpl(RawType raw, Rank) : raw_(raw) {} -template -struct StorageHelper { - using type = RegularToArrayTypeMap_t; + template + constexpr ArrayNonObjectTypeImpl(Array&& invalid_arg) + : raw_(nullptr) { + static_assert(std::is_same_v, + "JNI Error: Invalid array declaration, use Array { type{}, " + "Rank{} }."); + } + + template + constexpr bool operator==(const Array& rhs) const { + if constexpr (std::is_same_v) { + return (raw_ == rhs.raw_); + } + return false; + } + + template + constexpr bool operator!=(const Array& rhs) const { + return !(*this == rhs); + } }; -template -struct StorageHelper { - using type = T; +// Primitive array implementaiton. +template +struct ArrayImpl : public ArrayNonObjectTypeImpl, + ArrayTag> { + public: + using ArrayNonObjectTypeImpl::ArrayNonObjectTypeImpl; }; -template -using StorageHelper_t = typename StorageHelper::type; +//////////////////////////////////////////////////////////////////////////////// +// Array Object Implementation. +//////////////////////////////////////////////////////////////////////////////// +template +struct ArrayImpl : public ArrayTag { + RawType raw_; -} // namespace jni + constexpr ArrayImpl(RawType raw) : raw_(raw) {} -namespace jni::metaprogramming { + template + constexpr ArrayImpl(RawType raw, Rank) : raw_(raw) {} -template -struct RepeatString { - template - static constexpr std::string_view val = metaprogramming::StringConcatenate_v< - val_to_repeat, RepeatString::template val>; -}; + template + constexpr bool operator==(const Array& rhs) const { + if constexpr (std::is_same_v) { + return (raw_ == rhs.raw_); + } + return false; + } -template <> -struct RepeatString<0> { - template - static constexpr std::string_view val{""}; + template + constexpr bool operator!=(const Array& rhs) const { + return !(*this == rhs); + } }; -template -static constexpr auto RepeatString_v{ - RepeatString::template val}; +// This type correlates to those used in declarations, +// e.g. Field { Array { Array { jint {} } } }. +template +struct Array + : public ArrayImpl> { + constexpr Array() + : ArrayImpl>( + RawType{}) {} -} // namespace jni::metaprogramming + constexpr Array(RawType raw) + : ArrayImpl>(raw) {} -#include + template + constexpr Array(RawType raw, Rank) + : ArrayImpl>(raw) {} +}; -namespace jni::metaprogramming { +template +Array(RawType) -> Array; -struct Constants { - static constexpr std::string_view new_line = "\n"; +template +Array(RawType, Rank) -> Array; - static constexpr std::string_view left_bracket = "["; - static constexpr std::string_view right_bracket = "]"; +//////////////////////////////////////////////////////////////////////////////// +// Rank Utilities. +//////////////////////////////////////////////////////////////////////////////// +struct Rankifier { + template + struct Helper; - static constexpr std::string_view left_parenthesis = "("; - static constexpr std::string_view right_parenthesis = ")"; + template + struct Helper> { + static constexpr std::size_t kRank = kRank_; + }; - static constexpr std::string_view hash = "#"; - static constexpr std::string_view comma = ","; - static constexpr std::string_view semi_colon = ";"; + template + static inline constexpr std::size_t Rank(const ArrayT& maybe_array) { + if constexpr (kIsArrayType>) { + return Helper::kRank; + } else { + return 0; + } + } +}; - static constexpr std::string_view a = "a"; - static constexpr std::string_view b = "b"; - static constexpr std::string_view c = "c"; - static constexpr std::string_view d = "d"; - static constexpr std::string_view e = "e"; - static constexpr std::string_view f = "f"; - static constexpr std::string_view g = "g"; - static constexpr std::string_view h = "h"; - static constexpr std::string_view i = "i"; - static constexpr std::string_view j = "j"; - static constexpr std::string_view k = "k"; - static constexpr std::string_view l = "l"; - static constexpr std::string_view m = "m"; - static constexpr std::string_view n = "n"; - static constexpr std::string_view o = "o"; - static constexpr std::string_view p = "p"; - static constexpr std::string_view q = "q"; - static constexpr std::string_view r = "r"; - static constexpr std::string_view s = "s"; - static constexpr std::string_view t = "t"; - static constexpr std::string_view u = "u"; - static constexpr std::string_view v = "v"; - static constexpr std::string_view w = "w"; - static constexpr std::string_view x = "x"; - static constexpr std::string_view y = "y"; - static constexpr std::string_view z = "z"; +//////////////////////////////////////////////////////////////////////////////// +// Strip Utilities. +// Takes an native array like type, and emits the innermost type. +// e.g. {Array, Array{Rank<2>{}, int{}, Array{Rank<3>{}, int{}} } => int. +//////////////////////////////////////////////////////////////////////////////// +template +struct ArrayStrip { + using type = T; +}; - static constexpr std::string_view A = "A"; - static constexpr std::string_view B = "B"; - static constexpr std::string_view C = "C"; - static constexpr std::string_view D = "D"; - static constexpr std::string_view E = "E"; - static constexpr std::string_view F = "F"; - static constexpr std::string_view G = "G"; - static constexpr std::string_view H = "H"; - static constexpr std::string_view I = "I"; - static constexpr std::string_view J = "J"; - static constexpr std::string_view K = "K"; - static constexpr std::string_view L = "L"; - static constexpr std::string_view M = "M"; - static constexpr std::string_view N = "N"; - static constexpr std::string_view O = "O"; - static constexpr std::string_view P = "P"; - static constexpr std::string_view Q = "Q"; - static constexpr std::string_view R = "R"; - static constexpr std::string_view S = "S"; - static constexpr std::string_view T = "T"; - static constexpr std::string_view U = "U"; - static constexpr std::string_view V = "V"; - static constexpr std::string_view W = "W"; - static constexpr std::string_view X = "X"; - static constexpr std::string_view Y = "Y"; - static constexpr std::string_view Z = "Z"; +template +using ArrayStrip_t = typename ArrayStrip::type; + +template +struct ArrayStrip> { + using type = T; }; -} // namespace jni::metaprogramming +template +constexpr auto FullArrayStripV(const T& val) { + if constexpr (kIsArrayType>) { + return FullArrayStripV(val.raw_); + } else { + return val; + } +} -#include -#include -#include +} // namespace jni -namespace jni::metaprogramming { -constexpr std::size_t kNegativeOne = std::numeric_limits::max(); +#include -// This function returns a std::size_t with a symbolic -1 that will not be -// included. This can be useful for building masks of indexes. -// -// When passed an empty set, this function returns kNegativeOne. -// When passed n elements, this function returns the maximum value, or -// kNegativeOne if all elements are kNegativeOne. -constexpr std::size_t ModifiedMax( - std::initializer_list initializer_lister) { - if (initializer_lister.size() == 0) { - return kNegativeOne; - } +namespace jni { - // If all values -1, return -1. - bool non_trivial_value_found = false; - for (const std::size_t val : initializer_lister) { - non_trivial_value_found |= (val != kNegativeOne); - } - if (!non_trivial_value_found) { - return kNegativeOne; - } +// The set of classes that a ClassLoader can load. +template +class SupportedClassSet { + public: + const std::tuple supported_classes_; - std::size_t max = 0; - for (const std::size_t val : initializer_lister) { - if (max < val && val != kNegativeOne) { - max = val; - } + constexpr SupportedClassSet(Classes_... supported_classes) + : supported_classes_(supported_classes...) { + // TODO(b/143908983): Classloaders should enforce unique classes. + // static_assert(metaprogramming::AllUniqueValues(supported_classes...), + //"All classes supported by the class loader must be unique."); } +}; - return max; -} +template +SupportedClassSet(Classes...) -> SupportedClassSet; -} // namespace jni::metaprogramming +} // namespace jni -#include + +#include namespace jni { -// Translates a single JNI term (e.g. jint -> "I") as if it were being used as a -// parameter to a method. -// -// Note, the context a parameter is used on occasion will alter a signature, -// e.g. void in a return is explicit, whereas when used as a parameter, it is -// represented as the omission of any value. -// -// Additionally, Android will obnoxiously fail to compile the standard looking: -// static constexpr char kStr[] = "SomeString"; -// -// Because it is against style to import a using declaration header wide, -// but these are also template definitions, they must remain in this header, and -// so there are goofy looking "using literal" declarations throughout. -// -// https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html -// -// TODO: Rename to JavaPrimitiveTypeToString -template -constexpr std::string_view JavaTypeToString(); +static constexpr std::size_t kDefaultClassLoaderIdx = 0; +static constexpr std::size_t kClassNotInLoaderSetIdx = + metaprogramming::kNegativeOne; -template <> -constexpr std::string_view JavaTypeToString() { - // Note: This only applies when used as a return, not as a parameter. This - // could be enforced through type system, but maybe feels excessive to do so. - // For now, enforcing this is unnecesssary, as this function is only called - // for each Param, which, in the case of no params, is 0 times. - using namespace std::literals; - return "V"sv; -} +// Class loader that can supply any class (to be used when none is specified). +// Setting this as the root loader for user defined classes will disable checks +// that classes are explicitly listed under a loader's class list. +class DefaultClassLoader { + public: + const char* name_ = "__JNI_BIND_DEFAULT_CLASS_LOADER__"; + std::tuple<> supported_classes_{}; -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "Z"sv; -} + // Note, this will return true iff ignore_default_loader is true, but the + // corresponding IdxOfAncestor will be kClassNotInLoaderSetIdx. + template + constexpr bool SupportedDirectlyOrIndirectly() const { + if constexpr (ignore_default_loader) { + // Note, it's an implementation detail that kDefaultClassLoader returns + // false for |SupportedByThisSet|. Otherwise, all classes will always + // defer to the default loader. See |ParentLoaderForClass|. + return false; + } else { + return true; + } + } -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "B"sv; -} + template + constexpr std::size_t IdxOfClass() const { + return kClassNotInLoaderSetIdx; + } -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "C"sv; -} + template + constexpr std::size_t IdxOfAncestor(std::size_t cur_idx = 0) const { + return kClassNotInLoaderSetIdx; + } -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "S"sv; -} + template + bool constexpr operator==(const T& rhs) const { + return false; + } + bool constexpr operator==(const DefaultClassLoader&) const { return true; } -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "I"sv; -} + template + bool constexpr operator!=(const T& rhs) const { + return !(*this == rhs); + } +}; -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "J"sv; -} +// Class loader that cannot supply any classes. This should be the root loader +// for most user defined classes. +class NullClassLoader { + public: + const char* name_ = "__JNI_BIND_NULL_CLASS_LOADER__"; -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "F"sv; -} + template + constexpr bool SupportedDirectlyOrIndirectly() const { + return false; + } -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "D"sv; -} + template + constexpr std::size_t IdxOfClass() const { + return kNoIdx; + } -template <> -constexpr std::string_view JavaTypeToString() { - using namespace std::literals; - return "Ljava/lang/String;"sv; -} + template + constexpr std::size_t IdxOfAncestor(std::size_t cur_idx = 0) const { + return kClassNotInLoaderSetIdx; + } + + template + bool constexpr operator==(const T& rhs) const { + return false; + } + bool constexpr operator==(const NullClassLoader&) const { return true; } + + template + bool constexpr operator!=(const T& rhs) const { + return !(*this == rhs); + } +}; + +static constexpr NullClassLoader kNullClassLoader; +static constexpr DefaultClassLoader kDefaultClassLoader; + +// DO NOT USE: This obviates a compiler bug for value based enablement on ctor. +static constexpr auto kShadowNullClassLoader = kNullClassLoader; + +// DO NOT USE: This obviates a compiler bug for value based enablement on ctor. +static constexpr auto kShadowDefaultClassLoader = kDefaultClassLoader; } // namespace jni -#include -#include namespace jni { -// Metafunction that returns either "" if a member called |name_| isn't -// present, or a constexpr std::string_view of the name if it is. -template -struct NameOrNothing { - static constexpr std::string_view val{""}; -}; +// clang-format off +inline constexpr Class kJavaLangClass{"java/lang/Class"}; -template -struct NameOrNothing> { - static constexpr std::string_view val{val_.name_}; +inline constexpr Class kJavaLangObject{"java/lang/Object"}; + +inline constexpr Class kJavaLangClassLoader{ + "java/lang/ClassLoader", + Method{"loadClass", Return{kJavaLangClass}, Params{}}, + Method{"toString", Return{jstring{}}, Params<>{}}, }; -template -static constexpr auto NameOrNothing_v = NameOrNothing::val; +static constexpr Class kJavaLangString{ + "java/lang/String", -static constexpr std::string_view kInit{""}; + Constructor{jstring{}}, + Constructor{Array{jbyte{}}}, + + Method{"toString", Return{jstring{}}, Params<>{}}, +}; +// clang-format on } // namespace jni -namespace jni { +#include +#include -enum class IdType { - CLASS, - STATIC_OVERLOAD_SET, - STATIC_OVERLOAD, - STATIC_OVERLOAD_PARAM, - OVERLOAD_SET, - OVERLOAD, - OVERLOAD_PARAM, - STATIC_FIELD, - FIELD, +namespace jni::metaprogramming { + +struct StringConcatenate { + template + struct Helper { + static constexpr auto BuildConcatenation() noexcept { + constexpr std::size_t len = (Vs.size() + ... + 0); + std::array arr{}; + auto append_single_string = + [i = 0, &arr](auto const& string_to_concatenate) mutable { + for (auto c : string_to_concatenate) arr[i++] = c; + }; + (append_single_string(Vs), ...); + arr[len] = 0; + + return arr; + } + + static constexpr auto arr = BuildConcatenation(); + static constexpr std::string_view value{arr.data(), arr.size() - 1}; + }; + + template + static constexpr std::string_view value = Helper::value; }; -} // namespace jni +template +static constexpr auto StringConcatenate_v = StringConcatenate::value; -#include +} // namespace jni::metaprogramming + +#include namespace jni { -template -struct Array; +enum class LifecycleType { + LOCAL, + GLOBAL, + // WEAK, // not implemented yet. +}; -template -struct Rank {}; +template +struct LifecycleHelper; -//////////////////////////////////////////////////////////////////////////////// -// Array Non-Object Implementation. -//////////////////////////////////////////////////////////////////////////////// -template -struct ArrayNonObjectTypeImpl { - RawType raw_; +// Shared implementation for local jobjects (jobject, jstring). +template +struct LifecycleLocalBase { + static inline void Delete(Span object) { + JniEnv::GetEnv()->DeleteLocalRef(object); + } - constexpr ArrayNonObjectTypeImpl(RawType raw) : raw_(raw) {} + static inline Span NewReference(Span object) { + return static_cast(JniEnv::GetEnv()->NewLocalRef(object)); + } +}; - constexpr ArrayNonObjectTypeImpl(RawType raw, Rank) : raw_(raw) {} +template +struct LifecycleHelper + : public LifecycleLocalBase { + using Base = LifecycleLocalBase; + using Base::Base; +}; - template - constexpr ArrayNonObjectTypeImpl(Array&& invalid_arg) - : raw_(nullptr) { - static_assert(std::is_same_v, - "JNI Error: Invalid array declaration, use Array { type{}, " - "Rank{} }."); +// Shared implementation for global jobjects (jobject, jstring). +template +struct LifecycleGlobalBase { + static inline Span Promote(Span object) { + jobject ret = JniEnv::GetEnv()->NewGlobalRef(object); + JniEnv::GetEnv()->DeleteLocalRef(object); + + return static_cast(ret); } - template - constexpr bool operator==(const Array& rhs) const { - if constexpr (std::is_same_v) { - return (raw_ == rhs.raw_); - } - return false; + static inline void Delete(Span object) { + JniEnv::GetEnv()->DeleteGlobalRef(object); } - template - constexpr bool operator!=(const Array& rhs) const { - return !(*this == rhs); - } -}; + static inline Span NewReference(Span object) { + return static_cast(JniEnv::GetEnv()->NewGlobalRef(object)); + } +}; + +template +struct LifecycleHelper + : public LifecycleLocalBase { + using Base = LifecycleGlobalBase; + using Base::Base; +}; + +} // namespace jni + + +#include +#include +#include + +namespace jni { + +inline constexpr struct NoClassLoader { +} kNoClassLoaderSpecified; + +// This is just the list of classes we expect to be loadable from a class loader +// and its parent loader. +// +// Classes from different loaders are typically incompatible, but Class loaders +// delegate classes that they cannot directly load to their parent loaders, so +// classes attached to two different class loaders will still be compatible if +// they were loaded by a shared parent loader. +// +// To annotate a class in a function or field declaration, use `LoadedBy`. +template +class ClassLoader : public Object { + public: + const ParentLoader_ parent_loader_; + const std::tuple supported_classes_; + + explicit constexpr ClassLoader(const char* class_loader_name) + : Object(class_loader_name) {} -// Primitive array implementaiton. -template -struct ArrayImpl : public ArrayNonObjectTypeImpl, - ArrayTag> { - public: - using ArrayNonObjectTypeImpl::ArrayNonObjectTypeImpl; -}; + // Default classloader (no name needed). + explicit constexpr ClassLoader( + ParentLoader_ parent_loader, + SupportedClassSet supported_class_set) + __attribute__(( + enable_if(parent_loader == kDefaultClassLoader, + "You must provide a name for classloaders (except " + "kNullClassLoader and kDefaultClassLoader)"))) + : Object("__JNI_BIND_DEFAULT_CLASS_LOADER__"), + parent_loader_(parent_loader), + supported_classes_(supported_class_set.supported_classes_) {} -//////////////////////////////////////////////////////////////////////////////// -// Array Object Implementation. -//////////////////////////////////////////////////////////////////////////////// -template -struct ArrayImpl : public ArrayTag { - RawType raw_; + // Null classloader (no name needed). + explicit constexpr ClassLoader( + ParentLoader_ parent_loader, + SupportedClassSet supported_class_set) + __attribute__(( + enable_if(parent_loader == kNullClassLoader, + "You must provide a name for classloaders (except " + "kNullClassLoader and kDefaultClassLoader)"))) + : Object("__JNI_BIND_NULL_CLASS_LOADER__"), + parent_loader_(parent_loader), + supported_classes_(supported_class_set.supported_classes_) {} - constexpr ArrayImpl(RawType raw) : raw_(raw) {} + // TODO(b/143908983): Loaders should not be able to supply classes that their + // parents do. + explicit constexpr ClassLoader( + const char* class_loader_name, ParentLoader_ parent_loader, + SupportedClassSet supported_class_set) - template - constexpr ArrayImpl(RawType raw, Rank) : raw_(raw) {} + : Object(class_loader_name), + parent_loader_(parent_loader), + supported_classes_(supported_class_set.supported_classes_) {} - template - constexpr bool operator==(const Array& rhs) const { - if constexpr (std::is_same_v) { - return (raw_ == rhs.raw_); - } + bool constexpr operator==( + const ClassLoader& rhs) const { + return (*this).parent_loader_ == rhs.parent_loader_ && + (*this).supported_classes_ == rhs.supported_classes_; + } + template + bool constexpr operator==(const T& rhs) const { return false; } - - template - constexpr bool operator!=(const Array& rhs) const { + template + bool constexpr operator!=(const T& rhs) const { return !(*this == rhs); } -}; - -// This type correlates to those used in declarations, -// e.g. Field { Array { Array { jint {} } } }. -template -struct Array - : public ArrayImpl> { - constexpr Array() - : ArrayImpl>( - RawType{}) {} - - constexpr Array(RawType raw) - : ArrayImpl>(raw) {} - - template - constexpr Array(RawType raw, Rank) - : ArrayImpl>(raw) {} -}; -template -Array(RawType) -> Array; + template + constexpr std::size_t IdxOfClassHelper( + std::integer_sequence) const { + // std::max appears to be missing the initializer list overload in Bazel's + // implementation of clang. This should simply be std::max. + return metaprogramming::ModifiedMax( + {((std::get(supported_classes_) == class_v) + ? std::size_t{Is} + : metaprogramming::kNegativeOne)..., + metaprogramming::kNegativeOne}); + } -template -Array(RawType, Rank) -> Array; + // Returns the index for a given class within this set (any given class ref is + // defined by this index). + template + constexpr std::size_t IdxOfClass() const { + return IdxOfClassHelper( + std::make_integer_sequence()); + } -//////////////////////////////////////////////////////////////////////////////// -// Rank Utilities. -//////////////////////////////////////////////////////////////////////////////// -struct Rankifier { - template - struct Helper; + // Tests if a class is supported by this class loader (not ancestors). + template + constexpr bool SupportedByThisSet() const { + return IdxOfClass() != kClassNotInLoaderSetIdx; + } - template - struct Helper> { - static constexpr std::size_t kRank = kRank_; - }; + // Tests if a class is supported by this class loader (ancestors included). + template + constexpr bool SupportedDirectlyOrIndirectly() const { + return parent_loader_.template SupportedDirectlyOrIndirectly< + possibly_supported_class>() || + SupportedByThisSet(); + } - template - static inline constexpr std::size_t Rank(const ArrayT& maybe_array) { - if constexpr (kIsArrayType>) { - return Helper::kRank; - } else { - return 0; + // Returns the index for parent-most ancestor that supports a given class. + template + constexpr std::size_t IdxOfAncestor(std::size_t cur_idx = 0) const { + if (SupportedByThisSet() && + !parent_loader_.template SupportedDirectlyOrIndirectly< + possibly_supported_class, true>()) { + return cur_idx; } + return parent_loader_.template IdxOfAncestor( + cur_idx + 1); } }; -//////////////////////////////////////////////////////////////////////////////// -// Strip Utilities. -// Takes an native array like type, and emits the innermost type. -// e.g. {Array, Array{Rank<2>{}, int{}, Array{Rank<3>{}, int{}} } => int. -//////////////////////////////////////////////////////////////////////////////// -template -struct ArrayStrip { - using type = T; -}; +// Note: Null is chosen, not default, because LoadedBy requires a syntax like +// LoadedBy{ClassLoader{"kClass"}} (using the CTAD loader type below), but +// we want to prevent explicit usage of a default loader (as it makes no sense). +ClassLoader(const char*) + -> ClassLoader>; -template -using ArrayStrip_t = typename ArrayStrip::type; +template +ClassLoader(ParentLoader_ parent_loader, + SupportedClassSet supported_classes) + -> ClassLoader; -template -struct ArrayStrip> { - using type = T; -}; +template +ClassLoader(SupportedClassSet) + -> ClassLoader; -template -constexpr auto FullArrayStripV(const T& val) { - if constexpr (kIsArrayType>) { - return FullArrayStripV(val.raw_); +template +constexpr auto& GetAncestor(const T& loader) { + if constexpr (I == 0) { + return loader; } else { - return val; + return GetAncestor( + loader.parent_loader_); + } +} + +template +constexpr const auto& ParentLoaderForClass() { + if constexpr (!loader.template SupportedDirectlyOrIndirectly< + possibly_supported_class>()) { + return kNullClassLoader; + } else if constexpr (loader.template IdxOfAncestor< + possibly_supported_class>() != + kClassNotInLoaderSetIdx) { + return GetAncestor< + decltype(loader), + loader.template IdxOfAncestor()>(loader); + } else { + return kDefaultClassLoader; } } @@ -2061,22 +1963,117 @@ struct TypeIndexMask { template using Get = typename GetHelper, Ts...>::type; - template - struct SequenceGenerator {}; + template + struct SequenceGenerator {}; + + template + struct SequenceGenerator> { + using type = Get; + }; + + template + using type = typename SequenceGenerator::type; +}; + +template +using TypeTupFromIndexMask_t = + typename TypeIndexMask::template type; + +} // namespace jni::metaprogramming + +namespace jni::metaprogramming { + +template +struct RepeatString { + template + static constexpr std::string_view val = metaprogramming::StringConcatenate_v< + val_to_repeat, RepeatString::template val>; +}; + +template <> +struct RepeatString<0> { + template + static constexpr std::string_view val{""}; +}; + +template +static constexpr auto RepeatString_v{ + RepeatString::template val}; + +} // namespace jni::metaprogramming + +#include + +namespace jni::metaprogramming { + +struct Constants { + static constexpr std::string_view new_line = "\n"; + + static constexpr std::string_view left_bracket = "["; + static constexpr std::string_view right_bracket = "]"; + + static constexpr std::string_view left_parenthesis = "("; + static constexpr std::string_view right_parenthesis = ")"; + + static constexpr std::string_view hash = "#"; + static constexpr std::string_view comma = ","; + static constexpr std::string_view semi_colon = ";"; - template - struct SequenceGenerator> { - using type = Get; - }; + static constexpr std::string_view a = "a"; + static constexpr std::string_view b = "b"; + static constexpr std::string_view c = "c"; + static constexpr std::string_view d = "d"; + static constexpr std::string_view e = "e"; + static constexpr std::string_view f = "f"; + static constexpr std::string_view g = "g"; + static constexpr std::string_view h = "h"; + static constexpr std::string_view i = "i"; + static constexpr std::string_view j = "j"; + static constexpr std::string_view k = "k"; + static constexpr std::string_view l = "l"; + static constexpr std::string_view m = "m"; + static constexpr std::string_view n = "n"; + static constexpr std::string_view o = "o"; + static constexpr std::string_view p = "p"; + static constexpr std::string_view q = "q"; + static constexpr std::string_view r = "r"; + static constexpr std::string_view s = "s"; + static constexpr std::string_view t = "t"; + static constexpr std::string_view u = "u"; + static constexpr std::string_view v = "v"; + static constexpr std::string_view w = "w"; + static constexpr std::string_view x = "x"; + static constexpr std::string_view y = "y"; + static constexpr std::string_view z = "z"; - template - using type = typename SequenceGenerator::type; + static constexpr std::string_view A = "A"; + static constexpr std::string_view B = "B"; + static constexpr std::string_view C = "C"; + static constexpr std::string_view D = "D"; + static constexpr std::string_view E = "E"; + static constexpr std::string_view F = "F"; + static constexpr std::string_view G = "G"; + static constexpr std::string_view H = "H"; + static constexpr std::string_view I = "I"; + static constexpr std::string_view J = "J"; + static constexpr std::string_view K = "K"; + static constexpr std::string_view L = "L"; + static constexpr std::string_view M = "M"; + static constexpr std::string_view N = "N"; + static constexpr std::string_view O = "O"; + static constexpr std::string_view P = "P"; + static constexpr std::string_view Q = "Q"; + static constexpr std::string_view R = "R"; + static constexpr std::string_view S = "S"; + static constexpr std::string_view T = "T"; + static constexpr std::string_view U = "U"; + static constexpr std::string_view V = "V"; + static constexpr std::string_view W = "W"; + static constexpr std::string_view X = "X"; + static constexpr std::string_view Y = "Y"; + static constexpr std::string_view Z = "Z"; }; -template -using TypeTupFromIndexMask_t = - typename TypeIndexMask::template type; - } // namespace jni::metaprogramming #include @@ -2101,49 +2098,6 @@ struct NBit { } // namespace jni::metaprogramming -#include -#include -#include - -#define STR(x) []() { return x; } - -namespace jni::metaprogramming { - -template -using identifier_type = decltype(std::declval()()); - -constexpr std::size_t ConstexprStrlen(const char* str) { - return str[0] == 0 ? 0 : ConstexprStrlen(str + 1) + 1; -} - -struct StringAsTypeBase {}; - -// Represents a string by embedding a sequence of characters in a type. -template -struct StringAsType : StringAsTypeBase { - static constexpr char static_chars[] = {chars..., 0}; - static constexpr std::string_view chars_as_sv = {static_chars, - sizeof...(chars)}; -}; - -template -constexpr auto LambdaToStr(Identifier id, std::index_sequence) { - return StringAsType{}; -} - -template < - typename Identifier, - std::enable_if_t, const char*>, - int> = 0> -constexpr auto LambdaToStr(Identifier id) { - return LambdaToStr(id, std::make_index_sequence{}); -} - -template -using LambdaStringToType = decltype(LambdaToStr(std::declval())); - -} // namespace jni::metaprogramming - #include #include @@ -2172,276 +2126,203 @@ using Increment_t = typename Increment::template type; } // namespace jni::metaprogramming -#include -#include - -namespace jni::metaprogramming { - -// Metafunction that detects a partial specialisation for a Container. -template