Search code examples
javac++java-native-interfaceswig

javaout typemap doesn't work for std::vector of pointers


With vector of structures everything works fine

%include <std_vector.i>

%typemap(javaout) const S1& std::vector<S1>::get {
  //custom code
}

struct S1 {};
std::vector<S1> val;

%template(vector_s1) std::vector<S1>;

But doesn't work with vector of pointers

%include <std_vector.i>

%typemap(javaout) const S1*& std::vector<S1*>::get {
  //custom code
}

struct S1 {};
std::vector<S1*> val;

%template(vector_s1) std::vector<S1*>;

Samples were compiled with swig -java -c++ -module sample sample.i

SWIG version:

$ swig -version

SWIG Version 3.0.7

Compiled with i586-mingw32msvc-g++ [i586-pc-mingw32msvc]

Configured options: +pcre

Solution

  • If you have a look in the file swig/Lib/std/std_vector.i that provides language independent wrapper code for std::vector, you will find the following comment:

    // ***
    // This specialization should disappear or get simplified when
    // a 'const SWIGTYPE*&' can be defined
    // ***
    template<class _Tp, class _Alloc >
    class vector<_Tp*, _Alloc > { ...
    

    So it appears that SWIG currently cannot handle the const S1*& in your above typemap definition.

    Now, the file swig/Lib/java/std_vector.i that provides the java wrappers for std::vector is much less sophisticated and lacks the specialization for std::vector<T*>.

    Adding such a specialization yourself should solve your problem:

    file std_vector_pointer.i:

    %include <std_vector.i>
    namespace std {
    template<class T> class vector<T*> {
      public:
        typedef size_t size_type;
        typedef T* value_type;
        typedef value_type const_reference;
        vector();
        vector(size_type n);
        size_type size() const;
        size_type capacity() const;
        void reserve(size_type n);
        %rename(isEmpty) empty;
        bool empty() const;
        void clear();
        %rename(add) push_back;
        void push_back(T* x);
        %extend {
            T* get(int i) throw (std::out_of_range) {
                int size = int(self->size());
                if (i>=0 && i<size)
                    return (*self)[i];
                else
                    throw std::out_of_range("vector index out of range");
            }
            void set(int i, T* val) throw (std::out_of_range) {
                int size = int(self->size());
                if (i>=0 && i<size)
                    (*self)[i] = val;
                else
                    throw std::out_of_range("vector index out of range");
            }
        }
    };
    }
    

    Then the following should work for your above example:

    %include "std_vector_pointer.i"
    
    %typemap(javaout) S1* std::vector<S1*>::get {
      //custom code
    }
    
    struct S1 {};
    std::vector<S1*> val;
    
    %template(vector_s1) std::vector<S1*>;