![](/img/trans.png)
[英]How to return std::vector<std::pair<std::string, int> > from java to c++ using swig typemaps
[英]How would you create a typemap for std::list<std::string> to List<String> in C++ to Java in SWIG?
在SWIG 3.0.8中,C ++到Java映射中没有实现std::list
实现,只有std::vector
。 在大多数情况下,这不是很理想,因此我想知道是否可以创建自己的std::list
SWIG定义,我将如何做?
我编写了一组类型映射,这些类型映射应该可以很好地用Java包装std::list
。 他们使用java.util.AbstractSequentialList
作为基类,因此仅存在一个数据副本,它可以很好地用作Java和C ++数据结构。 这个答案大致上是对我在较旧的答案包装std::vector
使用的相同技术的改进和移植。
首先,我从以前的答案中提取了“ autobox”类型映射,并将其放入一个独立文件autobox.i中,因为现在我已经大量使用了它:
// Java typemaps for autoboxing in return types of generics
%define AUTOBOX(CTYPE, JTYPE)
%typemap(autobox) CTYPE, const CTYPE&, CTYPE& "JTYPE"
%enddef
AUTOBOX(double, Double)
AUTOBOX(float, Float)
AUTOBOX(boolean, Boolean)
AUTOBOX(signed char, Byte)
AUTOBOX(short, Short)
AUTOBOX(int, Integer)
AUTOBOX(long, Long)
AUTOBOX(SWIGTYPE, $typemap(jstype,$1_basetype))
然后我在下面的std_list.i文件中使用了它:
%include <autobox.i>
%include <stdint.i>
%{
#include <list>
#include <algorithm>
%}
namespace std {
template <typename T> class list {
public:
// This typedef is a weird hack to make stuff work
typedef std::list<T>::iterator iterator;
typedef size_t size_type;
typedef T value_type;
typedef T& reference;
void assign(size_type n, const value_type &val);
bool empty() const;
list(size_type n, const value_type &value=value_type());
list(const list &o);
list();
~list();
size_type max_size () const;
void pop_back();
void pop_front();
void push_back(const value_type &x);
void push_front(const value_type &x);
void remove(const T &v);
// Possible bug: jint != size_type
jint size () const;
void sort();
%javamethodmodifiers "private";
// Only for helping implement listIterator
iterator begin();
iterator insert(iterator pos, const value_type &v);
%extend {
static void set(iterator pos, const value_type& v) {
*pos = v;
}
jint previous_index(const iterator& pos) const {
return pos == self->begin() ? -1 : std::distance(self->begin(), static_cast<std::list<T>::const_iterator>(pos));
}
jint next_index(const iterator& pos) const {
return pos == self->end() ? self->size() : std::distance(self->begin(), static_cast<std::list<T>::const_iterator>(pos));
}
static iterator next(iterator pos) {
return ++pos;
}
static iterator previous(iterator pos) {
return --pos;
}
static value_type deref(const iterator& pos) {
return *pos;
}
static void advance(iterator& pos, jint index) {
std::advance(pos, index);
}
bool has_next(const iterator& pos) const {
return pos != $self->end();
}
}
%javamethodmodifiers "public";
};
}
%typemap(javaimports) std::list %{
import java.util.AbstractSequentialList;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Collection;
%}
%typemap(javabase) std::list "AbstractSequentialList<$typemap(autobox,$1_basetype::value_type)>"
#define JAVA_VALUE_TYPE $typemap(autobox,$1_basetype::value_type)
#define JAVA_ITERATOR_TYPE $typemap(jstype, $1_basetype::iterator)
%typemap(javacode,noblock=1) std::list {
public $javaclassname(Collection c) {
this();
ListIterator<JAVA_VALUE_TYPE> it = listIterator(0);
for (Object o: c) {
it.add((JAVA_VALUE_TYPE)o);
}
}
public ListIterator<JAVA_VALUE_TYPE> listIterator(int index) {
return new ListIterator<JAVA_VALUE_TYPE>() {
private JAVA_ITERATOR_TYPE pos;
private JAVA_ITERATOR_TYPE last;
private ListIterator<JAVA_VALUE_TYPE> init(int index) {
pos = $javaclassname.this.begin();
$javaclassname.advance(pos, index);
return this;
}
public void add(JAVA_VALUE_TYPE v) {
// Technically we can invalidate last here, but this makes more sense
last=$javaclassname.this.insert(pos, v);
}
public void set(JAVA_VALUE_TYPE v) {
if (null==last) {
throw new IllegalStateException();
}
$javaclassname.set(last, v);
}
public void remove() {
if (null==last) {
throw new IllegalStateException();
}
$javaclassname.this.remove(last);
last=null;
}
public int previousIndex() {
return $javaclassname.this.previous_index(pos);
}
public int nextIndex() {
return $javaclassname.this.next_index(pos);
}
public JAVA_VALUE_TYPE previous() {
if (previousIndex() < 0) {
throw new NoSuchElementException();
}
last = pos;
pos = $javaclassname.previous(pos);
return $javaclassname.deref(last);
}
public JAVA_VALUE_TYPE next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
last = pos;
pos = $javaclassname.next(pos);
return $javaclassname.deref(last);
}
public boolean hasPrevious() {
return previousIndex() != -1;
}
public boolean hasNext() {
return $javaclassname.this.has_next(pos);
}
}.init(index);
}
}
这个文件实现了AbstractSequentialList
,它主要归结为实现ListIterator
。 这有点奇怪,因为Java实现迭代器概念的方式与C ++抽象有所不同,尽管并不完全不同。
我们的ListIterator
Java实现大部分只是一个不透明的C ++迭代器的包装,并需要一些胶水来调用一些额外的C ++代码,这些代码实际上使用std::advance
, std::distance
和operator++
/ operator--
满足所需的需求。 胶水内部有各种检查,以确保接口安全/可靠(如Java程序员所期望的)。
std :: list的SWIG接口包括以下主要部分:
std::list
本身相关部分的声明。 (有些是私有的,因为除了实现细节之外,它对Java没有任何意义) %template
时所需的一些模板化C ++迭代器代码。 std::list
设置import / baseclass 我们包装的每个std::list<X>
一些其他Java代码:
listIterator
抽象方法的实现,该方法返回一个匿名类型,该类型将所有内容粘合在一起,以满足可变ListIterator
所有要求。 它包装在{ }
,且未启用noblock,以便发生预处理器宏,但是{ }
不会插入到生成的Java中。
我还使用此Java技巧在构造过程 中将 数据传递给匿名类 (但本来可以使用双括号魔术 )。
有了这个,我们可以通过运行SWIG模块test.i来验证它:
%module test
%include "std_list.i"
%include <std_string.i>
%template(DoubleList) std::list<double>;
%template(StringList) std::list<std::string>;
和一些实际的Java来练习它:
import java.util.ArrayList;
public class run {
public static void dump(java.util.AbstractCollection c) {
for (Object o: c) {
System.out.println(o);
}
}
public static void main(String[] argv) {
System.loadLibrary("test");
for (int i = 0; i < 1; ++i) {
go();
// System.gc();
}
}
public static void go() {
StringList sl = new StringList();
dump(sl);
sl.add(0,"HELLO"); // 1 arg form also worked
sl.add(1,"WORLD");
sl.add(2,"testing");
sl.add(3,"some more");
System.out.println(sl.size());
dump(sl);
sl = new StringList(new ArrayList<String>() {{
add("A");
add("B");
add("C");
}});
dump(sl);
}
}
哪个按预期工作:
swig3.0 -java -c++ -Wall test.i
javac *.java
g++ -Wall -Wextra -shared -o libtest.so test_wrap.cxx -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux -fPIC -D_GLIBCXX_DEBUG
LD_LIBRARY_PATH=. java run
给出:
4
HELLO
WORLD
testing
some more
A
B
C
随机说明: hasNext()
和向前迭代可能比hasPrevious()
和反向迭代更快,这是因为避免在这种情况下进行std::distance
调用更容易。
(注意:我急忙阅读Java文档,了解ListIterator成员函数的语义应该是什么急事。我可能误解其中的一个或多个)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.