// offset allows linking the data object to a sub-volume (in the z direction) // offset is measured in floats. CFloat32CustomMemoryMatlab3D(const mxArray* _pArray, bool bUnshare, size_t iOffset) { // Convert from slice to offset mwSize dims[3]; get3DMatrixDims(_pArray, dims); iOffset *= dims[0]; iOffset *= dims[1]; //fprintf(stderr, "Passed:\narray: %p\tdata: %p\n", (void*)_pArray, (void*)mxGetData(_pArray)); // First unshare the input array, so that we may modify it. if (bUnshare) { #if 0 // Unsupported in Matlab R2014b if (mxIsSharedArray(_pArray)) { fprintf(stderr, "Performance note: unsharing shared array in link\n"); } #endif mxUnshareArray(_pArray, false); //fprintf(stderr, "Unshared:\narray: %p\tdata: %p\n", (void*)_pArray, (void*)mxGetData(_pArray)); } // Then create a (persistent) copy so the data won't be deleted // or changed. m_pLink = mxCreateSharedDataCopy(_pArray); //fprintf(stderr, "SharedDataCopy:\narray: %p\tdata: %p\n", (void*)m_pLink, (void*)mxGetData(m_pLink)); mexMakeArrayPersistent(m_pLink); m_fPtr = (float *)mxGetData(m_pLink); m_fPtr += iOffset; }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { struct mxArray_Tag *mx; mwSize inbytes, outbytes, i, k, idim, ndim; mwSize *dims_old, *dims_new; char *outstring; mxClassID outclass; int out_numeric; /* Check input arguments */ if( nrhs > 2 ) { mexErrMsgTxt("Too many input arguments."); } if( nrhs < 2 ) { mexErrMsgTxt("Not enough input arguments."); } if( nlhs > 1 ) { mexErrMsgTxt("Too many output arguments."); } if( mxIsSparse(prhs[0]) || (!mxIsNumeric(prhs[0]) && !mxIsChar(prhs[0]) && !mxIsLogical(prhs[0])) ) { mexErrMsgTxt("The first input argument must be a full numeric value, or char, or logical."); } if( !mxIsChar(prhs[1]) ) { mexErrMsgTxt("The second input argument must be a character array."); } /* Get input argument byte length */ inbytes = mxGetElementSize(prhs[0]); /* Check second input argument for desired output type */ outstring = mxArrayToString(prhs[1]); out_numeric = 1; if( strcmp(outstring,"int8") == 0 ) { outclass = mxINT8_CLASS; outbytes = 1; } else if( strcmp(outstring,"uint8") == 0 ) { outclass = mxUINT8_CLASS; outbytes = 1; } else if( strcmp(outstring,"int16") == 0 ) { outclass = mxINT16_CLASS; outbytes = 2; } else if( strcmp(outstring,"uint16") == 0 ) { outclass = mxUINT16_CLASS; outbytes = 2; } else if( strcmp(outstring,"int32") == 0 ) { outclass = mxINT32_CLASS; outbytes = 4; } else if( strcmp(outstring,"uint32") == 0 ) { outclass = mxUINT32_CLASS; outbytes = 4; } else if( strcmp(outstring,"int64") == 0 ) { outclass = mxINT64_CLASS; outbytes = 8; } else if( strcmp(outstring,"uint64") == 0 ) { outclass = mxUINT64_CLASS; outbytes = 8; } else if( strcmp(outstring,"double") == 0 ) { outclass = mxDOUBLE_CLASS; outbytes = 8; } else if( strcmp(outstring,"single") == 0 ) { outclass = mxSINGLE_CLASS; outbytes = 4; } else if( strcmp(outstring,"char") == 0 ) { outclass = mxCHAR_CLASS; outbytes = 2; out_numeric = 0; } else if( strcmp(outstring,"logical") == 0 ) { outclass = mxLOGICAL_CLASS; outbytes = 1; out_numeric = 0; } else { mxFree(outstring); mexErrMsgTxt("Unsupported class.\n"); } mxFree(outstring); /* Check for complex coversion to non-numeric */ if( mxIsComplex(prhs[0]) && !out_numeric ) { mexErrMsgTxt("Cannot typecast a complex input to a non-numeric class.\n"); } /* Check for empty input. No data to share, so simply create a new empty variable */ if( mxIsEmpty(prhs[0]) ) { if( out_numeric ) { plhs[0] = mxCreateNumericArray(mxGetNumberOfDimensions(prhs[0]), mxGetDimensions(prhs[0]), outclass, mxREAL); } else if( outclass == mxCHAR_CLASS ) { plhs[0] = mxCreateCharArray(mxGetNumberOfDimensions(prhs[0]), mxGetDimensions(prhs[0])); } else { plhs[0] = mxCreateLogicalArray(mxGetNumberOfDimensions(prhs[0]), mxGetDimensions(prhs[0])); } return; } /* Check the old & new sizes for compatibility */ ndim = mxGetNumberOfDimensions(prhs[0]); dims_old = mxGetDimensions(prhs[0]); for( i=0; i<ndim; i++ ) { if( dims_old[i] != 1 || i == ndim-1 ) { k = (dims_old[i] * inbytes) / outbytes; if( k * outbytes != dims_old[i] * inbytes ) { mexErrMsgTxt("Too few input values to make output type.\n"); } idim = i; break; } } dims_new = mxMalloc(ndim * sizeof(*dims_new)); for( i=0; i<ndim; i++ ) { dims_new[i] = dims_old[i]; } dims_new[idim] = k; /* Create the output array as a shared data copy, then manually set the class * and size parameters by accessing the structure fields directly. Note that * this is using undocumented MATLAB API functions and hacking of the * mxArray_tag structure, so this may not work in future versions of MATLAB. */ // mx = (struct mxArray_Tag *) prhs[0]; // printf("old flags: %#6x\n", mx->flags); plhs[0] = mxCreateSharedDataCopy(prhs[0]); mx = (struct mxArray_Tag *) plhs[0]; mx->ClassID = outclass; mx->VariableType = VariableType_Temporary; mxSetDimensions(plhs[0],dims_new,ndim); mxFree(dims_new); //mexPrintf("post shared data copy\n"); // printf("new flags: %#6x\n", mx->flags); return; // this breaks in R2018a, @djoshea removing /* Also need to fix up the flags */ if( outclass == mxDOUBLE_CLASS ) { if( mxGetNumberOfElements(plhs[0]) == 1 ) { mx->flags = 0x0211; /* Set numeric, temporary, and full double scalar bits */ } else { mx->flags = 0x0210; /* Set numeric and temporary bits */ } } else if( out_numeric ) { mx->flags = 0x0210; /* Set numeric and temporary bits */ } else { mx->flags = 0x0010; /* Set the temporary bit */ } }