00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #include "mx-base.h"
00029
00030 #include "defun-dld.h"
00031 #include "error.h"
00032 #include "gripes.h"
00033 #include "oct-obj.h"
00034 #include "unwind-prot.h"
00035
00036 static dim_vector
00037 get_vec_dims (const dim_vector& old_dims, octave_idx_type n)
00038 {
00039 if (old_dims.length () == 2 && old_dims(0) == 1)
00040 return dim_vector (1, n);
00041 else if (old_dims.length () == 2 && old_dims (0) == 0 && old_dims (1) == 0)
00042 return dim_vector ();
00043 else
00044 return dim_vector (n, 1);
00045 }
00046
00047 template <class ArrayType>
00048 static void
00049 get_data_and_bytesize (const ArrayType& array,
00050 const void *& data,
00051 octave_idx_type& byte_size,
00052 dim_vector& old_dims,
00053 unwind_protect& frame)
00054 {
00055
00056
00057 frame.add_delete (new ArrayType (array));
00058
00059 data = reinterpret_cast<const void *> (array.data ());
00060 byte_size = array.byte_size ();
00061
00062 old_dims = array.dims ();
00063 }
00064
00065 template <class ArrayType>
00066 static ArrayType
00067 reinterpret_copy (const void *data, octave_idx_type byte_size,
00068 const dim_vector& old_dims)
00069 {
00070 typedef typename ArrayType::element_type T;
00071 octave_idx_type n = byte_size / sizeof (T);
00072
00073 if (n * static_cast<int> (sizeof (T)) == byte_size)
00074 {
00075 ArrayType retval (get_vec_dims (old_dims, n));
00076 T *dest = retval.fortran_vec ();
00077 std::memcpy (dest, data, n * sizeof (T));
00078
00079 return retval;
00080 }
00081 else
00082 {
00083 error ("typecast: incorrect number of input values to make output value");
00084 return ArrayType ();
00085 }
00086 }
00087
00088
00089 DEFUN_DLD (typecast, args, ,
00090 "-*- texinfo -*-\n\
00091 @deftypefn {Loadable Function} {} typecast (@var{x}, @var{class})\n\
00092 Return a new array @var{y} resulting from interpreting the data of\n\
00093 @var{x} in memory as data of the numeric class @var{class}. Both the class\n\
00094 of @var{x} and @var{class} must be one of the built-in numeric classes:\n\
00095 \n\
00096 @example\n\
00097 @group\n\
00098 \"logical\"\n\
00099 \"char\"\n\
00100 \"int8\"\n\
00101 \"int16\"\n\
00102 \"int32\"\n\
00103 \"int64\"\n\
00104 \"uint8\"\n\
00105 \"uint16\"\n\
00106 \"uint32\"\n\
00107 \"uint64\"\n\
00108 \"double\"\n\
00109 \"single\"\n\
00110 \"double complex\"\n\
00111 \"single complex\"\n\
00112 @end group\n\
00113 @end example\n\
00114 \n\
00115 @noindent\n\
00116 the last two are reserved for @var{class}; they indicate that a\n\
00117 complex-valued result is requested. Complex arrays are stored in memory as\n\
00118 consecutive pairs of real numbers. The sizes of integer types are given by\n\
00119 their bit counts. Both logical and char are typically one byte wide;\n\
00120 however, this is not guaranteed by C++. If your system is IEEE conformant,\n\
00121 single and double should be 4 bytes and 8 bytes wide, respectively.\n\
00122 \"logical\" is not allowed for @var{class}. If the input is a row vector,\n\
00123 the return value is a row vector, otherwise it is a column vector. If the\n\
00124 bit length of @var{x} is not divisible by that of @var{class}, an error\n\
00125 occurs.\n\
00126 \n\
00127 An example of the use of typecast on a little-endian machine is\n\
00128 \n\
00129 @example\n\
00130 @group\n\
00131 @var{x} = uint16 ([1, 65535]);\n\
00132 typecast (@var{x}, 'uint8')\n\
00133 @result{} [ 1, 0, 255, 255]\n\
00134 @end group\n\
00135 @end example\n\
00136 @seealso{cast, bitunpack, bitpack, swapbytes}\n\
00137 @end deftypefn")
00138 {
00139 octave_value retval;
00140
00141 if (args.length () == 2)
00142 {
00143 unwind_protect frame;
00144 const void *data = 0;
00145 octave_idx_type byte_size = 0;
00146 dim_vector old_dims;
00147
00148 octave_value array = args(0);
00149
00150 if (array.is_bool_type ())
00151 get_data_and_bytesize (array.bool_array_value (), data, byte_size, old_dims, frame);
00152 else if (array.is_string ())
00153 get_data_and_bytesize (array.char_array_value (), data, byte_size, old_dims, frame);
00154 else if (array.is_integer_type ())
00155 {
00156 if (array.is_int8_type ())
00157 get_data_and_bytesize (array.int8_array_value (), data, byte_size, old_dims, frame);
00158 else if (array.is_int16_type ())
00159 get_data_and_bytesize (array.int16_array_value (), data, byte_size, old_dims, frame);
00160 else if (array.is_int32_type ())
00161 get_data_and_bytesize (array.int32_array_value (), data, byte_size, old_dims, frame);
00162 else if (array.is_int64_type ())
00163 get_data_and_bytesize (array.int64_array_value (), data, byte_size, old_dims, frame);
00164 else if (array.is_uint8_type ())
00165 get_data_and_bytesize (array.uint8_array_value (), data, byte_size, old_dims, frame);
00166 else if (array.is_uint16_type ())
00167 get_data_and_bytesize (array.uint16_array_value (), data, byte_size, old_dims, frame);
00168 else if (array.is_uint32_type ())
00169 get_data_and_bytesize (array.uint32_array_value (), data, byte_size, old_dims, frame);
00170 else if (array.is_uint64_type ())
00171 get_data_and_bytesize (array.uint64_array_value (), data, byte_size, old_dims, frame);
00172 else
00173 assert (0);
00174 }
00175 else if (array.is_complex_type ())
00176 {
00177 if (array.is_single_type ())
00178 get_data_and_bytesize (array.float_complex_array_value (), data, byte_size, old_dims, frame);
00179 else
00180 get_data_and_bytesize (array.complex_array_value (), data, byte_size, old_dims, frame);
00181 }
00182 else if (array.is_real_type ())
00183 {
00184 if (array.is_single_type ())
00185 get_data_and_bytesize (array.float_array_value (), data, byte_size, old_dims, frame);
00186 else
00187 get_data_and_bytesize (array.array_value (), data, byte_size, old_dims, frame);
00188 }
00189 else
00190 error ("typecast: invalid input class: %s", array.class_name ().c_str ());
00191
00192 std::string numclass = args(1).string_value ();
00193
00194 if (error_state || numclass.size () == 0)
00195 ;
00196 else if (numclass == "char")
00197 retval = octave_value (reinterpret_copy<charNDArray> (data, byte_size, old_dims), array.is_dq_string () ? '"' : '\'');
00198 else if (numclass[0] == 'i')
00199 {
00200 if (numclass == "int8")
00201 retval = reinterpret_copy<int8NDArray> (data, byte_size, old_dims);
00202 else if (numclass == "int16")
00203 retval = reinterpret_copy<int16NDArray> (data, byte_size, old_dims);
00204 else if (numclass == "int32")
00205 retval = reinterpret_copy<int32NDArray> (data, byte_size, old_dims);
00206 else if (numclass == "int64")
00207 retval = reinterpret_copy<int64NDArray> (data, byte_size, old_dims);
00208 }
00209 else if (numclass[0] == 'u')
00210 {
00211 if (numclass == "uint8")
00212 retval = reinterpret_copy<uint8NDArray> (data, byte_size, old_dims);
00213 else if (numclass == "uint16")
00214 retval = reinterpret_copy<uint16NDArray> (data, byte_size, old_dims);
00215 else if (numclass == "uint32")
00216 retval = reinterpret_copy<uint32NDArray> (data, byte_size, old_dims);
00217 else if (numclass == "uint64")
00218 retval = reinterpret_copy<uint64NDArray> (data, byte_size, old_dims);
00219 }
00220 else if (numclass == "single")
00221 retval = reinterpret_copy<FloatNDArray> (data, byte_size, old_dims);
00222 else if (numclass == "double")
00223 retval = reinterpret_copy<NDArray> (data, byte_size, old_dims);
00224 else if (numclass == "single complex")
00225 retval = reinterpret_copy<FloatComplexNDArray> (data, byte_size, old_dims);
00226 else if (numclass == "double complex")
00227 retval = reinterpret_copy<ComplexNDArray> (data, byte_size, old_dims);
00228
00229 if (! error_state && retval.is_undefined ())
00230 error ("typecast: cannot convert to %s class", numclass.c_str ());
00231 }
00232 else
00233 print_usage ();
00234
00235 return retval;
00236 }
00237
00238 template <class ArrayType>
00239 ArrayType
00240 do_bitpack (const boolNDArray& bitp)
00241 {
00242 typedef typename ArrayType::element_type T;
00243 octave_idx_type n = bitp.numel () / (sizeof (T) * CHAR_BIT);
00244
00245 if (n * static_cast<int> (sizeof (T)) * CHAR_BIT == bitp.numel ())
00246 {
00247
00248 ArrayType retval (get_vec_dims (bitp.dims (), n));
00249
00250 const bool *bits = bitp.fortran_vec ();
00251 char *packed = reinterpret_cast<char *> (retval.fortran_vec ());
00252
00253 octave_idx_type m = n * sizeof (T);
00254
00255 for (octave_idx_type i = 0; i < m; i++)
00256 {
00257 char c = bits[0];
00258 for (int j = 1; j < CHAR_BIT; j++)
00259 c |= bits[j] << j;
00260
00261 packed[i] = c;
00262 bits += CHAR_BIT;
00263 }
00264
00265 return retval;
00266 }
00267 else
00268 {
00269 error ("bitpack: incorrect number of bits to make up output value");
00270 return ArrayType ();
00271 }
00272 }
00273
00274 DEFUN_DLD (bitpack, args, ,
00275 "-*- texinfo -*-\n\
00276 @deftypefn {Loadable Function} {@var{y} =} bitpack (@var{x}, @var{class})\n\
00277 Return a new array @var{y} resulting from interpreting an array\n\
00278 @var{x} as raw bit patterns for data of the numeric class @var{class}.\n\
00279 @var{class} must be one of the built-in numeric classes:\n\
00280 \n\
00281 @example\n\
00282 @group\n\
00283 \"char\"\n\
00284 \"int8\"\n\
00285 \"int16\"\n\
00286 \"int32\"\n\
00287 \"int64\"\n\
00288 \"uint8\"\n\
00289 \"uint16\"\n\
00290 \"uint32\"\n\
00291 \"uint64\"\n\
00292 \"double\"\n\
00293 \"single\"\n\
00294 @end group\n\
00295 @end example\n\
00296 \n\
00297 The number of elements of @var{x} should be divisible by the bit length of\n\
00298 @var{class}. If it is not, excess bits are discarded. Bits come in\n\
00299 increasing order of significance, i.e., @code{x(1)} is bit 0, @code{x(2)} is\n\
00300 bit 1, etc. The result is a row vector if @var{x} is a row vector, otherwise\n\
00301 it is a column vector.\n\
00302 @seealso{bitunpack, typecast}\n\
00303 @end deftypefn")
00304 {
00305 octave_value retval;
00306
00307 if (args.length () == 2 && args(0).is_bool_type ())
00308 {
00309 boolNDArray bitp = args(0).bool_array_value ();
00310
00311 std::string numclass = args(1).string_value ();
00312
00313 if (error_state || numclass.size () == 0)
00314 ;
00315 else if (numclass == "char")
00316 retval = octave_value (do_bitpack<charNDArray> (bitp), '\'');
00317 else if (numclass[0] == 'i')
00318 {
00319 if (numclass == "int8")
00320 retval = do_bitpack<int8NDArray> (bitp);
00321 else if (numclass == "int16")
00322 retval = do_bitpack<int16NDArray> (bitp);
00323 else if (numclass == "int32")
00324 retval = do_bitpack<int32NDArray> (bitp);
00325 else if (numclass == "int64")
00326 retval = do_bitpack<int64NDArray> (bitp);
00327 }
00328 else if (numclass[0] == 'u')
00329 {
00330 if (numclass == "uint8")
00331 retval = do_bitpack<uint8NDArray> (bitp);
00332 else if (numclass == "uint16")
00333 retval = do_bitpack<uint16NDArray> (bitp);
00334 else if (numclass == "uint32")
00335 retval = do_bitpack<uint32NDArray> (bitp);
00336 else if (numclass == "uint64")
00337 retval = do_bitpack<uint64NDArray> (bitp);
00338 }
00339 else if (numclass == "single")
00340 retval = do_bitpack<FloatNDArray> (bitp);
00341 else if (numclass == "double")
00342 retval = do_bitpack<NDArray> (bitp);
00343 else if (numclass == "single complex")
00344 retval = do_bitpack<FloatComplexNDArray> (bitp);
00345 else if (numclass == "double complex")
00346 retval = do_bitpack<ComplexNDArray> (bitp);
00347
00348 if (! error_state && retval.is_undefined ())
00349 error ("bitpack: cannot pack to %s class", numclass.c_str ());
00350 }
00351 else
00352 print_usage ();
00353
00354 return retval;
00355 }
00356
00357 template <class ArrayType>
00358 boolNDArray
00359 do_bitunpack (const ArrayType& array)
00360 {
00361 typedef typename ArrayType::element_type T;
00362 octave_idx_type n = array.numel () * sizeof (T) * CHAR_BIT;
00363
00364 boolNDArray retval (get_vec_dims (array.dims (), n));
00365
00366 const char *packed = reinterpret_cast<const char *> (array.fortran_vec ());
00367 bool *bits = retval.fortran_vec ();
00368
00369 octave_idx_type m = n / CHAR_BIT;
00370
00371 for (octave_idx_type i = 0; i < m; i++)
00372 {
00373 char c = packed[i];
00374 bits[0] = c & 1;
00375 for (int j = 1; j < CHAR_BIT; j++)
00376 bits[j] = (c >>= 1) & 1;
00377 bits += CHAR_BIT;
00378 }
00379
00380 return retval;
00381 }
00382
00383 DEFUN_DLD (bitunpack, args, ,
00384 "-*- texinfo -*-\n\
00385 @deftypefn {Loadable Function} {@var{y} =} bitunpack (@var{x})\n\
00386 Return an array @var{y} corresponding to the raw bit patterns of\n\
00387 @var{x}. @var{x} must belong to one of the built-in numeric classes:\n\
00388 \n\
00389 @example\n\
00390 @group\n\
00391 \"char\"\n\
00392 \"int8\"\n\
00393 \"int16\"\n\
00394 \"int32\"\n\
00395 \"int64\"\n\
00396 \"uint8\"\n\
00397 \"uint16\"\n\
00398 \"uint32\"\n\
00399 \"uint64\"\n\
00400 \"double\"\n\
00401 \"single\"\n\
00402 @end group\n\
00403 @end example\n\
00404 \n\
00405 The result is a row vector if @var{x} is a row vector; otherwise, it is a\n\
00406 column vector.\n\
00407 @seealso{bitpack, typecast}\n\
00408 @end deftypefn")
00409 {
00410 octave_value retval;
00411
00412 if (args.length () == 1 && (args(0).is_numeric_type () || args(0).is_string ()))
00413 {
00414 octave_value array = args(0);
00415
00416 if (array.is_string ())
00417 retval = do_bitunpack (array.char_array_value ());
00418 else if (array.is_integer_type ())
00419 {
00420 if (array.is_int8_type ())
00421 retval = do_bitunpack (array.int8_array_value ());
00422 else if (array.is_int16_type ())
00423 retval = do_bitunpack (array.int16_array_value ());
00424 else if (array.is_int32_type ())
00425 retval = do_bitunpack (array.int32_array_value ());
00426 else if (array.is_int64_type ())
00427 retval = do_bitunpack (array.int64_array_value ());
00428 else if (array.is_uint8_type ())
00429 retval = do_bitunpack (array.uint8_array_value ());
00430 else if (array.is_uint16_type ())
00431 retval = do_bitunpack (array.uint16_array_value ());
00432 else if (array.is_uint32_type ())
00433 retval = do_bitunpack (array.uint32_array_value ());
00434 else if (array.is_uint64_type ())
00435 retval = do_bitunpack (array.uint64_array_value ());
00436 else
00437 assert (0);
00438 }
00439 else if (array.is_complex_type ())
00440 {
00441 if (array.is_single_type ())
00442 retval = do_bitunpack (array.float_complex_array_value ());
00443 else
00444 retval = do_bitunpack (array.complex_array_value ());
00445 }
00446 else if (array.is_real_type ())
00447 {
00448 if (array.is_single_type ())
00449 retval = do_bitunpack (array.float_array_value ());
00450 else
00451 retval = do_bitunpack (array.array_value ());
00452 }
00453 else
00454 error ("bitunpack: invalid input class: %s", array.class_name ().c_str ());
00455 }
00456 else
00457 print_usage ();
00458
00459 return retval;
00460 }