Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
214 views
in Technique[技术] by (71.8m points)

c++ - std::vector to java.util.Vector code generation with swig

I try to generate java code with SWIG

In MyList.h I declared a custom list object called _list

List<T*> _list;

and this List class inherits from vector

class List : public vector<T>

In a business class (in C++) I return a List of custom objects

List<MyObject> getMyList(){
   ....
   return list;
}

so I want to generate java code where I can retrieve this C++ List as java.util.List or java.util.Vector.

in my swig.i file I couldn't manage how to embody

%typemap(jstype) List "java.util.Vector"
namespace std {
   %template(CustomVector) vector<MyObject>;
}

any kind help how to configure this swig.i template file or some sample code to generate a java.util.List / Vector returning function will be appreciated.

Thank you.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You don't really want to be touching java.util.Vector with your wrapped interfaces because you will end up duplicating storage or making large numbers of copy operations every time you pass it in/out of a function. (Note also that in general in C++ inhering from containers is odd design).

Instead in Java the "right" thing to do is to inherit from java.util.AbstractList. This answer is a more generic version of my older answer to a similar question.

It works for all std::vector types, not just a fixed type and handles primitives which need to be accessed via Objects using an "autobox" custom type map. It's missing support for the specialized std::vector<bool>, but that should be simple to add 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 fairly similar to the default std_vector.i that SWIG currently provides, the new bits are the renaming, extending and typemaps that extend AbstractList and implement RandomAccess. It also adds a constructor that takes other Collections - this is recommended by the Java documentation and easy enough to do. (There's an overload for other std::vector types which is much faster).

I tested this vector wrapping within 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>;

Which 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);
    }
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...