"tests/git@developer.sourcefind.cn:renzhc/diffusers_dcu.git" did not exist on "8ae8008b0d096d2b093f5b7c660715a93f74f17a"
Commit cf24f025 authored by Davis King's avatar Davis King
Browse files

Added an object that lets you hold a copyable reference to a java array. Also

renamed the objects and generally improved documentation.
parent fa5c666b
......@@ -119,8 +119,26 @@ FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/swig.i
%module global
%{
#include \"swig_api.h\"
#include <exception>
#include <stdexcept>
static JavaVM *cached_jvm = 0;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
cached_jvm = jvm;
return JNI_VERSION_1_6;
}
static JNIEnv * JNI_GetEnv() {
JNIEnv *env;
jint rc = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
if (rc == JNI_EDETACHED)
throw std::runtime_error(\"current thread not attached\");
if (rc == JNI_EVERSION)
throw std::runtime_error(\"jni version not supported\");
return env;
}
#include \"swig_api.h\"
%}
// Convert all C++ exceptions into java.lang.Exception
......
This diff is collapsed.
// Copyright (C) 2017 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_SWIG_JVECTOR_H_
#define DLIB_SWIG_JVECTOR_H_
/*
This file defines two special classes, jvector and jvector_crit. Both of them have the
interface defined by jvector_base, that is, the interface of a simple array object like
std::vector (except without any ability to be resized). These classes are simple
interfaces to java native arrays. So for example, suppose you had an array of int in
java and you wanted to pass it to C++. You could create a C++ function like this:
void my_function(const jvector<int>& array);
and then within java you could call it with code like this:
int[] array = new int[100];
my_function(array);
and it will work just like you would expect. The jvector<int> will usually result in
the JVM doing a copy in the background. However, you can also declare your function
like this:
void my_function(const jvector_crit<int>& array);
and still call it the same way in java, however, using jvector_crit<int> will usually
not result in any copying, and is therefore very fast. jvector_crit uses the JNI
routine GetPrimitiveArrayCritical() to get a lock on the java memory underlying the
array. So it will probably prevent the garbage collector from running while your
function is executing. The JNI documentation is somewhat vague on the limitations of
GetPrimitiveArrayCritical(), saying only that you shouldn't hold the lock on the array
for "an extended period" or call back into the JVM. Deciding whether or not this
matters in your application is left as an exercise for the reader.
There are two ways you can declare your methods. Taking a const reference or a
non-const reference. E.g.:
void my_function(const jvector<int>& array);
void my_function(jvector<int>& array);
The non-const version allows you to modify the contents of the array and the
modifications will be visible to java, as you would expect.
You can also of course use functions taking many arguments, as is normally the case
with SWIG. Finally, jvector works with the following primitive types:
- int16_t
- int32_t
- int64_t
- char (corresponding to java byte)
- float
- double
*/
// ----------------------------------------------------------------------------------------
template <typename T>
class jvector_base
{
public:
jvector_base() = default;
size_t size() const { return sz; }
T* data() { return pdata; }
const T* data() const { return pdata; }
T* begin() { return pdata; }
T* end() { return pdata+sz; }
const T* begin() const { return pdata; }
const T* end() const { return pdata+sz; }
T& operator[](size_t i) { return pdata[i]; }
const T& operator[](size_t i) const { return pdata[i]; }
protected:
T* pdata = nullptr;
size_t sz = 0;
private:
// this object is non-copyable
jvector_base(const jvector_base&);
jvector_base& operator=(const jvector_base&);
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename T> class jvector;
#define JVECTOR_CLASS_SPEC(ctype, type, Type) \
template <> class jvector<ctype> : public jvector_base<ctype> \
{ \
public: \
~jvector() { clear(); } \
void reset(JNIEnv* jenv_, j##type##Array arr, bool mightBeModified_) { \
clear(); \
jenv = jenv_; \
oldArr = arr; \
pdata = (ctype*)jenv->Get##Type##ArrayElements(arr, 0); \
sz = jenv->GetArrayLength(arr); \
mightBeModified = mightBeModified_; \
} \
private: \
void clear() { \
if (pdata) { \
jenv->Release##Type##ArrayElements(oldArr, (j##type*)pdata, mightBeModified?0:JNI_ABORT); \
pdata = nullptr; \
} \
} \
JNIEnv* jenv = nullptr; \
j##type##Array oldArr; \
bool mightBeModified; \
};
JVECTOR_CLASS_SPEC(int16_t,short, Short)
JVECTOR_CLASS_SPEC(int32_t,int, Int)
JVECTOR_CLASS_SPEC(int64_t,long, Long)
JVECTOR_CLASS_SPEC(char,byte, Byte)
JVECTOR_CLASS_SPEC(float,float, Float)
JVECTOR_CLASS_SPEC(double,double, Double)
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename T, typename JARR>
class jvector_crit_base
{
public:
jvector_crit_base() = default;
size_t size() const { return sz; }
T* data() { return pdata; }
const T* data() const { return pdata; }
T* begin() { return pdata; }
T* end() { return pdata+sz; }
const T* begin() const { return pdata; }
const T* end() const { return pdata+sz; }
T& operator[](size_t i) { return pdata[i]; }
const T& operator[](size_t i) const { return pdata[i]; }
~jvector_crit_base() { clear(); }
void reset(JNIEnv* jenv_, JARR arr, bool mightBeModified_)
{
clear();
jenv = jenv_;
oldArr = arr;
pdata = (T*)jenv->GetPrimitiveArrayCritical(arr, 0);
sz = jenv->GetArrayLength(arr);
mightBeModified = mightBeModified_;
}
private:
void clear()
{
if (pdata) {
jenv->ReleasePrimitiveArrayCritical(oldArr, pdata, mightBeModified?0:JNI_ABORT);
pdata = nullptr;
}
}
// this object is non-copyable
jvector_crit_base(const jvector_crit_base&);
jvector_crit_base& operator=(const jvector_crit_base&);
T* pdata = nullptr;
size_t sz = 0;
JNIEnv* jenv = nullptr;
JARR oldArr;
bool mightBeModified;
};
template <typename T> class jvector_crit;
template <> class jvector_crit<int16_t> : public jvector_crit_base<int16_t,jshortArray> {};
template <> class jvector_crit<int32_t> : public jvector_crit_base<int32_t,jintArray> {};
template <> class jvector_crit<int64_t> : public jvector_crit_base<int64_t,jlongArray> {};
template <> class jvector_crit<char> : public jvector_crit_base<char,jbyteArray> {};
template <> class jvector_crit<float> : public jvector_crit_base<float,jfloatArray> {};
template <> class jvector_crit<double> : public jvector_crit_base<double,jdoubleArray> {};
// ----------------------------------------------------------------------------------------
// Define SWIG typemaps so SWIG will know what to do with the jvector and jvector_crit
// objects.
#ifdef SWIG
%define tostring(token)
#token
%enddef
%define define_jvector_converion(type, java_type)
// Define array conversions for non-const arrays
%typemap(jtype) (jvector<type>&) "java_type[]"
%typemap(jstype) (jvector<type>&) "java_type[]"
%typemap(jni) (jvector<type>&) tostring(j##java_type##Array)
%typemap(javain) (jvector<type>&) "$javainput"
%typemap(arginit) (jvector<type>&) { $1 = &temp$argnum; }
%typemap(in) (jvector<type>&) (jvector<type> temp) { $1->reset(jenv, $input, true); }
%typemap(jtype) (const jvector<type>&) "java_type[]"
%typemap(jstype) (const jvector<type>&) "java_type[]"
%typemap(jni) (const jvector<type>&) tostring(j##java_type##Array)
%typemap(javain) (const jvector<type>&) "$javainput"
%typemap(arginit) (const jvector<type>&) { $1 = &temp$argnum; }
%typemap(in) (const jvector<type>&) (jvector<type> temp) { $1->reset(jenv, $input, false); }
%enddef
define_jvector_converion(int16_t,short)
define_jvector_converion(int32_t,int)
define_jvector_converion(int64_t,long)
define_jvector_converion(char,byte)
define_jvector_converion(float,float)
define_jvector_converion(double,double)
%define define_jvector_crit_converion(type, java_type)
// Define array conversions for non-const arrays
%typemap(jtype) (jvector_crit<type>&) "java_type[]"
%typemap(jstype) (jvector_crit<type>&) "java_type[]"
%typemap(jni) (jvector_crit<type>&) tostring(j##java_type##Array)
%typemap(javain) (jvector_crit<type>&) "$javainput"
%typemap(arginit) (jvector_crit<type>&) { $1 = &temp$argnum; }
%typemap(in) (jvector_crit<type>&) (jvector_crit<type> temp) { $1->reset(jenv, $input, true); }
%typemap(jtype) (const jvector_crit<type>&) "java_type[]"
%typemap(jstype) (const jvector_crit<type>&) "java_type[]"
%typemap(jni) (const jvector_crit<type>&) tostring(j##java_type##Array)
%typemap(javain) (const jvector_crit<type>&) "$javainput"
%typemap(arginit) (const jvector_crit<type>&) { $1 = &temp$argnum; }
%typemap(in) (const jvector_crit<type>&) (jvector_crit<type> temp) { $1->reset(jenv, $input, false); }
%enddef
define_jvector_crit_converion(int16_t,short)
define_jvector_crit_converion(int32_t,int)
define_jvector_crit_converion(int64_t,long)
define_jvector_crit_converion(char,byte)
define_jvector_crit_converion(float,float)
define_jvector_crit_converion(double,double)
#endif // SWIG
#endif // DLIB_SWIG_JVECTOR_H_
#ifndef EXAMPLE_SWIG_ApI_H_
#define EXAMPLE_SWIG_ApI_H_
// This file is essentially a small unit test for the swig cmake scripts and the jvector
// This file is essentially a small unit test for the swig cmake scripts and the java array
// classes. All it does it define a few simple functions for writing to and summing
// arrays. The swig_test.java file then calls these C++ functions and checks if they work
// correctly.
// Let's use the jvector, a tool for efficiently binding java native arrays to C++ function
// arguments. You do this by putting this pair of include statements in your swig_api.h
// file. Then after that you can use the jvector and jvector_crit classes.
#include "jvector.h"
// Let's use java_array.h, a tool for efficiently binding java native arrays to C++
// function arguments. You do this by putting this pair of include statements in your
// swig_api.h file. Then after that you can use the java::array, java::array_view, and
// java::array_view_crit classes.
#include "java_array.h"
#ifdef SWIG
%include "jvector.h"
%include "java_array.h"
#endif
// ----------------------------------------------------------------------------------------
using namespace java;
// SWIG can't expose templated functions to java. We declare these here as helper
// functions to make the non-templated routines swig will expose easier to write. You can
// see these java exposed methods below (i.e. sum(), sum_crit(), assign(), and
// assign_crit()).
template <typename T>
T tsum(const jvector_crit<T>& arr)
T tsum(const array_view_crit<T>& arr)
{
T s = 0;
for (auto& v : arr)
......@@ -32,7 +34,7 @@ T tsum(const jvector_crit<T>& arr)
return s;
}
template <typename T>
T tsum(const jvector<T>& arr)
T tsum(const array_view<T>& arr)
{
T s = 0;
for (auto& v : arr)
......@@ -56,41 +58,64 @@ void tassign(T& arr)
// "global", which is where these sum and assign routines will appear. You can see
// examples of java code that calls them in swig_test.java.
inline int sum_crit(const jvector_crit<int16_t>& arr) { return tsum(arr); }
inline int sum(const jvector<int16_t>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<int16_t>& arr) { tassign(arr); }
inline void assign(jvector<int16_t>& arr) { tassign(arr); }
inline int sum_crit(const array_view_crit<int16_t>& arr) { return tsum(arr); }
inline int sum(const array_view<int16_t>& arr) { return tsum(arr); }
inline void assign_crit(array_view_crit<int16_t>& arr) { tassign(arr); }
inline void assign(array_view<int16_t>& arr) { tassign(arr); }
inline int sum_crit(const array_view_crit<int32_t>& arr) { return tsum(arr); }
inline int sum(const array_view<int32_t>& arr) { return tsum(arr); }
inline void assign_crit(array_view_crit<int32_t>& arr) { tassign(arr); }
inline void assign(array_view<int32_t>& arr) { tassign(arr); }
inline int sum_crit(const array_view_crit<int64_t>& arr) { return tsum(arr); }
inline int sum(const array_view<int64_t>& arr) { return tsum(arr); }
inline void assign_crit(array_view_crit<int64_t>& arr) { tassign(arr); }
inline void assign(array_view<int64_t>& arr) { tassign(arr); }
inline int sum_crit(const jvector_crit<int32_t>& arr) { return tsum(arr); }
inline int sum(const jvector<int32_t>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<int32_t>& arr) { tassign(arr); }
inline void assign(jvector<int32_t>& arr) { tassign(arr); }
inline int sum_crit(const array_view_crit<char>& arr) { return tsum(arr); }
inline int sum(const array_view<char>& arr) { return tsum(arr); }
inline void assign_crit(array_view_crit<char>& arr) { tassign(arr); }
inline void assign(array_view<char>& arr) { tassign(arr); }
inline int sum_crit(const jvector_crit<int64_t>& arr) { return tsum(arr); }
inline int sum(const jvector<int64_t>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<int64_t>& arr) { tassign(arr); }
inline void assign(jvector<int64_t>& arr) { tassign(arr); }
inline int sum_crit(const jvector_crit<char>& arr) { return tsum(arr); }
inline int sum(const jvector<char>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<char>& arr) { tassign(arr); }
inline void assign(jvector<char>& arr) { tassign(arr); }
inline double sum_crit(const array_view_crit<double>& arr) { return tsum(arr); }
inline double sum(const array_view<double>& arr) { return tsum(arr); }
inline void assign_crit(array_view_crit<double>& arr) { tassign(arr); }
inline void assign(array_view<double>& arr) { tassign(arr); }
inline float sum_crit(array<float> arr)
{
array_view_crit<float> a(arr);
return tsum(a);
}
inline float sum(const array<float>& arr)
{
array_view<float> a(arr);
return tsum(a);
}
inline void assign_crit(array_view_crit<float>& arr) { tassign(arr); }
inline void assign(array<float>& arr)
{
array_view<float> a(arr);
tassign(a);
}
inline double sum_crit(const jvector_crit<double>& arr) { return tsum(arr); }
inline double sum(const jvector<double>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<double>& arr) { tassign(arr); }
inline void assign(jvector<double>& arr) { tassign(arr); }
array<int32_t> make_an_array(size_t s)
{
array<int32_t> arr(s);
array_view_crit<int32_t> a(arr);
for (size_t i = 0; i < a.size(); ++i)
a[i] = i;
inline float sum_crit(const jvector_crit<float>& arr) { return tsum(arr); }
inline float sum(const jvector<float>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<float>& arr) { tassign(arr); }
inline void assign(jvector<float>& arr) { tassign(arr); }
return arr;
}
// ----------------------------------------------------------------------------------------
......
......@@ -69,6 +69,14 @@ public class swig_test
}
}
public static void assertIsEqual(int val1, int val2)
{
if (val1 != val2)
{
throw new RuntimeException("Test failed " + val1 + " should be equal to " + val2);
}
}
public static double sum(double[] arr)
{
double s = 0;
......@@ -233,6 +241,13 @@ public class swig_test
assertIs28(global.sum_crit(arr));
}
}
{
int[] a = global.make_an_array(4);
for (int i = 0; i < a.length; ++i)
{
assertIsEqual(a[i], i);
}
}
System.out.println("\n\n ALL TESTS COMPLETED SUCCESSFULLY\n");
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment