在SWIG 3.0.8中,C ++到Java地图中没有std::list
的实现,只有std::vector
。对于大多数情况,这不是很理想,所以我想知道是否可以创建我自己的std::list
的SWIG定义,我该怎么做?
答案 0 :(得分:0)
我编写了一组类型映射,它们只适用于在Java中很好地包装std::list
。他们使用java.util.AbstractSequentialList
作为基类,因此只存在一个数据副本,它作为Java和C ++数据结构很好地工作。这个答案大体上是我在an older answer wrapping 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
和{ {1}} / operator++
以满足所需的要求。在胶水内部是各种检查,以使接口安全/健壮,正如Java程序员所期望的那样。
std :: list的SWIG接口包含以下主要部分:
operator--
本身的相关部分。 (有些是私有的,因为除了实现细节之外,Java没有任何意义)std::list
时需要的一些模板化C ++迭代器代码。%template
我们打包的每个std::list
的一些额外Java代码:
std::list<X>
抽象方法的实现,它返回一个匿名类型,将所有内容粘合在一起以满足可变listIterator
的所有要求。在ListIterator
内部打开noblock,以便预处理器宏发生,但{ }
不会插入到生成的Java中。
我也使用了此Java trick to pass data to an anonymous class during construction(但可能已使用the double brace magic代替。)
有了这个,我们可以通过编写SWIG模块test.i:
来验证它{ }
和一些实际的Java来练习它:
%module test
%include "std_list.i"
%include <std_string.i>
%template(DoubleList) std::list<double>;
%template(StringList) std::list<std::string>;
按预期工作:
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()
调用。
(警告:我阅读了关于ListIterator成员函数的语义应该是匆忙的Java文档。我可能有一个或多个巧妙地错了。)