mirror of
https://github.com/status-im/react-native.git
synced 2025-02-04 21:53:30 +00:00
Update fbjni from upstream
Reviewed By: @mkonicek Differential Revision: D2517281 fb-gh-sync-id: 9deeae6821f13394a2886d6d86781b4f563aadf6
This commit is contained in:
parent
e3e9be9efb
commit
23a16f60f8
@ -149,33 +149,36 @@ DEFINE_PRIMITIVE_METHODS(jdouble, Double)
|
||||
|
||||
|
||||
#define DEFINE_PRIMITIVE_ARRAY_UTILS(TYPE, NAME) \
|
||||
\
|
||||
local_ref<j ## TYPE ## Array> make_ ## TYPE ## _array(jsize size) { \
|
||||
auto array = internal::getEnv()->New ## NAME ## Array(size); \
|
||||
FACEBOOK_JNI_THROW_EXCEPTION_IF(!array); \
|
||||
return adopt_local(array); \
|
||||
} \
|
||||
\
|
||||
j ## TYPE* \
|
||||
JObjectWrapper<j ## TYPE ## Array>::getRegion(jsize start, jsize length, j ## TYPE* buf) { \
|
||||
local_ref<j ## TYPE ## Array> JArray ## NAME::newArray(size_t count) { \
|
||||
return make_ ## TYPE ## _array(count); \
|
||||
} \
|
||||
\
|
||||
j ## TYPE* JArray ## NAME::getRegion(jsize start, jsize length, j ## TYPE* buf) { \
|
||||
internal::getEnv()->Get ## NAME ## ArrayRegion(self(), start, length, buf); \
|
||||
FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \
|
||||
return buf; \
|
||||
} \
|
||||
\
|
||||
std::unique_ptr<j ## TYPE[]> \
|
||||
JObjectWrapper<j ## TYPE ## Array>::getRegion(jsize start, jsize length) { \
|
||||
std::unique_ptr<j ## TYPE[]> JArray ## NAME::getRegion(jsize start, jsize length) { \
|
||||
auto buf = std::unique_ptr<j ## TYPE[]>{new j ## TYPE[length]}; \
|
||||
internal::getEnv()->Get ## NAME ## ArrayRegion(self(), start, length, buf.get()); \
|
||||
FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \
|
||||
return buf; \
|
||||
} \
|
||||
\
|
||||
void JObjectWrapper<j ## TYPE ## Array>::setRegion(jsize start, jsize length, j ## TYPE* buf) { \
|
||||
void JArray ## NAME::setRegion(jsize start, jsize length, const j ## TYPE* buf) { \
|
||||
internal::getEnv()->Set ## NAME ## ArrayRegion(self(), start, length, buf); \
|
||||
FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \
|
||||
} \
|
||||
\
|
||||
PinnedPrimitiveArray<j ## TYPE> JObjectWrapper<j ## TYPE ## Array>::pin() { \
|
||||
PinnedPrimitiveArray<j ## TYPE> JArray ## NAME::pin() { \
|
||||
return PinnedPrimitiveArray<j ## TYPE>{self()}; \
|
||||
} \
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "../Environment.h"
|
||||
#include "../ALog.h"
|
||||
#include <jni/Environment.h>
|
||||
#include <jni/ALog.h>
|
||||
|
||||
/// @cond INTERNAL
|
||||
|
||||
|
@ -304,17 +304,9 @@ inline ElementProxy<T>::ElementProxy::operator local_ref<T> () {
|
||||
return target_->getElement(idx_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::string JObjectWrapper<jtypeArray<T>>::bareClassName() {
|
||||
// Use the initializer to strip off the leading and trailing character.
|
||||
const char* className = JObjectWrapper<T>::kJavaDescriptor;
|
||||
return std::string(className + 1, strlen(className) - 2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
local_ref<jtypeArray<T>> JObjectWrapper<jtypeArray<T>>::newArray(size_t size) {
|
||||
static auto elementClass = findClassStatic(
|
||||
JObjectWrapper<jtypeArray<T>>::bareClassName().c_str());
|
||||
static auto elementClass = findClassStatic(jtype_traits<T>::base_name().c_str());
|
||||
const auto env = internal::getEnv();
|
||||
auto rawArray = env->NewObjectArray(size, elementClass.get(), nullptr);
|
||||
FACEBOOK_JNI_THROW_EXCEPTION_IF(!rawArray);
|
||||
@ -435,15 +427,15 @@ DECLARE_PRIMITIVE_METHODS(jdouble, Double)
|
||||
#pragma pop_macro("DECLARE_PRIMITIVE_METHODS")
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline alias_ref<jclass> JavaClass<T>::javaClassStatic() {
|
||||
template<typename T, typename Base>
|
||||
inline alias_ref<jclass> JavaClass<T, Base>::javaClassStatic() {
|
||||
static auto cls = findClassStatic(
|
||||
std::string(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2).c_str());
|
||||
return cls;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline local_ref<jclass> JavaClass<T>::javaClassLocal() {
|
||||
template<typename T, typename Base>
|
||||
inline local_ref<jclass> JavaClass<T, Base>::javaClassLocal() {
|
||||
std::string className(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2);
|
||||
return findClassLocal(className.c_str());
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ class JObjectWrapper<jtypeArray<T>> : public JObjectWrapper<jobject> {
|
||||
public:
|
||||
static constexpr const char* kJavaDescriptor = nullptr;
|
||||
static std::string get_instantiated_java_descriptor() {
|
||||
return jtype_traits<T>::array_descriptor();
|
||||
return "[" + jtype_traits<T>::descriptor();
|
||||
};
|
||||
|
||||
using JObjectWrapper<jobject>::JObjectWrapper;
|
||||
@ -328,7 +328,6 @@ class JObjectWrapper<jtypeArray<T>> : public JObjectWrapper<jobject> {
|
||||
|
||||
private:
|
||||
jtypeArray<T> self() const noexcept;
|
||||
static std::string bareClassName();
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@ -366,7 +365,8 @@ class PinnedPrimitiveArray;
|
||||
|
||||
#pragma push_macro("DECLARE_PRIMITIVE_ARRAY_UTILS")
|
||||
#undef DECLARE_PRIMITIVE_ARRAY_UTILS
|
||||
#define DECLARE_PRIMITIVE_ARRAY_UTILS(TYPE, DESC) \
|
||||
#define DECLARE_PRIMITIVE_ARRAY_UTILS(TYPE, NAME, DESC) \
|
||||
\
|
||||
local_ref<j ## TYPE ## Array> make_ ## TYPE ## _array(jsize size); \
|
||||
\
|
||||
template<> class JObjectWrapper<j ## TYPE ## Array> : public JArray { \
|
||||
@ -375,25 +375,30 @@ template<> class JObjectWrapper<j ## TYPE ## Array> : public JArray { \
|
||||
\
|
||||
using JArray::JArray; \
|
||||
\
|
||||
static local_ref<j ## TYPE ## Array> newArray(size_t count); \
|
||||
\
|
||||
j ## TYPE* getRegion(jsize start, jsize length, j ## TYPE* buf); \
|
||||
std::unique_ptr<j ## TYPE[]> getRegion(jsize start, jsize length); \
|
||||
void setRegion(jsize start, jsize length, j ## TYPE* buf); \
|
||||
void setRegion(jsize start, jsize length, const j ## TYPE* buf); \
|
||||
PinnedPrimitiveArray<j ## TYPE> pin(); \
|
||||
\
|
||||
private: \
|
||||
j ## TYPE ## Array self() const noexcept { \
|
||||
return static_cast<j ## TYPE ## Array>(this_); \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
using JArray ## NAME = JObjectWrapper<j ## TYPE ## Array> \
|
||||
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(boolean, "Z");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(byte, "B");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(char, "C");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(short, "S");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(int, "I");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(long, "J");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(float, "F");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(double, "D");
|
||||
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(boolean, Boolean, "Z");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(byte, Byte, "B");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(char, Char, "C");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(short, Short, "S");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(int, Int, "I");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(long, Long, "J");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(float, Float, "F");
|
||||
DECLARE_PRIMITIVE_ARRAY_UTILS(double, Double, "D");
|
||||
|
||||
#pragma pop_macro("DECLARE_PRIMITIVE_ARRAY_UTILS")
|
||||
|
||||
@ -444,6 +449,16 @@ class PinnedPrimitiveArray {
|
||||
};
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
class BaseJavaClass {
|
||||
public:
|
||||
typedef _jobject _javaobject;
|
||||
typedef _javaobject* javaobject;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Together, these classes allow convenient use of any class with the fbjni
|
||||
// helpers. To use:
|
||||
//
|
||||
@ -453,11 +468,11 @@ class PinnedPrimitiveArray {
|
||||
//
|
||||
// alias_ref<MyClass::javaobject> myClass = foo();
|
||||
|
||||
template <typename T>
|
||||
template <typename T, typename Base = detail::BaseJavaClass>
|
||||
class JavaClass {
|
||||
public:
|
||||
// JNI pattern for jobject assignable pointer
|
||||
struct _javaobject : public _jobject {
|
||||
struct _javaobject : public Base::_javaobject {
|
||||
typedef T javaClass;
|
||||
};
|
||||
typedef _javaobject* javaobject;
|
||||
@ -478,6 +493,13 @@ public:
|
||||
std::remove_pointer<T>::type::javaClass::kJavaDescriptor;
|
||||
|
||||
using JObjectWrapper<jobject>::JObjectWrapper;
|
||||
|
||||
template<typename U>
|
||||
JObjectWrapper(const JObjectWrapper<U>& w)
|
||||
: JObjectWrapper<jobject>(w) {
|
||||
static_assert(std::is_convertible<U, T>::value,
|
||||
"U must be convertible to T");
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "CoreClasses.h"
|
||||
#include "../ALog.h"
|
||||
#include <jni/ALog.h>
|
||||
|
||||
#include <fb/assert.h>
|
||||
|
||||
|
@ -17,13 +17,13 @@
|
||||
namespace facebook {
|
||||
namespace jni {
|
||||
|
||||
class BaseHybridClass {
|
||||
namespace detail {
|
||||
|
||||
class BaseHybridClass : public BaseJavaClass {
|
||||
public:
|
||||
virtual ~BaseHybridClass() {}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct HybridData : public JavaClass<HybridData> {
|
||||
constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridData;";
|
||||
};
|
||||
@ -83,6 +83,21 @@ struct Convert<const char*> {
|
||||
}
|
||||
};
|
||||
|
||||
// jboolean is an unsigned char, not a bool. Allow it to work either way.
|
||||
template<>
|
||||
struct Convert<bool> {
|
||||
typedef jboolean jniType;
|
||||
static bool fromJni(jniType t) {
|
||||
return t;
|
||||
}
|
||||
static jniType toJniRet(bool t) {
|
||||
return t;
|
||||
}
|
||||
static jniType toCall(bool t) {
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
// convert to alias_ref<T> from T
|
||||
template <typename T>
|
||||
struct Convert<alias_ref<T>> {
|
||||
@ -145,17 +160,28 @@ struct jstring_holder {
|
||||
operator jstring() { return s_.get(); }
|
||||
};
|
||||
|
||||
}
|
||||
template <typename T, typename Enabled = void>
|
||||
struct HybridRoot {};
|
||||
|
||||
template <typename T>
|
||||
class HybridClass : public BaseHybridClass
|
||||
, public JavaClass<T> {
|
||||
struct HybridRoot<T,
|
||||
typename std::enable_if<!std::is_base_of<BaseHybridClass, T>::value>::type>
|
||||
: public BaseHybridClass {};
|
||||
|
||||
}
|
||||
|
||||
template <typename T, typename Base = detail::BaseHybridClass>
|
||||
class HybridClass : public Base
|
||||
, public detail::HybridRoot<Base>
|
||||
, public JavaClass<T, Base> {
|
||||
public:
|
||||
typedef detail::HybridData::javaobject jhybriddata;
|
||||
typedef typename JavaClass<T>::javaobject jhybridobject;
|
||||
typedef typename JavaClass<T, Base>::javaobject jhybridobject;
|
||||
|
||||
// I'm not sure why I need this, but I get errors without it.
|
||||
using JavaClass<T>::javaClassStatic;
|
||||
using JavaClass<T, Base>::javaClassStatic;
|
||||
using JavaClass<T, Base>::javaClassLocal;
|
||||
using JavaClass<T, Base>::javaobject;
|
||||
typedef typename JavaClass<T, Base>::_javaobject _javaobject;
|
||||
|
||||
protected:
|
||||
typedef HybridClass HybridBase;
|
||||
@ -163,7 +189,7 @@ protected:
|
||||
// This ensures that a C++ hybrid part cannot be created on its own
|
||||
// by default. If a hybrid wants to enable this, it can provide its
|
||||
// own public ctor, or change the accessibility of this to public.
|
||||
HybridClass() = default;
|
||||
using Base::Base;
|
||||
|
||||
static void registerHybrid(std::initializer_list<NativeMethod> methods) {
|
||||
javaClassStatic()->registerNatives(methods);
|
||||
|
@ -153,15 +153,23 @@ inline local_ref<T*> JNonvirtualMethod<T*(Args...)>::operator()(
|
||||
/// support for your user defined type.
|
||||
template<typename T>
|
||||
struct jtype_traits {
|
||||
// The jni type signature (described at
|
||||
// http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html).
|
||||
static std::string descriptor() {
|
||||
if (JObjectWrapper<T>::kJavaDescriptor != nullptr) {
|
||||
return std::string{JObjectWrapper<T>::kJavaDescriptor};
|
||||
};
|
||||
return JObjectWrapper<T>::get_instantiated_java_descriptor();
|
||||
static const auto descriptor = JObjectWrapper<T>::kJavaDescriptor != nullptr ?
|
||||
std::string{JObjectWrapper<T>::kJavaDescriptor} :
|
||||
JObjectWrapper<T>::get_instantiated_java_descriptor();
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
static std::string array_descriptor() {
|
||||
return '[' + std::string{JObjectWrapper<T>::kJavaDescriptor};
|
||||
// The signature used for class lookups. See
|
||||
// http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getName().
|
||||
static std::string base_name() {
|
||||
if (JObjectWrapper<T>::kJavaDescriptor != nullptr) {
|
||||
std::string base_name = JObjectWrapper<T>::kJavaDescriptor;
|
||||
return base_name.substr(1, base_name.size() - 2);
|
||||
}
|
||||
return JObjectWrapper<T>::get_instantiated_java_descriptor();
|
||||
}
|
||||
};
|
||||
|
||||
@ -172,10 +180,12 @@ struct jtype_traits {
|
||||
template<> \
|
||||
struct jtype_traits<TYPE> { \
|
||||
static std::string descriptor() { return std::string{#DSC}; } \
|
||||
static std::string base_name() { return descriptor(); } \
|
||||
}; \
|
||||
template<> \
|
||||
struct jtype_traits<TYPE ## Array> { \
|
||||
static std::string descriptor() { return std::string{"[" #DSC}; } \
|
||||
static std::string base_name() { return descriptor(); } \
|
||||
};
|
||||
|
||||
// There is no voidArray, handle that without the macro.
|
||||
|
@ -129,6 +129,12 @@ inline base_owned_ref<T, Alloc>::base_owned_ref(
|
||||
: object_{Alloc{}.newReference(other.getPlainJniReference())}
|
||||
{}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
template<typename U>
|
||||
inline base_owned_ref<T, Alloc>::base_owned_ref(const base_owned_ref<U, Alloc>& other)
|
||||
: object_{Alloc{}.newReference(other.getPlainJniReference())}
|
||||
{}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
inline facebook::jni::base_owned_ref<T, Alloc>::base_owned_ref(
|
||||
T reference) noexcept
|
||||
@ -148,6 +154,17 @@ inline base_owned_ref<T, Alloc>::base_owned_ref(
|
||||
other.object_.set(nullptr);
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
template<typename U>
|
||||
base_owned_ref<T, Alloc>::base_owned_ref(base_owned_ref<U, Alloc>&& other) noexcept
|
||||
: object_{other.object_} {
|
||||
internal::dbglog("New move from ref=%p other=%p", other.getPlainJniReference(), &other);
|
||||
internal::dbglog("New move to ref=%p this=%p", getPlainJniReference(), this);
|
||||
// JObjectWrapper is a simple type and does not support move semantics so we explicitly
|
||||
// clear other
|
||||
other.object_.set(nullptr);
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
inline base_owned_ref<T, Alloc>::~base_owned_ref() noexcept {
|
||||
reset();
|
||||
|
@ -238,9 +238,13 @@ class base_owned_ref {
|
||||
|
||||
/// Copy constructor (note creates a new reference)
|
||||
base_owned_ref(const base_owned_ref& other);
|
||||
template<typename U>
|
||||
base_owned_ref(const base_owned_ref<U, Alloc>& other);
|
||||
|
||||
/// Transfers ownership of an underlying reference from one unique reference to another
|
||||
base_owned_ref(base_owned_ref&& other) noexcept;
|
||||
template<typename U>
|
||||
base_owned_ref(base_owned_ref<U, Alloc>&& other) noexcept;
|
||||
|
||||
/// The delete the underlying reference if applicable
|
||||
~base_owned_ref() noexcept;
|
||||
@ -259,6 +263,9 @@ class base_owned_ref {
|
||||
|
||||
|
||||
friend T jni::getPlainJniReference<>(const base_owned_ref& ref);
|
||||
|
||||
template<typename U, typename UAlloc>
|
||||
friend class base_owned_ref;
|
||||
};
|
||||
|
||||
|
||||
@ -279,6 +286,8 @@ class weak_ref : public base_owned_ref<T, WeakGlobalReferenceAllocator> {
|
||||
using PlainJniType = T;
|
||||
using Allocator = WeakGlobalReferenceAllocator;
|
||||
|
||||
// This inherits non-default, non-copy, non-move ctors.
|
||||
using base_owned_ref<T, Allocator>::base_owned_ref;
|
||||
|
||||
/// Create a null reference
|
||||
constexpr weak_ref() noexcept
|
||||
@ -343,10 +352,11 @@ class basic_strong_ref : public base_owned_ref<T, Alloc> {
|
||||
using PlainJniType = T;
|
||||
using Allocator = Alloc;
|
||||
|
||||
// This inherits non-default, non-copy, non-move ctors.
|
||||
using base_owned_ref<T, Alloc>::base_owned_ref;
|
||||
using base_owned_ref<T, Alloc>::release;
|
||||
using base_owned_ref<T, Alloc>::reset;
|
||||
|
||||
|
||||
/// Create a null reference
|
||||
constexpr basic_strong_ref() noexcept
|
||||
: base_owned_ref<T, Alloc>{} {}
|
||||
@ -363,7 +373,6 @@ class basic_strong_ref : public base_owned_ref<T, Alloc> {
|
||||
basic_strong_ref(basic_strong_ref&& other) noexcept
|
||||
: base_owned_ref<T, Alloc>{std::move(other)} {}
|
||||
|
||||
|
||||
/// Assignment operator (note creates a new reference)
|
||||
basic_strong_ref& operator=(const basic_strong_ref& other);
|
||||
|
||||
|
@ -32,6 +32,8 @@ struct Convert<
|
||||
// There is no automatic return conversion for objects.
|
||||
};
|
||||
|
||||
// registration wrapper for legacy JNI-style functions
|
||||
|
||||
template<typename F, F func, typename C, typename... Args>
|
||||
inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(JNIEnv*, C, Args... args)) {
|
||||
struct funcWrapper {
|
||||
@ -50,25 +52,6 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(JNIEnv*, C, Args...
|
||||
return reinterpret_cast<NativeMethodWrapper*>(&(funcWrapper::call));
|
||||
}
|
||||
|
||||
template<typename F, F func, typename C, typename... Args>
|
||||
inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(C, Args... args)) {
|
||||
struct funcWrapper {
|
||||
static void call(JNIEnv* env, jobject obj, Args... args) {
|
||||
// Note that if func was declared noexcept, then both gcc and clang are smart
|
||||
// enough to elide the try/catch.
|
||||
try {
|
||||
(void) env;
|
||||
(*func)(static_cast<C>(obj), args...);
|
||||
} catch (...) {
|
||||
translatePendingCppExceptionToJavaException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This intentionally erases the real type; JNI will do it anyway
|
||||
return reinterpret_cast<NativeMethodWrapper*>(&(funcWrapper::call));
|
||||
}
|
||||
|
||||
template<typename F, F func, typename C, typename R, typename... Args>
|
||||
inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... args)) {
|
||||
struct funcWrapper {
|
||||
@ -86,6 +69,8 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... arg
|
||||
return reinterpret_cast<NativeMethodWrapper*>(&(funcWrapper::call));
|
||||
}
|
||||
|
||||
// registration wrappers for functions, with autoconversion of arguments.
|
||||
|
||||
template<typename F, F func, typename C, typename... Args>
|
||||
inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(alias_ref<C>, Args... args)) {
|
||||
struct funcWrapper {
|
||||
@ -124,6 +109,8 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(alias_ref<C>, Args... a
|
||||
return reinterpret_cast<NativeMethodWrapper*>(&(funcWrapper::call));
|
||||
}
|
||||
|
||||
// registration wrappers for non-static methods, with autoconvertion of arguments.
|
||||
|
||||
template<typename M, M method, typename C, typename... Args>
|
||||
inline NativeMethodWrapper* exceptionWrapJNIMethod(void (C::*method0)(Args... args)) {
|
||||
struct funcWrapper {
|
||||
|
Loading…
x
Reference in New Issue
Block a user