Commit d62c5a7c authored by Davis King's avatar Davis King
Browse files

merged

parents 420eba0e cf24f025
......@@ -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 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<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 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 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<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 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 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); }
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(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); }
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);
}
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;
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");
}
......
......@@ -424,7 +424,7 @@ namespace dlib
template <typename T>
int get_ld (const matrix_op<op_pointer_to_col_vect<T> >& m) { return m.nc(); }
template <typename T>
int get_ld (const matrix_op<op_pointer_to_mat<T> >& m) { return m.nc(); }
int get_ld (const matrix_op<op_pointer_to_mat<T> >& m) { return m.op.stride; }
// --------
......@@ -443,7 +443,7 @@ namespace dlib
template <typename T>
int get_inc (const matrix_op<op_pointer_to_col_vect<T> >& ) { return 1; }
template <typename T>
int get_inc (const matrix_op<op_pointer_to_mat<T> >& ) { return 1; }
int get_inc (const matrix_op<op_pointer_to_mat<T> >& m) { return m.op.stride==m.op.cols ? 1 : 0; }
template <typename T, long NR, long NC, typename MM, typename L>
int get_inc (const matrix<T,NR,NC,MM,L>& ) { return 1; }
......
......@@ -319,11 +319,19 @@ namespace dlib
const T* ptr_,
const long nr_,
const long nc_
) : ptr(ptr_), rows(nr_), cols(nc_){}
) : ptr(ptr_), rows(nr_), cols(nc_), stride(nc_){}
op_pointer_to_mat(
const T* ptr_,
const long nr_,
const long nc_,
const long stride_
) : ptr(ptr_), rows(nr_), cols(nc_), stride(stride_){}
const T* ptr;
const long rows;
const long cols;
const long stride;
const static long cost = 1;
const static long NR = 0;
......@@ -333,7 +341,7 @@ namespace dlib
typedef default_memory_manager mem_manager_type;
typedef row_major_layout layout_type;
const_ret_type apply (long r, long c) const { return ptr[r*cols + c]; }
const_ret_type apply (long r, long c) const { return ptr[r*stride + c]; }
long nr () const { return rows; }
long nc () const { return cols; }
......@@ -419,6 +427,27 @@ namespace dlib
return matrix_op<op>(op(ptr,nr,nc));
}
template <
typename T
>
const matrix_op<op_pointer_to_mat<T> > mat (
const T* ptr,
long nr,
long nc,
long stride
)
{
DLIB_ASSERT(nr >= 0 && nc >= 0 && stride > 0 ,
"\tconst matrix_exp mat(ptr, nr, nc, stride)"
<< "\n\t nr and nc must be >= 0 while stride > 0"
<< "\n\t nr: " << nr
<< "\n\t nc: " << nc
<< "\n\t stride: " << stride
);
typedef op_pointer_to_mat<T> op;
return matrix_op<op>(op(ptr,nr,nc,stride));
}
// ----------------------------------------------------------------------------------------
}
......
......@@ -153,6 +153,35 @@ namespace dlib
the pointer and thus will not delete or free it.
!*/
// ----------------------------------------------------------------------------------------
template <
typename T
>
const matrix_exp mat (
const T* ptr,
long nr,
long nc,
long stride
);
/*!
requires
- nr >= 0
- nc >= 0
- stride > 0
- ptr == a pointer to at least (nr-1)*stride+nc T objects (or the NULL pointer if nr*nc==0)
ensures
- returns a matrix M such that:
- M.nr() == nr
- m.nc() == nc
- for all valid r and c:
M(r,c) == ptr[r*stride + c]
(i.e. the pointer is interpreted as a matrix laid out in memory
in row major order, with a row stride of the given stride amount.)
- Note that the returned matrix doesn't take "ownership" of
the pointer and thus will not delete or free it.
!*/
// ----------------------------------------------------------------------------------------
template <
......
......@@ -870,7 +870,7 @@ namespace
conv2.get_gradient_for_filters(true, gi, data, filter_gradient2);
dlog << LINFO << "filter gradient error: "<< max(abs(mat(filter_gradient1)-mat(filter_gradient2)));
DLIB_TEST_MSG(max(abs(mat(filter_gradient1)-mat(filter_gradient2))) < 1e-3, max(abs(mat(filter_gradient1)-mat(filter_gradient2))));
DLIB_TEST_MSG(max(abs(mat(filter_gradient1)-mat(filter_gradient2))) < 2e-3, max(abs(mat(filter_gradient1)-mat(filter_gradient2))));
}
}
......
......@@ -1350,6 +1350,21 @@ namespace
DLIB_TEST(mm(3) == 4);
}
{
const long n = 5;
matrix<double> m1, m2, m3, truth;
m1 = randm(n,n);
m2 = randm(n,n);
rectangle rect1(1,1,3,3);
rectangle rect2(2,1,4,3);
truth = subm(m1,rect1)*subm(m2,rect2);
m3 = mat(&m1(0,0)+6, 3,3, m1.nc()) * mat(&m2(0,0)+7, 3,3, m2.nc());
DLIB_TEST(max(abs(truth-m3)) < 1e-13);
}
{
const long n = 5;
matrix<double> m1, m2, m3, truth;
......
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