C ++ callbacks back to Java

I encoded the following for numerical integration in C ++:

// integrate.h: #ifdef BUILDING_DLL #define DLL_MACRO __declspec(dllexport) #else #define DLL_MACRO __declspec(dllimport) #endif extern "C" { typedef double (*Function1VariablePtr)(double x); double DLL_MACRO integrate(Function1VariablePtr function, double min, double max); } // integrate.cpp: #include "integrate.h" double integrate(Function1VariablePtr function, double min, double max) { const int n = 1001; double dx = (max - min)/(1.0*(n - 1)); double sum = 0.0; for(int i = 0; i < n; i++) { double xmid = min + (i + 0.5)*dx; sum += function(xmid)*dx; } return sum; } 

Now I want to call this function from Java. I found how I can implement the integration directly in the JNI bridge code:

 // C++ "bridge" code to from/to Java: JNIEXPORT jdouble JNICALL Java_IntegrateJApp_JIntegrate(JNIEnv *jnienv, jclass jc, jdouble xmin, jdouble xmax) { jmethodID mid = jnienv->GetStaticMethodID(jc, "Function1D","(D)D"); if (mid == 0) return - 1.0; const int n = 1001; double dx = (xmax - xmin)/(1.0*(n - 1)); double sum = 0.0; for(int i = 0; i < n; i++) { double xmid = xmin + (i + 0.5)*dx; double f = jnienv->CallStaticDoubleMethod(jc, mid, xmid); sum += f*dx; } return sum; } // Java code calling "bridge": class IntegrateJApp { public static void main(String[] args) { System.loadLibrary("JIntegrate"); double I = JIntegrate(0.0, 2*Math.PI); System.out.println( Double.toString(I) ); } public static double Function1D(double x) { return Math.sin(x); } public static native double JIntegrate(double xmin, double xmax); } 

However, I do not want to implement numerical integration directly in the C ++ bridge code, but rather call the code in the integrate.cpp file.

How can I do it? The integrate () function inside integrate.cpp requires a pointer to a function that I don't have. Is there a way to get a function pointer inside Java using JNI?

Thanks in advance for any answers!

+6
source share
2 answers

One way to do this is to use a pointer to a member function and change the signature of the integration function.

See below for a general idea:

functionwrapper.h

Declare a function wrapper class.

 class FunctionWrapper { public: typedef double (FunctionWrapper::*Function1VariablePtr)(double x); FunctionWrapper(JNIEnv*, jclass); double compute(double x); }; 

integrate.h

Eliminate the previous pointer to the typedef function and change the signature of the method to include the wrapper object and a pointer to its member function.

 #include "functionwrapper.h" extern "C" { double DLL_MACRO integrate(FunctionWrapper*, FunctionWrapper::Function1VariablePtr, double min, double max); } 

integrate.cpp

Change a function call to a member function call.

 #include "integrate.h" double integrate(FunctionWrapper* wrapper, FunctionWrapper::Function1VariablePtr function, double min, double max) { // ... sum += (wrapper->*function)(xmid)*dx; // ... } 

refund amount; }

JNI code "bridge":

Define a shell code and define a function that performs the actual call. Call the integrate function directly from the JNI function:

 #include "functionwrapper.h" FunctionWrapper::FunctionWrapper(JNIEnv *jnienv, jclass jc) : m_jnienv(jnienv), m_jc(jc) { m_method= jnienv->GetStaticMethodID(jc, "Function1D","(D)D"); } double FunctionWrapper:compute(double x) { return m_jnienv->CallStaticDoubleMethod(m_jc, m_method, x);; } // C++ "bridge" code to from/to Java: JNIEXPORT jdouble JNICALL Java_IntegrateJApp_JIntegrate(JNIEnv *jnienv, jclass jc, jdouble xmin, jdouble xmax) { FunctionWrapper wrapper(jnienv, jc); return integrate(&wrapper, &FunctionWrapper::compute, 2, 3); } 
+2
source

You need to create a DLL with C ++ code and call it from JNI

Download the DLL:

 System.loadLibrary("PATH\\yourdllname.dll"); 

Link to your function

 public static native integrate(parameters); 
+3
source

Source: https://habr.com/ru/post/890745/


All Articles