Now while one can do this with MTensor_setMTensor as I just discovered, one should NOT really go for this approach as it is simpler and nicer to get the starting address of your raw data and index from there as one would do with plain C/C++.
EXTERN_C DLLEXPORT int RandomRealLDBN( WolframLibraryData libData,
mint Argc, MArgument* Args, MArgument Res)
{
// Error
int err = LIBRARY_NO_ERROR;
// Args
const mint isamples = MArgument_getInteger(Args[0]);
// Setup nb of samples
const mint nsamples = std::floor(std::sqrt((double)isamples)) *2;
const mint nrealslots = 2;
// Tensor to hold nsamples slots of 2 reals
MTensor oT;
mint oDims[2];
oDims[0] = nsamples;
oDims[1] = nrealslots;
const mint oRank = 2;
err = libData->MTensor_new(MType_Real, oRank, oDims, &oT);
if(err) return err;
// Low-Discrepancy BlueNoise
std::vector<Point> samples;
initSamplers();
ldbnBNOT(nsamples, samples);
// Setup subtensor to hold sample data
MTensor iT;
mint iDims[] = {nrealslots};
const mint iRank = 1;
const mint nPos = 1;
mint pos[1];
// Yep, MTensor is a 1-based array as in WM
for(int i=1; i<=nsamples; i++)
{
Point s = samples[i-1];
// allocate a tensor to hold the sample
err = libData->MTensor_new(MType_Real, iRank, iDims, &iT);
if(err) return err;
// fill in the sample data
mreal *sample = libData->MTensor_getRealData(iT);
sample[0] = s[0]; //copy sample data
sample[1] = s[1];
// update index
pos[0] = i;
//insert subtensor in our main tensor list at pos
err = libData->MTensor_setMTensor(oT, iT, pos, nPos);
if(err) return err;
}
//[....]
// Get back to WM
MArgument_setMTensor(Res, oT);
return err;
}
The function signature in WM is:
RandomRealLDBN =
LibraryFunctionLoad[randomRealLDBNLib,
"RandomRealLDBN", {Integer}, {Real, 2}]
We'll have data back in WM with this layout
{{0.25, 0.4375}, {0.6875, 0.125}, {0.40625, 0.9375}, {0.8125, 0.625}}
So as Szabolcs is saying we can go as simple as
EXTERN_C DLLEXPORT int RandomRealLDBN( WolframLibraryData libData,
mint Argc, MArgument *Args, MArgument Res)
{
// Error
int err = LIBRARY_NO_ERROR;
// Args
const mint isamples = MArgument_getInteger(Args[0]);
// Setup nb of samples
const mint samplerow = std::floor(std::sqrt((double)isamples));
const mint nsamples = pow(samplerow,2);
const mint nrealslots = 2;
// Tensor to hold nsamples slots of 2 reals
MTensor oT;
const mint oDims[2] = {nsamples, nrealslots};
const mint oRank = 2;
err = libData->MTensor_new(MType_Real, oRank, oDims, &oT);
if(err) return err;
// Low-Discrepancy BlueNoise
std::vector<Point> samples;
initSamplers();
ldbnBNOT(samplerow, samples);
// Get the starting address of the data to be filled in
mreal *datastartingaddress = libData->MTensor_getRealData(oT);
// Fill in samples data
memcpy(datastartingaddress, &samples[0], sizeof(double)*nsamples*nrealslots);
// Same as above
/*for(int i=0; i < nsamples; i++){
Point s = samples[i];
datastartingaddress[i*nrealslots +0] = s[0];
datastartingaddress[i*nrealslots +1] = s[1];
}*/
//[...]
// Get back to WM
MArgument_setMTensor(Res, oT);
return err;
}