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