You really don't want to touch java.util.Vector
on your wrapped interfaces, because you will duplicate the repository or do a lot of copy operations every time you pass it to / from a function. (Note also that in general in C ++, inherit an odd construct from containers).
Instead, the โrightโ thing in Java is to inherit from java.util.AbstractList
. This answer is a more general version of my older answer to a similar question .
It works for all types of std::vector
, and not just fixed types and processes primitives that must be accessed through objects using a map of the "autobox" type. It lacks support for specialized std::vector<bool>
, but you just need to add it if you need it.
%{ #include <vector> #include <stdexcept> %} %include <stdint.i> %include <std_except.i> namespace std { template<class T> class vector { public: typedef size_t size_type; typedef T value_type; typedef const value_type& const_reference; vector(); vector(size_type n); vector(const vector& o); 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(int i) const throw (std::out_of_range) { return $self->at(i); } value_type set(int i, const value_type& VECTOR_VALUE_IN) throw (std::out_of_range) { const T old = $self->at(i); $self->at(i) = VECTOR_VALUE_IN; return old; } int32_t size() const { return $self->size(); } void removeRange(int32_t from, int32_t to) { $self->erase($self->begin()+from, $self->begin()+to); } } }; } // 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)) %typemap(javabase) std::vector "java.util.AbstractList<$typemap(autobox,$1_basetype::value_type)>" %typemap(javainterface) std::vector "java.util.RandomAccess" %typemap(jstype) std::vector get "$typemap(autobox,$1_basetype)" %typemap(jstype) std::vector set "$typemap(autobox,$1_basetype)" %typemap(jstype) std::vector &VECTOR_VALUE_IN "$typemap(autobox,$1_basetype)" %typemap(javacode) std::vector %{ $javaclassname(java.util.Collection<$typemap(autobox,$1_basetype::value_type)> e) { this.reserve(e.size()); for($typemap(autobox,$1_basetype::value_type) value: e) { this.push_back(value); } } %}
Most of this is pretty similar to the standard std_vector.i that SWIG currently provides, the new bits are renaming, extension, and type characters that extend AbstractList
and implement RandomAccess
. He also adds a constructor that accepts another Collection
- this is recommended in the Java documentation and is easy enough to do. (There is overload for other types of std::vector
, which is much faster).
I tested this vector packaging in another SWIG interface:
%module test %include "vector.i" %template(DblVec) std::vector<double>; %template(ByteVec) std::vector<signed char>; %include <std_string.i> %template(StringVec) std::vector<std::string>; %inline %{ struct foo {}; %} %template(FooVec) std::vector<foo>;
What I was able to compile and run with:
public class run { public static void main(String argv[]) { System.loadLibrary("test"); DblVec dv = new DblVec(100); for (int i = 0; i < 100; ++i) { dv.set(i,(double)i); } FooVec fv = new FooVec(1); fv.set(0, new foo()); for (double d: dv) { System.out.println(d); } } }