00001
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifndef MEXUTILS_H
00015 #define MEXUTILS_H
00016
00017 #include"mex.h"
00018 #include<vl/generic.h>
00019 #include<vl/array.h>
00020 #include<vl/stringop.h>
00021 #include<ctype.h>
00022 #include<string.h>
00023 #include<stdio.h>
00024 #include<stdarg.h>
00025
00026 #ifdef VL_COMPILER_MSC
00027 #define snprintf _snprintf
00028 #define vsnprintf _vsnprintf
00029 #endif
00030
00031 #if (! defined(MX_API_VER) || (MX_API_VER < 0x07030000)) && \
00032 (! defined(HAVE_OCTAVE))
00033 typedef vl_uint32 mwSize ;
00034 typedef vl_int32 mwIndex ;
00035 #endif
00036
00038 #undef IN
00039 #define IN(x) (in[IN_ ## x])
00040
00042 #undef OUT
00043 #define OUT(x) (out[OUT_ ## x])
00044
00045 #ifdef HAVE_OCTAVE
00046 static void *
00047 mxReallocOctaveWorkaround(void * ptr, size_t size)
00048 {
00049
00050 if (ptr) {
00051 return mxRealloc(ptr, size) ;
00052 } else {
00053 return mxMalloc(size) ;
00054 }
00055 }
00056 #define mxRealloc mxReallocOctaveWorkaround
00057 static int
00058 mxSetDimensionsOctaveWorkaround(mxArray * array, const mwSize *dims, int ndims)
00059 {
00060 mwSize * dims_ = mxMalloc(sizeof(mwSize)*ndims) ;
00061 int i ;
00062 for (i = 0 ; i < ndims ; ++i) dims_[i] = dims[i] ;
00063 mxSetDimensions(array,dims_,ndims) ;
00064 return 0 ;
00065 }
00066 #define mxSetDimensions mxSetDimensionsOctaveWorkaround
00067
00068 #endif
00069
00076 #define VL_USE_MATLAB_ENV \
00077 vl_set_alloc_func (mxMalloc, mxRealloc, mxCalloc, mxFree) ; \
00078 vl_set_printf_func ((printf_func_t)mexPrintf) ;
00079
00080
00172
00173 #ifdef VL_COMPILER_GNUC
00174 #if (! defined(HAVE_OCTAVE))
00175 EXTERN_C void __attribute__((noreturn))
00176 mexErrMsgIdAndTxt (const char * identifier, const char * err_msg, ...) ;
00177 #else
00178 extern void __attribute__((noreturn))
00179 mexErrMsgIdAndTxt (const char *id, const char *s, ...);
00180 #endif
00181 #endif
00182
00183 #define MEXUTILS_RAISE_HELPER_A \
00184 char const * errorString ; \
00185 char formattedErrorId [512] ; \
00186 char formattedErrorMessage [1024] ; \
00187 \
00188 switch (errorId) { \
00189 case vlmxErrAlloc : errorString = "outOfMemory" ; break ; \
00190 case vlmxErrInvalidArgument : errorString = "invalidArgument" ; break ; \
00191 case vlmxErrNotEnoughInputArguments : errorString = "notEnoughInputArguments" ; break ; \
00192 case vlmxErrTooManyInputArguments : errorString = "tooManyInputArguments" ; break ; \
00193 case vlmxErrNotEnoughOutputArguments : errorString = "notEnoughOutputArguments" ; break ; \
00194 case vlmxErrTooManyOutputArguments : errorString = "tooManyOutputArguments" ; break ; \
00195 case vlmxErrInvalidOption : errorString = "invalidOption" ; break ; \
00196 case vlmxErrInconsistentData : errorString = "inconsistentData" ; break ; \
00197 default : errorString = "undefinedError" ; break ; \
00198 } \
00199 \
00200 if (! errorMessage) { \
00201 switch (errorId) { \
00202 case vlmxErrAlloc: errorMessage = "Out of memory." ; break ; \
00203 case vlmxErrInvalidArgument: errorMessage = "Invalid argument." ; break ; \
00204 case vlmxErrNotEnoughInputArguments: errorMessage = "Not enough input arguments." ; break ; \
00205 case vlmxErrTooManyInputArguments: errorMessage = "Too many input arguments." ; break ; \
00206 case vlmxErrNotEnoughOutputArguments: errorMessage = "Not enough output arguments." ; break ; \
00207 case vlmxErrTooManyOutputArguments: errorMessage = "Too many output arguments." ; break ; \
00208 case vlmxErrInconsistentData: errorMessage = "Inconsistent data." ; break ; \
00209 case vlmxErrInvalidOption: errorMessage = "Invalid option." ; break ; \
00210 default: errorMessage = "Undefined error message." ; \
00211 } \
00212 }
00213
00214 #ifdef VL_COMPILER_LCC
00215 #define MEXUTILS_RAISE_HELPER_B \
00216 { \
00217 va_list args ; \
00218 va_start(args, errorMessage) ; \
00219 sprintf(formattedErrorId, \
00220 "vl:%s", errorString) ; \
00221 vsprintf(formattedErrorMessage, \
00222 errorMessage, args) ; \
00223 va_end(args) ; \
00224 }
00225 #else
00226 #define MEXUTILS_RAISE_HELPER_B \
00227 { \
00228 va_list args ; \
00229 va_start(args, errorMessage) ; \
00230 snprintf(formattedErrorId, \
00231 sizeof(formattedErrorId)/sizeof(char), \
00232 "vl:%s", errorString) ; \
00233 vsnprintf(formattedErrorMessage, \
00234 sizeof(formattedErrorMessage)/sizeof(char), \
00235 errorMessage, args) ; \
00236 va_end(args) ; \
00237 }
00238 #endif
00239
00240 #define MEXUTILS_RAISE_HELPER MEXUTILS_RAISE_HELPER_A MEXUTILS_RAISE_HELPER_B
00241
00247 typedef enum _VlmxErrorId {
00248 vlmxErrAlloc = 1,
00249 vlmxErrInvalidArgument,
00250 vlmxErrNotEnoughInputArguments,
00251 vlmxErrTooManyInputArguments,
00252 vlmxErrNotEnoughOutputArguments,
00253 vlmxErrTooManyOutputArguments,
00254 vlmxErrInvalidOption,
00255 vlmxErrInconsistentData
00256 } VlmxErrorId ;
00257
00258
00268 #if defined(VL_COMPILER_GNUC) & ! defined(__DOXYGEN__)
00269 static void __attribute__((noreturn))
00270 #else
00271 static void
00272 #endif
00273 vlmxError (VlmxErrorId errorId, char const * errorMessage, ...)
00274 {
00275 MEXUTILS_RAISE_HELPER ;
00276 mexErrMsgIdAndTxt (formattedErrorId, formattedErrorMessage) ;
00277 }
00278
00287 static void
00288 vlmxWarning (VlmxErrorId errorId, char const * errorMessage, ...)
00289 {
00290 MEXUTILS_RAISE_HELPER ;
00291 mexWarnMsgIdAndTxt (formattedErrorId, formattedErrorMessage) ;
00292 }
00293
00307 VL_INLINE vl_bool
00308 vlmxIsOfClass (mxArray const * array, mxClassID classId)
00309 {
00310 return mxGetClassID (array) == classId ;
00311 }
00312
00320 VL_INLINE vl_bool
00321 vlmxIsReal (mxArray const * array)
00322 {
00323 return mxIsNumeric (array) && ! mxIsComplex (array) ;
00324 }
00325
00338 VL_INLINE vl_bool
00339 vlmxIsScalar (mxArray const * array)
00340 {
00341 return (! mxIsSparse (array)) && (mxGetNumberOfElements (array) == 1) ;
00342 }
00343
00352 static vl_bool
00353 vlmxIsVector (mxArray const * array, vl_index numElements)
00354 {
00355 vl_size numDimensions = (unsigned) mxGetNumberOfDimensions (array) ;
00356 mwSize const * dimensions = mxGetDimensions (array) ;
00357 vl_uindex di ;
00358
00359
00360 if (mxIsSparse (array)) {
00361 return VL_FALSE ;
00362 }
00363
00364
00365 if ((numElements >= 0) && ((unsigned) mxGetNumberOfElements (array) !=
00366 (unsigned) numElements)) {
00367 return VL_FALSE ;
00368 }
00369
00370
00371 for (di = 0 ; di < numDimensions ; ++ di) {
00372 if (dimensions[di] != 1) break ;
00373 }
00374 for (++ di ; di < numDimensions ; ++di) {
00375 if (dimensions[di] != 1) return VL_FALSE ;
00376 }
00377 return VL_TRUE ;
00378 }
00379
00389 static vl_bool
00390 vlmxIsMatrix (mxArray const * array, vl_index M, vl_index N)
00391 {
00392 vl_size numDimensions = (unsigned) mxGetNumberOfDimensions (array) ;
00393 mwSize const * dimensions = mxGetDimensions (array) ;
00394 vl_uindex di ;
00395
00396
00397 if (mxIsSparse (array)) {
00398 return VL_FALSE ;
00399 }
00400
00401
00402 if ((M >= 0) && ((unsigned) mxGetM (array) != (unsigned) M)) {
00403 return VL_FALSE;
00404 }
00405 if ((N >= 0) && ((unsigned) mxGetN (array) != (unsigned) N)) {
00406 return VL_FALSE;
00407 }
00408
00409
00410 if ((mxGetNumberOfElements (array) == 0) && (mxGetM (array) == 0 || mxGetN (array) == 0)) {
00411 return VL_TRUE ;
00412 }
00413
00414
00415 for (di = 2 ; ((unsigned)dimensions[di] == 1) && di < numDimensions ; ++ di) ;
00416 return di == numDimensions ;
00417 }
00418
00419
00433 static vl_bool
00434 vlmxIsArray (mxArray const * array, vl_index numDimensions, vl_index* dimensions)
00435 {
00436 if (numDimensions >= 0) {
00437 vl_index d ;
00438 mwSize const * actualDimensions = mxGetDimensions (array) ;
00439
00440 if ((unsigned) mxGetNumberOfDimensions (array) != (unsigned) numDimensions) {
00441 return VL_FALSE ;
00442 }
00443
00444 if(dimensions != NULL) {
00445 for(d = 0 ; d < numDimensions ; ++d) {
00446 if (dimensions[d] >= 0 && (unsigned) dimensions[d] != (unsigned) actualDimensions[d])
00447 return VL_FALSE ;
00448 }
00449 }
00450 }
00451 return VL_TRUE ;
00452 }
00453
00466 VL_INLINE vl_bool
00467 vlmxIsPlain (mxArray const * array)
00468 {
00469 return
00470 vlmxIsReal (array) &&
00471 vlmxIsOfClass (array, mxDOUBLE_CLASS) ;
00472 }
00473
00474
00482 VL_INLINE vl_bool
00483 vlmxIsPlainScalar (mxArray const * array)
00484 {
00485 return vlmxIsPlain (array) && vlmxIsScalar (array) ;
00486 }
00487
00496 VL_INLINE vl_bool
00497 vlmxIsPlainVector (mxArray const * array, vl_index numElements)
00498 {
00499 return vlmxIsPlain (array) && vlmxIsVector (array, numElements) ;
00500 }
00501
00502
00512 VL_INLINE vl_bool
00513 vlmxIsPlainMatrix (mxArray const * array, vl_index M, vl_index N)
00514 {
00515 return vlmxIsPlain (array) && vlmxIsMatrix (array, M, N) ;
00516 }
00517
00530 static int
00531 vlmxIsString (const mxArray* array, vl_index length)
00532 {
00533 mwSize M = (mwSize) mxGetM (array) ;
00534 mwSize N = (mwSize) mxGetN (array) ;
00535
00536 return
00537 mxIsChar(array) &&
00538 mxGetNumberOfDimensions(array) == 2 &&
00539 (M == 1 || (M == 0 && N == 0)) &&
00540 (length < 0 || (signed)N == length) ;
00541 }
00542
00543
00552 static mxArray *
00553 vlmxCreatePlainScalar (double x)
00554 {
00555 mxArray * array = mxCreateDoubleMatrix (1,1,mxREAL) ;
00556 *mxGetPr(array) = x ;
00557 return array ;
00558 }
00559
00566 static mxArray *
00567 vlmxCreateArrayFromVlArray (VlArray const * x)
00568 {
00569 mwSize dimensions [VL_ARRAY_MAX_NUM_DIMENSIONS] ;
00570 mxArray * array = NULL ;
00571 mxClassID classId = (mxClassID)0 ;
00572 vl_uindex d ;
00573 vl_size numElements = vl_array_get_num_elements(x) ;
00574 vl_size numDimensions = vl_array_get_num_dimensions(x) ;
00575 vl_size const * xdimensions = vl_array_get_dimensions(x) ;
00576 vl_type type = vl_array_get_data_type(x) ;
00577 vl_size typeSize = vl_get_type_size(type) ;
00578
00579 for (d = 0 ; d < numDimensions ; ++d) {
00580 dimensions[d] = (mwSize) xdimensions[d] ;
00581 }
00582
00583 switch (type) {
00584 case VL_TYPE_FLOAT : classId = mxSINGLE_CLASS ; break ;
00585 case VL_TYPE_DOUBLE : classId = mxDOUBLE_CLASS ; break ;
00586 case VL_TYPE_INT8 : classId = mxINT8_CLASS ; break ;
00587 case VL_TYPE_INT16 : classId = mxINT16_CLASS ; break ;
00588 case VL_TYPE_INT32 : classId = mxINT32_CLASS ; break ;
00589 case VL_TYPE_INT64 : classId = mxINT64_CLASS ; break ;
00590 case VL_TYPE_UINT8 : classId = mxUINT8_CLASS ; break ;
00591 case VL_TYPE_UINT16 : classId = mxUINT16_CLASS ; break ;
00592 case VL_TYPE_UINT32 : classId = mxUINT32_CLASS ; break ;
00593 case VL_TYPE_UINT64 : classId = mxUINT64_CLASS ; break ;
00594 default: assert(VL_FALSE) ;
00595 }
00596
00597 array = mxCreateNumericArray(numDimensions,
00598 dimensions,
00599 classId,
00600 mxREAL) ;
00601
00602 if (array == NULL) return NULL ;
00603
00604 memcpy(mxGetData(array), vl_array_get_data(x), typeSize * numElements) ;
00605
00606 return array ;
00607 }
00608
00616 static VlArray *
00617 vlmxEnvelopeArrayInVlArray (VlArray * v, mxArray * x)
00618 {
00619 vl_size numDimensions = mxGetNumberOfDimensions(x) ;
00620 mwSize const * dimensions = mxGetDimensions(x) ;
00621 mxClassID classId = mxGetClassID(x) ;
00622 vl_size vdimensions [VL_ARRAY_MAX_NUM_DIMENSIONS] ;
00623 vl_type type ;
00624 vl_uindex d ;
00625
00626 for (d = 0 ; d < numDimensions ; ++d) {
00627 vdimensions[d] = dimensions[d] ;
00628 }
00629
00630 switch (classId) {
00631 case mxSINGLE_CLASS: type = VL_TYPE_FLOAT ; break ;
00632 case mxDOUBLE_CLASS: type = VL_TYPE_DOUBLE ; break ;
00633 case mxINT8_CLASS : type = VL_TYPE_INT8 ; break ;
00634 case mxINT16_CLASS : type = VL_TYPE_INT16 ; break ;
00635 case mxINT32_CLASS : type = VL_TYPE_INT32 ; break ;
00636 case mxINT64_CLASS : type = VL_TYPE_INT64 ; break ;
00637 case mxUINT8_CLASS : type = VL_TYPE_UINT8 ; break ;
00638 case mxUINT16_CLASS: type = VL_TYPE_UINT16 ; break ;
00639 case mxUINT32_CLASS: type = VL_TYPE_UINT32 ; break ;
00640 case mxUINT64_CLASS: type = VL_TYPE_UINT64 ; break ;
00641 default: assert(VL_FALSE) ; abort() ;
00642 }
00643
00644 vl_array_init_envelope(v, mxGetData(x), type, numDimensions, vdimensions) ;
00645 return v ;
00646 }
00647
00659 static int
00660 vlmxCompareStringsI(const char *s1, const char *s2)
00661 {
00662
00663
00664
00665
00666 while (tolower((unsigned char)*s1) == tolower((unsigned char)*s2))
00667 {
00668 if (*s1 == 0) return 0 ;
00669 s1++;
00670 s2++;
00671 }
00672 return tolower((unsigned char)*s1) - tolower((unsigned char)*s2) ;
00673 }
00674
00686 static int
00687 vlmxCompareToStringI(mxArray const * array, char const * string)
00688 {
00689 mxChar const * s1 = (mxChar const *) mxGetData(array) ;
00690 char unsigned const * s2 = (char unsigned const*) string ;
00691 vl_size n = mxGetNumberOfElements(array) ;
00692
00693
00694
00695
00696
00697 while (n && tolower((unsigned)*s1) == tolower(*s2)) {
00698 if (*s2 == 0) return 1 ;
00699 s1 ++ ;
00700 s2 ++ ;
00701 n -- ;
00702 }
00703 return tolower(n ? (unsigned)*s1 : 0) - tolower(*s2) ;
00704 }
00705
00713 static int
00714 vlmxIsEqualToStringI(mxArray const * array, char const * string)
00715 {
00716 return vlmxCompareToStringI(array, string) == 0 ;
00717 }
00718
00719
00720
00721
00722
00725 struct _vlmxOption
00726 {
00727 const char *name ;
00728 int has_arg ;
00729 int val ;
00730 } ;
00731
00734 typedef struct _vlmxOption vlmxOption ;
00735
00764 static int
00765 vlmxNextOption (mxArray const *args[], int nargs,
00766 vlmxOption const *options,
00767 int *next,
00768 mxArray const **optarg)
00769 {
00770 char name [1024] ;
00771 int opt = -1, i;
00772
00773 if (*next >= nargs) {
00774 return opt ;
00775 }
00776
00777
00778 if (! vlmxIsString (args [*next], -1)) {
00779 vlmxError (vlmxErrInvalidOption,
00780 "The option name is not a string (argument number %d)",
00781 *next + 1) ;
00782 }
00783
00784
00785 if (mxGetString (args [*next], name, sizeof(name))) {
00786 vlmxError (vlmxErrInvalidOption,
00787 "The option name is too long (argument number %d)",
00788 *next + 1) ;
00789 }
00790
00791
00792 ++ (*next) ;
00793
00794
00795 for (i = 0 ; options[i].name != 0 ; ++i) {
00796 if (vlmxCompareStringsI(name, options[i].name) == 0) {
00797 opt = options[i].val ;
00798 break ;
00799 }
00800 }
00801
00802
00803 if (opt < 0) {
00804 vlmxError (vlmxErrInvalidOption, "Unknown option '%s'.", name) ;
00805 }
00806
00807
00808 if (! options [i].has_arg) {
00809 if (optarg) *optarg = 0 ;
00810 return opt ;
00811 }
00812
00813
00814 if (*next >= nargs) {
00815 vlmxError(vlmxErrInvalidOption,
00816 "Option '%s' requires an argument.", options[i].name) ;
00817 }
00818
00819 if (optarg) *optarg = args [*next] ;
00820 ++ (*next) ;
00821 return opt ;
00822 }
00823
00831 static VlEnumerator *
00832 vlmxDecodeEnumeration (mxArray const *name_array,
00833 VlEnumerator const *enumeration,
00834 vl_bool caseInsensitive)
00835 {
00836 char name [1024] ;
00837
00838
00839 if (! vlmxIsString (name_array, -1)) {
00840 vlmxError (vlmxErrInvalidArgument, "The array is not a string.") ;
00841 }
00842
00843
00844 if (mxGetString (name_array, name, sizeof(name))) {
00845 vlmxError (vlmxErrInvalidArgument, "The string array is too long.") ;
00846 }
00847
00848 if (caseInsensitive) {
00849 return vl_enumeration_get_casei(enumeration, name) ;
00850 } else {
00851 return vl_enumeration_get(enumeration, name) ;
00852 }
00853 }
00854
00855
00856 #endif