swig
swig copied to clipboard
Standard library typemaps
The typemaps for std::vector
and std::map
do not work properly. For my own project, I have redefined these typemaps, so this is not really an issue for me, but we should get this working with default typemaps also.
I think it makes sense to write input typemaps from MATLAB arrays (row vectors or column vectors) and cell arrays (row vectors or column vectors).
As for output typemaps, my suggest to use normal row vector (not cell array) whenever possible (i.e. for built-in datatypes such as doubles or integer types) and cell array row vector otherwise.
In CasADi, I have mapped MATLAB structs to std::map<std::string, T>
also.
CasADi's typemaps for std::vector
and std::map
are available here: https://github.com/casadi/casadi/blob/develop/swig/casadi.i.
Yes, this would be great!!
Just to be clear: I don't plan to work on this at the moment (as I don't need it for my project). Would be great if someone else could take the lead here.
I see... I understand your issue, but I am a bit stuck since these typemaps don't work natively. I have a function with prototype like:
std::vector<std::vector<double> > PropsSImulti(const std::vector<std::string> &Outputs,
const std::string &Name1,
const std::vector<double> &Prop1,
const std::string &Name2,
const std::vector<double> &Prop2,
const std::string &backend,
const std::vector<std::string> &fluids,
const std::vector<double> &fractions);
which requires a very large number of proxy classes and I sincerely want to avoid that.
You can fix it by patching swig, or by writing your own typemaps (as I did).
Yeah, I just don't have much (any) experience with writing the necessary typemaps.
On Mon, Jun 29, 2015 at 8:43 AM, Joel Andersson [email protected] wrote:
You can fix it by patching swig, or by writing your own typemaps (as I did).
— Reply to this email directly or view it on GitHub https://github.com/jaeandersson/swig/issues/29#issuecomment-116710508.
Was this issue supposed to be fixed by d886034de67bcf03562cfabcec8248fdf591cc07 ?
std::map
is a tricky thing to get working. It's not a 100 % match with MATLAB structs (far from it) and you'll get into troubles if you want to have cell arrays as members.
std::vector
maps well to row vector cell array. But for std::vector<double>
a simple row vector (1-by-n matrix) is probably a more natural match. And for std::vector<std::string>
, a char matrix with multiple rows.
Was this issue supposed to be fixed by d886034de67bcf03562cfabcec8248fdf591cc07 ?
No, I think that was just to resolve compilation errors.
bump.
If you can explain how to extract the necessaries from your CasADi .i file, that would also be ok for me. There is a lot of code in your interface file and I can't decipher what is and is not needed to use the vector
I can imagine there will be many people stuck with the same sort of problem once MATLAB+SWIG gets merged into the master.
The casadi.i file redefines all of the typemaps we use, using a combination of typemaps, fragments and defines. I'm not sure if that's the way forward for you though. We chose that way to have full control of all typemaps and be able to use the same approach for multiple languages.
For you, it might be easier to just fix the std typemaps. It should be pretty easy. I can't say that I fully understand how these typemaps are structured, but I think it should be enough for you to edit the file "matlabcontainer.swg". There are traits there for both input and output typemaps: I think you need to edit traits_asptr_stdseq
and traits_from_stdseq
respectively. I would make a template specialization to handle std::vector<double>
(both input and output typemaps) and std::vector<std::string>
(at least the input typemap). Other primitive types (std::vector<int>
, std::vector<long>
, std::vector<bool>
) are probably best handled like std::vector<double>
.
The casadi.i could be useful if you want to see how to convert to and from MATLAB types, e.g. for conversion MATLAB types to std::vector<T>
in general:
template<typename M> bool to_ptr(GUESTOBJECT *p, std::vector<M>** m) {
// Treat Null
if (is_null(p)) return false;
#ifdef SWIGMATLAB
// Cell arrays (only row vectors)
if (mxGetClassID(p)==mxCELL_CLASS && mxGetM(p)==1) {
// Get size
int sz = mxGetN(p);
// Allocate elements
if (m) {
(**m).clear();
(**m).reserve(sz);
}
// Temporary
M tmp;
// Loop over elements
for (int i=0; i<sz; ++i) {
// Get element
mxArray* pe = mxGetCell(p, i);
if (pe==0) return false;
// Convert element
M *m_i = m ? &tmp : 0;
if (!to_ptr(pe, m_i ? &m_i : 0)) {
return false;
}
if (m) (**m).push_back(*m_i);
}
return true;
}
#endif // SWIGMATLAB
// No match
return false;
}
or the following specialization to std::vector<std::string>
, converting char matrix with multiple rows to a vector of strings:
bool to_ptr(GUESTOBJECT *p, std::vector<std::string>** m) {
if (mxIsChar(p)) {
if (m) {
// Get data
size_t nrow = mxGetM(p);
size_t ncol = mxGetN(p);
mxChar *data = mxGetChars(p);
// Allocate space for output
(**m).resize(nrow);
std::vector<std::string> &m_ref = **m;
// For all strings
for (size_t j=0; j!=nrow; ++j) {
// Get length without trailing spaces
size_t len = ncol;
while (len!=0 && data[j + nrow*(len-1)]==' ') --len;
// Check if null-terminated
for (size_t i=0; i!=len; ++i) {
if (data[j + nrow*i]=='\0') {
len = i;
break;
}
}
// Create a string of the desired length
m_ref[j] = std::string(len, ' ');
// Get string content
for (size_t i=0; i!=len; ++i) {
m_ref[j][i] = data[j + nrow*i];
}
}
}
return true;
} else {
return false;
}
}