GNU Octave  4.0.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
typecast.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2007-2015 David Bateman
4 Copyright (C) 2009 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <limits>
29 
30 #include "mx-base.h"
31 
32 #include "defun.h"
33 #include "error.h"
34 #include "gripes.h"
35 #include "oct-obj.h"
36 #include "unwind-prot.h"
37 
38 static dim_vector
40 {
41  if (old_dims.length () == 2 && old_dims(0) == 1)
42  return dim_vector (1, n);
43  else if (old_dims.length () == 2 && old_dims (0) == 0 && old_dims (1) == 0)
44  return dim_vector ();
45  else
46  return dim_vector (n, 1);
47 }
48 
49 template <class ArrayType>
50 static void
51 get_data_and_bytesize (const ArrayType& array,
52  const void *& data,
53  octave_idx_type& byte_size,
54  dim_vector& old_dims,
55  unwind_protect& frame)
56 {
57  // The array given may be a temporary, constructed from a scalar or sparse
58  // array. This will ensure the data will be deallocated after we exit.
59  frame.add_delete (new ArrayType (array));
60 
61  data = reinterpret_cast<const void *> (array.data ());
62  byte_size = array.byte_size ();
63 
64  old_dims = array.dims ();
65 }
66 
67 template <class ArrayType>
68 static ArrayType
69 reinterpret_copy (const void *data, octave_idx_type byte_size,
70  const dim_vector& old_dims)
71 {
72  typedef typename ArrayType::element_type T;
73  octave_idx_type n = byte_size / sizeof (T);
74 
75  if (n * static_cast<int> (sizeof (T)) == byte_size)
76  {
77  ArrayType retval (get_vec_dims (old_dims, n));
78  T *dest = retval.fortran_vec ();
79  std::memcpy (dest, data, n * sizeof (T));
80 
81  return retval;
82  }
83  else
84  {
85  error ("typecast: incorrect number of input values to make output value");
86  return ArrayType ();
87  }
88 }
89 
90 
91 DEFUN (typecast, args, ,
92  "-*- texinfo -*-\n\
93 @deftypefn {Built-in Function} {@var{y} =} typecast (@var{x}, \"@var{class}\")\n\
94 Return a new array @var{y} resulting from interpreting the data of @var{x}\n\
95 in memory as data of the numeric class @var{class}.\n\
96 \n\
97 Both the class of @var{x} and @var{class} must be one of the built-in\n\
98 numeric classes:\n\
99 \n\
100 @example\n\
101 @group\n\
102 \"logical\"\n\
103 \"char\"\n\
104 \"int8\"\n\
105 \"int16\"\n\
106 \"int32\"\n\
107 \"int64\"\n\
108 \"uint8\"\n\
109 \"uint16\"\n\
110 \"uint32\"\n\
111 \"uint64\"\n\
112 \"double\"\n\
113 \"single\"\n\
114 \"double complex\"\n\
115 \"single complex\"\n\
116 @end group\n\
117 @end example\n\
118 \n\
119 @noindent\n\
120 the last two are only used with @var{class}; they indicate that a\n\
121 complex-valued result is requested. Complex arrays are stored in memory as\n\
122 consecutive pairs of real numbers. The sizes of integer types are given by\n\
123 their bit counts. Both logical and char are typically one byte wide;\n\
124 however, this is not guaranteed by C++. If your system is IEEE conformant,\n\
125 single and double will be 4 bytes and 8 bytes wide, respectively.\n\
126 @qcode{\"logical\"} is not allowed for @var{class}.\n\
127 \n\
128 If the input is a row vector, the return value is a row vector, otherwise it\n\
129 is a column vector.\n\
130 \n\
131 If the bit length of @var{x} is not divisible by that of @var{class}, an\n\
132 error occurs.\n\
133 \n\
134 An example of the use of typecast on a little-endian machine is\n\
135 \n\
136 @example\n\
137 @group\n\
138 @var{x} = uint16 ([1, 65535]);\n\
139 typecast (@var{x}, \"uint8\")\n\
140 @result{} [ 1, 0, 255, 255]\n\
141 @end group\n\
142 @end example\n\
143 @seealso{cast, bitpack, bitunpack, swapbytes}\n\
144 @end deftypefn")
145 {
146  octave_value retval;
147 
148  if (args.length () == 2)
149  {
150  unwind_protect frame;
151  const void *data = 0;
152  octave_idx_type byte_size = 0;
153  dim_vector old_dims;
154 
155  octave_value array = args(0);
156 
157  if (array.is_bool_type ())
158  get_data_and_bytesize (array.bool_array_value (), data, byte_size,
159  old_dims, frame);
160  else if (array.is_string ())
161  get_data_and_bytesize (array.char_array_value (), data, byte_size,
162  old_dims, frame);
163  else if (array.is_integer_type ())
164  {
165  if (array.is_int8_type ())
166  get_data_and_bytesize (array.int8_array_value (), data, byte_size,
167  old_dims, frame);
168  else if (array.is_int16_type ())
169  get_data_and_bytesize (array.int16_array_value (), data, byte_size,
170  old_dims, frame);
171  else if (array.is_int32_type ())
172  get_data_and_bytesize (array.int32_array_value (), data, byte_size,
173  old_dims, frame);
174  else if (array.is_int64_type ())
175  get_data_and_bytesize (array.int64_array_value (), data, byte_size,
176  old_dims, frame);
177  else if (array.is_uint8_type ())
178  get_data_and_bytesize (array.uint8_array_value (), data, byte_size,
179  old_dims, frame);
180  else if (array.is_uint16_type ())
181  get_data_and_bytesize (array.uint16_array_value (), data, byte_size,
182  old_dims, frame);
183  else if (array.is_uint32_type ())
184  get_data_and_bytesize (array.uint32_array_value (), data, byte_size,
185  old_dims, frame);
186  else if (array.is_uint64_type ())
187  get_data_and_bytesize (array.uint64_array_value (), data, byte_size,
188  old_dims, frame);
189  else
190  assert (0);
191  }
192  else if (array.is_complex_type ())
193  {
194  if (array.is_single_type ())
196  byte_size, old_dims, frame);
197  else
199  byte_size, old_dims, frame);
200  }
201  else if (array.is_real_type ())
202  {
203  if (array.is_single_type ())
204  get_data_and_bytesize (array.float_array_value (), data, byte_size,
205  old_dims, frame);
206  else
207  get_data_and_bytesize (array.array_value (), data, byte_size,
208  old_dims, frame); }
209  else
210  error ("typecast: invalid input class: %s",
211  array.class_name ().c_str ());
212 
213  std::string numclass = args(1).string_value ();
214 
215  if (error_state || numclass.size () == 0)
216  ;
217  else if (numclass == "char")
218  retval = octave_value (reinterpret_copy<charNDArray>
219  (data, byte_size, old_dims), array.is_dq_string () ? '"'
220  : '\'');
221  else if (numclass[0] == 'i')
222  {
223  if (numclass == "int8")
224  retval = reinterpret_copy<int8NDArray> (data, byte_size, old_dims);
225  else if (numclass == "int16")
226  retval = reinterpret_copy<int16NDArray> (data, byte_size, old_dims);
227  else if (numclass == "int32")
228  retval = reinterpret_copy<int32NDArray> (data, byte_size, old_dims);
229  else if (numclass == "int64")
230  retval = reinterpret_copy<int64NDArray> (data, byte_size, old_dims);
231  }
232  else if (numclass[0] == 'u')
233  {
234  if (numclass == "uint8")
235  retval = reinterpret_copy<uint8NDArray> (data, byte_size, old_dims);
236  else if (numclass == "uint16")
237  retval = reinterpret_copy<uint16NDArray> (data, byte_size,
238  old_dims);
239  else if (numclass == "uint32")
240  retval = reinterpret_copy<uint32NDArray> (data, byte_size,
241  old_dims);
242  else if (numclass == "uint64")
243  retval = reinterpret_copy<uint64NDArray> (data, byte_size,
244  old_dims);
245  }
246  else if (numclass == "single")
247  retval = reinterpret_copy<FloatNDArray> (data, byte_size, old_dims);
248  else if (numclass == "double")
249  retval = reinterpret_copy<NDArray> (data, byte_size, old_dims);
250  else if (numclass == "single complex")
251  retval = reinterpret_copy<FloatComplexNDArray> (data, byte_size,
252  old_dims);
253  else if (numclass == "double complex")
254  retval = reinterpret_copy<ComplexNDArray> (data, byte_size, old_dims);
255 
256  if (! error_state && retval.is_undefined ())
257  error ("typecast: cannot convert to %s class", numclass.c_str ());
258  }
259  else
260  print_usage ();
261 
262  return retval;
263 }
264 
265 template <class ArrayType>
266 ArrayType
267 do_bitpack (const boolNDArray& bitp)
268 {
269  typedef typename ArrayType::element_type T;
271  = bitp.numel () / (sizeof (T) * std::numeric_limits<unsigned char>::digits);
272 
273  if (n * static_cast<int> (sizeof (T)) * std::numeric_limits<unsigned char>::digits == bitp.numel ())
274  {
275 
276  ArrayType retval (get_vec_dims (bitp.dims (), n));
277 
278  const bool *bits = bitp.fortran_vec ();
279  char *packed = reinterpret_cast<char *> (retval.fortran_vec ());
280 
281  octave_idx_type m = n * sizeof (T);
282 
283  for (octave_idx_type i = 0; i < m; i++)
284  {
285  char c = bits[0];
286  for (int j = 1; j < std::numeric_limits<unsigned char>::digits; j++)
287  c |= bits[j] << j;
288 
289  packed[i] = c;
290  bits += std::numeric_limits<unsigned char>::digits;
291  }
292 
293  return retval;
294  }
295  else
296  {
297  error ("bitpack: incorrect number of bits to make up output value");
298  return ArrayType ();
299  }
300 }
301 
302 DEFUN (bitpack, args, ,
303  "-*- texinfo -*-\n\
304 @deftypefn {Built-in Function} {@var{y} =} bitpack (@var{x}, @var{class})\n\
305 Return a new array @var{y} resulting from interpreting the logical array\n\
306 @var{x} as raw bit patterns for data of the numeric class @var{class}.\n\
307 \n\
308 @var{class} must be one of the built-in numeric classes:\n\
309 \n\
310 @example\n\
311 @group\n\
312 \"double\"\n\
313 \"single\"\n\
314 \"double complex\"\n\
315 \"single complex\"\n\
316 \"char\"\n\
317 \"int8\"\n\
318 \"int16\"\n\
319 \"int32\"\n\
320 \"int64\"\n\
321 \"uint8\"\n\
322 \"uint16\"\n\
323 \"uint32\"\n\
324 \"uint64\"\n\
325 @end group\n\
326 @end example\n\
327 \n\
328 The number of elements of @var{x} should be divisible by the bit length of\n\
329 @var{class}. If it is not, excess bits are discarded. Bits come in\n\
330 increasing order of significance, i.e., @code{x(1)} is bit 0, @code{x(2)} is\n\
331 bit 1, etc.\n\
332 \n\
333 The result is a row vector if @var{x} is a row vector, otherwise it is a\n\
334 column vector.\n\
335 @seealso{bitunpack, typecast}\n\
336 @end deftypefn")
337 {
338  octave_value retval;
339 
340  if (args.length () != 2)
341  print_usage ();
342  else if (! args(0).is_bool_type ())
343  error ("bitpack: X must be a logical array");
344  else
345  {
346  boolNDArray bitp = args(0).bool_array_value ();
347 
348  std::string numclass = args(1).string_value ();
349 
350  if (error_state || numclass.size () == 0)
351  ;
352  else if (numclass == "char")
353  retval = octave_value (do_bitpack<charNDArray> (bitp), '\'');
354  else if (numclass[0] == 'i')
355  {
356  if (numclass == "int8")
357  retval = do_bitpack<int8NDArray> (bitp);
358  else if (numclass == "int16")
359  retval = do_bitpack<int16NDArray> (bitp);
360  else if (numclass == "int32")
361  retval = do_bitpack<int32NDArray> (bitp);
362  else if (numclass == "int64")
363  retval = do_bitpack<int64NDArray> (bitp);
364  }
365  else if (numclass[0] == 'u')
366  {
367  if (numclass == "uint8")
368  retval = do_bitpack<uint8NDArray> (bitp);
369  else if (numclass == "uint16")
370  retval = do_bitpack<uint16NDArray> (bitp);
371  else if (numclass == "uint32")
372  retval = do_bitpack<uint32NDArray> (bitp);
373  else if (numclass == "uint64")
374  retval = do_bitpack<uint64NDArray> (bitp);
375  }
376  else if (numclass == "single")
377  retval = do_bitpack<FloatNDArray> (bitp);
378  else if (numclass == "double")
379  retval = do_bitpack<NDArray> (bitp);
380  else if (numclass == "single complex")
381  retval = do_bitpack<FloatComplexNDArray> (bitp);
382  else if (numclass == "double complex")
383  retval = do_bitpack<ComplexNDArray> (bitp);
384 
385  if (! error_state && retval.is_undefined ())
386  error ("bitpack: cannot pack to %s class", numclass.c_str ());
387  }
388 
389  return retval;
390 }
391 
392 template <class ArrayType>
394 do_bitunpack (const ArrayType& array)
395 {
396  typedef typename ArrayType::element_type T;
397  octave_idx_type n = array.numel () * sizeof (T)
398  * std::numeric_limits<unsigned char>::digits;
399 
400  boolNDArray retval (get_vec_dims (array.dims (), n));
401 
402  const char *packed = reinterpret_cast<const char *> (array.fortran_vec ());
403  bool *bits = retval.fortran_vec ();
404 
405  octave_idx_type m = n / std::numeric_limits<unsigned char>::digits;
406 
407  for (octave_idx_type i = 0; i < m; i++)
408  {
409  char c = packed[i];
410  bits[0] = c & 1;
411  for (int j = 1; j < std::numeric_limits<unsigned char>::digits; j++)
412  bits[j] = (c >>= 1) & 1;
413  bits += std::numeric_limits<unsigned char>::digits;
414  }
415 
416  return retval;
417 }
418 
419 DEFUN (bitunpack, args, ,
420  "-*- texinfo -*-\n\
421 @deftypefn {Built-in Function} {@var{y} =} bitunpack (@var{x})\n\
422 Return a logical array @var{y} corresponding to the raw bit patterns of\n\
423 @var{x}.\n\
424 \n\
425 @var{x} must belong to one of the built-in numeric classes:\n\
426 \n\
427 @example\n\
428 @group\n\
429 \"double\"\n\
430 \"single\"\n\
431 \"char\"\n\
432 \"int8\"\n\
433 \"int16\"\n\
434 \"int32\"\n\
435 \"int64\"\n\
436 \"uint8\"\n\
437 \"uint16\"\n\
438 \"uint32\"\n\
439 \"uint64\"\n\
440 @end group\n\
441 @end example\n\
442 \n\
443 The result is a row vector if @var{x} is a row vector; otherwise, it is a\n\
444 column vector.\n\
445 @seealso{bitpack, typecast}\n\
446 @end deftypefn")
447 {
448  octave_value retval;
449 
450  if (args.length () == 1
451  && (args(0).is_numeric_type () || args(0).is_string ()))
452  {
453  octave_value array = args(0);
454 
455  if (array.is_string ())
456  retval = do_bitunpack (array.char_array_value ());
457  else if (array.is_integer_type ())
458  {
459  if (array.is_int8_type ())
460  retval = do_bitunpack (array.int8_array_value ());
461  else if (array.is_int16_type ())
462  retval = do_bitunpack (array.int16_array_value ());
463  else if (array.is_int32_type ())
464  retval = do_bitunpack (array.int32_array_value ());
465  else if (array.is_int64_type ())
466  retval = do_bitunpack (array.int64_array_value ());
467  else if (array.is_uint8_type ())
468  retval = do_bitunpack (array.uint8_array_value ());
469  else if (array.is_uint16_type ())
470  retval = do_bitunpack (array.uint16_array_value ());
471  else if (array.is_uint32_type ())
472  retval = do_bitunpack (array.uint32_array_value ());
473  else if (array.is_uint64_type ())
474  retval = do_bitunpack (array.uint64_array_value ());
475  else
476  assert (0);
477  }
478  else if (array.is_complex_type ())
479  {
480  if (array.is_single_type ())
481  retval = do_bitunpack (array.float_complex_array_value ());
482  else
483  retval = do_bitunpack (array.complex_array_value ());
484  }
485  else if (array.is_real_type ())
486  {
487  if (array.is_single_type ())
488  retval = do_bitunpack (array.float_array_value ());
489  else
490  retval = do_bitunpack (array.array_value ());
491  }
492  else
493  error ("bitunpack: invalid input class: %s",
494  array.class_name ().c_str ());
495  }
496  else
497  print_usage ();
498 
499  return retval;
500 }
uint8NDArray uint8_array_value(void) const
Definition: ov.h:882
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:798
charNDArray char_array_value(bool frc_str_conv=false) const
Definition: ov.h:817
bool is_real_type(void) const
Definition: ov.h:651
int8NDArray int8_array_value(void) const
Definition: ov.h:870
bool is_uint16_type(void) const
Definition: ov.h:634
OCTINTERP_API void print_usage(void)
Definition: defun.cc:51
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:275
int16NDArray int16_array_value(void) const
Definition: ov.h:873
uint64NDArray uint64_array_value(void) const
Definition: ov.h:891
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:44
void error(const char *fmt,...)
Definition: error.cc:476
int32NDArray int32_array_value(void) const
Definition: ov.h:876
bool is_int8_type(void) const
Definition: ov.h:619
bool is_int32_type(void) const
Definition: ov.h:625
boolNDArray bool_array_value(bool warn=false) const
Definition: ov.h:811
ArrayType do_bitpack(const boolNDArray &bitp)
Definition: typecast.cc:267
int64NDArray int64_array_value(void) const
Definition: ov.h:879
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:337
void add_delete(T *obj)
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:782
bool is_bool_type(void) const
Definition: ov.h:645
FloatComplexNDArray float_complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:802
bool is_string(void) const
Definition: ov.h:562
int error_state
Definition: error.cc:101
bool is_complex_type(void) const
Definition: ov.h:654
bool is_int64_type(void) const
Definition: ov.h:628
bool is_int16_type(void) const
Definition: ov.h:622
static void get_data_and_bytesize(const ArrayType &array, const void *&data, octave_idx_type &byte_size, dim_vector &old_dims, unwind_protect &frame)
Definition: typecast.cc:51
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:779
static ArrayType reinterpret_copy(const void *data, octave_idx_type byte_size, const dim_vector &old_dims)
Definition: typecast.cc:69
bool is_dq_string(void) const
Definition: ov.h:568
boolNDArray do_bitunpack(const ArrayType &array)
Definition: typecast.cc:394
bool is_uint8_type(void) const
Definition: ov.h:631
std::string class_name(void) const
Definition: ov.h:1049
static dim_vector get_vec_dims(const dim_vector &old_dims, octave_idx_type n)
Definition: typecast.cc:39
bool is_undefined(void) const
Definition: ov.h:523
bool is_uint64_type(void) const
Definition: ov.h:640
const T * fortran_vec(void) const
Definition: Array.h:481
bool is_single_type(void) const
Definition: ov.h:611
bool is_uint32_type(void) const
Definition: ov.h:637
uint32NDArray uint32_array_value(void) const
Definition: ov.h:888
int length(void) const
Definition: dim-vector.h:281
uint16NDArray uint16_array_value(void) const
Definition: ov.h:885
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
bool is_integer_type(void) const
Definition: ov.h:648