# HG changeset patch # User Jaroslav Hajek # Date 1254204250 -7200 # Node ID 5627b5865d99c3107e1bc51e8f44510f552cdab1 # Parent 63249224f78d0f25a40fcbfbd5191f44b5a42123 implement reinterpret, bitpack & bitunpack diff -r 63249224f78d -r 5627b5865d99 src/ChangeLog --- a/src/ChangeLog Mon Sep 28 21:52:27 2009 -0400 +++ b/src/ChangeLog Tue Sep 29 08:04:10 2009 +0200 @@ -1,3 +1,8 @@ +2009-09-29 Jaroslav Hajek + + * DLD-FUNCTIONS/reinterpret.cc: New source. + * Makefile.in: Add it here. + 2009-09-28 Shai Ayal * DLD-FUNCTIONS/fltk_backend.cc (plot_window::handle): Redraw the diff -r 63249224f78d -r 5627b5865d99 src/DLD-FUNCTIONS/reinterpret.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DLD-FUNCTIONS/reinterpret.cc Tue Sep 29 08:04:10 2009 +0200 @@ -0,0 +1,424 @@ +/* + +Copyright (C) 2009 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "mx-base.h" + +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "oct-obj.h" +#include "unwind-prot.h" + +static dim_vector +get_vec_dims (const dim_vector& old_dims, octave_idx_type n) +{ + if (old_dims.length () == 2 && old_dims(0) == 1) + return dim_vector (1, n); + else if (old_dims.length () == 2 && old_dims (0) == 0 && old_dims (1) == 0) + return dim_vector (); + else + return dim_vector (n, 1); +} + +template +static void +get_data_and_bytesize (const ArrayType& array, + const void *& data, + octave_idx_type& byte_size, + dim_vector& old_dims) +{ + // The array given may be a temporary, constructed from a scalar or sparse + // array. This will ensure the data will be deallocated after we exit. + unwind_protect::add_delete (new ArrayType (array)); + + data = reinterpret_cast (array.data ()); + byte_size = array.byte_size (); + + old_dims = array.dims (); +} + +template +static ArrayType +reinterpret_copy (const void *data, octave_idx_type byte_size, + const dim_vector& old_dims) +{ + typedef typename ArrayType::element_type T; + octave_idx_type n = byte_size / sizeof (T); + + if (n * static_cast (sizeof (T)) < byte_size) + warning ("reinterpret: discarding excess data"); + + ArrayType retval (get_vec_dims (old_dims, n)); + T *dest = retval.fortran_vec (); + std::memcpy (dest, data, n * sizeof (T)); + + return retval; +} + +DEFUN_DLD (reinterpret, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{y} =} reinterpret (@var{x}, @var{class})\n\ +Returns a new array @var{y} resulting from interpreting the data of\n\ +@var{x} in memory as data of the numeric class @var{class}. Both the class\n\ +of @var{x} and @var{class} must be one of the built-in numeric classes:\n\ +\n\ +@example\n\ + \"logical\"\n\ + \"char\"\n\ + \"int8\"\n\ + \"int16\"\n\ + \"int32\"\n\ + \"int64\"\n\ + \"uint8\"\n\ + \"uint16\"\n\ + \"uint32\"\n\ + \"uint64\"\n\ + \"double\"\n\ + \"single\"\n\ + \"double complex\"\n\ + \"single complex\"\n\ +@end example\n\ +\n\ +the last two are reserved for @var{class}; they indicate that a complex-valued result\n\ +is requested. Complex arrays are stored in memory as consecutive pairs of real numbers.\n\ +The sizes of integer types are given by their bit counts. Both logical and char are typically\n\ +one byte wide; however, this is not guaranteed by C++. If your system is IEEE conformant,\n\ +single and double should be 4 bytes and 8 bytes wide, respectively.\n\ +\"logical\" is not allowed for @var{class}.\n\ +If the input is a row vector, the return value is a row vector, otherwise it is a column vector.\n\ +If the bit length of @var{x} is not divisible by that of @var{class}, excess bits are discarded.\n\ +@seealso{bitunpack,bitpack}\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 2) + { + const void *data = 0; + octave_idx_type byte_size = 0; + dim_vector old_dims; + + octave_value array = args(0); + + if (array.is_bool_type ()) + get_data_and_bytesize (array.bool_array_value (), data, byte_size, old_dims); + else if (array.is_string ()) + get_data_and_bytesize (array.char_array_value (), data, byte_size, old_dims); + else if (array.is_integer_type ()) + { + if (array.is_int8_type ()) + get_data_and_bytesize (array.int8_array_value (), data, byte_size, old_dims); + else if (array.is_int16_type ()) + get_data_and_bytesize (array.int16_array_value (), data, byte_size, old_dims); + else if (array.is_int32_type ()) + get_data_and_bytesize (array.int32_array_value (), data, byte_size, old_dims); + else if (array.is_int64_type ()) + get_data_and_bytesize (array.int64_array_value (), data, byte_size, old_dims); + else if (array.is_uint8_type ()) + get_data_and_bytesize (array.uint8_array_value (), data, byte_size, old_dims); + else if (array.is_uint16_type ()) + get_data_and_bytesize (array.uint16_array_value (), data, byte_size, old_dims); + else if (array.is_uint32_type ()) + get_data_and_bytesize (array.uint32_array_value (), data, byte_size, old_dims); + else if (array.is_uint64_type ()) + get_data_and_bytesize (array.uint64_array_value (), data, byte_size, old_dims); + else + assert (0); + } + else if (array.is_complex_type ()) + { + if (array.is_single_type ()) + get_data_and_bytesize (array.float_complex_array_value (), data, byte_size, old_dims); + else + get_data_and_bytesize (array.complex_array_value (), data, byte_size, old_dims); + } + else if (array.is_real_type ()) + { + if (array.is_single_type ()) + get_data_and_bytesize (array.float_array_value (), data, byte_size, old_dims); + else + get_data_and_bytesize (array.array_value (), data, byte_size, old_dims); + } + else + error ("reinterpret: invalid input class: %s", array.class_name ().c_str ()); + + std::string numclass = args(1).string_value (); + + if (error_state || numclass.size () == 0) + ; + else if (numclass == "char") + retval = octave_value (reinterpret_copy (data, byte_size, old_dims), true); + else if (numclass[0] == 'i') + { + if (numclass == "int8") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "int16") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "int32") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "int64") + retval = reinterpret_copy (data, byte_size, old_dims); + } + else if (numclass[0] == 'u') + { + if (numclass == "uint8") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "uint16") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "uint32") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "uint64") + retval = reinterpret_copy (data, byte_size, old_dims); + } + else if (numclass == "single") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "double") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "single complex") + retval = reinterpret_copy (data, byte_size, old_dims); + else if (numclass == "double complex") + retval = reinterpret_copy (data, byte_size, old_dims); + + if (! error_state && retval.is_undefined ()) + error ("reinterpret: cannot convert to %s class", numclass.c_str ()); + } + else + print_usage (); + + return retval; +} + +template +ArrayType +do_bitpack (const boolNDArray& bitp) +{ + typedef typename ArrayType::element_type T; + octave_idx_type n = bitp.numel () / (sizeof (T) * CHAR_BIT); + + if (n * static_cast (sizeof (T)) * CHAR_BIT < bitp.numel ()) + warning ("bitpack: discarding excess data"); + + ArrayType retval (get_vec_dims (bitp.dims (), n)); + + const bool *bits = bitp.fortran_vec (); + char *packed = reinterpret_cast (retval.fortran_vec ()); + + octave_idx_type m = n * sizeof (T); + + for (octave_idx_type i = 0; i < m; i++) + { + char c = bits[0]; + for (int j = 1; j < CHAR_BIT; j++) + c |= bits[j] << j; + + packed[i] = c; + bits += CHAR_BIT; + } + + return retval; +} + +DEFUN_DLD (bitpack, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{y} =} bitpack (@var{x}, @var{class})\n\ +Returns a new array @var{y} resulting from interpreting a logical array @var{x}\n\ +as raw bit pattern for data of the numeric class @var{class}. @var{class} must be\n\ +one of the built-in numeric classes:\n\ +\n\ +@example\n\ + \"char\"\n\ + \"int8\"\n\ + \"int16\"\n\ + \"int32\"\n\ + \"int64\"\n\ + \"uint8\"\n\ + \"uint16\"\n\ + \"uint32\"\n\ + \"uint64\"\n\ + \"double\"\n\ + \"single\"\n\ +@end example\n\ +\n\ +The number of elements of @var{x} should be divisible by the bit length of @var{class}.\n\ +If it is not, excess bits are discarded. Bits come in increasing order of significance, i.e.\n\ +@code{x(1)} is bit 0, @code{x(2)} is bit 1, etc.\n\ +The result is a row vector if @var{x} is a row vector, otherwise it is a column vector.\n\ +@seealso{bitunpack,reinterpret,bitget,bitset}\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 2 && args(0).is_bool_type ()) + { + boolNDArray bitp = args(0).bool_array_value (); + + std::string numclass = args(1).string_value (); + + if (error_state || numclass.size () == 0) + ; + else if (numclass == "char") + retval = octave_value (do_bitpack (bitp), true); + else if (numclass[0] == 'i') + { + if (numclass == "int8") + retval = do_bitpack (bitp); + else if (numclass == "int16") + retval = do_bitpack (bitp); + else if (numclass == "int32") + retval = do_bitpack (bitp); + else if (numclass == "int64") + retval = do_bitpack (bitp); + } + else if (numclass[0] == 'u') + { + if (numclass == "uint8") + retval = do_bitpack (bitp); + else if (numclass == "uint16") + retval = do_bitpack (bitp); + else if (numclass == "uint32") + retval = do_bitpack (bitp); + else if (numclass == "uint64") + retval = do_bitpack (bitp); + } + else if (numclass == "single") + retval = do_bitpack (bitp); + else if (numclass == "double") + retval = do_bitpack (bitp); + else if (numclass == "single complex") + retval = do_bitpack (bitp); + else if (numclass == "double complex") + retval = do_bitpack (bitp); + + if (! error_state && retval.is_undefined ()) + error ("bitpack: cannot pack to %s class", numclass.c_str ()); + } + else + print_usage (); + + return retval; +} + +template +boolNDArray +do_bitunpack (const ArrayType& array) +{ + typedef typename ArrayType::element_type T; + octave_idx_type n = array.numel () * sizeof (T) * CHAR_BIT; + + boolNDArray retval (get_vec_dims (array.dims (), n)); + + const char *packed = reinterpret_cast (array.fortran_vec ()); + bool *bits = retval.fortran_vec (); + + octave_idx_type m = n / CHAR_BIT; + + for (octave_idx_type i = 0; i < m; i++) + { + char c = packed[i]; + bits[0] = c & 1; + for (int j = 1; j < CHAR_BIT; j++) + bits[j] = (c >>= 1) & 1; + bits += CHAR_BIT; + } + + return retval; +} + +DEFUN_DLD (bitunpack, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{y} =} bitpack (@var{x})\n\ +Returns a logical array @var{y} corresponding to the raw bit pattern of @var{x}.\n\ +@var{x} must belong to one of the built-in numeric classes:\n\ +\n\ +@example\n\ + \"char\"\n\ + \"int8\"\n\ + \"int16\"\n\ + \"int32\"\n\ + \"int64\"\n\ + \"uint8\"\n\ + \"uint16\"\n\ + \"uint32\"\n\ + \"uint64\"\n\ + \"double\"\n\ + \"single\"\n\ +@end example\n\ +\n\ +The result is a row vector if @var{x} is a row vector, otherwise it is a column vector.\n\ +@seealso{bitpack,reinterpret,bitget,bitset}\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1 && (args(0).is_numeric_type () || args(0).is_string ())) + { + octave_value array = args(0); + + if (array.is_string ()) + retval = do_bitunpack (array.char_array_value ()); + else if (array.is_integer_type ()) + { + if (array.is_int8_type ()) + retval = do_bitunpack (array.int8_array_value ()); + else if (array.is_int16_type ()) + retval = do_bitunpack (array.int16_array_value ()); + else if (array.is_int32_type ()) + retval = do_bitunpack (array.int32_array_value ()); + else if (array.is_int64_type ()) + retval = do_bitunpack (array.int64_array_value ()); + else if (array.is_uint8_type ()) + retval = do_bitunpack (array.uint8_array_value ()); + else if (array.is_uint16_type ()) + retval = do_bitunpack (array.uint16_array_value ()); + else if (array.is_uint32_type ()) + retval = do_bitunpack (array.uint32_array_value ()); + else if (array.is_uint64_type ()) + retval = do_bitunpack (array.uint64_array_value ()); + else + assert (0); + } + else if (array.is_complex_type ()) + { + if (array.is_single_type ()) + retval = do_bitunpack (array.float_complex_array_value ()); + else + retval = do_bitunpack (array.complex_array_value ()); + } + else if (array.is_real_type ()) + { + if (array.is_single_type ()) + retval = do_bitunpack (array.float_array_value ()); + else + retval = do_bitunpack (array.array_value ()); + } + else + error ("bitunpack: invalid input class: %s", array.class_name ().c_str ()); + } + else + print_usage (); + + return retval; +} diff -r 63249224f78d -r 5627b5865d99 src/Makefile.in --- a/src/Makefile.in Mon Sep 28 21:52:27 2009 -0400 +++ b/src/Makefile.in Tue Sep 29 08:04:10 2009 +0200 @@ -71,7 +71,7 @@ gammainc.cc gcd.cc getgrent.cc getpwent.cc getrusage.cc \ givens.cc hess.cc hex2num.cc inv.cc kron.cc lookup.cc \ lsode.cc lu.cc luinc.cc matrix_type.cc max.cc md5sum.cc \ - pinv.cc qr.cc quad.cc qz.cc rand.cc rcond.cc regexp.cc \ + pinv.cc qr.cc quad.cc qz.cc rand.cc rcond.cc regexp.cc reinterpret.cc \ schur.cc sparse.cc spparms.cc sqrtm.cc sub2ind.cc svd.cc syl.cc \ symrcm.cc symbfact.cc time.cc tsearch.cc typecast.cc \ urlwrite.cc __contourc__.cc __delaunayn__.cc \