As you have already discovered, the table class is not directly supported in the mex API. The table class is a classdef type of object, and the only support you get in the mex API for classdef objects is mxGetProperty and mxPutProperty. These have two drawbacks when working with tables. First, mxGetProperty and mxPutProperty both force a deep data copy ... so simply examining large properties in a mex routine can seriously blow up your memory. Not good. Second, you have to know the property names in order to use these routines. For your own classdef objects at least you know that. But for tables you don't ... at least not at the mex level. Consider the following example:
classdef myclass
properties
a
b
c
end
end
Then at the MATLAB command line:
>> a = rand(10,1);
>> b = int32(a*100);
>> c = a<.5;
>> t = table(a,b,c)
t =
a b c
_______ __ _____
0.15761 16 true
0.97059 97 false
0.95717 96 false
0.48538 49 true
0.80028 80 false
0.14189 14 true
0.42176 42 true
0.91574 92 false
0.79221 79 false
0.95949 96 false
>> m = myclass;
>> m.a = a;
>> m.b = b;
>> m.c = c;
>> m
m =
myclass with properties:
a: [10x1 double]
b: [10x1 int32]
c: [10x1 logical]
Now look at the properties of each:
>> properties(t)
Properties for class table:
a
b
c
Properties
>> properties(m)
Properties for class myclass:
a
b
c
Seems pretty straightforward, right? Both of them show that they have properties named 'a', 'b', and 'c'. (And t apparently has an extra property named 'Properties'). You can even get at them with the .property syntax:
>> t.a
ans =
0.1576
0.9706
0.9572
0.4854
0.8003
0.1419
0.4218
0.9157
0.7922
0.9595
>> m.a
ans =
0.1576
0.9706
0.9572
0.4854
0.8003
0.1419
0.4218
0.9157
0.7922
0.9595
Etc.
But a look at these variables inside a mex routine reveals the truth ... that t is not a classdef object with a first level property named 'a'. E.g.,
// table_test1.c
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mxArray *property;
mexPrintf("Class name of input is %s\n",mxGetClassName(prhs[0]));
property = mxGetProperty(prhs[0],0,"a");
mexPrintf("The 'a' property pointer (a deep copy) is %p\n",property);
property = mxGetProperty(prhs[0],0,"b");
mexPrintf("The 'b' property pointer (a deep copy) is %p\n",property);
property = mxGetProperty(prhs[0],0,"c");
mexPrintf("The 'c' property pointer (a deep copy) is %p\n",property);
}
>> table_test1(m)
Class name of input is myclass
The 'a' property pointer (a deep copy) is 08C08720
The 'b' property pointer (a deep copy) is 08C08E20
The 'c' property pointer (a deep copy) is 08C08100
>> table_test1(t)
Class name of input is table
The 'a' property pointer (a deep copy) is 00000000
The 'b' property pointer (a deep copy) is 00000000
The 'c' property pointer (a deep copy) is 00000000
So the thot plickens, since those NULL pointer returns indicate that the 'a', 'b', and 'c' properties are not there. As far as the physical storage is concerned, at least at the first level, there are no properties named 'a', 'b', or 'c' for tables like there are for the simply user defined myclass classdef object. This is, of course, a major complication for the mex programmer. Not only are classdef objects poorly supported (only deep copies with mxGetProperty and mxPutProperty), but with tables you can't even get at the data since you don't know how to get at it. The only apparent clue is that the properties(t) output is formatted differently than the properties(m) output ... leading me to believe that this is a special output from MATLAB because those properties really aren't at the first level, even though you can get at them from MATLAB with the .property notation.
Well, what the heck is in that extra property named Properties?
>> t.Properties
ans =
Description: ''
VariableDescriptions: {}
VariableUnits: {}
DimensionNames: {'Row' 'Variable'}
UserData: []
RowNames: {}
VariableNames: {'a' 'b' 'c'}
At least this is something. Properties is a struct with a variety of information in it. In particular, Properties.VariableNames is a cell array of strings that contain the property names. All well and good ... at least you can get at all of this stuff in a mex routine if you want, but unfortunately there is nothing in there that connects you to the data. My guess is that the data is locked up inside a private area of the object, and there is no way to get at it from within a mex routine. In fact, when I hack into the mxArray variables inside a mex routine I can see all 3 shared copies of a, b, and c (the variables a, b, c in the workspace, the properties .a, .b, .c that are part of m, and the "properties" .a, .b, .c that are part of t). But other than the (not officially supported and highly discouraged) hack, I can think of no way to get at the data inside a mex routine.
So you are stuck with pulling the data out at the MATLAB level like you are doing before you pass it into the mex routine. My only advice here is to try to do it in a way that results in shared data copies. Cells and structs (and the old OOP class method btw) are very mex friendly since mxGetField and friends do not do a deep data copy ... they return the actual pointer to the data area inside the struct (yea!).
One thing I would change in your code would be to move the RowNames field to the end of your struct, not at the beginning. That way you always know that the field numbering 1, 2, 3, etc always corresponds to your variables. The way you have it currently coded the variables could be in either fields 1, 2, 3, etc or in fields 2, 3, 4, etc. The only way to know is to check to see if RowNames is present. Why make the user do that? In fact, why not just always append it at the end even if it is empty? E.g., something like this:
VariableNames = inTable.Properties.VariableNames;
struct_arguments = cell(2,numel(VariableNames));
struct_arguments(1,:) = VariableNames;
outStruct = struct(struct_arguments{:});
for varNum=1:width(inTable)
outStruct.(VariableNames{varNum}) = inTable.(varNum);
end
outStruct.RowNames = inTable.Properties.RowNames;
FINAL NOTE: I have checked with a mex hack of the resulting struct that the field variables are indeed shared copies (in this case reference copies) of the original table variables, so your method is a pretty good one for data efficiency.