KerMor  0.9
Model order reduction for nonlinear dynamical systems and nonlinear approximation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
typecast.c
Go to the documentation of this file.
1 /*************************************************************************************
2  *
3  * MATLAB (R) is a trademark of The Mathworks (R) Corporation
4  *
5  * Function: typecast
6  * Filename: typecast.c
7  * Programmer: James Tursa
8  * Version: 3.00
9  * Date: March 17, 2011
10  * Copyright: (c) 2009, 2011 by James Tursa, All Rights Reserved
11  *
12  % This code uses the BSD License:
13  %
14  % Redistribution and use in source and binary forms, with or without
15  % modification, are permitted provided that the following conditions are
16  % met:
17  %
18  % * Redistributions of source code must retain the above copyright
19  % notice, this list of conditions and the following disclaimer.
20  % * Redistributions in binary form must reproduce the above copyright
21  % notice, this list of conditions and the following disclaimer in
22  % the documentation and/or other materials provided with the distribution
23  %
24  % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25  % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28  % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  % POSSIBILITY OF SUCH DAMAGE.
35  *
36  * typecast is a mex function intended to mimic the MATLAB intrinsic typecast function
37  * for those users with older versions of MATLAB that do not have this intrinsic. Users
38  * of newer versions of MATLAB may be interested in this C-mex version to take advantage
39  * of the several extensions offered. This C-mex version of typecast differs from the
40  * intrinsic typecast in the following important aspects:
41  *
42  * Intrinsic typecast C-mex typecast
43  * ------------------ --------------
44  * Type of copy: Deep Data Copy Shared Data Copy
45  * Allows complex: No Yes
46  * Allows logical: No Yes (cannot convert from complex)
47  * Allows char: No Yes (cannot convert from complex)
48  * Allows non-vector: No Yes
49  *
50  * Since this C-mex typecast produces a shared data copy of the original, it
51  * is more efficient than the MATLAB intrinsic typecast, which may be important
52  * if you are working with large variables. For non-vector inputs, the first
53  * non-singleton dimension must be compatible for the conversion.
54  *
55  * Building:
56  *
57  * typecast requires that a mex routine be built (one time only). This
58  * process is typically self-building the first time you call the function
59  * as long as you have the files typecast.m and typecast.c in the same
60  * directory somewhere on the MATLAB path. If you need to manually build
61  * the mex function, here are the commands:
62  *
63  * >> mex -setup
64  * (then follow instructions to select a C or C++ compiler of your choice)
65  * >> mex typecast.c
66  *
67  * The usage is as follows (from The Mathworks website documentation):
68  *
69  * Syntax
70  *
71  * Y = typecast(X, type)
72  *
73  * Description
74  *
75  * Y = typecast(X, type) converts a value in X to the data type specified by type.
76  * Input X must be a full numeric or char or logical variable. The type input is a string
77  * set to one of the following: 'uint8', 'int8', 'uint16', 'int16', 'uint32', 'int32',
78  * 'uint64', 'int64', 'single', 'double', 'char' or 'logical'. typecast is different
79  * from the MATLAB cast function in that it does not alter the input data. typecast
80  * always returns the same number of bytes in the output Y as were in the input X.
81  * For example, casting the 16-bit integer 1000 to uint8 with typecast returns the full
82  * 16 bits in two 8-bit segments (3 and 232) thus keeping its original value
83  * (3*256 + 232 = 1000). The cast function, on the other hand, truncates the input value
84  * to 255.
85  *
86  * The output of typecast can be formatted differently depending on what system you use it on.
87  * Some computer systems store data starting with its most significant byte (an ordering
88  * called big-endian), while others start with the least significant byte (called little-endian).
89  *
90  * typecast issues an error if X contains fewer values than are needed to make an output value.
91  *
92  */
93 
94 #include "mex.h"
95 #include <string.h>
96 
97 /* Needed for older versions of MATLAB that do not have the mwSize typedef */
98 
99 #ifndef MWSIZE_MAX
100 #define mwIndex int
101 #define mwSignedIndex int
102 #define mwSize int
103 #endif
104 
105 /* Used for setting the varible type */
106 
107 #define VariableType_Temporary 4
108 
109 /* mxArray struct for hacking into the fields */
110 
111 struct mxArray_Tag {
112  char *name; /* Name of variable in workspace, NULL for R2009a and later */
113  mxClassID ClassID; /* 0 = unknown
114  1 = cell
115  2 = struct
116  3 = logical
117  4 = char
118  5 = void
119  6 = double
120  7 = single
121  8 = int8
122  9 = uint8
123  10 = int16
124  11 = uint16
125  12 = int32
126  13 = uint32
127  14 = int64
128  15 = uint64
129  16 = function_handle
130  17 = opaque (User Defined Class indicator new classdef style)
131  18 = object (User Defined Class indicator old @directory style)
132  19 = index (deprecated)
133  20 = sparse (deprecated)
134  */
135  int VariableType; /* 0 = normal
136  1 = persistent
137  2 = global
138  3 = sub-element (field or cell)
139  4 = temporary
140  5 = (unknown)
141  6 = property of opaque class object
142  */
143  mxArray *CrossLink; /* Address of next shared-data variable in linked list */
144  size_t ndim;
145  unsigned int RefCount; /* Number of sub-elements identical to this one */
146  unsigned int flags; /* bit 0 = is scalar double full
147  bit 2 = is empty double full
148  bit 4 = is temporary
149  bit 5 = is sparse
150  bit 8 = is constant from parsed m-file
151  bit 9 = is numeric
152  bits 24 - 31 = User Bits
153  */
154  union {
155  size_t M; /* Row size for 2D matrices, or */
156  size_t *dims; /* Pointer to dims array for nD > 2 arrays */
157  } Mdims;
158  size_t N; /* Column size for 2D matrices */
159  void *pr; /* Pointer to real data (or pointer to cell or field elements */
160  void *pi; /* Pointer to imag data (or pointer to field information */
161  union {
162  mwIndex *ir; /* Pointer to row values for sparse arrays, or */
163  mxClassID ClassID; /* User Defined Class ID (opaque new style), or */
164  char *ClassName; /* Pointer to User Defined Class Name (object old style) */
165  } irClassNameID;
166  union {
167  mwIndex *jc; /* Pointer to column values for sparse arrays, or */
168  mxClassID ClassID; /* User Defined Class ID (object old style) */
169  } jcClassID;
170  size_t nzmax; /* Number of elements allocated for sparse matrix */
171  unsigned int reserved; /* (unknown) */
172 };
173 
174 /* Prototype */
175 
176 mxArray *mxCreateSharedDataCopy(const mxArray *mx); /* Undocumented function */
177 
178 /* Gateway function */
179 
180 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
181 {
182  struct mxArray_Tag *mx;
183  mwSize inbytes, outbytes, i, k, idim, ndim;
184  mwSize *dims_old, *dims_new;
185  char *outstring;
186  mxClassID outclass;
187  int out_numeric;
188 
189 /* Check input arguments */
190 
191  if( nrhs > 2 ) {
192  mexErrMsgTxt("Too many input arguments.");
193  }
194  if( nrhs < 2 ) {
195  mexErrMsgTxt("Not enough input arguments.");
196  }
197  if( nlhs > 1 ) {
198  mexErrMsgTxt("Too many output arguments.");
199  }
200  if( mxIsSparse(prhs[0]) || (!mxIsNumeric(prhs[0]) && !mxIsChar(prhs[0]) && !mxIsLogical(prhs[0])) ) {
201  mexErrMsgTxt("The first input argument must be a full numeric value, or char, or logical.");
202  }
203  if( !mxIsChar(prhs[1]) ) {
204  mexErrMsgTxt("The second input argument must be a character array.");
205  }
206 
207 /* Get input argument byte length */
208 
209  inbytes = mxGetElementSize(prhs[0]);
210 
211 /* Check second input argument for desired output type */
212 
213  outstring = mxArrayToString(prhs[1]);
214 
215  out_numeric = 1;
216  if( strcmp(outstring,"int8") == 0 ) {
217  outclass = mxINT8_CLASS;
218  outbytes = 1;
219  } else if( strcmp(outstring,"uint8") == 0 ) {
220  outclass = mxUINT8_CLASS;
221  outbytes = 1;
222  } else if( strcmp(outstring,"int16") == 0 ) {
223  outclass = mxINT16_CLASS;
224  outbytes = 2;
225  } else if( strcmp(outstring,"uint16") == 0 ) {
226  outclass = mxUINT16_CLASS;
227  outbytes = 2;
228  } else if( strcmp(outstring,"int32") == 0 ) {
229  outclass = mxINT32_CLASS;
230  outbytes = 4;
231  } else if( strcmp(outstring,"uint32") == 0 ) {
232  outclass = mxUINT32_CLASS;
233  outbytes = 4;
234  } else if( strcmp(outstring,"int64") == 0 ) {
235  outclass = mxINT64_CLASS;
236  outbytes = 8;
237  } else if( strcmp(outstring,"uint64") == 0 ) {
238  outclass = mxUINT64_CLASS;
239  outbytes = 8;
240  } else if( strcmp(outstring,"double") == 0 ) {
241  outclass = mxDOUBLE_CLASS;
242  outbytes = 8;
243  } else if( strcmp(outstring,"single") == 0 ) {
244  outclass = mxSINGLE_CLASS;
245  outbytes = 4;
246  } else if( strcmp(outstring,"char") == 0 ) {
247  outclass = mxCHAR_CLASS;
248  outbytes = 2;
249  out_numeric = 0;
250  } else if( strcmp(outstring,"logical") == 0 ) {
251  outclass = mxLOGICAL_CLASS;
252  outbytes = 1;
253  out_numeric = 0;
254  } else {
255  mxFree(outstring);
256  mexErrMsgTxt("Unsupported class.\n");
257  }
258  mxFree(outstring);
259 
260 /* Check for complex coversion to non-numeric */
261 
262  if( mxIsComplex(prhs[0]) && !out_numeric ) {
263  mexErrMsgTxt("Cannot typecast a complex input to a non-numeric class.\n");
264  }
265 
266 /* Check for empty input. No data to share, so simply create a new empty variable */
267 
268  if( mxIsEmpty(prhs[0]) ) {
269  if( out_numeric ) {
270  plhs[0] = mxCreateNumericArray(mxGetNumberOfDimensions(prhs[0]),
271  mxGetDimensions(prhs[0]),
272  outclass, mxREAL);
273  } else if( outclass == mxCHAR_CLASS ) {
274  plhs[0] = mxCreateCharArray(mxGetNumberOfDimensions(prhs[0]),
275  mxGetDimensions(prhs[0]));
276  } else {
277  plhs[0] = mxCreateLogicalArray(mxGetNumberOfDimensions(prhs[0]),
278  mxGetDimensions(prhs[0]));
279  }
280  return;
281  }
282 
283 /* Check the old & new sizes for compatibility */
284 
285  ndim = mxGetNumberOfDimensions(prhs[0]);
286  dims_old = mxGetDimensions(prhs[0]);
287  for( i=0; i<ndim; i++ ) {
288  if( dims_old[i] != 1 || i == ndim-1 ) {
289  k = (dims_old[i] * inbytes) / outbytes;
290  if( k * outbytes != dims_old[i] * inbytes ) {
291  mexErrMsgTxt("Too few input values to make output type.\n");
292  }
293  idim = i;
294  break;
295  }
296  }
297  dims_new = mxMalloc(ndim * sizeof(*dims_new));
298  for( i=0; i<ndim; i++ ) {
299  dims_new[i] = dims_old[i];
300  }
301  dims_new[idim] = k;
302 
303 /* Create the output array as a shared data copy, then manually set the class
304  * and size parameters by accessing the structure fields directly. Note that
305  * this is using undocumented MATLAB API functions and hacking of the
306  * mxArray_tag structure, so this may not work in future versions of MATLAB.
307  */
308 
309  plhs[0] = mxCreateSharedDataCopy(prhs[0]);
310  mx = (struct mxArray_Tag *) plhs[0];
311  mx->ClassID = outclass;
313  mxSetDimensions(plhs[0],dims_new,ndim);
314  mxFree(dims_new);
315 
316 /* Also need to fix up the flags */
317 
318  if( outclass == mxDOUBLE_CLASS ) {
319  if( mxGetNumberOfElements(plhs[0]) == 1 ) {
320  mx->flags = 0x0211; /* Set numeric, temporary, and full double scalar bits */
321  } else {
322  mx->flags = 0x0210; /* Set numeric and temporary bits */
323  }
324  } else if( out_numeric ) {
325  mx->flags = 0x0210; /* Set numeric and temporary bits */
326  } else {
327  mx->flags = 0x0010; /* Set the temporary bit */
328  }
329 }
mxArray * CrossLink
Definition: typecast.c:143
union mxArray_Tag::@1 irClassNameID
unsigned int reserved
Definition: typecast.c:171
size_t nzmax
Definition: typecast.c:170
size_t M
Definition: typecast.c:155
void * pi
Definition: typecast.c:160
#define VariableType_Temporary
Definition: typecast.c:107
char * ClassName
Definition: typecast.c:164
mwIndex * jc
Definition: typecast.c:167
void * pr
Definition: typecast.c:159
union mxArray_Tag::@2 jcClassID
union mxArray_Tag::@0 Mdims
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
Definition: typecast.c:180
size_t N
Definition: typecast.c:158
unsigned int RefCount
Definition: typecast.c:145
mwIndex * ir
Definition: typecast.c:162
size_t ndim
Definition: typecast.c:144
char * name
Definition: typecast.c:112
#define mwSize
Definition: typecast.c:102
unsigned int flags
Definition: typecast.c:146
mxArray * mxCreateSharedDataCopy(const mxArray *mx)
size_t * dims
Definition: typecast.c:156
#define mwIndex
Definition: typecast.c:100
int VariableType
Definition: typecast.c:135
mxClassID ClassID
Definition: typecast.c:113