Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use std::vector in PHP using SWIG

Tags:

c++

php

swig

I am working on wrapping a C++ API in PHP using SWIG. I am most of the way there but I am having problems with a function that returns a vector. The header looks something like this:

#include <vector>

namespace STF
{
class MyClass
{
    public:
        const std::vector<MyOtherClass> &getList();
};
}

The interface file looks like this:

%include <std_vector.i>
%import "STF_MyOtherClass.i"

%{
    #include "STF_MyOtherClass.h"
    #include "STF_MyClass.h"
%}

%include "STF_MyClass.h"

I seem to be able to call the function fine but it is returning a PHP resource instead of an object. Specifically it is a resource of type: "_p_std__vectorT_STF__MyClass_t".

How can I either get this to return an object that I can iterate through (preferably with a foreach loop) or how can I iterate through this resource?

Update:

I have been working on a solution based off of what I read here: http://permalink.gmane.org/gmane.comp.programming.swig/16817

Basically I am trying to convert the vector into a python array:

%typemap(out) std::vector<STF::MyOtherClass>
{
    array_init( return_value );

    std::vector<STF::MyOtherClass>::iterator itr;

    itr = $1.begin();

    for( itr; itr != $1.end(); itr++ )
    {
        zval* tmp;

        MAKE_STD_ZVAL( tmp );
        SWIG_SetPointerZval( tmp, &*itr, $descriptor(STF::MyOtherClass*), 2 );

        add_next_index_zval( return_value, tmp );
    }
}

This is very close to working. I put a breakpoint inside the wrapper code within SWIG_ZTS_SetPointerZval. When it goes to initialize the object it does a zend_lookup_class for "stf__myotherclass" which fails (it doesn't find a clasS). I am not sure why it can't find the class.

like image 726
drewag Avatar asked Dec 07 '11 16:12

drewag


2 Answers

You're almost there, but as well as %include <std_vector.i> you'll also need something like:

%template (MyVector) std::vector<MyOtherClass>;

This instructs SWIG to expose vectors of MyOtherClass to the target language as a type called MyVector. Without doing this SWIG doesn't know which types you want to instantiate std::vector for, so it's reduced to the default wrapping.

Side note:

Is there a reason you've got the const in const std::vector<MyOtherClass> getList(); when it's not a reference? I'd either make it a reference and make the method const also (const std::vector<MyOtherClass>& getList() const;) or drop the const entirely since it does nothing there.

like image 98
Flexo Avatar answered Nov 02 '22 17:11

Flexo


In the end this is what I did to convert the vector into a PHP array (put this in the interface file for MyOtherClass):

%typemap(out) const std::vector<STF::MyOtherClass>&
{
    array_init( return_value );

    std::vector<STF::MyOtherClass>::const_iterator itr;

    itr = $1->begin();

    for( itr; itr != $1->end(); itr++ )
    {
        zval* tmp;

        STF::MyOtherClass * res = new STF::MyOtherClass( *itr );

        MAKE_STD_ZVAL( tmp );

        swig_type_info type = *$descriptor(STF::MyOtherClass*);
        type.name = (char*)"_p_CustomNamespace\\MyOtherClass";

        SWIG_SetPointerZval( tmp, res, &type, 2 );

        add_next_index_zval( return_value, tmp );
    }
}

The %template that awoodland did not work for me. I think it is probably because I did not put the PHP class in a different custom namespace. Instead, I did this manually and passed in the exact php class I wanted it to use.

like image 1
drewag Avatar answered Nov 02 '22 18:11

drewag