ov-base-int.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2004-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <climits>
00028 
00029 #include <iostream>
00030 #include <vector>
00031 
00032 #include "lo-ieee.h"
00033 #include "lo-utils.h"
00034 #include "mx-base.h"
00035 #include "quit.h"
00036 #include "oct-locbuf.h"
00037 
00038 #include "defun.h"
00039 #include "gripes.h"
00040 #include "oct-obj.h"
00041 #include "oct-lvalue.h"
00042 #include "oct-stream.h"
00043 #include "ops.h"
00044 #include "ov-base.h"
00045 #include "ov-base-mat.h"
00046 #include "ov-base-mat.cc"
00047 #include "ov-base-scalar.h"
00048 #include "ov-base-scalar.cc"
00049 #include "ov-base-int.h"
00050 #include "ov-int-traits.h"
00051 #include "pr-output.h"
00052 #include "variables.h"
00053 
00054 #include "byte-swap.h"
00055 #include "ls-oct-ascii.h"
00056 #include "ls-utils.h"
00057 #include "ls-hdf5.h"
00058 
00059 // We have all the machinery below (octave_base_int_helper and
00060 // octave_base_int_helper_traits) to avoid a few warnings from GCC
00061 // about comparisons always false due to limited range of data types.
00062 // Ugh.  The cure may be worse than the disease.
00063 
00064 template <class T, bool is_signed = true, bool can_be_too_big = true>
00065 struct octave_base_int_helper
00066 {
00067   static bool
00068   char_value_out_of_range (T val) { return val < 0 || val > UCHAR_MAX; }
00069 };
00070 
00071 template <class T>
00072 struct octave_base_int_helper<T, false, false>
00073 {
00074   static bool char_value_out_of_range (T) { return false; }
00075 };
00076 
00077 template <class T>
00078 struct octave_base_int_helper<T, false, true>
00079 {
00080   static bool char_value_out_of_range (T val) { return val > UCHAR_MAX; }
00081 };
00082 
00083 template <class T>
00084 struct octave_base_int_helper<T, true, false>
00085 {
00086   static bool char_value_out_of_range (T val) { return val < 0; }
00087 };
00088 
00089 // For all types other than char, signed char, and unsigned char, we
00090 // assume that the upper limit for the range of allowable values is
00091 // larger than the range for unsigned char.  If that's not true, we
00092 // are still OK, but will see the warnings again for any other types
00093 // that do not meet this assumption.
00094 
00095 template <class T>
00096 struct octave_base_int_helper_traits
00097 {
00098   static const bool can_be_larger_than_uchar_max = true;
00099 };
00100 
00101 template <>
00102 struct octave_base_int_helper_traits<char>
00103 {
00104   static const bool can_be_larger_than_uchar_max = false;
00105 };
00106 
00107 template <>
00108 struct octave_base_int_helper_traits<signed char>
00109 {
00110   static const bool can_be_larger_than_uchar_max = false;
00111 };
00112 
00113 template <>
00114 struct octave_base_int_helper_traits<unsigned char>
00115 {
00116   static const bool can_be_larger_than_uchar_max = false;
00117 };
00118 
00119 
00120 template <class T>
00121 octave_base_value *
00122 octave_base_int_matrix<T>::try_narrowing_conversion (void)
00123 {
00124   octave_base_value *retval = 0;
00125 
00126   if (this->matrix.nelem () == 1)
00127     retval = new typename octave_value_int_traits<T>::scalar_type (this->matrix (0));
00128 
00129   return retval;
00130 }
00131 
00132 template <class T>
00133 octave_value
00134 octave_base_int_matrix<T>::convert_to_str_internal (bool, bool, char type) const
00135 {
00136   octave_value retval;
00137   dim_vector dv = this->dims ();
00138   octave_idx_type nel = dv.numel ();
00139 
00140   charNDArray chm (dv);
00141 
00142   bool warned = false;
00143 
00144   for (octave_idx_type i = 0; i < nel; i++)
00145     {
00146       octave_quit ();
00147 
00148       typename T::element_type tmp = this->matrix(i);
00149 
00150       typedef typename T::element_type::val_type val_type;
00151 
00152       val_type ival = tmp.value ();
00153 
00154       static const bool is_signed = std::numeric_limits<val_type>::is_signed;
00155       static const bool can_be_larger_than_uchar_max
00156         = octave_base_int_helper_traits<val_type>::can_be_larger_than_uchar_max;
00157 
00158       if (octave_base_int_helper<val_type, is_signed,
00159           can_be_larger_than_uchar_max>::char_value_out_of_range (ival))
00160         {
00161           // FIXME -- is there something better we could do?
00162 
00163           ival = 0;
00164 
00165           if (! warned)
00166             {
00167               ::warning ("range error for conversion to character value");
00168               warned = true;
00169             }
00170         }
00171       else
00172         chm (i) = static_cast<char> (ival);
00173     }
00174 
00175   retval = octave_value (chm, type);
00176 
00177   return retval;
00178 }
00179 
00180 template <class T>
00181 bool
00182 octave_base_int_matrix<T>::save_ascii (std::ostream& os)
00183 {
00184   dim_vector d = this->dims ();
00185 
00186   os << "# ndims: " << d.length () << "\n";
00187 
00188   for (int i = 0; i < d.length (); i++)
00189     os << " " << d (i);
00190 
00191   os << "\n" << this->matrix;
00192 
00193   return true;
00194 }
00195 
00196 template <class T>
00197 bool
00198 octave_base_int_matrix<T>::load_ascii (std::istream& is)
00199 {
00200   int mdims = 0;
00201   bool success = true;
00202 
00203   if (extract_keyword (is, "ndims", mdims, true))
00204     {
00205       if (mdims >= 0)
00206         {
00207           dim_vector dv;
00208           dv.resize (mdims);
00209 
00210           for (int i = 0; i < mdims; i++)
00211             is >> dv(i);
00212 
00213           T tmp(dv);
00214 
00215           is >> tmp;
00216 
00217           if (!is)
00218             {
00219               error ("load: failed to load matrix constant");
00220               success = false;
00221             }
00222 
00223           this->matrix = tmp;
00224         }
00225       else
00226         {
00227           error ("load: failed to extract number of rows and columns");
00228           success = false;
00229         }
00230     }
00231   else
00232     error ("load: failed to extract number of dimensions");
00233 
00234   return success;
00235 }
00236 
00237 template <class T>
00238 bool
00239 octave_base_int_matrix<T>::save_binary (std::ostream& os, bool&)
00240 {
00241   dim_vector d = this->dims ();
00242   if (d.length() < 1)
00243     return false;
00244 
00245   // Use negative value for ndims to differentiate with old format!!
00246   int32_t tmp = - d.length();
00247   os.write (reinterpret_cast<char *> (&tmp), 4);
00248   for (int i=0; i < d.length (); i++)
00249     {
00250       tmp = d(i);
00251       os.write (reinterpret_cast<char *> (&tmp), 4);
00252     }
00253 
00254   os.write (reinterpret_cast<const char *> (this->matrix.data()), this->byte_size());
00255 
00256   return true;
00257 }
00258 
00259 template <class T>
00260 bool
00261 octave_base_int_matrix<T>::load_binary (std::istream& is, bool swap,
00262                                         oct_mach_info::float_format )
00263 {
00264   int32_t mdims;
00265   if (! is.read (reinterpret_cast<char *> (&mdims), 4))
00266     return false;
00267   if (swap)
00268     swap_bytes<4> (&mdims);
00269   if (mdims >= 0)
00270     return false;
00271 
00272   mdims = - mdims;
00273   int32_t di;
00274   dim_vector dv;
00275   dv.resize (mdims);
00276 
00277   for (int i = 0; i < mdims; i++)
00278     {
00279       if (! is.read (reinterpret_cast<char *> (&di), 4))
00280         return false;
00281       if (swap)
00282         swap_bytes<4> (&di);
00283       dv(i) = di;
00284     }
00285 
00286   // Convert an array with a single dimension to be a row vector.
00287   // Octave should never write files like this, other software
00288   // might.
00289 
00290   if (mdims == 1)
00291     {
00292       mdims = 2;
00293       dv.resize (mdims);
00294       dv(1) = dv(0);
00295       dv(0) = 1;
00296     }
00297 
00298   T m (dv);
00299 
00300   if (! is.read (reinterpret_cast<char *> (m.fortran_vec ()), m.byte_size ()))
00301     return false;
00302 
00303   if (swap)
00304     {
00305       int nel = dv.numel ();
00306       int bytes = nel / m.byte_size();
00307       for (int i = 0; i < nel; i++)
00308         switch (bytes)
00309           {
00310           case 8:
00311             swap_bytes<8> (&m(i));
00312             break;
00313           case 4:
00314             swap_bytes<4> (&m(i));
00315             break;
00316           case 2:
00317             swap_bytes<2> (&m(i));
00318             break;
00319           case 1:
00320           default:
00321             break;
00322           }
00323     }
00324 
00325   this->matrix = m;
00326   return true;
00327 }
00328 
00329 #if defined (HAVE_HDF5)
00330 
00331 template <class T>
00332 bool
00333 octave_base_int_matrix<T>::save_hdf5 (hid_t loc_id, const char *name, bool)
00334 {
00335   hid_t save_type_hid = HDF5_SAVE_TYPE;
00336   bool retval = true;
00337   dim_vector dv = this->dims ();
00338   int empty = save_hdf5_empty (loc_id, name, dv);
00339   if (empty)
00340     return (empty > 0);
00341 
00342   int rank = dv.length ();
00343   hid_t space_hid = -1, data_hid = -1;
00344   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
00345 
00346   // Octave uses column-major, while HDF5 uses row-major ordering
00347   for (int i = 0; i < rank; i++)
00348     hdims[i] = dv (rank-i-1);
00349 
00350   space_hid = H5Screate_simple (rank, hdims, 0);
00351 
00352   if (space_hid < 0) return false;
00353 #if HAVE_HDF5_18
00354   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
00355                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00356 #else
00357   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
00358                         H5P_DEFAULT);
00359 #endif
00360   if (data_hid < 0)
00361     {
00362       H5Sclose (space_hid);
00363       return false;
00364     }
00365 
00366   retval = H5Dwrite (data_hid, save_type_hid, H5S_ALL, H5S_ALL,
00367                      H5P_DEFAULT, this->matrix.data()) >= 0;
00368 
00369   H5Dclose (data_hid);
00370   H5Sclose (space_hid);
00371 
00372   return retval;
00373 }
00374 
00375 template <class T>
00376 bool
00377 octave_base_int_matrix<T>::load_hdf5 (hid_t loc_id, const char *name)
00378 {
00379   hid_t save_type_hid = HDF5_SAVE_TYPE;
00380   bool retval = false;
00381   dim_vector dv;
00382   int empty = load_hdf5_empty (loc_id, name, dv);
00383   if (empty > 0)
00384     this->matrix.resize(dv);
00385   if (empty)
00386       return (empty > 0);
00387 
00388 #if HAVE_HDF5_18
00389   hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
00390 #else
00391   hid_t data_hid = H5Dopen (loc_id, name);
00392 #endif
00393   hid_t space_id = H5Dget_space (data_hid);
00394 
00395   hsize_t rank = H5Sget_simple_extent_ndims (space_id);
00396 
00397   if (rank < 1)
00398     {
00399       H5Sclose (space_id);
00400       H5Dclose (data_hid);
00401       return false;
00402     }
00403 
00404   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
00405   OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
00406 
00407   H5Sget_simple_extent_dims (space_id, hdims, maxdims);
00408 
00409   // Octave uses column-major, while HDF5 uses row-major ordering
00410   if (rank == 1)
00411     {
00412       dv.resize (2);
00413       dv(0) = 1;
00414       dv(1) = hdims[0];
00415     }
00416   else
00417     {
00418       dv.resize (rank);
00419       for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
00420         dv(j) = hdims[i];
00421     }
00422 
00423   T m (dv);
00424   if (H5Dread (data_hid, save_type_hid, H5S_ALL, H5S_ALL,
00425                H5P_DEFAULT, m.fortran_vec()) >= 0)
00426     {
00427       retval = true;
00428       this->matrix = m;
00429     }
00430 
00431   H5Sclose (space_id);
00432   H5Dclose (data_hid);
00433 
00434   return retval;
00435 }
00436 
00437 #endif
00438 
00439 template <class T>
00440 void
00441 octave_base_int_matrix<T>::print_raw (std::ostream& os,
00442                                       bool pr_as_read_syntax) const
00443 {
00444   octave_print_internal (os, this->matrix, pr_as_read_syntax,
00445                          this->current_print_indent_level ());
00446 }
00447 
00448 template <class T>
00449 octave_value
00450 octave_base_int_scalar<T>::convert_to_str_internal (bool, bool, char type) const
00451 {
00452   octave_value retval;
00453 
00454   T tmp = this->scalar;
00455 
00456   typedef typename T::val_type val_type;
00457 
00458   val_type ival = tmp.value ();
00459 
00460   static const bool is_signed = std::numeric_limits<val_type>::is_signed;
00461   static const bool can_be_larger_than_uchar_max
00462     = octave_base_int_helper_traits<val_type>::can_be_larger_than_uchar_max;
00463 
00464   if (octave_base_int_helper<val_type, is_signed,
00465       can_be_larger_than_uchar_max>::char_value_out_of_range (ival))
00466     {
00467       // FIXME -- is there something better we could do?
00468 
00469       ival = 0;
00470 
00471       ::warning ("range error for conversion to character value");
00472     }
00473   else
00474     retval = octave_value (std::string (1, static_cast<char> (ival)), type);
00475 
00476   return retval;
00477 }
00478 
00479 template <class T>
00480 bool
00481 octave_base_int_scalar<T>::save_ascii (std::ostream& os)
00482 {
00483   os << this->scalar << "\n";
00484   return true;
00485 }
00486 
00487 template <class T>
00488 bool
00489 octave_base_int_scalar<T>::load_ascii (std::istream& is)
00490 {
00491   is >> this->scalar;
00492   if (!is)
00493     {
00494       error ("load: failed to load scalar constant");
00495       return false;
00496     }
00497   return true;
00498 }
00499 
00500 template <class T>
00501 bool
00502 octave_base_int_scalar<T>::save_binary (std::ostream& os, bool&)
00503 {
00504   os.write (reinterpret_cast<char *> (&(this->scalar)), this->byte_size());
00505   return true;
00506 }
00507 
00508 template <class T>
00509 bool
00510 octave_base_int_scalar<T>::load_binary (std::istream& is, bool swap,
00511                                         oct_mach_info::float_format)
00512 {
00513   T tmp;
00514   if (! is.read (reinterpret_cast<char *> (&tmp), this->byte_size()))
00515     return false;
00516 
00517   if (swap)
00518     switch (this->byte_size())
00519       {
00520       case 8:
00521         swap_bytes<8> (&tmp);
00522         break;
00523       case 4:
00524         swap_bytes<4> (&tmp);
00525         break;
00526       case 2:
00527         swap_bytes<2> (&tmp);
00528         break;
00529       case 1:
00530       default:
00531         break;
00532       }
00533   this->scalar = tmp;
00534   return true;
00535 }
00536 
00537 #if defined (HAVE_HDF5)
00538 
00539 template <class T>
00540 bool
00541 octave_base_int_scalar<T>::save_hdf5 (hid_t loc_id, const char *name, bool)
00542 {
00543   hid_t save_type_hid = HDF5_SAVE_TYPE;
00544   bool retval = true;
00545   hsize_t dimens[3];
00546   hid_t space_hid = -1, data_hid = -1;
00547 
00548   space_hid = H5Screate_simple (0, dimens, 0);
00549   if (space_hid < 0) return false;
00550 
00551 #if HAVE_HDF5_18
00552   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
00553                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00554 #else
00555   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
00556                         H5P_DEFAULT);
00557 #endif
00558   if (data_hid < 0)
00559     {
00560       H5Sclose (space_hid);
00561       return false;
00562     }
00563 
00564   retval = H5Dwrite (data_hid, save_type_hid, H5S_ALL, H5S_ALL,
00565                      H5P_DEFAULT, &(this->scalar)) >= 0;
00566 
00567   H5Dclose (data_hid);
00568   H5Sclose (space_hid);
00569 
00570   return retval;
00571 }
00572 
00573 template <class T>
00574 bool
00575 octave_base_int_scalar<T>::load_hdf5 (hid_t loc_id, const char *name)
00576 {
00577   hid_t save_type_hid = HDF5_SAVE_TYPE;
00578 #if HAVE_HDF5_18
00579   hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
00580 #else
00581   hid_t data_hid = H5Dopen (loc_id, name);
00582 #endif
00583   hid_t space_id = H5Dget_space (data_hid);
00584 
00585   hsize_t rank = H5Sget_simple_extent_ndims (space_id);
00586 
00587   if (rank != 0)
00588     {
00589       H5Dclose (data_hid);
00590       return false;
00591     }
00592 
00593   T tmp;
00594   if (H5Dread (data_hid, save_type_hid, H5S_ALL, H5S_ALL,
00595                H5P_DEFAULT, &tmp) < 0)
00596     {
00597       H5Dclose (data_hid);
00598       return false;
00599     }
00600 
00601   this->scalar = tmp;
00602 
00603   H5Dclose (data_hid);
00604 
00605   return true;
00606 }
00607 
00608 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines