// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory // License: Boost Software License See LICENSE.txt for the full license. // Authors: Davis E. King (davis@dlib.net) /* READ THIS FIRST ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### \############/ \##########/ \########/ \######/ \####/ \##/ \/ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! See example_mex_function.cpp for a discussion of how to use the mex wrapper. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /\ /##\ /####\ /######\ /########\ /##########\ /############\ ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### READ THIS FIRST */ // Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory // License: Boost Software License See LICENSE.txt for the full license. // Authors: Davis E. King (davis@dlib.net) // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // BEGIN IMPLEMENTATION DETAILS // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- #include "../matrix.h" #include "../array2d.h" #include "../array.h" #include "../image_transforms.h" #include "../is_kind.h" #include "../any.h" // for sig_traits #if defined(_MSC_VER) #define DLL_EXPORT_SYM __declspec(dllexport) #endif #include "mex.h" #include <sstream> #include "call_matlab.h" // ---------------------------------------------------------------------------------------- #ifdef ARG_1_DEFAULT #define ELSE_ASSIGN_ARG_1 else A1 = ARG_1_DEFAULT; #else #define ELSE_ASSIGN_ARG_1 #endif #ifdef ARG_2_DEFAULT #define ELSE_ASSIGN_ARG_2 else A2 = ARG_2_DEFAULT; #else #define ELSE_ASSIGN_ARG_2 #endif #ifdef ARG_3_DEFAULT #define ELSE_ASSIGN_ARG_3 else A3 = ARG_3_DEFAULT; #else #define ELSE_ASSIGN_ARG_3 #endif #ifdef ARG_4_DEFAULT #define ELSE_ASSIGN_ARG_4 else A4 = ARG_4_DEFAULT; #else #define ELSE_ASSIGN_ARG_4 #endif #ifdef ARG_5_DEFAULT #define ELSE_ASSIGN_ARG_5 else A5 = ARG_5_DEFAULT; #else #define ELSE_ASSIGN_ARG_5 #endif #ifdef ARG_6_DEFAULT #define ELSE_ASSIGN_ARG_6 else A6 = ARG_6_DEFAULT; #else #define ELSE_ASSIGN_ARG_6 #endif #ifdef ARG_7_DEFAULT #define ELSE_ASSIGN_ARG_7 else A7 = ARG_7_DEFAULT; #else #define ELSE_ASSIGN_ARG_7 #endif #ifdef ARG_8_DEFAULT #define ELSE_ASSIGN_ARG_8 else A8 = ARG_8_DEFAULT; #else #define ELSE_ASSIGN_ARG_8 #endif #ifdef ARG_9_DEFAULT #define ELSE_ASSIGN_ARG_9 else A9 = ARG_9_DEFAULT; #else #define ELSE_ASSIGN_ARG_9 #endif #ifdef ARG_10_DEFAULT #define ELSE_ASSIGN_ARG_10 else A10 = ARG_10_DEFAULT; #else #define ELSE_ASSIGN_ARG_10 #endif // ---------------------------------------------------------------------------------------- namespace mex_binding { using namespace dlib; template <typename T> struct is_input_type { const static unsigned long value = (!is_same_type<void,T>::value && (!is_reference_type<T>::value || is_const_type<T>::value )) ? 1 : 0; }; template <typename T> struct is_output_type { const static unsigned long value = (!is_same_type<void,T>::value && is_reference_type<T>::value && !is_const_type<T>::value) ? 1 : 0; }; template <typename funct> struct funct_traits { const static unsigned long num_inputs = is_input_type<typename sig_traits<funct>::arg1_type>::value + is_input_type<typename sig_traits<funct>::arg2_type>::value + is_input_type<typename sig_traits<funct>::arg3_type>::value + is_input_type<typename sig_traits<funct>::arg4_type>::value + is_input_type<typename sig_traits<funct>::arg5_type>::value + is_input_type<typename sig_traits<funct>::arg6_type>::value + is_input_type<typename sig_traits<funct>::arg7_type>::value + is_input_type<typename sig_traits<funct>::arg8_type>::value + is_input_type<typename sig_traits<funct>::arg9_type>::value + is_input_type<typename sig_traits<funct>::arg10_type>::value; const static unsigned long num_outputs= is_output_type<typename sig_traits<funct>::arg1_type>::value + is_output_type<typename sig_traits<funct>::arg2_type>::value + is_output_type<typename sig_traits<funct>::arg3_type>::value + is_output_type<typename sig_traits<funct>::arg4_type>::value + is_output_type<typename sig_traits<funct>::arg5_type>::value + is_output_type<typename sig_traits<funct>::arg6_type>::value + is_output_type<typename sig_traits<funct>::arg7_type>::value + is_output_type<typename sig_traits<funct>::arg8_type>::value + is_output_type<typename sig_traits<funct>::arg9_type>::value + is_output_type<typename sig_traits<funct>::arg10_type>::value; }; // ---------------------------------------------------------------------------------------- template <typename T> struct is_array_type { // true if T is std::vector or dlib::array const static bool value = is_std_vector<T>::value || dlib::is_array<T>::value; }; // ---------------------------------------------------------------------------------------- template < typename T, typename enabled = void > struct inner_type { typedef T type; }; template < typename T> struct inner_type<T, typename dlib::enable_if_c<is_matrix<T>::value || is_array2d<T>::value || dlib::is_array<T>::value >::type> { typedef typename T::type type; }; template < typename T> struct inner_type<T, typename dlib::enable_if<is_std_vector<T> >::type> { typedef typename T::value_type type; }; // ------------------------------------------------------- struct invalid_args_exception { invalid_args_exception(const std::string& msg_): msg(msg_) {} std::string msg; }; // ------------------------------------------------------- template < typename matrix_type, typename EXP > typename dlib::enable_if_c<is_matrix<matrix_type>::value && is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type assign_mat ( const long arg_idx, matrix_type& m, const matrix_exp<EXP>& src ) { if (matrix_type::NR != 0 && matrix_type::NR != src.nc()) { std::ostringstream sout; sout << "Argument " << arg_idx+1 << " expects a matrix with " << matrix_type::NR << " rows but got one with " << src.nc(); mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", sout.str().c_str()); } if (matrix_type::NC != 0 && matrix_type::NC != src.nr()) { std::ostringstream sout; sout << "Argument " << arg_idx+1 << " expects a matrix with " << matrix_type::NC << " columns but got one with " << src.nr(); mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", sout.str().c_str()); } m = trans(src); } template < typename matrix_type, typename EXP > typename dlib::enable_if_c<is_array2d<matrix_type>::value && is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type assign_mat ( const long arg_idx, matrix_type& m, const matrix_exp<EXP>& src ) { assign_image(m , trans(src)); } template < typename matrix_type, typename EXP > typename disable_if_c<(is_array2d<matrix_type>::value || is_matrix<matrix_type>::value) && is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type assign_mat ( const long arg_idx, matrix_type& , const matrix_exp<EXP>& ) { std::ostringstream sout; sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1; mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", sout.str().c_str()); } // ------------------------------------------------------- template < typename T, typename U > typename dlib::enable_if_c<is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value >::type assign_scalar ( const long arg_idx, T& dest, const U& src ) { if (is_signed_type<U>::value && src < 0 && is_unsigned_type<T>::value) { std::ostringstream sout; sout << "Error, input argument " << arg_idx+1 << " must be a non-negative number."; mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", sout.str().c_str()); } else { dest = src; } } template < typename T, typename U > typename dlib::disable_if_c<is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value >::type assign_scalar ( const long arg_idx, T& , const U& ) { std::ostringstream sout; sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1; mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", sout.str().c_str()); } // ------------------------------------------------------- void assign_function_handle ( const long arg_idx, function_handle& dest, const mxArray* src ) { const_cast<void*&>(dest.h) = (void*)src; } template < typename T > void assign_function_handle ( const long arg_idx, T& , const mxArray* ) { std::ostringstream sout; sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1; mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", sout.str().c_str()); } // ------------------------------------------------------- template < typename T > typename dlib::enable_if<is_array_type<T> >::type assign_std_vector ( const long arg_idx, T& dest, const mxArray* src ) { const long nr = mxGetM(src); const long nc = mxGetN(src); typedef typename inner_type<T>::type type; if (!mxIsCell(src)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a cell array"; throw invalid_args_exception(sout.str()); } if (nr != 1 && nc != 1) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a cell array with exactly 1 row or 1 column (i.e. a row or column vector)"; throw invalid_args_exception(sout.str()); } const long size = nr*nc; dest.resize(size); for (unsigned long i = 0; i < dest.size(); ++i) { try { validate_and_populate_arg(i, mxGetCell(src, i), dest[i]); } catch (invalid_args_exception& e) { std::ostringstream sout; sout << "Error in argument " << arg_idx+1 << ": element " << i+1 << " of cell array not the expected type.\n"; sout << "\t" << e.msg; throw invalid_args_exception(sout.str()); } } } template < typename T > typename disable_if<is_array_type<T> >::type assign_std_vector ( const long arg_idx, T& , const mxArray* ) { std::ostringstream sout; sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1; mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", sout.str().c_str()); } // ------------------------------------------------------- template <typename T> void assign_image ( const long arg_idx, T&, const dlib::uint8* data, long nr, long nc ) { std::ostringstream sout; sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1; mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", sout.str().c_str()); } template <typename MM> void assign_image( const long , array2d<dlib::rgb_pixel,MM>& img, const dlib::uint8* data, long nr, long nc ) { img.set_size(nr, nc); for (long c = 0; c < img.nc(); ++c) for (long r = 0; r < img.nr(); ++r) img[r][c].red = *data++; for (long c = 0; c < img.nc(); ++c) for (long r = 0; r < img.nr(); ++r) img[r][c].green = *data++; for (long c = 0; c < img.nc(); ++c) for (long r = 0; r < img.nr(); ++r) img[r][c].blue = *data++; } // ------------------------------------------------------- template <typename T> void validate_and_populate_arg ( long arg_idx, const mxArray *prhs, T& arg ) { using namespace mex_binding; if (is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value) { if( !(mxIsDouble(prhs) || mxIsSingle(prhs) || mxIsLogical(prhs) ) || mxIsComplex(prhs) || mxGetNumberOfElements(prhs)!=1 ) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a scalar"; throw invalid_args_exception(sout.str()); } assign_scalar(arg_idx, arg , mxGetScalar(prhs)); } else if (is_matrix<T>::value || is_array2d<T>::value) { typedef typename inner_type<T>::type type; const int num_dims = mxGetNumberOfDimensions(prhs); const long nr = mxGetM(prhs); const long nc = mxGetN(prhs); if (is_same_type<type,dlib::rgb_pixel>::value) { if (!(num_dims == 3 && mxGetDimensions(prhs)[2] == 3 && mxIsUint8(prhs))) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a 3-D NxMx3 image matrix of uint8"; throw invalid_args_exception(sout.str()); } const long rows = mxGetDimensions(prhs)[0]; const long cols = mxGetDimensions(prhs)[1]; assign_image(arg_idx, arg , (const dlib::uint8*)mxGetData(prhs), rows, cols); return; } if (num_dims != 2) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a 2-D matrix (got a " << num_dims << "-D matrix)"; throw invalid_args_exception(sout.str()); } if (is_same_type<type,double>::value) { if (!mxIsDouble(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of doubles"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix(mxGetPr(prhs), nc, nr)); } else if (is_same_type<type, float>::value) { if (!mxIsSingle(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of single/float"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const float*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, bool>::value) { if (!mxIsLogical(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of logical elements."; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const bool*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, dlib::uint8>::value) { if (!mxIsUint8(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of uint8"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const dlib::uint8*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, dlib::int8>::value) { if (!mxIsInt8(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of int8"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const dlib::int8*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, dlib::int16>::value || (is_same_type<type, short>::value && sizeof(short) == sizeof(dlib::int16))) { if (!mxIsInt16(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of int16"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, dlib::uint16>::value || (is_same_type<type, unsigned short>::value && sizeof(unsigned short) == sizeof(dlib::uint16))) { if (!mxIsUint16(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of uint16"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, dlib::int32>::value || (is_same_type<type, int>::value && sizeof(int) == sizeof(dlib::int32)) || (is_same_type<type, long>::value && sizeof(long) == sizeof(dlib::int32))) { if (!mxIsInt32(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of int32"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, dlib::uint32>::value || (is_same_type<type, unsigned int>::value && sizeof(unsigned int) == sizeof(dlib::uint32)) || (is_same_type<type, unsigned long>::value && sizeof(unsigned long) == sizeof(dlib::uint32))) { if (!mxIsUint32(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of uint32"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, dlib::uint64>::value || (is_same_type<type, unsigned int>::value && sizeof(unsigned int) == sizeof(dlib::uint64)) || (is_same_type<type, unsigned long>::value && sizeof(unsigned long) == sizeof(dlib::uint64))) { if (!mxIsUint64(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of uint64"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr)); } else if (is_same_type<type, dlib::int64>::value || (is_same_type<type, int>::value && sizeof(int) == sizeof(dlib::int64)) || (is_same_type<type, long>::value && sizeof(long) == sizeof(dlib::int64))) { if (!mxIsInt64(prhs) || mxIsComplex(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a matrix of int64"; throw invalid_args_exception(sout.str()); } assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr)); } else { mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", "mex_function uses unsupported matrix type"); } } else if (is_array_type<T>::value) { assign_std_vector(arg_idx, arg, prhs); } else if (is_same_type<T,function_handle>::value) { if (!mxIsClass(prhs, "function_handle")) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a function handle."; throw invalid_args_exception(sout.str()); } assign_function_handle(arg_idx, arg, prhs); } else { mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", "mex_function uses unsupported input argument type"); } } void validate_and_populate_arg( long arg_idx, const mxArray *prhs, std::string& arg ) { if (!mxIsChar(prhs)) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " must be a char string"; throw invalid_args_exception(sout.str()); } const long nr = mxGetM(prhs); const long nc = mxGetN(prhs); const long size = nr*nc; arg.resize(size+1); if (mxGetString(prhs, &arg[0], arg.size())) { std::ostringstream sout; sout << " argument " << arg_idx+1 << " encountered an error while calling mxGetString()"; throw invalid_args_exception(sout.str()); } arg.resize(size); } // ---------------------------------------------------------------------------------------- template <typename EXP> typename dlib::enable_if<is_same_type<dlib::rgb_pixel,typename EXP::type> >::type assign_image_to_matlab ( dlib::uint8* mat, const matrix_exp<EXP>& item ) { for (long c = 0; c < item.nc(); ++c) for (long r = 0; r < item.nr(); ++r) *mat++ = item(r,c).red; for (long c = 0; c < item.nc(); ++c) for (long r = 0; r < item.nr(); ++r) *mat++ = item(r,c).green; for (long c = 0; c < item.nc(); ++c) for (long r = 0; r < item.nr(); ++r) *mat++ = item(r,c).blue; } template <typename T, typename EXP> typename disable_if<is_same_type<dlib::rgb_pixel,typename EXP::type> >::type assign_image_to_matlab ( T* mat, const matrix_exp<EXP>& ) { mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", "mex_function uses unsupported output image argument type"); } template <typename T> typename dlib::enable_if<is_matrix<T> >::type assign_to_matlab( mxArray*& plhs, const T& item ) { typedef typename T::type type; type* mat = 0; if (is_same_type<double, type>::value) { plhs = mxCreateDoubleMatrix(item.nr(), item.nc(), mxREAL); mat = (type*)mxGetPr(plhs); } else if (is_same_type<float, type>::value ) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxSINGLE_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<bool, type>::value ) { plhs = mxCreateLogicalMatrix(item.nr(), item.nc()); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::uint8, type>::value ) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxUINT8_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::int8, type>::value ) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxINT8_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::int16, type>::value || (is_same_type<short,type>::value && sizeof(short) == sizeof(dlib::int16))) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxINT16_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::uint16, type>::value || (is_same_type<unsigned short,type>::value && sizeof(unsigned short) == sizeof(dlib::uint16))) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxUINT16_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::int32, type>::value || (is_same_type<long,type>::value && sizeof(long) == sizeof(dlib::int32))) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxINT32_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::uint32, type>::value || (is_same_type<unsigned long,type>::value && sizeof(unsigned long) == sizeof(dlib::uint32))) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxUINT32_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::uint64, type>::value || (is_same_type<unsigned long,type>::value && sizeof(unsigned long) == sizeof(dlib::uint64))) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxUINT64_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::int64, type>::value || (is_same_type<long,type>::value && sizeof(long) == sizeof(dlib::int64))) { plhs = mxCreateNumericMatrix(item.nr(), item.nc(), mxINT64_CLASS, mxREAL); mat = (type*)mxGetData(plhs); } else if (is_same_type<dlib::rgb_pixel, type>::value) { mwSize dims[3] = {item.nr(), item.nc(), 3}; plhs = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); assign_image_to_matlab((dlib::uint8*)mxGetData(plhs), item); return; } else { mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", "mex_function uses unsupported output argument type"); } for (long c = 0; c < item.nc(); ++c) { for ( long r= 0; r < item.nr(); ++r) { *mat++ = item(r,c); } } } void assign_to_matlab( mxArray*& plhs, const std::string& item ) { plhs = mxCreateString(item.c_str()); } template <typename T, typename MM> void assign_to_matlab( mxArray*& plhs, const array2d<T,MM>& item ) { assign_to_matlab(plhs,array_to_matrix(item)); } template <typename T> typename dlib::enable_if<is_array_type<T> >::type assign_to_matlab( mxArray*& plhs, const T& item ) { mwSize dims[1] = {item.size()}; plhs = mxCreateCellArray(1,dims); for (unsigned long i = 0; i < item.size(); ++i) { mxArray* next = 0; assign_to_matlab(next, item[i]); mxSetCell(plhs, i, next); } } template <typename T> typename dlib::disable_if_c<is_matrix<T>::value || is_array_type<T>::value || is_same_type<T,function_handle>::value>::type assign_to_matlab( mxArray*& plhs, const T& item ) { plhs = mxCreateDoubleScalar(item); } void assign_to_matlab ( mxArray*& plhs, const char* str ) { assign_to_matlab(plhs, std::string(str)); } void assign_to_matlab( mxArray*& plhs, const function_handle& h ) { } // ---------------------------------------------------------------------------------------- template < unsigned long num_args > struct call_mex_function_helper; template <> struct call_mex_function_helper<1> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typename basic_type<arg1_type>::type A1; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; mex_function(A1); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} } }; template <> struct call_mex_function_helper<2> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; mex_function(A1,A2); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} } }; template <> struct call_mex_function_helper<3> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typedef typename sig_traits<funct>::arg3_type arg3_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; typename basic_type<arg3_type>::type A3; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3; mex_function(A1,A2,A3); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;} } }; template <> struct call_mex_function_helper<4> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typedef typename sig_traits<funct>::arg3_type arg3_type; typedef typename sig_traits<funct>::arg4_type arg4_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; typename basic_type<arg3_type>::type A3; typename basic_type<arg4_type>::type A4; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3; if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4; mex_function(A1,A2,A3,A4); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;} if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;} } }; template <> struct call_mex_function_helper<5> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typedef typename sig_traits<funct>::arg3_type arg3_type; typedef typename sig_traits<funct>::arg4_type arg4_type; typedef typename sig_traits<funct>::arg5_type arg5_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; typename basic_type<arg3_type>::type A3; typename basic_type<arg4_type>::type A4; typename basic_type<arg5_type>::type A5; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3; if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4; if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5; mex_function(A1,A2,A3,A4,A5); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;} if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;} if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;} } }; template <> struct call_mex_function_helper<6> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typedef typename sig_traits<funct>::arg3_type arg3_type; typedef typename sig_traits<funct>::arg4_type arg4_type; typedef typename sig_traits<funct>::arg5_type arg5_type; typedef typename sig_traits<funct>::arg6_type arg6_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; typename basic_type<arg3_type>::type A3; typename basic_type<arg4_type>::type A4; typename basic_type<arg5_type>::type A5; typename basic_type<arg6_type>::type A6; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3; if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4; if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5; if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6; mex_function(A1,A2,A3,A4,A5,A6); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;} if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;} if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;} if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;} } }; template <> struct call_mex_function_helper<7> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typedef typename sig_traits<funct>::arg3_type arg3_type; typedef typename sig_traits<funct>::arg4_type arg4_type; typedef typename sig_traits<funct>::arg5_type arg5_type; typedef typename sig_traits<funct>::arg6_type arg6_type; typedef typename sig_traits<funct>::arg7_type arg7_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; typename basic_type<arg3_type>::type A3; typename basic_type<arg4_type>::type A4; typename basic_type<arg5_type>::type A5; typename basic_type<arg6_type>::type A6; typename basic_type<arg7_type>::type A7; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3; if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4; if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5; if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6; if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7; mex_function(A1,A2,A3,A4,A5,A6,A7); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;} if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;} if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;} if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;} if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;} } }; template <> struct call_mex_function_helper<8> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typedef typename sig_traits<funct>::arg3_type arg3_type; typedef typename sig_traits<funct>::arg4_type arg4_type; typedef typename sig_traits<funct>::arg5_type arg5_type; typedef typename sig_traits<funct>::arg6_type arg6_type; typedef typename sig_traits<funct>::arg7_type arg7_type; typedef typename sig_traits<funct>::arg8_type arg8_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; typename basic_type<arg3_type>::type A3; typename basic_type<arg4_type>::type A4; typename basic_type<arg5_type>::type A5; typename basic_type<arg6_type>::type A6; typename basic_type<arg7_type>::type A7; typename basic_type<arg8_type>::type A8; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3; if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4; if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5; if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6; if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7; if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8; mex_function(A1,A2,A3,A4,A5,A6,A7,A8); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;} if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;} if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;} if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;} if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;} if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;} } }; template <> struct call_mex_function_helper<9> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typedef typename sig_traits<funct>::arg3_type arg3_type; typedef typename sig_traits<funct>::arg4_type arg4_type; typedef typename sig_traits<funct>::arg5_type arg5_type; typedef typename sig_traits<funct>::arg6_type arg6_type; typedef typename sig_traits<funct>::arg7_type arg7_type; typedef typename sig_traits<funct>::arg8_type arg8_type; typedef typename sig_traits<funct>::arg9_type arg9_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; typename basic_type<arg3_type>::type A3; typename basic_type<arg4_type>::type A4; typename basic_type<arg5_type>::type A5; typename basic_type<arg6_type>::type A6; typename basic_type<arg7_type>::type A7; typename basic_type<arg8_type>::type A8; typename basic_type<arg9_type>::type A9; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3; if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4; if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5; if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6; if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7; if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8; if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9; mex_function(A1,A2,A3,A4,A5,A6,A7,A8,A9); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;} if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;} if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;} if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;} if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;} if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;} if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;} } }; template <> struct call_mex_function_helper<10> { template <typename funct> void callit( const funct& , int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) const { typedef typename sig_traits<funct>::arg1_type arg1_type; typedef typename sig_traits<funct>::arg2_type arg2_type; typedef typename sig_traits<funct>::arg3_type arg3_type; typedef typename sig_traits<funct>::arg4_type arg4_type; typedef typename sig_traits<funct>::arg5_type arg5_type; typedef typename sig_traits<funct>::arg6_type arg6_type; typedef typename sig_traits<funct>::arg7_type arg7_type; typedef typename sig_traits<funct>::arg8_type arg8_type; typedef typename sig_traits<funct>::arg9_type arg9_type; typedef typename sig_traits<funct>::arg10_type arg10_type; typename basic_type<arg1_type>::type A1; typename basic_type<arg2_type>::type A2; typename basic_type<arg3_type>::type A3; typename basic_type<arg4_type>::type A4; typename basic_type<arg5_type>::type A5; typename basic_type<arg6_type>::type A6; typename basic_type<arg7_type>::type A7; typename basic_type<arg8_type>::type A8; typename basic_type<arg9_type>::type A9; typename basic_type<arg10_type>::type A10; int i = 0; if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1; if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2; if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3; if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4; if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5; if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6; if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7; if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8; if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9; if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10; mex_function(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10); i = 0; if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;} if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;} if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;} if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;} if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;} if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;} if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;} if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;} if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;} if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;} } }; // ---------------------------------------------------------------------------------------- template < typename funct > void call_mex_function ( const funct& f, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { const long expected_nrhs = funct_traits<funct>::num_inputs; const long expected_nlhs = funct_traits<funct>::num_outputs; const long expected_args = expected_nrhs + expected_nlhs; long defaulted_args = 0; #ifdef ARG_1_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg1_type>::value); #ifndef ARG_2_DEFAULT // You can't define a default for argument 1 if you don't define one for argument 2 also. COMPILE_TIME_ASSERT(expected_args < 2); #endif COMPILE_TIME_ASSERT(1 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_2_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg2_type>::value); #ifndef ARG_3_DEFAULT // You can't define a default for argument 2 if you don't define one for argument 3 also. COMPILE_TIME_ASSERT(expected_args < 3); #endif COMPILE_TIME_ASSERT(2 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_3_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg3_type>::value); #ifndef ARG_4_DEFAULT // You can't define a default for argument 3 if you don't define one for argument 4 also. COMPILE_TIME_ASSERT(expected_args < 4); #endif COMPILE_TIME_ASSERT(3 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_4_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg4_type>::value); #ifndef ARG_5_DEFAULT // You can't define a default for argument 4 if you don't define one for argument 5 also. COMPILE_TIME_ASSERT(expected_args < 5); #endif COMPILE_TIME_ASSERT(4 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_5_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg5_type>::value); #ifndef ARG_6_DEFAULT // You can't define a default for argument 5 if you don't define one for argument 6 also. COMPILE_TIME_ASSERT(expected_args < 6); #endif COMPILE_TIME_ASSERT(5 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_6_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg6_type>::value); #ifndef ARG_7_DEFAULT // You can't define a default for argument 6 if you don't define one for argument 7 also. COMPILE_TIME_ASSERT(expected_args < 7); #endif COMPILE_TIME_ASSERT(6 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_7_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg7_type>::value); #ifndef ARG_8_DEFAULT // You can't define a default for argument 7 if you don't define one for argument 8 also. COMPILE_TIME_ASSERT(expected_args < 8); #endif COMPILE_TIME_ASSERT(7 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_8_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg8_type>::value); #ifndef ARG_9_DEFAULT // You can't define a default for argument 8 if you don't define one for argument 9 also. COMPILE_TIME_ASSERT(expected_args < 9); #endif COMPILE_TIME_ASSERT(8 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_9_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg9_type>::value); #ifndef ARG_10_DEFAULT // You can't define a default for argument 9 if you don't define one for argument 10 also. COMPILE_TIME_ASSERT(expected_args < 10); #endif COMPILE_TIME_ASSERT(9 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif #ifdef ARG_10_DEFAULT ++defaulted_args; // You can only set an argument's default value if it is an input argument. COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg10_type>::value); COMPILE_TIME_ASSERT(10 <= expected_args); // You can't define a default for an argument that doesn't exist. #endif /* check for proper number of arguments */ if(nrhs > expected_nrhs || nrhs < expected_nrhs - defaulted_args) { std::ostringstream sout; sout << "Expected between " << expected_nrhs-defaulted_args << " and " << expected_nrhs << " input arguments, got " << nrhs << "."; mexErrMsgIdAndTxt("mex_function:nrhs", sout.str().c_str()); } if (nlhs > expected_nlhs) { std::ostringstream sout; sout << "Expected at most " << expected_nlhs << " output arguments, got " << nlhs << "."; mexErrMsgIdAndTxt("mex_function:nlhs", sout.str().c_str()); } try { call_mex_function_helper<sig_traits<funct>::num_args> helper; helper.callit(f, nlhs, plhs, nrhs, prhs); } catch (invalid_args_exception& e) { mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg", ("Input" + e.msg).c_str()); } catch (dlib::error& e) { mexErrMsgIdAndTxt("mex_function:error", e.what()); } } // ---------------------------------------------------------------------------------------- class mex_streambuf : public std::streambuf { public: mex_streambuf ( ) { buf.resize(1000); setp(&buf[0], &buf[0] + buf.size()-2); // make cout send data to mex_streambuf std::cout.rdbuf(this); } protected: int sync ( ) { int num = static_cast<int>(pptr()-pbase()); if (num != 0) { buf[num] = 0; // null terminate the string mexPrintf("%s",&buf[0]); mexEvalString("drawnow"); // flush print to screen pbump(-num); } return 0; } int_type overflow ( int_type c ) { if (c != EOF) { *pptr() = c; pbump(1); } sync(); return c; } private: std::vector<char> buf; }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template <typename T> void setup_input_args ( mxArray*& array, const T& item, int& nrhs ) { assign_to_matlab(array, item); ++nrhs; } void setup_input_args ( mxArray*& array, const function_handle& item, int& nrhs ) { array = static_cast<mxArray*>(item.h); ++nrhs; } template <typename T> void setup_input_args ( mxArray*& array, const output_decorator<T>& item, int& nrhs ) { } template <typename T> void setup_output_args ( const std::string& function_name, mxArray* array, const T& item, int& nrhs ) { } template <typename T> void setup_output_args ( const std::string& function_name, mxArray* array, const output_decorator<T>& item, int& i ) { try { validate_and_populate_arg(i,array,const_cast<T&>(item.item)); ++i; } catch (invalid_args_exception& e) { throw dlib::error("Error occurred calling MATLAB function '" + function_name + "' from mex file. \n" "The MATLAB function didn't return what we expected it to. \nIn particular, return" + e.msg); } } void call_matlab_for_real ( int nlhs, mxArray* plhs[], int nrhs, mxArray* prhs[], const std::string& function_name ) { int status = mexCallMATLAB(nlhs, plhs, nrhs, prhs, function_name.c_str()); if (status) { throw dlib::error("Error, an exception was thrown when we tried to call the MATLAB function '" + function_name + "'."); } } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- void call_matlab ( const std::string& function_name ) { using namespace mex_binding; call_matlab_for_real(0,NULL,0,NULL, function_name); } template <typename T1> void free_callback_resources ( int nlhs, mxArray* plhs[], int nrhs, mxArray* prhs[] ) { // free resources for (int i = 0; i < nlhs; ++i) mxDestroyArray(plhs[i]); for (int i = 0; i < nrhs; ++i) { // don't call mxDestroyArray() on function handles (which should only ever be in prhs[0]) if (i == 0 && dlib::is_same_type<T1,function_handle>::value) continue; mxDestroyArray(prhs[i]); } } template < typename T1 > void call_matlab ( const std::string& function_name, const T1& A1 ) { using namespace mex_binding; const int num_args = 1; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2 ) { using namespace mex_binding; const int num_args = 2; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2, typename T3 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2, const T3& A3 ) { using namespace mex_binding; const int num_args = 3; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); setup_input_args(prhs[nrhs], A3, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); setup_output_args(function_name, plhs[i], A3, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2, typename T3, typename T4 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2, const T3& A3, const T4& A4 ) { using namespace mex_binding; const int num_args = 4; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); setup_input_args(prhs[nrhs], A3, nrhs); setup_input_args(prhs[nrhs], A4, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); setup_output_args(function_name, plhs[i], A3, i); setup_output_args(function_name, plhs[i], A4, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2, typename T3, typename T4, typename T5 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5 ) { using namespace mex_binding; const int num_args = 5; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); setup_input_args(prhs[nrhs], A3, nrhs); setup_input_args(prhs[nrhs], A4, nrhs); setup_input_args(prhs[nrhs], A5, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); setup_output_args(function_name, plhs[i], A3, i); setup_output_args(function_name, plhs[i], A4, i); setup_output_args(function_name, plhs[i], A5, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2, typename T3, typename T4, typename T5, typename T6 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6 ) { using namespace mex_binding; const int num_args = 6; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); setup_input_args(prhs[nrhs], A3, nrhs); setup_input_args(prhs[nrhs], A4, nrhs); setup_input_args(prhs[nrhs], A5, nrhs); setup_input_args(prhs[nrhs], A6, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); setup_output_args(function_name, plhs[i], A3, i); setup_output_args(function_name, plhs[i], A4, i); setup_output_args(function_name, plhs[i], A5, i); setup_output_args(function_name, plhs[i], A6, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, const T7& A7 ) { using namespace mex_binding; const int num_args = 7; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); setup_input_args(prhs[nrhs], A3, nrhs); setup_input_args(prhs[nrhs], A4, nrhs); setup_input_args(prhs[nrhs], A5, nrhs); setup_input_args(prhs[nrhs], A6, nrhs); setup_input_args(prhs[nrhs], A7, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); setup_output_args(function_name, plhs[i], A3, i); setup_output_args(function_name, plhs[i], A4, i); setup_output_args(function_name, plhs[i], A5, i); setup_output_args(function_name, plhs[i], A6, i); setup_output_args(function_name, plhs[i], A7, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, const T7& A7, const T8& A8 ) { using namespace mex_binding; const int num_args = 8; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); setup_input_args(prhs[nrhs], A3, nrhs); setup_input_args(prhs[nrhs], A4, nrhs); setup_input_args(prhs[nrhs], A5, nrhs); setup_input_args(prhs[nrhs], A6, nrhs); setup_input_args(prhs[nrhs], A7, nrhs); setup_input_args(prhs[nrhs], A8, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); setup_output_args(function_name, plhs[i], A3, i); setup_output_args(function_name, plhs[i], A4, i); setup_output_args(function_name, plhs[i], A5, i); setup_output_args(function_name, plhs[i], A6, i); setup_output_args(function_name, plhs[i], A7, i); setup_output_args(function_name, plhs[i], A8, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, const T7& A7, const T8& A8, const T9& A9 ) { using namespace mex_binding; const int num_args = 9; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); setup_input_args(prhs[nrhs], A3, nrhs); setup_input_args(prhs[nrhs], A4, nrhs); setup_input_args(prhs[nrhs], A5, nrhs); setup_input_args(prhs[nrhs], A6, nrhs); setup_input_args(prhs[nrhs], A7, nrhs); setup_input_args(prhs[nrhs], A8, nrhs); setup_input_args(prhs[nrhs], A9, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); setup_output_args(function_name, plhs[i], A3, i); setup_output_args(function_name, plhs[i], A4, i); setup_output_args(function_name, plhs[i], A5, i); setup_output_args(function_name, plhs[i], A6, i); setup_output_args(function_name, plhs[i], A7, i); setup_output_args(function_name, plhs[i], A8, i); setup_output_args(function_name, plhs[i], A9, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } template < typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10 > void call_matlab ( const std::string& function_name, const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, const T7& A7, const T8& A8, const T9& A9, const T10& A10 ) { using namespace mex_binding; const int num_args = 10; mxArray* plhs[num_args] = {0}; mxArray* prhs[num_args] = {0}; int nrhs = 0; setup_input_args(prhs[nrhs], A1, nrhs); setup_input_args(prhs[nrhs], A2, nrhs); setup_input_args(prhs[nrhs], A3, nrhs); setup_input_args(prhs[nrhs], A4, nrhs); setup_input_args(prhs[nrhs], A5, nrhs); setup_input_args(prhs[nrhs], A6, nrhs); setup_input_args(prhs[nrhs], A7, nrhs); setup_input_args(prhs[nrhs], A8, nrhs); setup_input_args(prhs[nrhs], A10, nrhs); const int nlhs = num_args - nrhs; call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name); int i = 0; setup_output_args(function_name, plhs[i], A1, i); setup_output_args(function_name, plhs[i], A2, i); setup_output_args(function_name, plhs[i], A3, i); setup_output_args(function_name, plhs[i], A4, i); setup_output_args(function_name, plhs[i], A5, i); setup_output_args(function_name, plhs[i], A6, i); setup_output_args(function_name, plhs[i], A7, i); setup_output_args(function_name, plhs[i], A8, i); setup_output_args(function_name, plhs[i], A10, i); free_callback_resources<T1>(nlhs,plhs,nrhs,prhs); } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- void call_matlab ( const function_handle& funct ) { call_matlab("feval", funct); } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- /* The gateway function called by MATLAB*/ void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // Only remap cout if we aren't using octave since octave already does this. #if !defined(OCTAVE_IMPORT) && !defined(OCTAVE_API) // make it so cout prints to mexPrintf() static mex_binding::mex_streambuf sb; #endif mex_binding::call_mex_function(mex_function, nlhs, plhs, nrhs, prhs); } // ----------------------------------------------------------------------------------------