typecast.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2007-2012 David Bateman
00004 Copyright (C) 2009 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
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   // The array given may be a temporary, constructed from a scalar or sparse
00056   // array. This will ensure the data will be deallocated after we exit.
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 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines