00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #include <iostream>
00028
00029 #include "lo-ieee.h"
00030 #include "lo-utils.h"
00031
00032 #include "defun.h"
00033 #include "variables.h"
00034 #include "gripes.h"
00035 #include "ops.h"
00036 #include "oct-obj.h"
00037 #include "ov-range.h"
00038 #include "ov-re-mat.h"
00039 #include "ov-scalar.h"
00040 #include "pr-output.h"
00041
00042 #include "byte-swap.h"
00043 #include "ls-ascii-helper.h"
00044 #include "ls-hdf5.h"
00045 #include "ls-utils.h"
00046
00047
00048 bool Vallow_noninteger_range_as_index = false;
00049
00050 DEFINE_OCTAVE_ALLOCATOR (octave_range);
00051
00052 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range", "double");
00053
00054 static octave_base_value *
00055 default_numeric_conversion_function (const octave_base_value& a)
00056 {
00057 CAST_CONV_ARG (const octave_range&);
00058
00059 return new octave_matrix (v.matrix_value ());
00060 }
00061
00062 octave_base_value::type_conv_info
00063 octave_range::numeric_conversion_function (void) const
00064 {
00065 return octave_base_value::type_conv_info (default_numeric_conversion_function,
00066 octave_matrix::static_type_id ());
00067 }
00068
00069 octave_base_value *
00070 octave_range::try_narrowing_conversion (void)
00071 {
00072 octave_base_value *retval = 0;
00073
00074 switch (range.nelem ())
00075 {
00076 case 1:
00077 retval = new octave_scalar (range.base ());
00078 break;
00079
00080 case 0:
00081 retval = new octave_matrix (Matrix (1, 0));
00082 break;
00083
00084 case -2:
00085 retval = new octave_matrix (range.matrix_value ());
00086 break;
00087
00088 default:
00089 break;
00090 }
00091
00092 return retval;
00093 }
00094
00095 octave_value
00096 octave_range::subsref (const std::string& type,
00097 const std::list<octave_value_list>& idx)
00098 {
00099 octave_value retval;
00100
00101 switch (type[0])
00102 {
00103 case '(':
00104 retval = do_index_op (idx.front ());
00105 break;
00106
00107 case '{':
00108 case '.':
00109 {
00110 std::string nm = type_name ();
00111 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
00112 }
00113 break;
00114
00115 default:
00116 panic_impossible ();
00117 }
00118
00119 return retval.next_subsref (type, idx);
00120 }
00121
00122 octave_value
00123 octave_range::do_index_op (const octave_value_list& idx, bool resize_ok)
00124 {
00125 if (idx.length () == 1 && ! resize_ok)
00126 {
00127 octave_value retval;
00128
00129
00130 idx_vector i = idx(0).index_vector ();
00131 if (! error_state)
00132 {
00133 if (i.is_scalar () && i(0) < range.nelem ())
00134 retval = range.elem (i(0));
00135 else
00136 retval = range.index (i);
00137 }
00138
00139 return retval;
00140 }
00141 else
00142 {
00143 octave_value tmp (new octave_matrix (range.matrix_value ()));
00144
00145 return tmp.do_index_op (idx, resize_ok);
00146 }
00147 }
00148
00149 idx_vector
00150 octave_range::index_vector (void) const
00151 {
00152 if (idx_cache)
00153 return *idx_cache;
00154 else
00155 {
00156 if (! Vallow_noninteger_range_as_index
00157 || range.all_elements_are_ints ())
00158 return set_idx_cache (idx_vector (range));
00159 else
00160 {
00161 warning_with_id ("Octave:noninteger-range-as-index",
00162 "non-integer range used as index");
00163
00164 return octave_value (matrix_value ()).round ().index_vector ();
00165 }
00166 }
00167 }
00168
00169 double
00170 octave_range::double_value (bool) const
00171 {
00172 double retval = lo_ieee_nan_value ();
00173
00174 octave_idx_type nel = range.nelem ();
00175
00176 if (nel > 0)
00177 {
00178 gripe_implicit_conversion ("Octave:array-as-scalar",
00179 "range", "real scalar");
00180
00181 retval = range.base ();
00182 }
00183 else
00184 gripe_invalid_conversion ("range", "real scalar");
00185
00186 return retval;
00187 }
00188
00189 float
00190 octave_range::float_value (bool) const
00191 {
00192 float retval = lo_ieee_float_nan_value ();
00193
00194 octave_idx_type nel = range.nelem ();
00195
00196 if (nel > 0)
00197 {
00198 gripe_implicit_conversion ("Octave:array-as-scalar",
00199 "range", "real scalar");
00200
00201 retval = range.base ();
00202 }
00203 else
00204 gripe_invalid_conversion ("range", "real scalar");
00205
00206 return retval;
00207 }
00208
00209 charNDArray
00210 octave_range::char_array_value (bool) const
00211 {
00212 const Matrix matrix = range.matrix_value ();
00213 charNDArray retval (dims ());
00214
00215 octave_idx_type nel = numel ();
00216
00217 for (octave_idx_type i = 0; i < nel; i++)
00218 retval.elem (i) = static_cast<char>(matrix.elem (i));
00219
00220 return retval;
00221 }
00222
00223 octave_value
00224 octave_range::all (int dim) const
00225 {
00226
00227
00228 Matrix m = range.matrix_value ();
00229
00230 return m.all (dim);
00231 }
00232
00233 octave_value
00234 octave_range::any (int dim) const
00235 {
00236
00237
00238 Matrix m = range.matrix_value ();
00239
00240 return m.any (dim);
00241 }
00242
00243 octave_value
00244 octave_range::diag (octave_idx_type k) const
00245 {
00246 return (k == 0
00247 ? octave_value (DiagMatrix (DiagArray2<double> (range.matrix_value ())))
00248 : octave_value (range.diag (k)));
00249 }
00250
00251
00252 bool
00253 octave_range::is_true (void) const
00254 {
00255 bool retval = false;
00256
00257 if (range.nelem () != 0)
00258 {
00259
00260
00261 Matrix m ((range.matrix_value () . all ()) . all ());
00262
00263 retval = (m.rows () == 1 && m.columns () == 1 && m (0, 0) != 0.0);
00264 }
00265
00266 return retval;
00267 }
00268
00269 Complex
00270 octave_range::complex_value (bool) const
00271 {
00272 double tmp = lo_ieee_nan_value ();
00273
00274 Complex retval (tmp, tmp);
00275
00276 octave_idx_type nel = range.nelem ();
00277
00278 if (nel > 0)
00279 {
00280 gripe_implicit_conversion ("Octave:array-as-scalar",
00281 "range", "complex scalar");
00282
00283 retval = range.base ();
00284 }
00285 else
00286 gripe_invalid_conversion ("range", "complex scalar");
00287
00288 return retval;
00289 }
00290
00291 FloatComplex
00292 octave_range::float_complex_value (bool) const
00293 {
00294 float tmp = lo_ieee_float_nan_value ();
00295
00296 FloatComplex retval (tmp, tmp);
00297
00298 octave_idx_type nel = range.nelem ();
00299
00300 if (nel > 0)
00301 {
00302 gripe_implicit_conversion ("Octave:array-as-scalar",
00303 "range", "complex scalar");
00304
00305 retval = range.base ();
00306 }
00307 else
00308 gripe_invalid_conversion ("range", "complex scalar");
00309
00310 return retval;
00311 }
00312
00313 boolNDArray
00314 octave_range::bool_array_value (bool warn) const
00315 {
00316 Matrix m = range.matrix_value ();
00317
00318 if (m.any_element_is_nan ())
00319 gripe_nan_to_logical_conversion ();
00320 else if (warn && m.any_element_not_one_or_zero ())
00321 gripe_logical_conversion ();
00322
00323 return boolNDArray (m);
00324 }
00325
00326 octave_value
00327 octave_range::resize (const dim_vector& dv, bool fill) const
00328 {
00329 NDArray retval = array_value ();
00330 if (fill)
00331 retval.resize (dv, NDArray::resize_fill_value ());
00332 else
00333 retval.resize (dv);
00334 return retval;
00335 }
00336
00337 octave_value
00338 octave_range::convert_to_str_internal (bool pad, bool force, char type) const
00339 {
00340 octave_value tmp (range.matrix_value ());
00341 return tmp.convert_to_str (pad, force, type);
00342 }
00343
00344 void
00345 octave_range::print (std::ostream& os, bool pr_as_read_syntax) const
00346 {
00347 print_raw (os, pr_as_read_syntax);
00348 newline (os);
00349 }
00350
00351 void
00352 octave_range::print_raw (std::ostream& os, bool pr_as_read_syntax) const
00353 {
00354 octave_print_internal (os, range, pr_as_read_syntax,
00355 current_print_indent_level ());
00356 }
00357
00358 bool
00359 octave_range::print_name_tag (std::ostream& os, const std::string& name) const
00360 {
00361 bool retval = false;
00362
00363 octave_idx_type n = range.nelem ();
00364
00365 indent (os);
00366
00367 if (n == 0 || n == 1)
00368 os << name << " = ";
00369 else
00370 {
00371 os << name << " =";
00372 newline (os);
00373 if (! Vcompact_format)
00374 newline (os);
00375
00376 retval = true;
00377 }
00378
00379 return retval;
00380 }
00381
00382
00383
00384 static void
00385 skip_comments (std::istream& is)
00386 {
00387 char c = '\0';
00388 while (is.get (c))
00389 {
00390 if (c == ' ' || c == '\t' || c == '\n')
00391 ;
00392 else
00393 break;
00394 }
00395
00396 skip_until_newline (is, false);
00397 }
00398
00399 bool
00400 octave_range::save_ascii (std::ostream& os)
00401 {
00402 Range r = range_value ();
00403 double base = r.base ();
00404 double limit = r.limit ();
00405 double inc = r.inc ();
00406 octave_idx_type len = r.nelem ();
00407
00408 if (inc != 0)
00409 os << "# base, limit, increment\n";
00410 else
00411 os << "# base, length, increment\n";
00412
00413 octave_write_double (os, base);
00414 os << " ";
00415 if (inc != 0)
00416 octave_write_double (os, limit);
00417 else
00418 os << len;
00419 os << " ";
00420 octave_write_double (os, inc);
00421 os << "\n";
00422
00423 return true;
00424 }
00425
00426 bool
00427 octave_range::load_ascii (std::istream& is)
00428 {
00429
00430 skip_comments (is);
00431
00432 double base, limit, inc;
00433 is >> base >> limit >> inc;
00434
00435 if (!is)
00436 {
00437 error ("load: failed to load range constant");
00438 return false;
00439 }
00440
00441 if (inc != 0)
00442 range = Range (base, limit, inc);
00443 else
00444 range = Range (base, inc, static_cast<octave_idx_type> (limit));
00445
00446 return true;
00447 }
00448
00449 bool
00450 octave_range::save_binary (std::ostream& os, bool& )
00451 {
00452 char tmp = LS_DOUBLE;
00453 os.write (reinterpret_cast<char *> (&tmp), 1);
00454 Range r = range_value ();
00455 double bas = r.base ();
00456 double lim = r.limit ();
00457 double inc = r.inc ();
00458 if (inc == 0)
00459 lim = r.nelem ();
00460
00461 os.write (reinterpret_cast<char *> (&bas), 8);
00462 os.write (reinterpret_cast<char *> (&lim), 8);
00463 os.write (reinterpret_cast<char *> (&inc), 8);
00464
00465 return true;
00466 }
00467
00468 bool
00469 octave_range::load_binary (std::istream& is, bool swap,
00470 oct_mach_info::float_format )
00471 {
00472 char tmp;
00473 if (! is.read (reinterpret_cast<char *> (&tmp), 1))
00474 return false;
00475 double bas, lim, inc;
00476 if (! is.read (reinterpret_cast<char *> (&bas), 8))
00477 return false;
00478 if (swap)
00479 swap_bytes<8> (&bas);
00480 if (! is.read (reinterpret_cast<char *> (&lim), 8))
00481 return false;
00482 if (swap)
00483 swap_bytes<8> (&lim);
00484 if (! is.read (reinterpret_cast<char *> (&inc), 8))
00485 return false;
00486 if (swap)
00487 swap_bytes<8> (&inc);
00488 if (inc != 0)
00489 range = Range (bas, lim, inc);
00490 else
00491 range = Range (bas, inc, static_cast<octave_idx_type> (lim));
00492
00493 return true;
00494 }
00495
00496 #if defined (HAVE_HDF5)
00497
00498
00499
00500
00501
00502
00503
00504 static hid_t
00505 hdf5_make_range_type (hid_t num_type)
00506 {
00507 hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
00508
00509 H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
00510 H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
00511 H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
00512
00513 return type_id;
00514 }
00515
00516 bool
00517 octave_range::save_hdf5 (hid_t loc_id, const char *name,
00518 bool )
00519 {
00520 hsize_t dimens[3];
00521 hid_t space_hid = -1, type_hid = -1, data_hid = -1;
00522 bool retval = true;
00523
00524 space_hid = H5Screate_simple (0, dimens, 0);
00525 if (space_hid < 0) return false;
00526
00527 type_hid = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
00528 if (type_hid < 0)
00529 {
00530 H5Sclose (space_hid);
00531 return false;
00532 }
00533 #if HAVE_HDF5_18
00534 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid,
00535 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00536 #else
00537 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
00538 #endif
00539 if (data_hid < 0)
00540 {
00541 H5Sclose (space_hid);
00542 H5Tclose (type_hid);
00543 return false;
00544 }
00545
00546 Range r = range_value ();
00547 double range_vals[3];
00548 range_vals[0] = r.base ();
00549 range_vals[1] = r.inc () != 0 ? r.limit () : r.nelem ();
00550 range_vals[2] = r.inc ();
00551
00552 if (H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
00553 range_vals) >= 0)
00554 {
00555 octave_idx_type nel = r.nelem ();
00556 retval = hdf5_add_scalar_attr (data_hid, H5T_NATIVE_IDX,
00557 "OCTAVE_RANGE_NELEM", &nel) >= 0;
00558 }
00559 else
00560 retval = false;
00561
00562 H5Dclose (data_hid);
00563 H5Tclose (type_hid);
00564 H5Sclose (space_hid);
00565
00566 return retval;
00567 }
00568
00569 bool
00570 octave_range::load_hdf5 (hid_t loc_id, const char *name)
00571 {
00572 bool retval = false;
00573
00574 #if HAVE_HDF5_18
00575 hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
00576 #else
00577 hid_t data_hid = H5Dopen (loc_id, name);
00578 #endif
00579 hid_t type_hid = H5Dget_type (data_hid);
00580
00581 hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
00582
00583 if (! hdf5_types_compatible (type_hid, range_type))
00584 {
00585 H5Tclose (range_type);
00586 H5Dclose (data_hid);
00587 return false;
00588 }
00589
00590 hid_t space_hid = H5Dget_space (data_hid);
00591 hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
00592
00593 if (rank != 0)
00594 {
00595 H5Tclose (range_type);
00596 H5Sclose (space_hid);
00597 H5Dclose (data_hid);
00598 return false;
00599 }
00600
00601 double rangevals[3];
00602 if (H5Dread (data_hid, range_type, H5S_ALL, H5S_ALL, H5P_DEFAULT,
00603 rangevals) >= 0)
00604 {
00605 retval = true;
00606 octave_idx_type nel;
00607 if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX,
00608 "OCTAVE_RANGE_NELEM", &nel))
00609 range = Range (rangevals[0], rangevals[2], nel);
00610 else
00611 {
00612 if (rangevals[2] != 0)
00613 range = Range (rangevals[0], rangevals[1], rangevals[2]);
00614 else
00615 range = Range (rangevals[0], rangevals[2],
00616 static_cast<octave_idx_type> (rangevals[1]));
00617 }
00618 }
00619
00620 H5Tclose (range_type);
00621 H5Sclose (space_hid);
00622 H5Dclose (data_hid);
00623
00624 return retval;
00625 }
00626
00627 #endif
00628
00629 mxArray *
00630 octave_range::as_mxArray (void) const
00631 {
00632 mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
00633
00634 double *pr = static_cast<double *> (retval->get_data ());
00635
00636 mwSize nel = numel ();
00637
00638 Matrix m = matrix_value ();
00639
00640 const double *p = m.data ();
00641
00642 for (mwSize i = 0; i < nel; i++)
00643 pr[i] = p[i];
00644
00645 return retval;
00646 }
00647
00648 DEFUN (allow_noninteger_range_as_index, args, nargout,
00649 "-*- texinfo -*-\n\
00650 @deftypefn {Built-in Function} {@var{val} =} allow_noninteger_range_as_index ()\n\
00651 @deftypefnx {Built-in Function} {@var{old_val} =} allow_noninteger_range_as_index (@var{new_val})\n\
00652 @deftypefnx {Built-in Function} {} allow_noninteger_range_as_index (@var{new_val}, \"local\")\n\
00653 Query or set the internal variable that controls whether non-integer\n\
00654 ranges are allowed as indices. This might be useful for @sc{matlab}\n\
00655 compatibility; however, it is still not entirely compatible because\n\
00656 @sc{matlab} treats the range expression differently in different contexts.\n\
00657 \n\
00658 When called from inside a function with the \"local\" option, the variable is\n\
00659 changed locally for the function and any subroutines it calls. The original\n\
00660 variable value is restored when exiting the function.\n\
00661 @end deftypefn")
00662 {
00663 return SET_INTERNAL_VARIABLE (allow_noninteger_range_as_index);
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684