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