GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-range.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <istream>
31 #include <ostream>
32 #include <sstream>
33 
34 #include "dNDArray.h"
35 #include "fNDArray.h"
36 #include "int8NDArray.h"
37 #include "int16NDArray.h"
38 #include "int32NDArray.h"
39 #include "int64NDArray.h"
40 #include "uint8NDArray.h"
41 #include "uint16NDArray.h"
42 #include "uint32NDArray.h"
43 #include "uint64NDArray.h"
44 
45 #include "lo-ieee.h"
46 #include "lo-utils.h"
47 
48 #include "defun.h"
49 #include "variables.h"
50 #include "errwarn.h"
51 #include "mxarray.h"
52 #include "mx-type-traits.h"
53 #include "ops.h"
54 #include "ovl.h"
55 #include "oct-hdf5.h"
56 #include "ov-inline.h"
57 #include "ov-range-traits.h"
58 #include "ov-range.h"
59 #include "ov-re-mat.h"
60 #include "ov-scalar.h"
61 #include "pr-output.h"
62 
63 #include "byte-swap.h"
64 #include "ls-ascii-helper.h"
65 #include "ls-hdf5.h"
66 #include "ls-utils.h"
67 
68 #if defined (HAVE_HDF5)
69 
70 template <>
72 
73 // For now, enable only ov_range<double>.
74 
75 #else
76 
77 template <>
79 
80 // For now, enable only ov_range<double>.
81 
82 #endif
83 
85  "double_range", "double");
86 
87 // For now, enable only ov_range<double>.
88 
89 template <typename T>
90 static octave_base_value *
91 default_numeric_conversion_function (const octave_base_value& a)
92 {
93  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
94 
95  const ov_range<T>& v = dynamic_cast<const ov_range<T>&> (a);
96 
97  return new ov_mx_type (v.raw_array_value ());
98 }
99 
100 template <typename T>
103 {
104  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
105 
107  (default_numeric_conversion_function<T>, ov_mx_type::static_type_id ());
108 }
109 
110 template <typename T>
113 {
114  octave_base_value *retval = nullptr;
115 
116  switch (numel ())
117  {
118  case 1:
119  retval = new typename octave_value_range_traits<T>::scalar_type (m_range.elem (0));
120  break;
121 
122  case 0:
123  {
124  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
125  typename ov_mx_type::object_type m (dim_vector (1, 0));
126  retval = new ov_mx_type (m);
127  }
128  break;
129 
130  case -2:
131  // FIXME: is this case possible now? It would have to be due to
132  // conversion from Range to range<double>, but even in that case,
133  // is the invalid numel value preserved?
134  retval = new typename octave_value_range_traits<T>::matrix_type (raw_array_value ());
135  break;
136 
137  default:
138  break;
139  }
140 
141  return retval;
142 }
143 
144 template <typename T>
146 ov_range<T>::subsref (const std::string& type,
147  const std::list<octave_value_list>& idx)
148 {
149  octave_value retval;
150 
151  switch (type[0])
152  {
153  case '(':
154  retval = do_index_op (idx.front ());
155  break;
156 
157  case '{':
158  case '.':
159  {
160  std::string nm = type_name ();
161  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
162  }
163  break;
164 
165  default:
166  panic_impossible ();
167  }
168 
169  return retval.next_subsref (type, idx);
170 }
171 
172 template <typename T>
175  bool resize_ok)
176 {
177  if (idx.length () == 1 && ! resize_ok)
178  {
179  octave_value retval;
180 
181  // The range can handle a single subscript.
182 
183  try
184  {
185  octave::idx_vector i = idx(0).index_vector ();
186 
187  if (i.is_scalar () && i(0) < numel ())
188  retval = m_range.elem (i(0));
189  else
190  retval = m_range.index (i);
191  }
192  catch (octave::index_exception& ie)
193  {
194  // More info may be added later before displaying error.
195 
196  ie.set_pos_if_unset (1, 1);
197  throw;
198  }
199 
200  return retval;
201  }
202  else
203  {
204  octave_value tmp (new typename octave_value_range_traits<T>::matrix_type (raw_array_value ()));
205 
206  return tmp.index_op (idx, resize_ok);
207  }
208 }
209 
210 template <typename T>
212 ov_range<T>::index_vector (bool require_integers) const
213 {
214  octave_value tmp (raw_array_value ());
215  return tmp.index_vector (require_integers);
216 }
217 
218 template <typename T>
219 double
221 {
222  octave_idx_type nel = numel ();
223 
224  if (nel == 0)
225  err_invalid_conversion ("range", "real scalar");
226 
227  warn_implicit_conversion ("Octave:array-to-scalar",
228  "range", "real scalar");
229 
230  return m_range.base ();
231 }
232 
233 template <typename T>
234 float
236 {
237  octave_idx_type nel = numel ();
238 
239  if (nel == 0)
240  err_invalid_conversion ("range", "real scalar");
241 
242  warn_implicit_conversion ("Octave:array-to-scalar",
243  "range", "real scalar");
244 
245  return m_range.base ();
246 }
247 
248 template <typename T>
251 {
252  const Array<T> matrix = raw_array_value ();
253  charNDArray retval (dims ());
254 
255  octave_idx_type nel = numel ();
256 
257  for (octave_idx_type i = 0; i < nel; i++)
258  retval.elem (i) = static_cast<char> (matrix.elem (i));
259 
260  return retval;
261 }
262 
263 template <typename T>
264 Complex
266 {
267  octave_idx_type nel = numel ();
268 
269  if (nel == 0)
270  err_invalid_conversion ("range", "complex scalar");
271 
272  warn_implicit_conversion ("Octave:array-to-scalar",
273  "range", "complex scalar");
274 
275  return Complex (m_range.base (), 0);
276 }
277 
278 template <typename T>
281 {
282  float tmp = lo_ieee_float_nan_value ();
283 
284  FloatComplex retval (tmp, tmp);
285 
286  octave_idx_type nel = numel ();
287 
288  if (nel == 0)
289  err_invalid_conversion ("range", "complex scalar");
290 
291  warn_implicit_conversion ("Octave:array-to-scalar",
292  "range", "complex scalar");
293 
294  retval = m_range.base ();
295 
296  return retval;
297 }
298 
299 template <typename T>
302 {
303  Array<T> matrix = raw_array_value ();
304 
305  if (warn && ! matrix.test_all (octave::is_one_or_zero<T>))
307 
308  return boolNDArray (matrix);
309 }
310 
311 template <typename T>
313 ov_range<T>::resize (const dim_vector& dv, bool fill) const
314 {
315  Array<T> retval = raw_array_value ();
316  if (fill)
317  retval.resize (dv, 0);
318  else
319  retval.resize (dv);
320  return retval;
321 }
322 
323 template <typename T>
324 octave::range<double>
326 {
327  err_wrong_type_arg ("ov_range<T>::range_value()", type_name ());
328 }
329 
330 // For now, enable only ov_range<double>.
331 
332 template <typename T>
334 ov_range<T>::convert_to_str_internal (bool pad, bool force, char type) const
335 {
336  octave_value tmp (raw_array_value ());
337  return tmp.convert_to_str (pad, force, type);
338 }
339 
340 // FIXME: could most of these fucntions preserve range type now?
341 
342 template <typename T>
345 {
346  return NDArray (raw_array_value ());
347 }
348 
349 template <typename T>
352 {
353  return FloatMatrix (raw_array_value ());
354 }
355 
356 template <typename T>
359 {
360  return int8NDArray (raw_array_value ());
361 }
362 
363 template <typename T>
366 {
367  return int16NDArray (raw_array_value ());
368 }
369 
370 template <typename T>
373 {
374  return int32NDArray (raw_array_value ());
375 }
376 
377 template <typename T>
380 {
381  return int64NDArray (raw_array_value ());
382 }
383 
384 template <typename T>
387 {
388  return uint8NDArray (raw_array_value ());
389 }
390 
391 template <typename T>
394 {
395  return uint16NDArray (raw_array_value ());
396 }
397 
398 template <typename T>
401 {
402  return uint32NDArray (raw_array_value ());
403 }
404 
405 template <typename T>
408 {
409  return uint64NDArray (raw_array_value ());
410 }
411 
412 template <typename T>
413 void
414 ov_range<T>::print (std::ostream& os, bool pr_as_read_syntax)
415 {
416  print_raw (os, pr_as_read_syntax);
417  newline (os);
418 }
419 
420 template <typename T>
421 void
422 ov_range<T>::print_raw (std::ostream& os, bool pr_as_read_syntax) const
423 {
424  // FIXME: this is a potential waste of memory.
425 
426  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
427  typename ov_mx_type::object_type tmp (raw_array_value ());
428 
429  octave_print_internal (os, tmp, pr_as_read_syntax,
430  current_print_indent_level ());
431 }
432 
433 template <typename T>
434 bool
435 ov_range<T>::print_name_tag (std::ostream& os, const std::string& name) const
436 {
437  bool retval = false;
438 
439  octave_idx_type n = numel ();
440 
441  indent (os);
442 
443  if (n == 0 || n == 1)
444  os << name << " = ";
445  else
446  {
447  os << name << " =";
448  newline (os);
449  if (! Vcompact_format)
450  newline (os);
451 
452  retval = true;
453  }
454 
455  return retval;
456 }
457 
458 template <typename T>
459 void
460 ov_range<T>::short_disp (std::ostream& os) const
461 {
463 
464  if (len == 0)
465  os << "[]";
466  else
467  {
468  os << m_range.base () << ':';
469 
470  if (len > 1)
471  {
472  if (m_range.increment () != T (1))
473  os << m_range.increment () << ':';
474 
475  os << m_range.limit ();
476  }
477  }
478 }
479 
480 // Skip white space and comments on stream IS.
481 
482 static void
483 skip_comments (std::istream& is)
484 {
485  char c = '\0';
486  while (is.get (c))
487  {
488  if (c == ' ' || c == '\t' || c == '\n')
489  ; // Skip whitespace on way to beginning of next line.
490  else
491  break;
492  }
493 
494  octave::skip_until_newline (is, false);
495 }
496 
497 template <typename T>
500 {
501  return make_format (m_range);
502 }
503 
504 template <typename T>
505 std::string
508 {
509  std::ostringstream buf;
510  octave_print_internal (buf, fmt, m_range.elem (j));
511  return buf.str ();
512 }
513 
514 template <typename T>
515 bool
516 xsave_ascii (std::ostream& os, const octave::range<T>& r,
517  const bool with_reverse)
518 {
519  T base = r.base ();
520  T limit = r.limit ();
521  T inc = r.increment ();
522  bool rev = r.reverse ();
523  octave_idx_type len = r.numel ();
524 
525  if (inc != T (0))
526  os << "# base, limit, increment";
527  else
528  os << "# base, length, increment";
529 
530  if (with_reverse)
531  os << ", reverse\n";
532  else
533  os << "\n";
534 
535  octave::write_value<T> (os, base);
536  os << ' ';
537  if (inc != T (0))
538  octave::write_value<T> (os, limit);
539  else
540  os << len;
541  os << ' ';
542  octave::write_value<T> (os, inc);
543  if (with_reverse)
544  os << ' ' << rev;
545  os << "\n";
546 
547  return true;
548 }
549 
550 template <typename T>
551 bool
552 ov_range<T>::save_ascii (std::ostream& os)
553 {
554  return xsave_ascii (os, m_range, false);
555 }
556 
557 // specialize for saving with "reverse" flag
558 
559 // For now, enable only ov_range<double>.
560 
561 template <typename T>
562 bool
563 xload_ascii (std::istream& is, octave::range<T>& r, const bool with_reverse)
564 {
565  // # base, limit, range comment added by save ().
566  skip_comments (is);
567 
568  T base, limit, inc;
569  bool rev = false;
570  is >> base >> limit >> inc;
571 
572  if (with_reverse)
573  is >> rev;
574 
575  if (! is)
576  error ("load: failed to load range constant");
577 
578  r = octave::range<T> (base, inc, limit, rev);
579 
580  return true;
581 }
582 
583 template <typename T>
584 bool
585 ov_range<T>::load_ascii (std::istream& is)
586 {
587  return xload_ascii (is, m_range, false);
588 }
589 
590 // specialize for loading with "reverse" flag
591 
592 // For now, enable only ov_range<double>.
593 
594 /*
595 %!test
596 %! a = b = 1:4;
597 %! sv_file = [tempname(), ".sav"];
598 %! unwind_protect
599 %! save (sv_file, "a", "-text");
600 %! clear a;
601 %! load (sv_file);
602 %! assert (a, b);
603 %! unwind_protect_cleanup
604 %! unlink (sv_file);
605 %! end_unwind_protect
606 
607 %!test
608 %! a = b = uint8(5):-1:0;
609 %! sv_file = [tempname(), ".sav"];
610 %! unwind_protect
611 %! save (sv_file, "a", "-text");
612 %! clear a;
613 %! load (sv_file);
614 %! assert (a, b);
615 %! unwind_protect_cleanup
616 %! unlink (sv_file);
617 %! end_unwind_protect
618 */
619 
620 template <typename T>
621 bool
622 xsave_binary (std::ostream& os, bool /* save_as_floats */,
623  const octave::range<T>& r, const bool with_reverse)
624 {
625  // FIXME: Not always double!
626 
627  char tmp = LS_DOUBLE;
628  os.write (reinterpret_cast<char *> (&tmp), 1);
629  T bas = r.base ();
630  T lim = r.limit ();
631  T inc = r.increment ();
632  if (inc == T (0))
633  lim = r.numel ();
634 
635  os.write (reinterpret_cast<char *> (&bas), sizeof (T));
636  os.write (reinterpret_cast<char *> (&lim), sizeof (T));
637  os.write (reinterpret_cast<char *> (&inc), sizeof (T));
638  if (with_reverse)
639  {
640  bool rev = r.reverse ();
641  os.write (reinterpret_cast<char *> (&rev), sizeof (bool));
642  }
643 
644  return true;
645 }
646 
647 template <typename T>
648 bool
649 ov_range<T>::save_binary (std::ostream& os, bool save_as_floats)
650 {
651  return xsave_binary (os, save_as_floats, m_range, false);
652 }
653 
654 // For now, enable only ov_range<double>.
655 
656 template <typename T>
657 bool
658 xload_binary (std::istream& is, bool swap,
660  octave::range<T>& r, const bool with_reverse)
661 {
662  // FIXME: Not always double!
663 
664  char tmp;
665  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
666  return false;
667  T bas, lim, inc;
668  if (! is.read (reinterpret_cast<char *> (&bas), sizeof (T)))
669  return false;
670  if (swap)
671  swap_bytes<sizeof (T)> (&bas);
672  if (! is.read (reinterpret_cast<char *> (&lim), sizeof (T)))
673  return false;
674  if (swap)
675  swap_bytes<sizeof (T)> (&lim);
676  if (! is.read (reinterpret_cast<char *> (&inc), sizeof (T)))
677  return false;
678  if (swap)
679  swap_bytes<sizeof (T)> (&inc);
680  bool rev = false;
681  if (with_reverse)
682  {
683  if (! is.read (reinterpret_cast<char *> (&rev), sizeof (bool)))
684  return false;
685  if (swap)
686  swap_bytes<sizeof (bool)> (&rev);
687  }
688 
689  r = octave::range<T> (bas, inc, lim, rev);
690 
691  return true;
692 }
693 
694 template <typename T>
695 bool
696 ov_range<T>::load_binary (std::istream& is, bool swap,
698 {
699  return xload_binary (is, swap, fmt, m_range, false);
700 }
701 
702 // For now, enable only ov_range<double>.
703 
704 /*
705 %!test
706 %! a = b = 1:4;
707 %! sv_file = [tempname(), ".dat"];
708 %! unwind_protect
709 %! save (sv_file, "a", "-binary");
710 %! clear a;
711 %! load (sv_file);
712 %! assert (a, b);
713 %! unwind_protect_cleanup
714 %! unlink (sv_file);
715 %! end_unwind_protect
716 
717 %!test
718 %! a = b = uint8(5):-1:0;
719 %! sv_file = [tempname(), ".dat"];
720 %! unwind_protect
721 %! save (sv_file, "a", "-binary");
722 %! clear a;
723 %! load (sv_file);
724 %! assert (a, b);
725 %! unwind_protect_cleanup
726 %! unlink (sv_file);
727 %! end_unwind_protect
728 */
729 
730 #if defined (HAVE_HDF5)
731 
732 // The following subroutines creates an HDF5 representation of the way
733 // we will store Octave range types (triplets of floating-point numbers).
734 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g.
735 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary
736 // conversions are handled automatically by HDF5.
737 
738 template <typename T>
739 static hid_t
740 hdf5_make_range_type (hid_t num_type)
741 {
742  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (T) * 3);
743 
744  H5Tinsert (type_id, "base", 0 * sizeof (T), num_type);
745  H5Tinsert (type_id, "limit", 1 * sizeof (T), num_type);
746  H5Tinsert (type_id, "increment", 2 * sizeof (T), num_type);
747 
748  return type_id;
749 }
750 
751 template <typename T>
752 static hid_t
753 hdf5_make_range_rev_type (hid_t num_type)
754 {
755  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (T) * 4);
756 
757  H5Tinsert (type_id, "base", 0 * sizeof (T), num_type);
758  H5Tinsert (type_id, "limit", 1 * sizeof (T), num_type);
759  H5Tinsert (type_id, "increment", 2 * sizeof (T), num_type);
760  // FIXME: Storing "reverse" with the same width is inefficient.
761  H5Tinsert (type_id, "reverse", 3 * sizeof (T), num_type);
762 
763  return type_id;
764 }
765 
766 template <typename T>
767 bool
768 xsave_hdf5 (octave_hdf5_id loc_id, const char *name,
769  bool /* save_as_floats */, const octave::range<T>& r,
770  const octave_hdf5_id h5_save_type, const bool with_reverse)
771 {
772  bool retval = false;
773 
774  hsize_t dimens[3] = {0};
775  hid_t space_hid, type_hid, data_hid;
776  space_hid = type_hid = data_hid = -1;
777 
778  space_hid = H5Screate_simple (0, dimens, nullptr);
779  if (space_hid < 0) return false;
780 
781  type_hid = with_reverse
782  ? hdf5_make_range_rev_type<T> (h5_save_type)
783  : hdf5_make_range_type<T> (h5_save_type);
784  if (type_hid < 0)
785  {
786  H5Sclose (space_hid);
787  return false;
788  }
789 # if defined (HAVE_HDF5_18)
790  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid,
793 # else
794  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, octave_H5P_DEFAULT);
795 # endif
796  if (data_hid < 0)
797  {
798  H5Sclose (space_hid);
799  H5Tclose (type_hid);
800  return false;
801  }
802 
803  T range_vals[4];
804  range_vals[0] = r.base ();
805  if (r.increment () != T (0))
806  range_vals[1] = r.limit ();
807  else
808  range_vals[1] = r.numel ();
809  range_vals[2] = r.increment ();
810  range_vals[3] = r.reverse ();
811 
812  if (H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
813  octave_H5P_DEFAULT, range_vals)
814  >= 0)
815  {
816  octave_idx_type nel = r.numel ();
817  retval = hdf5_add_scalar_attr (data_hid, H5T_NATIVE_IDX,
818  "OCTAVE_RANGE_NELEM", &nel) >= 0;
819  }
820  else
821  retval = false;
822 
823  H5Dclose (data_hid);
824  H5Tclose (type_hid);
825  H5Sclose (space_hid);
826 
827  return retval;
828 }
829 
830 #endif
831 
832 template <typename T>
833 bool
834 ov_range<T>::save_hdf5 (octave_hdf5_id loc_id, const char *name,
835  bool save_as_floats)
836 {
837 #if defined (HAVE_HDF5)
838  return xsave_hdf5 (loc_id, name, save_as_floats, m_range, hdf5_save_type,
839  false);
840 #else
841  octave_unused_parameter (loc_id);
842  octave_unused_parameter (name);
843  octave_unused_parameter (save_as_floats);
844 
845  warn_save ("hdf5");
846 
847  return false;
848 #endif
849 }
850 
851 // For now, enable only ov_range<double>.
852 
853 #if defined (HAVE_HDF5)
854 
855 template <typename T>
856 bool
857 xload_hdf5 (octave_hdf5_id loc_id, const char *name, octave::range<T>& r,
858  const octave_hdf5_id h5_save_type, const bool with_reverse)
859 {
860  bool retval = false;
861 
862 # if defined (HAVE_HDF5_18)
863  hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
864 # else
865  hid_t data_hid = H5Dopen (loc_id, name);
866 # endif
867  hid_t type_hid = H5Dget_type (data_hid);
868 
869  hid_t range_type = with_reverse
870  ? hdf5_make_range_rev_type<T> (h5_save_type)
871  : hdf5_make_range_type<T> (h5_save_type);
872 
873  if (! hdf5_types_compatible (type_hid, range_type))
874  {
875  H5Tclose (range_type);
876  H5Dclose (data_hid);
877  return false;
878  }
879 
880  hid_t space_hid = H5Dget_space (data_hid);
881  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
882 
883  if (rank != 0)
884  {
885  H5Tclose (range_type);
886  H5Sclose (space_hid);
887  H5Dclose (data_hid);
888  return false;
889  }
890 
891  T rangevals[4];
892  if (H5Dread (data_hid, range_type, octave_H5S_ALL, octave_H5S_ALL,
893  octave_H5P_DEFAULT, rangevals)
894  >= 0)
895  {
896  retval = true;
897 
898  // Don't use OCTAVE_RANGE_NELEM attribute, just reconstruct the range.
899 
900  bool rev = with_reverse ? static_cast<bool> (rangevals[3]) : false;
901 
902  r = octave::range<T> (rangevals[0], rangevals[2], rangevals[1], rev);
903  }
904 
905  H5Tclose (range_type);
906  H5Sclose (space_hid);
907  H5Dclose (data_hid);
908 
909  return retval;
910 }
911 
912 #endif
913 
914 template <typename T>
915 bool
916 ov_range<T>::load_hdf5 (octave_hdf5_id loc_id, const char *name)
917 {
918 #if defined (HAVE_HDF5)
919  return xload_hdf5 (loc_id, name, m_range, hdf5_save_type, false);
920 #else
921  octave_unused_parameter (loc_id);
922  octave_unused_parameter (name);
923 
924  warn_load ("hdf5");
925 
926  return false;
927 #endif
928 }
929 
930 // For now, enable only ov_range<double>.
931 
932 /*
933 %!testif HAVE_HDF5
934 %! a = b = 1:4;
935 %! sv_file = [tempname(), ".h5"];
936 %! unwind_protect
937 %! save (sv_file, "a", "-hdf5");
938 %! clear a;
939 %! load (sv_file);
940 %! assert (a, b);
941 %! unwind_protect_cleanup
942 %! unlink (sv_file);
943 %! end_unwind_protect
944 
945 %!testif HAVE_HDF5
946 %! a = b = uint8(5):-1:0;
947 %! sv_file = [tempname(), ".h5"];
948 %! unwind_protect
949 %! save (sv_file, "a", "-hdf5");
950 %! clear a;
951 %! load (sv_file);
952 %! assert (a, b);
953 %! unwind_protect_cleanup
954 %! unlink (sv_file);
955 %! end_unwind_protect
956 */
957 
958 template <typename T>
959 mxArray *
960 ov_range<T>::as_mxArray (bool interleaved) const
961 {
963 
964  mxArray *retval = new mxArray (interleaved, mx_class, dims (), mxREAL);
965 
966  typedef typename mx_type_traits<T>::mx_type mx_type;
967  mx_type *pd = static_cast<mx_type *> (retval->get_data ());
968 
969  mwSize nel = numel ();
970 
971  Array<T> matrix = raw_array_value ();
972 
973  const T *pdata = matrix.data ();
974 
975  for (mwSize i = 0; i < nel; i++)
976  pd[i] = pdata[i];
977 
978  return retval;
979 }
980 
982  "trivial range", "double");
983 
984 template <typename T>
985 bool
987 
988 template <>
989 bool
991 {
992  octave_idx_type n = m_range.numel ();
994  return false;
995  if (n <= 1)
996  return false;
997 
998  if (m_range.final_value () > std::numeric_limits<int>::max ()
999  || m_range.final_value () < std::numeric_limits<int>::min ())
1000  return false;
1001  if (m_range.increment () > std::numeric_limits<int>::max ()
1002  || m_range.increment () < std::numeric_limits<int>::min ())
1003  return false;
1004  if (m_range.base () > std::numeric_limits<int>::max ()
1005  || m_range.base () < std::numeric_limits<int>::min ())
1006  return false;
1007  if (m_range.limit () > std::numeric_limits<int>::max ()
1008  || m_range.limit () < std::numeric_limits<int>::min ())
1009  return false;
1010 
1011  if (std::isnan (m_range.final_value ()))
1012  return false;
1013  if (std::isnan (m_range.increment ()))
1014  return false;
1015  if (std::isnan (m_range.base ()))
1016  return false;
1017  if (std::isnan (m_range.limit ()))
1018  return false;
1019 
1020  if (static_cast<int> (m_range.final_value ()) != m_range.final_value ())
1021  return false;
1022  if (static_cast<int> (m_range.increment ()) != m_range.increment ())
1023  return false;
1024  if (static_cast<int> (m_range.base ()) != m_range.base ())
1025  return false;
1026  if (static_cast<int> (m_range.limit ()) != m_range.limit ())
1027  return false;
1028 
1029  if (m_range.reverse ())
1030  return false;
1031 
1032  return true;
1033 }
1034 
1035 template <typename T>
1038 {
1039  error ("Type error returning trivial range");
1040 }
1041 
1042 template <>
1045 {
1046  return octave_value (new octave_trivial_range (m_range.numel (), m_range.base (), m_range.increment ()));
1047 }
1048 
1049 template <typename T>
1052 {
1053  return (n < numel () ? octave_value (m_range.elem (n)) : octave_value ());
1054 }
1055 
1056 // Specializations.
1057 
1058 template <>
1059 octave::range<double>
1061 {
1062  return m_range;
1063 }
1064 
1065 template <typename T>
1068 {
1069  octave_value ov = octave_value_factory::make (m_range.elem (n));
1070 
1071  return ov.as_double_or_copy ();
1072 }
1073 
1074 template <>
1077 {
1078  octave_value ov = octave_value_factory::make (m_range.elem (n));
1079 
1080  return ov;
1081 }
1082 
1083 // For now, enable only ov_range<double>.
1084 
1085 template <>
1087 ov_range<double>::index_vector (bool require_integers) const
1088 {
1089  if (m_idx_cache)
1090  return *m_idx_cache;
1091 
1092  if (require_integers || m_range.all_elements_are_ints ())
1093  return set_idx_cache (octave::idx_vector (m_range));
1094 
1095  warning_with_id ("Octave:noninteger-range-as-index",
1096  "non-integer range used as index");
1097 
1098  return octave_value (matrix_value ()).round ().index_vector ();
1099 }
1100 
1101 template <>
1104 {
1105  return m_range.nnz ();
1106 }
1107 
1108 // The following specialization is also historical baggage. For double
1109 // ranges, we can produce special double-valued diagnoal matrix objects
1110 // but Octave currently provides only double and Complex diagonal matrix
1111 // objects.
1112 
1113 template <>
1116 {
1117  // FIXME: this is a potential waste of memory.
1118 
1119  return
1120  (k == 0
1121  ? octave_value (DiagMatrix (DiagArray2<double> (matrix_value ())))
1122  : octave_value (m_range.diag (k)));
1123 }
1124 
1125 template <>
1128 {
1129  Matrix mat = matrix_value ();
1130 
1131  return mat.diag (nr, nc);
1132 }
1133 
1134 template <>
1135 void
1136 ov_range<double>::print_raw (std::ostream& os, bool pr_as_read_syntax) const
1137 {
1138  octave_print_internal (os, m_range, pr_as_read_syntax,
1139  current_print_indent_level ());
1140 }
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:562
bool test_all(F fcn) const
Size of the specified dimension.
Definition: Array.h:922
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1023
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
Definition: dMatrix.h:42
Matrix diag(octave_idx_type k=0) const
Definition: dMatrix.cc:2407
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
void * get_data() const
Definition: mxarray.h:473
static octave_value make(double d)
Definition: ov-inline.h:47
octave_idx_type length() const
Definition: ovl.h:113
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:504
octave::idx_vector index_vector(bool require_integers=false) const
Definition: ov.h:534
octave_value next_subsref(const std::string &type, const std::list< octave_value_list > &idx, std::size_t skip=1)
octave_value convert_to_str(bool pad=false, bool force=false, char type='\'') const
Definition: ov.h:1307
octave_value as_double_or_copy() const
Definition: ov.h:442
FloatComplex float_complex_value(bool=false) const
Definition: ov-range.cc:280
virtual octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-base.cc:248
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov-range.cc:174
octave_value fast_elem_extract(octave_idx_type n) const
Definition: ov-range.cc:1051
octave_value as_int64() const
Definition: ov-range.cc:379
octave_value diag(octave_idx_type k=0) const
Definition: ov-range.h:272
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool flag)
Definition: ov-range.cc:834
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov-range.cc:313
octave_value as_uint32() const
Definition: ov-range.cc:400
octave_value as_uint16() const
Definition: ov-range.cc:393
bool could_be_trivial_range()
Definition: ov-range.cc:986
bool load_ascii(std::istream &is)
Definition: ov-range.cc:585
void short_disp(std::ostream &os) const
Definition: ov-range.cc:460
octave_value as_single() const
Definition: ov-range.cc:351
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
Definition: ov-range.cc:422
bool save_ascii(std::ostream &os)
Definition: ov-range.cc:552
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
Definition: ov-range.cc:506
bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov-range.cc:649
double double_value(bool=false) const
Definition: ov-range.cc:220
Array< T > raw_array_value() const
Definition: ov-range.h:317
octave_value as_uint64() const
Definition: ov-range.cc:407
float_display_format get_edit_display_format() const
Definition: ov-range.cc:499
octave_idx_type nnz() const
Definition: ov-range.h:179
octave_value as_int8() const
Definition: ov-range.cc:358
octave_value as_int16() const
Definition: ov-range.cc:365
charNDArray char_array_value(bool=false) const
Definition: ov-range.cc:250
octave_value vm_extract_forloop_value(octave_idx_type idx)
Definition: ov-range.cc:1067
boolNDArray bool_array_value(bool warn=false) const
Definition: ov-range.cc:301
type_conv_info numeric_conversion_function() const
Definition: ov-range.cc:102
float float_value(bool=false) const
Definition: ov-range.cc:235
mxArray * as_mxArray(bool interleaved) const
Definition: ov-range.cc:960
octave_value as_trivial_range()
Definition: ov-range.cc:1037
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
Definition: ov-range.cc:916
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition: ov-range.cc:696
octave_value as_double() const
Definition: ov-range.cc:344
octave::range< double > range_value() const
Definition: ov-range.cc:325
void print(std::ostream &os, bool pr_as_read_syntax=false)
Definition: ov-range.cc:414
octave_value convert_to_str_internal(bool pad, bool force, char type) const
Definition: ov-range.cc:334
octave_base_value * try_narrowing_conversion()
Definition: ov-range.cc:112
octave_value as_uint8() const
Definition: ov-range.cc:386
octave::idx_vector index_vector(bool require_integers=false) const
Definition: ov-range.cc:212
bool print_name_tag(std::ostream &os, const std::string &name) const
Definition: ov-range.cc:435
octave_value as_int32() const
Definition: ov-range.cc:372
Complex complex_value(bool=false) const
Definition: ov-range.cc:265
const octave_hdf5_id octave_H5P_DEFAULT
const octave_hdf5_id octave_H5S_ALL
@ LS_DOUBLE
Definition: data-conv.h:95
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1078
void() error(const char *fmt,...)
Definition: error.cc:988
#define panic_impossible()
Definition: error.h:503
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
void err_invalid_conversion(const std::string &from, const std::string &to)
Definition: errwarn.cc:71
void warn_logical_conversion()
Definition: errwarn.cc:365
void warn_implicit_conversion(const char *id, const char *from, const char *to)
Definition: errwarn.cc:344
octave::idx_vector idx_vector
Definition: idx-vector.h:1022
intNDArray< octave_int16 > int16NDArray
Definition: int16NDArray.h:36
intNDArray< octave_int32 > int32NDArray
Definition: int32NDArray.h:36
intNDArray< octave_int64 > int64NDArray
Definition: int64NDArray.h:36
intNDArray< octave_int8 > int8NDArray
Definition: int8NDArray.h:36
float lo_ieee_float_nan_value()
Definition: lo-ieee.cc:116
bool isnan(bool)
Definition: lo-mappers.h:178
void skip_until_newline(std::istream &is, bool keep_newline)
bool hdf5_types_compatible(octave_hdf5_id t1, octave_hdf5_id t2)
Definition: ls-hdf5.cc:269
octave_hdf5_err hdf5_add_scalar_attr(octave_hdf5_id loc_id, octave_hdf5_id type_id, const char *attr_name, void *buf)
Definition: ls-hdf5.cc:1205
float_format
Definition: mach-info.h:38
void mxArray
Definition: mex.h:58
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
T * r
Definition: mx-inlines.cc:781
mxClassID
Definition: mxtypes.h:57
@ mxREAL
Definition: mxtypes.h:80
int64_t mwSize
Definition: mxtypes.h:124
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
int64_t octave_hdf5_id
#define H5T_NATIVE_IDX
Definition: oct-hdf5.h:42
T::size_type numel(const T &str)
Definition: oct-string.cc:74
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
#define DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:232
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:235
bool xsave_ascii(std::ostream &os, const octave::range< T > &r, const bool with_reverse)
Definition: ov-range.cc:516
bool xsave_binary(std::ostream &os, bool, const octave::range< T > &r, const bool with_reverse)
Definition: ov-range.cc:622
bool xload_binary(std::istream &is, bool swap, octave::mach_info::float_format, octave::range< T > &r, const bool with_reverse)
Definition: ov-range.cc:658
bool xsave_hdf5(octave_hdf5_id loc_id, const char *name, bool, const octave::range< T > &r, const octave_hdf5_id h5_save_type, const bool with_reverse)
Definition: ov-range.cc:768
bool xload_hdf5(octave_hdf5_id loc_id, const char *name, octave::range< T > &r, const octave_hdf5_id h5_save_type, const bool with_reverse)
Definition: ov-range.cc:857
bool xload_ascii(std::istream &is, octave::range< T > &r, const bool with_reverse)
Definition: ov-range.cc:563
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1761
float_display_format make_format(const double &d)
Definition: pr-output.cc:525
bool Vcompact_format
Definition: pr-output.cc:102
intNDArray< octave_uint16 > uint16NDArray
Definition: uint16NDArray.h:36
intNDArray< octave_uint32 > uint32NDArray
Definition: uint32NDArray.h:36
intNDArray< octave_uint64 > uint64NDArray
Definition: uint64NDArray.h:36
intNDArray< octave_uint8 > uint8NDArray
Definition: uint8NDArray.h:36
F77_RET_T len
Definition: xerbla.cc:61