Skip to content

Commit

Permalink
Support arguments for native peer initializers
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed Mar 3, 2016
1 parent a2e71d9 commit 9ce08b1
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 21 deletions.
4 changes: 2 additions & 2 deletions examples/native_peer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*)
{
static constexpr auto Name() { return "Calculator"; }

Calculator() { std::cout << "Native peer initialized" << std::endl; }
Calculator(JNIEnv&) { std::cout << "Native peer initialized" << std::endl; }
~Calculator() { std::cout << "Native peer finalized" << std::endl; }

jni::jlong Add(jni::JNIEnv&, jni::jlong a, jni::jlong b) { return a + b; }
Expand All @@ -20,7 +20,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*)
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)

jni::RegisterNativePeer<Calculator>(env, jni::Class<Calculator>::Find(env), "peer",
std::make_unique<Calculator>,
std::make_unique<Calculator, JNIEnv&>,
"initialize",
"finalize",
METHOD(&Calculator::Add, "add"),
Expand Down
59 changes: 41 additions & 18 deletions include/jni/native_method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,33 +285,56 @@ namespace jni
RegisterNatives(env, clazz, methods.template operator()<Peer>(field)...);
}

template < class Peer, class TagType, class Constructor, class... Methods >
template < class Peer, class TagType, class >
struct NativePeerHelper;

template < class Peer, class TagType, class... Args >
struct NativePeerHelper< Peer, TagType, std::unique_ptr<Peer> (JNIEnv&, Args...) >
{
using UniquePeer = std::unique_ptr<Peer>;
using Initializer = UniquePeer (JNIEnv&, Args...);

auto MakeInitializer(const Field<TagType, jlong>& field, const char* name, Initializer* initializer) const
{
auto wrapper = [field, initializer] (JNIEnv& e, Object<TagType> obj, std::decay_t<Args>... args)
{
UniquePeer previous(reinterpret_cast<Peer*>(obj.Get(e, field)));
UniquePeer instance(initializer(e, std::move(args)...));
obj.Set(e, field, reinterpret_cast<jlong>(instance.get()));
instance.release();
};

return MakeNativeMethod(name, wrapper);
}

auto MakeFinalizer(const Field<TagType, jlong>& field, const char* name) const
{
auto wrapper = [field] (JNIEnv& e, Object<TagType> obj)
{
UniquePeer instance(reinterpret_cast<Peer*>(obj.Get(e, field)));
if (instance) obj.Set(e, field, jlong(0));
instance.reset();
};

return MakeNativeMethod(name, wrapper);
}
};

template < class Peer, class TagType, class Initializer, class... Methods >
void RegisterNativePeer(JNIEnv& env, const Class<TagType>& clazz, const char* fieldName,
Constructor constructor,
Initializer initialize,
const char* initializeMethodName,
const char* finalizeMethodName,
Methods&&... methods)
{
static Field<TagType, jlong> field { env, clazz, fieldName };

auto finalize = [] (JNIEnv& e, Object<TagType> obj)
{
std::unique_ptr<Peer> instance(reinterpret_cast<Peer*>(obj.Get(e, field)));
if (instance) obj.Set(e, field, jlong(0));
instance.reset();
};

auto initialize = [constructor] (JNIEnv& e, Object<TagType> obj)
{
std::unique_ptr<Peer> previous(reinterpret_cast<Peer*>(obj.Get(e, field)));
std::unique_ptr<Peer> instance(constructor());
obj.Set(e, field, reinterpret_cast<jlong>(instance.get()));
instance.release();
};
using InitializerMethodType = typename NativeMethodTraits<Initializer>::Type;
NativePeerHelper<Peer, TagType, InitializerMethodType> helper;

RegisterNatives(env, clazz,
MakeNativeMethod(initializeMethodName, initialize),
MakeNativeMethod(finalizeMethodName, finalize),
helper.MakeInitializer(field, initializeMethodName, initialize),
helper.MakeFinalizer(field, finalizeMethodName),
methods.template operator()<Peer>(field)...);
}
}
16 changes: 15 additions & 1 deletion test/high_level.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace

struct Peer
{
Peer() {}
Peer(jni::JNIEnv&, jni::jboolean) {}
jni::jboolean True(jni::JNIEnv&) { return jni::jni_true; }
jni::jboolean False(jni::JNIEnv&) { return jni::jni_false; }
void Void(jni::JNIEnv&, jni::jboolean b) { assert(b == jni::jni_true); }
Expand Down Expand Up @@ -746,7 +748,7 @@ int main()
env.functions->RegisterNatives = [] (JNIEnv*, jclass, const JNINativeMethod* m, jint len) -> jint
{
assert(len == 6);
std::copy(m, m + 6, methods);
std::copy(m, m + len, methods);
return JNI_OK;
};

Expand All @@ -767,5 +769,17 @@ int main()
assert(reinterpret_cast<jboolean (*)(JNIEnv&, jobject)>(methods[1].fnPtr)(env, jni::Unwrap(objectValue.Ptr())) == jni::jni_false);
reinterpret_cast<void (*)(JNIEnv&, jobject, jboolean)>(methods[2].fnPtr)(env, jni::Unwrap(objectValue.Ptr()), jni::jni_true);

jni::RegisterNativePeer<Peer>(env, testClass, "peer",
std::make_unique<Peer, jni::JNIEnv&, jni::jboolean>,
"initialize",
"finalize",
METHOD("true", &Peer::True),
METHOD("false", &Peer::False),
METHOD("void", &Peer::Void),
jni::MakeNativePeerMethod("static", [] (JNIEnv&, Peer&) {}));

assert(methods[0].name == std::string("initialize"));
assert(methods[1].name == std::string("finalize"));

return 0;
}

0 comments on commit 9ce08b1

Please sign in to comment.