src/ov-range.cc
author Benjamin Lindner <lindnerb@users.sourceforge.net>
Wed Mar 18 15:23:14 2009 +0100 (2009-03-18)
changeset 7685 34b75a47e712
parent 7017 a1dbe9d80eee
permissions -rw-r--r--
fix leaving stray '\r' in stream when reading from CRLF data file
* * *
fix CRLF issues with text-mode reading in windows when loading ascii data
     1 /*
     2 
     3 Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2006,
     4               2007 John W. Eaton
     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 <iostream>
    29 
    30 #include "lo-ieee.h"
    31 #include "lo-utils.h"
    32 
    33 #include "gripes.h"
    34 #include "ops.h"
    35 #include "oct-obj.h"
    36 #include "ov-range.h"
    37 #include "ov-re-mat.h"
    38 #include "ov-scalar.h"
    39 #include "pr-output.h"
    40 
    41 #include "byte-swap.h"
    42 #include "ls-hdf5.h"
    43 #include "ls-utils.h"
    44 #include "ls-ascii-helper.h"
    45 
    46 DEFINE_OCTAVE_ALLOCATOR (octave_range);
    47 
    48 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range", "double");
    49 
    50 static octave_base_value *
    51 default_numeric_conversion_function (const octave_base_value& a)
    52 {
    53   CAST_CONV_ARG (const octave_range&);
    54 
    55   return new octave_matrix (v.matrix_value ());
    56 }
    57 
    58 octave_base_value::type_conv_fcn
    59 octave_range::numeric_conversion_function (void) const
    60 {
    61   return default_numeric_conversion_function;
    62 }
    63 
    64 octave_base_value *
    65 octave_range::try_narrowing_conversion (void)
    66 {
    67   octave_base_value *retval = 0;
    68 
    69   switch (range.nelem ())
    70     {
    71     case 1:
    72       retval = new octave_scalar (range.base ());
    73       break;
    74 
    75     case 0:
    76       retval = new octave_matrix (Matrix (1, 0));
    77       break;
    78 
    79     default:
    80       break;
    81     }
    82 
    83   return retval;
    84 }
    85 
    86 octave_value
    87 octave_range::subsref (const std::string& type,
    88 		       const std::list<octave_value_list>& idx)
    89 {
    90   octave_value retval;
    91 
    92   switch (type[0])
    93     {
    94     case '(':
    95       retval = do_index_op (idx.front ());
    96       break;
    97 
    98     case '{':
    99     case '.':
   100       {
   101 	std::string nm = type_name ();
   102 	error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
   103       }
   104       break;
   105 
   106     default:
   107       panic_impossible ();
   108     }
   109 
   110   return retval.next_subsref (type, idx);
   111 }
   112 
   113 octave_value
   114 octave_range::do_index_op (const octave_value_list& idx, bool resize_ok)
   115 {
   116   // FIXME -- this doesn't solve the problem of
   117   //
   118   //   a = 1:5; a(1, 1, 1)
   119   //
   120   // and similar constructions.  Hmm...
   121 
   122   // FIXME -- using this constructor avoids possibly narrowing
   123   // the range to a scalar value.  Need a better solution to this
   124   // problem.
   125 
   126   octave_value tmp (new octave_matrix (range.matrix_value ()));
   127 
   128   return tmp.do_index_op (idx, resize_ok);
   129 }
   130 
   131 double
   132 octave_range::double_value (bool) const
   133 {
   134   double retval = lo_ieee_nan_value ();
   135 
   136   octave_idx_type nel = range.nelem ();
   137 
   138   if (nel > 0)
   139     {
   140       gripe_implicit_conversion ("Octave:array-as-scalar",
   141 				 "range", "real scalar");
   142 
   143       retval = range.base ();
   144     }
   145   else
   146     gripe_invalid_conversion ("range", "real scalar");
   147 
   148   return retval;
   149 }
   150 
   151 octave_value
   152 octave_range::all (int dim) const
   153 {
   154   // FIXME -- this is a potential waste of memory.
   155 
   156   Matrix m = range.matrix_value ();
   157 
   158   return m.all (dim);
   159 }
   160 
   161 octave_value
   162 octave_range::any (int dim) const
   163 {
   164   // FIXME -- this is a potential waste of memory.
   165 
   166   Matrix m = range.matrix_value ();
   167 
   168   return m.any (dim);
   169 }
   170 
   171 bool
   172 octave_range::is_true (void) const
   173 {
   174   bool retval = false;
   175 
   176   if (range.nelem () != 0)
   177     {
   178       // FIXME -- this is a potential waste of memory.
   179 
   180       Matrix m ((range.matrix_value () . all ()) . all ());
   181 
   182       retval = (m.rows () == 1 && m.columns () == 1 && m (0, 0) != 0.0);
   183     }
   184 
   185   return retval;
   186 }
   187 
   188 Complex
   189 octave_range::complex_value (bool) const
   190 {
   191   double tmp = lo_ieee_nan_value ();
   192 
   193   Complex retval (tmp, tmp);
   194 
   195   octave_idx_type nel = range.nelem ();
   196 
   197   if (nel > 0)
   198     {
   199       gripe_implicit_conversion ("Octave:array-as-scalar",
   200 				 "range", "complex scalar");
   201 
   202       retval = range.base ();
   203     }
   204   else
   205     gripe_invalid_conversion ("range", "complex scalar");
   206 
   207   return retval;
   208 }
   209 
   210 octave_value 
   211 octave_range::resize (const dim_vector& dv, bool fill) const
   212 { 
   213   NDArray retval = array_value (); 
   214   if (fill)
   215     retval.resize (dv, NDArray::resize_fill_value());
   216   else
   217     retval.resize (dv); 
   218   return retval; 
   219 }
   220 
   221 octave_value
   222 octave_range::convert_to_str_internal (bool pad, bool force, char type) const
   223 {
   224   octave_value tmp (range.matrix_value ());
   225   return tmp.convert_to_str (pad, force, type);
   226 }
   227 
   228 void
   229 octave_range::print (std::ostream& os, bool pr_as_read_syntax) const
   230 {
   231   print_raw (os, pr_as_read_syntax);
   232   newline (os);
   233 }
   234 
   235 void
   236 octave_range::print_raw (std::ostream& os, bool pr_as_read_syntax) const
   237 {
   238   octave_print_internal (os, range, pr_as_read_syntax,
   239 			 current_print_indent_level ());
   240 }
   241 
   242 bool
   243 octave_range::print_name_tag (std::ostream& os, const std::string& name) const
   244 {
   245   bool retval = false;
   246 
   247   octave_idx_type n = range.nelem ();
   248 
   249   indent (os);
   250 
   251   if (n == 0 || n == 1)
   252     os << name << " = ";
   253   else
   254     {
   255       os << name << " =";
   256       newline (os);
   257       newline (os);
   258       retval = true;
   259     }
   260     
   261   return retval;
   262 }
   263 
   264 // Skip white space and comments on stream IS.
   265 
   266 static void
   267 skip_comments (std::istream& is)
   268 {
   269   char c = '\0';
   270   while (is.get (c))
   271     {
   272       if (c == ' ' || c == '\t' || c == '\n')
   273 	; // Skip whitespace on way to beginning of next line.
   274       else
   275 	break;
   276     }
   277 
   278   // Skip to beginning of next line, ignoring everything.
   279   skip_until_newline (is, false);
   280   
   281 }
   282 
   283 bool 
   284 octave_range::save_ascii (std::ostream& os)
   285 {
   286   Range r = range_value ();
   287   double base = r.base ();
   288   double limit = r.limit ();
   289   double inc = r.inc ();
   290 
   291   os << "# base, limit, increment\n";
   292   octave_write_double (os, base);
   293   os << " ";
   294   octave_write_double (os, limit);
   295   os << " ";
   296   octave_write_double (os, inc);
   297   os << "\n";
   298 
   299   return true;
   300 }
   301 
   302 bool 
   303 octave_range::load_ascii (std::istream& is)
   304 {
   305   // # base, limit, range comment added by save ().
   306   skip_comments (is);
   307 
   308   is >> range;
   309 
   310   if (!is)
   311     {
   312       error ("load: failed to load range constant");
   313       return false;
   314     }
   315 
   316   return true;
   317 }
   318 
   319 bool 
   320 octave_range::save_binary (std::ostream& os, bool& /* save_as_floats */)
   321 {
   322   char tmp = LS_DOUBLE;
   323   os.write (reinterpret_cast<char *> (&tmp), 1);
   324   Range r = range_value ();
   325   double bas = r.base ();
   326   double lim = r.limit ();
   327   double inc = r.inc ();
   328   os.write (reinterpret_cast<char *> (&bas), 8);
   329   os.write (reinterpret_cast<char *> (&lim), 8);
   330   os.write (reinterpret_cast<char *> (&inc), 8);
   331 
   332   return true;
   333 }
   334 
   335 bool 
   336 octave_range::load_binary (std::istream& is, bool swap,
   337 			   oct_mach_info::float_format /* fmt */)
   338 {
   339   char tmp;
   340   if (! is.read (reinterpret_cast<char *> (&tmp), 1))
   341     return false;
   342   double bas, lim, inc;
   343   if (! is.read (reinterpret_cast<char *> (&bas), 8))
   344     return false;
   345   if (swap)
   346     swap_bytes<8> (&bas);
   347   if (! is.read (reinterpret_cast<char *> (&lim), 8))
   348     return false;
   349   if (swap)
   350     swap_bytes<8> (&lim);
   351   if (! is.read (reinterpret_cast<char *> (&inc), 8))
   352     return false;
   353   if (swap)
   354     swap_bytes<8> (&inc);
   355   Range r (bas, lim, inc);
   356   range = r;
   357   return true;
   358 }
   359 
   360 #if defined (HAVE_HDF5)
   361 
   362 // The following subroutines creates an HDF5 representation of the way
   363 // we will store Octave range types (triplets of floating-point numbers). 
   364 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g. 
   365 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary 
   366 // conversions are handled automatically by HDF5.
   367 
   368 static hid_t
   369 hdf5_make_range_type (hid_t num_type)
   370 {
   371   hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
   372 
   373   H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
   374   H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
   375   H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
   376 
   377   return type_id;
   378 }
   379 
   380 bool
   381 octave_range::save_hdf5 (hid_t loc_id, const char *name,
   382 			 bool /* save_as_floats */)
   383 {
   384   hsize_t dimens[3];
   385   hid_t space_hid = -1, type_hid = -1, data_hid = -1;
   386   bool retval = true;
   387 
   388   space_hid = H5Screate_simple (0, dimens, 0);
   389   if (space_hid < 0) return false;
   390 
   391   type_hid = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
   392   if (type_hid < 0) 
   393     {
   394       H5Sclose (space_hid);
   395       return false;
   396     }
   397 
   398   data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
   399   if (data_hid < 0) 
   400     {
   401       H5Sclose (space_hid);
   402       H5Tclose (type_hid);
   403       return false;
   404     }
   405   
   406   Range r = range_value ();
   407   double range_vals[3];
   408   range_vals[0] = r.base ();
   409   range_vals[1] = r.limit ();
   410   range_vals[2] = r.inc ();
   411 
   412   retval = H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
   413 		     range_vals) >= 0;
   414 
   415   H5Dclose (data_hid);
   416   H5Tclose (type_hid);
   417   H5Sclose (space_hid);
   418 
   419   return retval;
   420 }
   421 
   422 bool 
   423 octave_range::load_hdf5 (hid_t loc_id, const char *name,
   424 			 bool /* have_h5giterate_bug */)
   425 {
   426   bool retval = false;
   427 
   428   hid_t data_hid = H5Dopen (loc_id, name);
   429   hid_t type_hid = H5Dget_type (data_hid);
   430 
   431   hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
   432 
   433   if (! hdf5_types_compatible (type_hid, range_type))
   434     {
   435       H5Tclose (range_type);
   436       H5Dclose (data_hid);
   437       return false;
   438     }
   439 
   440   hid_t space_hid = H5Dget_space (data_hid);
   441   hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
   442 
   443   if (rank != 0)
   444     {
   445       H5Tclose (range_type);
   446       H5Sclose (space_hid);
   447       H5Dclose (data_hid);
   448       return false;
   449     }
   450 
   451   double rangevals[3];
   452   if (H5Dread (data_hid, range_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, 
   453 	       rangevals) >= 0)
   454     {
   455       retval = true;
   456       Range r (rangevals[0], rangevals[1], rangevals[2]);
   457       range = r;
   458     }
   459 
   460   H5Tclose (range_type);
   461   H5Sclose (space_hid);
   462   H5Dclose (data_hid);
   463 
   464   return retval;
   465 }
   466 
   467 #endif
   468 
   469 mxArray *
   470 octave_range::as_mxArray (void) const
   471 {
   472   mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
   473 
   474   double *pr = static_cast<double *> (retval->get_data ());
   475 
   476   mwSize nel = numel ();
   477 
   478   Matrix m = matrix_value ();
   479 
   480   const double *p = m.data ();
   481 
   482   for (mwSize i = 0; i < nel; i++)
   483     pr[i] = p[i];
   484 
   485   return retval;
   486 }
   487 
   488 /*
   489 ;;; Local Variables: ***
   490 ;;; mode: C++ ***
   491 ;;; End: ***
   492 */