GNU Octave  3.8.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
ov-base-int.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2004-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <iostream>
28 #include <limits>
29 #include <vector>
30 
31 #include "lo-ieee.h"
32 #include "lo-utils.h"
33 #include "mx-base.h"
34 #include "quit.h"
35 #include "oct-locbuf.h"
36 
37 #include "defun.h"
38 #include "gripes.h"
39 #include "oct-obj.h"
40 #include "oct-lvalue.h"
41 #include "oct-stream.h"
42 #include "ops.h"
43 #include "ov-base.h"
44 #include "ov-base-mat.h"
45 #include "ov-base-mat.cc"
46 #include "ov-base-scalar.h"
47 #include "ov-base-scalar.cc"
48 #include "ov-base-int.h"
49 #include "ov-int-traits.h"
50 #include "pr-output.h"
51 #include "variables.h"
52 
53 #include "byte-swap.h"
54 #include "ls-oct-ascii.h"
55 #include "ls-utils.h"
56 #include "ls-hdf5.h"
57 
58 // We have all the machinery below (octave_base_int_helper and
59 // octave_base_int_helper_traits) to avoid a few warnings from GCC
60 // about comparisons always false due to limited range of data types.
61 // Ugh. The cure may be worse than the disease.
62 
63 template <class T, bool is_signed = true, bool can_be_too_big = true>
65 {
66  static bool
68  {
69  return val < 0 || val > std::numeric_limits<unsigned char>::max ();
70  }
71 };
72 
73 template <class T>
74 struct octave_base_int_helper<T, false, false>
75 {
76  static bool char_value_out_of_range (T) { return false; }
77 };
78 
79 template <class T>
80 struct octave_base_int_helper<T, false, true>
81 {
82  static bool char_value_out_of_range (T val)
83  {
85  }
86 };
87 
88 template <class T>
89 struct octave_base_int_helper<T, true, false>
90 {
91  static bool char_value_out_of_range (T val) { return val < 0; }
92 };
93 
94 // For all types other than char, signed char, and unsigned char, we
95 // assume that the upper limit for the range of allowable values is
96 // larger than the range for unsigned char. If that's not true, we
97 // are still OK, but will see the warnings again for any other types
98 // that do not meet this assumption.
99 
100 template <class T>
102 {
103  static const bool can_be_larger_than_uchar_max = true;
104 };
105 
106 template <>
108 {
109  static const bool can_be_larger_than_uchar_max = false;
110 };
111 
112 template <>
114 {
115  static const bool can_be_larger_than_uchar_max = false;
116 };
117 
118 template <>
120 {
121  static const bool can_be_larger_than_uchar_max = false;
122 };
123 
124 
125 template <class T>
128 {
129  octave_base_value *retval = 0;
130 
131  if (this->matrix.nelem () == 1)
132  retval = new typename octave_value_int_traits<T>::scalar_type
133  (this->matrix (0));
134 
135  return retval;
136 }
137 
138 template <class T>
141 {
142  octave_value retval;
143  dim_vector dv = this->dims ();
144  octave_idx_type nel = dv.numel ();
145 
146  charNDArray chm (dv);
147 
148  bool warned = false;
149 
150  for (octave_idx_type i = 0; i < nel; i++)
151  {
152  octave_quit ();
153 
154  typename T::element_type tmp = this->matrix(i);
155 
156  typedef typename T::element_type::val_type val_type;
157 
158  val_type ival = tmp.value ();
159 
160  static const bool is_signed = std::numeric_limits<val_type>::is_signed;
161  static const bool can_be_larger_than_uchar_max
163 
164  if (octave_base_int_helper<val_type, is_signed,
165  can_be_larger_than_uchar_max>::char_value_out_of_range (ival))
166  {
167  // FIXME: is there something better we could do?
168 
169  ival = 0;
170 
171  if (! warned)
172  {
173  ::warning ("range error for conversion to character value");
174  warned = true;
175  }
176  }
177  else
178  chm (i) = static_cast<char> (ival);
179  }
180 
181  retval = octave_value (chm, type);
182 
183  return retval;
184 }
185 
186 template <class T>
187 bool
189 {
190  dim_vector d = this->dims ();
191 
192  os << "# ndims: " << d.length () << "\n";
193 
194  for (int i = 0; i < d.length (); i++)
195  os << " " << d (i);
196 
197  os << "\n" << this->matrix;
198 
199  return true;
200 }
201 
202 template <class T>
203 bool
205 {
206  int mdims = 0;
207  bool success = true;
208 
209  if (extract_keyword (is, "ndims", mdims, true))
210  {
211  if (mdims >= 0)
212  {
213  dim_vector dv;
214  dv.resize (mdims);
215 
216  for (int i = 0; i < mdims; i++)
217  is >> dv(i);
218 
219  T tmp(dv);
220 
221  is >> tmp;
222 
223  if (!is)
224  {
225  error ("load: failed to load matrix constant");
226  success = false;
227  }
228 
229  this->matrix = tmp;
230  }
231  else
232  {
233  error ("load: failed to extract number of rows and columns");
234  success = false;
235  }
236  }
237  else
238  error ("load: failed to extract number of dimensions");
239 
240  return success;
241 }
242 
243 template <class T>
244 bool
245 octave_base_int_matrix<T>::save_binary (std::ostream& os, bool&)
246 {
247  dim_vector d = this->dims ();
248  if (d.length () < 1)
249  return false;
250 
251  // Use negative value for ndims to differentiate with old format!!
252  int32_t tmp = - d.length ();
253  os.write (reinterpret_cast<char *> (&tmp), 4);
254  for (int i=0; i < d.length (); i++)
255  {
256  tmp = d(i);
257  os.write (reinterpret_cast<char *> (&tmp), 4);
258  }
259 
260  os.write (reinterpret_cast<const char *> (this->matrix.data ()),
261  this->byte_size ());
262 
263  return true;
264 }
265 
266 template <class T>
267 bool
268 octave_base_int_matrix<T>::load_binary (std::istream& is, bool swap,
270 {
271  int32_t mdims;
272  if (! is.read (reinterpret_cast<char *> (&mdims), 4))
273  return false;
274  if (swap)
275  swap_bytes<4> (&mdims);
276  if (mdims >= 0)
277  return false;
278 
279  mdims = - mdims;
280  int32_t di;
281  dim_vector dv;
282  dv.resize (mdims);
283 
284  for (int i = 0; i < mdims; i++)
285  {
286  if (! is.read (reinterpret_cast<char *> (&di), 4))
287  return false;
288  if (swap)
289  swap_bytes<4> (&di);
290  dv(i) = di;
291  }
292 
293  // Convert an array with a single dimension to be a row vector.
294  // Octave should never write files like this, other software
295  // might.
296 
297  if (mdims == 1)
298  {
299  mdims = 2;
300  dv.resize (mdims);
301  dv(1) = dv(0);
302  dv(0) = 1;
303  }
304 
305  T m (dv);
306 
307  if (! is.read (reinterpret_cast<char *> (m.fortran_vec ()), m.byte_size ()))
308  return false;
309 
310  if (swap)
311  {
312  int nel = dv.numel ();
313  int bytes = nel / m.byte_size ();
314  for (int i = 0; i < nel; i++)
315  switch (bytes)
316  {
317  case 8:
318  swap_bytes<8> (&m(i));
319  break;
320  case 4:
321  swap_bytes<4> (&m(i));
322  break;
323  case 2:
324  swap_bytes<2> (&m(i));
325  break;
326  case 1:
327  default:
328  break;
329  }
330  }
331 
332  this->matrix = m;
333  return true;
334 }
335 
336 #if defined (HAVE_HDF5)
337 
338 template <class T>
339 bool
340 octave_base_int_matrix<T>::save_hdf5 (hid_t loc_id, const char *name, bool)
341 {
342  hid_t save_type_hid = HDF5_SAVE_TYPE;
343  bool retval = true;
344  dim_vector dv = this->dims ();
345  int empty = save_hdf5_empty (loc_id, name, dv);
346  if (empty)
347  return (empty > 0);
348 
349  int rank = dv.length ();
350  hid_t space_hid = -1, data_hid = -1;
351  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
352 
353  // Octave uses column-major, while HDF5 uses row-major ordering
354  for (int i = 0; i < rank; i++)
355  hdims[i] = dv (rank-i-1);
356 
357  space_hid = H5Screate_simple (rank, hdims, 0);
358 
359  if (space_hid < 0) return false;
360 #if HAVE_HDF5_18
361  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
362  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
363 #else
364  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
365  H5P_DEFAULT);
366 #endif
367  if (data_hid < 0)
368  {
369  H5Sclose (space_hid);
370  return false;
371  }
372 
373  retval = H5Dwrite (data_hid, save_type_hid, H5S_ALL, H5S_ALL,
374  H5P_DEFAULT, this->matrix.data ()) >= 0;
375 
376  H5Dclose (data_hid);
377  H5Sclose (space_hid);
378 
379  return retval;
380 }
381 
382 template <class T>
383 bool
384 octave_base_int_matrix<T>::load_hdf5 (hid_t loc_id, const char *name)
385 {
386  hid_t save_type_hid = HDF5_SAVE_TYPE;
387  bool retval = false;
388  dim_vector dv;
389  int empty = load_hdf5_empty (loc_id, name, dv);
390  if (empty > 0)
391  this->matrix.resize (dv);
392  if (empty)
393  return (empty > 0);
394 
395 #if HAVE_HDF5_18
396  hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
397 #else
398  hid_t data_hid = H5Dopen (loc_id, name);
399 #endif
400  hid_t space_id = H5Dget_space (data_hid);
401 
402  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
403 
404  if (rank < 1)
405  {
406  H5Sclose (space_id);
407  H5Dclose (data_hid);
408  return false;
409  }
410 
411  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
412  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
413 
414  H5Sget_simple_extent_dims (space_id, hdims, maxdims);
415 
416  // Octave uses column-major, while HDF5 uses row-major ordering
417  if (rank == 1)
418  {
419  dv.resize (2);
420  dv(0) = 1;
421  dv(1) = hdims[0];
422  }
423  else
424  {
425  dv.resize (rank);
426  for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
427  dv(j) = hdims[i];
428  }
429 
430  T m (dv);
431  if (H5Dread (data_hid, save_type_hid, H5S_ALL, H5S_ALL,
432  H5P_DEFAULT, m.fortran_vec ()) >= 0)
433  {
434  retval = true;
435  this->matrix = m;
436  }
437 
438  H5Sclose (space_id);
439  H5Dclose (data_hid);
440 
441  return retval;
442 }
443 
444 #endif
445 
446 template <class T>
447 void
449  bool pr_as_read_syntax) const
450 {
451  octave_print_internal (os, this->matrix, pr_as_read_syntax,
452  this->current_print_indent_level ());
453 }
454 
455 template <class T>
458 {
459  octave_value retval;
460 
461  T tmp = this->scalar;
462 
463  typedef typename T::val_type val_type;
464 
465  val_type ival = tmp.value ();
466 
467  static const bool is_signed = std::numeric_limits<val_type>::is_signed;
468  static const bool can_be_larger_than_uchar_max
470 
471  if (octave_base_int_helper<val_type, is_signed,
472  can_be_larger_than_uchar_max>::char_value_out_of_range (ival))
473  {
474  // FIXME: is there something better we could do?
475 
476  ival = 0;
477 
478  ::warning ("range error for conversion to character value");
479  }
480  else
481  retval = octave_value (std::string (1, static_cast<char> (ival)), type);
482 
483  return retval;
484 }
485 
486 template <class T>
487 bool
489 {
490  os << this->scalar << "\n";
491  return true;
492 }
493 
494 template <class T>
495 bool
497 {
498  is >> this->scalar;
499  if (!is)
500  {
501  error ("load: failed to load scalar constant");
502  return false;
503  }
504  return true;
505 }
506 
507 template <class T>
508 bool
509 octave_base_int_scalar<T>::save_binary (std::ostream& os, bool&)
510 {
511  os.write (reinterpret_cast<char *> (&(this->scalar)), this->byte_size ());
512  return true;
513 }
514 
515 template <class T>
516 bool
517 octave_base_int_scalar<T>::load_binary (std::istream& is, bool swap,
519 {
520  T tmp;
521  if (! is.read (reinterpret_cast<char *> (&tmp), this->byte_size ()))
522  return false;
523 
524  if (swap)
525  switch (this->byte_size ())
526  {
527  case 8:
528  swap_bytes<8> (&tmp);
529  break;
530  case 4:
531  swap_bytes<4> (&tmp);
532  break;
533  case 2:
534  swap_bytes<2> (&tmp);
535  break;
536  case 1:
537  default:
538  break;
539  }
540  this->scalar = tmp;
541  return true;
542 }
543 
544 #if defined (HAVE_HDF5)
545 
546 template <class T>
547 bool
548 octave_base_int_scalar<T>::save_hdf5 (hid_t loc_id, const char *name, bool)
549 {
550  hid_t save_type_hid = HDF5_SAVE_TYPE;
551  bool retval = true;
552  hsize_t dimens[3];
553  hid_t space_hid = -1, data_hid = -1;
554 
555  space_hid = H5Screate_simple (0, dimens, 0);
556  if (space_hid < 0) return false;
557 
558 #if HAVE_HDF5_18
559  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
560  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
561 #else
562  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
563  H5P_DEFAULT);
564 #endif
565  if (data_hid < 0)
566  {
567  H5Sclose (space_hid);
568  return false;
569  }
570 
571  retval = H5Dwrite (data_hid, save_type_hid, H5S_ALL, H5S_ALL,
572  H5P_DEFAULT, &(this->scalar)) >= 0;
573 
574  H5Dclose (data_hid);
575  H5Sclose (space_hid);
576 
577  return retval;
578 }
579 
580 template <class T>
581 bool
582 octave_base_int_scalar<T>::load_hdf5 (hid_t loc_id, const char *name)
583 {
584  hid_t save_type_hid = HDF5_SAVE_TYPE;
585 #if HAVE_HDF5_18
586  hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
587 #else
588  hid_t data_hid = H5Dopen (loc_id, name);
589 #endif
590  hid_t space_id = H5Dget_space (data_hid);
591 
592  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
593 
594  if (rank != 0)
595  {
596  H5Dclose (data_hid);
597  return false;
598  }
599 
600  T tmp;
601  if (H5Dread (data_hid, save_type_hid, H5S_ALL, H5S_ALL,
602  H5P_DEFAULT, &tmp) < 0)
603  {
604  H5Dclose (data_hid);
605  return false;
606  }
607 
608  this->scalar = tmp;
609 
610  H5Dclose (data_hid);
611 
612  return true;
613 }
614 
615 #endif