用Java打包std::vector
的適當基本類型是java.util.AbstractList
。使用java.util.Vector
作爲基礎會很奇怪,因爲您最終會得到兩組存儲空間,一個存儲在std::vector
中,一個存儲在java.util.Vector
中。
原因呷不爲你做的,雖然這是因爲you can't have AbstractList<double>
in Java,它必須是AbstractList<Double>
(從Object
Double
繼承而double
是基本類型)。
說完了我已經放在一起的一個小例子,它很好地用Java包裝了std::vector<double>
和std::vector<std::vector<double> >
。它並不完整,但它支持Java中的「for each」風格的迭代和元素上的「迭代」風格。它應該足以展示如何實現其他事情/當你想要他們。
我會在接下來的章節中討論接口文件,但基本上它們都是順序和完整的。
與num.i
定義我們的模塊num
開始:
%module num
%{
#include <vector>
#include <stdexcept>
std::vector<double> testVec() {
return std::vector<double>(10,1.0);
}
std::vector<std::vector<double> > testMat() {
return std::vector<std::vector<double> >(10, testVec());
}
%}
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("num");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}
我們#include
S代表的功能產生num_wrap.cxx
和兩個實現測試(他們可能是在一個單獨的文件,我只是把他們在這裏出懶惰/便利)。
還有一個技巧,我喜歡在Java SWIG接口中使用%pragma(java) jniclasscode=
,以便爲接口的用戶透明地加載共享對象/ DLL。
接下來在接口文件中是我們想包裝的部分std::vector
。我沒有使用std_vector.i
因爲我們需要做一些修改:
namespace std {
template<class T> class vector {
public:
typedef size_t size_type;
typedef T value_type;
typedef const value_type& const_reference;
%rename(size_impl) size;
vector();
vector(size_type n);
size_type size() const;
size_type capacity() const;
void reserve(size_type n);
%rename(isEmpty) empty;
bool empty() const;
void clear();
void push_back(const value_type& x);
%extend {
const_reference get_impl(int i) throw (std::out_of_range) {
// at will throw if needed, swig will handle
return self->at(i);
}
void set_impl(int i, const value_type& val) throw (std::out_of_range) {
// at can throw
self->at(i) = val;
}
}
};
}
這裏的主要變化是%rename(size_impl) size;
,它告訴夜風從std::vector
暴露size()
爲size_impl
代替。我們需要這樣做,因爲Java預計size
返回int
,其中std::vector
版本返回的size_type
很可能不會是int
。
接下來在接口文件中,我們告訴它我們想要的基類和接口來實現,以及編寫一些額外的Java代碼來強制功能之間的事情不兼容類型:
%typemap(javabase) std::vector<double> "java.util.AbstractList<Double>"
%typemap(javainterface) std::vector<double> "java.util.RandomAccess"
%typemap(javacode) std::vector<double> %{
public Double get(int idx) {
return get_impl(idx);
}
public int size() {
return (int)size_impl();
}
public Double set(int idx, Double d) {
Double old = get_impl(idx);
set_impl(idx, d.doubleValue());
return old;
}
%}
%typemap(javabase) std::vector<std::vector<double> > "java.util.AbstractList<Vector>"
%typemap(javainterface) std::vector<std::vector<double> > "java.util.RandomAccess"
%typemap(javacode) std::vector<std::vector<double> > %{
public Vector get(int idx) {
return get_impl(idx);
}
public int size() {
return (int)size_impl();
}
public Vector set(int idx, Vector v) {
Vector old = get_impl(idx);
set_impl(idx, v);
return old;
}
%}
此設置基準java.util.AbstractList<Double>
的類別爲std::vector<double>
和java.util.AbstractList<Vector>
爲std::vector<std::vector<double> >
(Vector
是我們將在界面的Java端調用std::vector<double>
)。
我們還提供在Java端的get
和set
的實現,它可以處理double
到Double
轉換並返回。
最後在接口我們添加:
namespace std {
%template(Vector) std::vector<double>;
%template(Matrix) std::vector<vector<double> >;
}
std::vector<double> testVec();
std::vector<std::vector<double> > testMat();
這告訴夜風指std::vector<double>
(與特定類型)爲Vector
同樣地,對於std::vector<vector<double> >
爲Matrix
。我們還告訴SWIG公開我們的兩個測試功能。
接下來,test.java
,一個簡單的main
在Java中行使我們的代碼一點:
import java.util.AbstractList;
public class test {
public static void main(String[] argv) {
Vector v = num.testVec();
AbstractList<Double> l = v;
for (Double d: l) {
System.out.println(d);
}
Matrix m = num.testMat();
m.get(5).set(5, new Double(5.0));
for (Vector col: m) {
for (Double d: col) {
System.out.print(d + " ");
}
System.out.println();
}
}
}
要構建和運行這個我們做的:
swig -java -c++ num.i
g++ -Wall -Wextra num_wrap.cxx -shared -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux/ -o libnum.so
javac test.java && LD_LIBRARY_PATH=. java test
我使用g ++ 4.4版本測試了這個和Linux/x86上的SWIG 1.3.40。
num.i
的完整版本可以找到here,但始終可以通過將每個部分粘貼到一個文件中從此答案重建。
事情我已經不AbstractList
實施:
add()
- 可以通過push_back()
實現,std_vector.i甚至試圖落實默認兼容的東西,但它不與Double
VS double
工作問題或匹配AbstractList
指定的返回類型(不要忘了增加modCount
)
remove()
- 不太適合std::vector
的時間複雜度,但並非不可能實現或者(與同樣)
- 推薦使用另一個
Collection
的構造函數,但在此處未實現。可以在相同的地方執行set()
和get()
,但將需要$javaclassname
正確命名生成的構造函數。
- 您可能想要使用類似this的內容來檢查中的
size_type
→int
轉換是否理智。
不是SWIG用戶,但是看着'std_vector.i'(我在網上找到它的版本,無論如何),'size()'應該是'unsigned int',SWIG應該將到Java'long'。如果你的尺寸是負值,是純粹的廢話,還是看起來像他們可能會把'unsigned'當作已簽名的? –