[英]How would you create a typemap for std::list<std::string> to List<String> in C++ to Java in SWIG?
In SWIG 3.0.8 there is no implementation for std::list
in the C++ to Java map, only std::vector
. 在SWIG 3.0.8中,C ++到Java映射中没有实现
std::list
实现,只有std::vector
。 This isn't very ideal for most cases, so I was wondering if it is possible to create my own SWIG definition of std::list
and how would I do so? 在大多数情况下,这不是很理想,因此我想知道是否可以创建自己的
std::list
SWIG定义,我将如何做?
I've written a set of typemaps that should just work for wrapping std::list
nicely in Java. 我编写了一组类型映射,这些类型映射应该可以很好地用Java包装
std::list
。 They use java.util.AbstractSequentialList
as a base class, so there's only ever one copy of data in existence and it works nicely as both a Java and C++ data structure. 他们使用
java.util.AbstractSequentialList
作为基类,因此仅存在一个数据副本,它可以很好地用作Java和C ++数据结构。 This answer is broadly an improvement and port of the same techniques I used in an older answer wrapping std::vector
similarly. 这个答案大致上是对我在较旧的答案包装
std::vector
使用的相同技术的改进和移植。
Firstly I pulled the 'autobox' typemap out of my older answer and into a standalone file, autobox.i since I'm now reusing it quite a lot: 首先,我从以前的答案中提取了“ 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))
Then I used this in my std_list.i file below: 然后我在下面的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);
}
}
This file implements AbstractSequentialList
, which mostly just boils down to implementing ListIterator
. 这个文件实现了
AbstractSequentialList
,它主要归结为实现ListIterator
。 That's somewhat fiddly because the way Java implements the concept of an iterator is somewhat different to the C++ abstraction, although not completely different. 这有点奇怪,因为Java实现迭代器概念的方式与C ++抽象有所不同,尽管并不完全不同。
Our Java implementation of ListIterator
is mostly just a wrapper around an opaque C++ iterator and some glue to call in to a little extra C++ code that actually uses std::advance
, std::distance
and operator++
/ operator--
to meet the requirements needed. 我们的
ListIterator
Java实现大部分只是一个不透明的C ++迭代器的包装,并需要一些胶水来调用一些额外的C ++代码,这些代码实际上使用std::advance
, std::distance
和operator++
/ operator--
满足所需的需求。 Inside the glue are the various checks needed to make the interface safe/robust as a Java programmer expects. 胶水内部有各种检查,以确保接口安全/可靠(如Java程序员所期望的)。
The SWIG interface to std::list consists of the following major parts: std :: list的SWIG接口包括以下主要部分:
std::list
itself. std::list
本身相关部分的声明。 (Some is private because it makes no sense to Java as anything other than an implementation detail) %template
inside SWIG later on. %template
时所需的一些模板化C ++迭代器代码。 std::list
std::list
设置import / baseclass Some additional Java code for every std::list<X>
we wrap: 我们包装的每个
std::list<X>
一些其他Java代码:
listIterator
abstract method that returns an anonymous type that glues everything together to meet all of the requirements for a mutable ListIterator
. listIterator
抽象方法的实现,该方法返回一个匿名类型,该类型将所有内容粘合在一起,以满足可变ListIterator
所有要求。 This is wrapped inside { }
with noblock turned on so that the preprocessor macros happen, but that { }
doesn't get inserted into the Java which is generated. 它包装在
{ }
,且未启用noblock,以便发生预处理器宏,但是{ }
不会插入到生成的Java中。
I also used this Java trick to pass data to an anonymous class during construction (but could have used the double brace magic instead). 我还使用此Java技巧在构造过程 中将 数据传递给匿名类 (但本来可以使用双括号魔术 )。
With that in place we can validate it by running writing a SWIG module, test.i: 有了这个,我们可以通过运行SWIG模块test.i来验证它:
%module test
%include "std_list.i"
%include <std_string.i>
%template(DoubleList) std::list<double>;
%template(StringList) std::list<std::string>;
And some actual Java to exercise it: 和一些实际的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);
}
}
Which works as expected: 哪个按预期工作:
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
Gives: 给出:
4
HELLO
WORLD
testing
some more
A
B
C
A random note: hasNext()
and forward iteration is probably faster than hasPrevious()
and reverse iteration simply because it's easier to avoid the std::distance
call int that case. 随机说明:
hasNext()
和向前迭代可能比hasPrevious()
和反向迭代更快,这是因为避免在这种情况下进行std::distance
调用更容易。
(Caveat: I read the Java docs on what the semantics of the ListIterator member functions should be in rather a hurry. I could have got one or more of them subtly wrong). (注意:我急忙阅读Java文档,了解ListIterator成员函数的语义应该是什么急事。我可能误解其中的一个或多个)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.