Mercurial > octave
changeset 28646:e26201931ea3
new template class for octave_range objects
* ov-range.h, ov-range.cc (class octave_range): Convert to template.
For now, use specializations to preserve existing behavior for
double-precision ranges. Change all uses.
* ov.h, ov.cc: Update range constructors to create range objects for
integer and float ranges. Provide value extractor functions for
range<T> types that forward to virtual functions in the
octave_base_value class.
* ov-base.cc: Provide virtual value extractor functions for range<T>
types.
* ov-range-traits.h: New file.
* libinterp/octave-value/module.mk: Update.
* Range.h, Range.cc (Range::Range): Deprecate public constructors.
* pt-eval.h, pt-eval.cc (tree_evaluator::execute_range_loop):
New template function.
(tree_evaluator::visit_simple_for_command): Use it to handle looping
when the loop variable expression is a range.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Wed, 12 Aug 2020 12:14:17 -0400 |
parents | 175eedccc085 |
children | f0414ee0fefe |
files | libinterp/octave-value/module.mk libinterp/octave-value/ov-base.cc libinterp/octave-value/ov-base.h libinterp/octave-value/ov-range-traits.h libinterp/octave-value/ov-range.cc libinterp/octave-value/ov-range.h libinterp/octave-value/ov.cc libinterp/octave-value/ov.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h liboctave/array/Range.h |
diffstat | 11 files changed, 1213 insertions(+), 442 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/octave-value/module.mk Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/octave-value/module.mk Wed Aug 12 12:14:17 2020 -0400 @@ -57,6 +57,7 @@ %reldir%/ov-null-mat.h \ %reldir%/ov-oncleanup.h \ %reldir%/ov-perm.h \ + %reldir%/ov-range-traits.h \ %reldir%/ov-range.h \ %reldir%/ov-re-diag.h \ %reldir%/ov-re-mat.h \
--- a/libinterp/octave-value/ov-base.cc Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/octave-value/ov-base.cc Wed Aug 12 12:14:17 2020 -0400 @@ -811,12 +811,66 @@ err_wrong_type_arg ("octave_base_value::cellstr_value()", type_name ()); } +octave::range<float> +octave_base_value::float_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::float_range_value()", type_name ()); +} + octave::range<double> octave_base_value::range_value (void) const { err_wrong_type_arg ("octave_base_value::range_value()", type_name ()); } +octave::range<octave_int8> +octave_base_value::int8_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::int8_range_value()", type_name ()); +} + +octave::range<octave_int16> +octave_base_value::int16_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::int16_range_value()", type_name ()); +} + +octave::range<octave_int32> +octave_base_value::int32_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::int32_range_value()", type_name ()); +} + +octave::range<octave_int64> +octave_base_value::int64_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::int64_range_value()", type_name ()); +} + +octave::range<octave_uint8> +octave_base_value::uint8_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::uint8_range_value()", type_name ()); +} + +octave::range<octave_uint16> +octave_base_value::uint16_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::uint16_range_value()", type_name ()); +} + +octave::range<octave_uint32> +octave_base_value::uint32_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::uint32_range_value()", type_name ()); +} + +octave::range<octave_uint64> +octave_base_value::uint64_range_value (void) const +{ + err_wrong_type_arg ("octave_base_value::uint64_range_value()", type_name ()); +} + octave_map octave_base_value::map_value (void) const {
--- a/libinterp/octave-value/ov-base.h Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/octave-value/ov-base.h Wed Aug 12 12:14:17 2020 -0400 @@ -622,8 +622,26 @@ virtual Array<std::string> cellstr_value (void) const; + virtual octave::range<float> float_range_value (void) const; + virtual octave::range<double> range_value (void) const; + virtual octave::range<octave_int8> int8_range_value (void) const; + + virtual octave::range<octave_int16> int16_range_value (void) const; + + virtual octave::range<octave_int32> int32_range_value (void) const; + + virtual octave::range<octave_int64> int64_range_value (void) const; + + virtual octave::range<octave_uint8> uint8_range_value (void) const; + + virtual octave::range<octave_uint16> uint16_range_value (void) const; + + virtual octave::range<octave_uint32> uint32_range_value (void) const; + + virtual octave::range<octave_uint64> uint64_range_value (void) const; + virtual octave_map map_value (void) const; virtual octave_scalar_map scalar_map_value (void) const;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-range-traits.h Wed Aug 12 12:14:17 2020 -0400 @@ -0,0 +1,154 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or <https://octave.org/copyright/>. +// +// This file is part of Octave. +// +// Octave is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Octave is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Octave; see the file COPYING. If not, see +// <https://www.gnu.org/licenses/>. +// +//////////////////////////////////////////////////////////////////////// + +#if ! defined (octave_ov_range_traits_h) +#define octave_ov_range_traits_h 1 + +#include "octave-config.h" + +#include "ov-bool-mat.h" +#include "ov-bool.h" +#include "ov-float.h" +#include "ov-flt-re-mat.h" +#include "ov-int16.h" +#include "ov-int32.h" +#include "ov-int64.h" +#include "ov-int8.h" +#include "ov-re-mat.h" +#include "ov-scalar.h" +#include "ov-uint16.h" +#include "ov-uint32.h" +#include "ov-uint64.h" +#include "ov-uint8.h" + +template <typename T> +class +octave_value_range_traits +{ +public: + typedef T scalar_type; + typedef T matrix_type; +}; + +template <> +class +octave_value_range_traits<bool> +{ +public: + typedef octave_bool scalar_type; + typedef octave_bool_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<float> +{ +public: + typedef octave_float_scalar scalar_type; + typedef octave_float_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<double> +{ +public: + typedef octave_scalar scalar_type; + typedef octave_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<octave_int8> +{ +public: + typedef octave_int8_scalar scalar_type; + typedef octave_int8_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<octave_int16> +{ +public: + typedef octave_int16_scalar scalar_type; + typedef octave_int16_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<octave_int32> +{ +public: + typedef octave_int32_scalar scalar_type; + typedef octave_int32_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<octave_int64> +{ +public: + typedef octave_int64_scalar scalar_type; + typedef octave_int64_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<octave_uint8> +{ +public: + typedef octave_uint8_scalar scalar_type; + typedef octave_uint8_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<octave_uint16> +{ +public: + typedef octave_uint16_scalar scalar_type; + typedef octave_uint16_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<octave_uint32> +{ +public: + typedef octave_uint32_scalar scalar_type; + typedef octave_uint32_matrix matrix_type; +}; + +template <> +class +octave_value_range_traits<octave_uint64> +{ +public: + typedef octave_uint64_scalar scalar_type; + typedef octave_uint64_matrix matrix_type; +}; + +#endif
--- a/libinterp/octave-value/ov-range.cc Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/octave-value/ov-range.cc Wed Aug 12 12:14:17 2020 -0400 @@ -23,9 +23,9 @@ // //////////////////////////////////////////////////////////////////////// -#if defined (HAVE_CONFIG_H) -# include "config.h" -#endif +// This file should not include config.h. It is only included in other +// C++ source files that should have included config.h before including +// this file. #include <istream> #include <ostream> @@ -49,9 +49,11 @@ #include "variables.h" #include "errwarn.h" #include "mxarray.h" +#include "mx-type-traits.h" #include "ops.h" #include "ovl.h" #include "oct-hdf5.h" +#include "ov-range-traits.h" #include "ov-range.h" #include "ov-re-mat.h" #include "ov-scalar.h" @@ -62,41 +64,148 @@ #include "ls-hdf5.h" #include "ls-utils.h" +#if defined (HAVE_HDF5) -DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range", "double"); +template <> +octave_hdf5_id ov_range<float>::hdf5_save_type = H5T_NATIVE_FLOAT; + +template <> +octave_hdf5_id ov_range<double>::hdf5_save_type = H5T_NATIVE_DOUBLE; + +template <> +octave_hdf5_id ov_range<octave_int8>::hdf5_save_type = H5T_NATIVE_INT8; + +template <> +octave_hdf5_id ov_range<octave_int16>::hdf5_save_type = H5T_NATIVE_INT16; + +template <> +octave_hdf5_id ov_range<octave_int32>::hdf5_save_type = H5T_NATIVE_INT32; + +template <> +octave_hdf5_id ov_range<octave_int64>::hdf5_save_type = H5T_NATIVE_INT64; + +template <> +octave_hdf5_id ov_range<octave_uint8>::hdf5_save_type = H5T_NATIVE_UINT8; + +template <> +octave_hdf5_id ov_range<octave_uint16>::hdf5_save_type = H5T_NATIVE_UINT16; + +template <> +octave_hdf5_id ov_range<octave_uint32>::hdf5_save_type = H5T_NATIVE_UINT32; + +template <> +octave_hdf5_id ov_range<octave_uint64>::hdf5_save_type = H5T_NATIVE_UINT64; + +#else + +template <> +octave_hdf5_id ov_range<float>::hdf5_save_type = 0; + +template <> +octave_hdf5_id ov_range<double>::hdf5_save_type = 0; + +template <> +octave_hdf5_id ov_range<octave_int8>::hdf5_save_type = 0; + +template <> +octave_hdf5_id ov_range<octave_int16>::hdf5_save_type = 0; + +template <> +octave_hdf5_id ov_range<octave_int32>::hdf5_save_type = 0; +template <> +octave_hdf5_id ov_range<octave_int64>::hdf5_save_type = 0; + +template <> +octave_hdf5_id ov_range<octave_uint8>::hdf5_save_type = 0; + +template <> +octave_hdf5_id ov_range<octave_uint16>::hdf5_save_type = 0; + +template <> +octave_hdf5_id ov_range<octave_uint32>::hdf5_save_type = 0; + +template <> +octave_hdf5_id ov_range<octave_uint64>::hdf5_save_type = 0; + +#endif + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<float>, + "float_range", "single"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<double>, + "range", "double"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int8>, + "int8_range", "int8"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int16>, + "int16_range", "int16"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int32>, + "int32_range", "int32"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int64>, + "int64_range", "int64"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint8>, + "uint8_range", "uint8"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint16>, + "uint16_range", "uint16"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint32>, + "uint32_range", "uint32"); + +DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint64>, + "uint64_range", "uint64"); + +template <typename T> static octave_base_value * default_numeric_conversion_function (const octave_base_value& a) { - const octave_range& v = dynamic_cast<const octave_range&> (a); + typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type; - return new octave_matrix (v.matrix_value ()); + const ov_range<T>& v = dynamic_cast<const ov_range<T>&> (a); + + return new ov_mx_type (v.raw_array_value ()); } +template <typename T> octave_base_value::type_conv_info -octave_range::numeric_conversion_function (void) const +ov_range<T>::numeric_conversion_function (void) const { - return octave_base_value::type_conv_info (default_numeric_conversion_function, - octave_matrix::static_type_id ()); + typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type; + + return octave_base_value::type_conv_info + (default_numeric_conversion_function<T>, ov_mx_type::static_type_id ()); } +template <typename T> octave_base_value * -octave_range::try_narrowing_conversion (void) +ov_range<T>::try_narrowing_conversion (void) { octave_base_value *retval = nullptr; switch (numel ()) { case 1: - retval = new octave_scalar (m_range.base ()); + retval = new typename octave_value_range_traits<T>::scalar_type (m_range.elem (0)); break; case 0: - retval = new octave_matrix (Matrix (1, 0)); + { + typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type; + typename ov_mx_type::object_type m (dim_vector (1, 0)); + retval = new ov_mx_type (m); + } break; case -2: - retval = new octave_matrix (matrix_value ()); + // FIXME: is this case possible now? It would have to be due to + // conversion from Range to range<double>, but even in that case, + // is the invalid numel value preserved? + retval = new typename octave_value_range_traits<T>::matrix_type (raw_array_value ()); break; default: @@ -106,9 +215,10 @@ return retval; } +template <typename T> octave_value -octave_range::subsref (const std::string& type, - const std::list<octave_value_list>& idx) +ov_range<T>::subsref (const std::string& type, + const std::list<octave_value_list>& idx) { octave_value retval; @@ -133,8 +243,10 @@ return retval.next_subsref (type, idx); } +template <typename T> octave_value -octave_range::do_index_op (const octave_value_list& idx, bool resize_ok) +ov_range<T>::do_index_op (const octave_value_list& idx, + bool resize_ok) { if (idx.length () == 1 && ! resize_ok) { @@ -163,47 +275,23 @@ } else { - octave_value tmp (new octave_matrix (matrix_value ())); + octave_value tmp (new typename octave_value_range_traits<T>::matrix_type (raw_array_value ())); return tmp.index_op (idx, resize_ok); } } +template <typename T> idx_vector -octave_range::index_vector (bool require_integers) const +ov_range<T>::index_vector (bool require_integers) const { - if (m_idx_cache) - return *m_idx_cache; - else - { - if (require_integers || m_range.all_elements_are_ints ()) - return set_idx_cache (idx_vector (m_range)); - else - { - warning_with_id ("Octave:noninteger-range-as-index", - "non-integer range used as index"); - - return octave_value (matrix_value ()).round ().index_vector (); - } - } + octave_value tmp (raw_array_value ()); + return tmp.index_vector (require_integers); } +template <typename T> double -octave_range::double_value (bool) const -{ - octave_idx_type nel = numel (); - - if (nel == 0) - err_invalid_conversion ("range", "real scalar"); - - warn_implicit_conversion ("Octave:array-to-scalar", - "range", "real scalar"); - - return m_range.base (); -} - -float -octave_range::float_value (bool) const +ov_range<T>::double_value (bool) const { octave_idx_type nel = numel (); @@ -216,10 +304,26 @@ return m_range.base (); } +template <typename T> +float +ov_range<T>::float_value (bool) const +{ + octave_idx_type nel = numel (); + + if (nel == 0) + err_invalid_conversion ("range", "real scalar"); + + warn_implicit_conversion ("Octave:array-to-scalar", + "range", "real scalar"); + + return m_range.base (); +} + +template <typename T> charNDArray -octave_range::char_array_value (bool) const +ov_range<T>::char_array_value (bool) const { - const Matrix matrix = matrix_value (); + const Array<T> matrix = raw_array_value (); charNDArray retval (dims ()); octave_idx_type nel = numel (); @@ -230,83 +334,9 @@ return retval; } -octave_value -octave_range::all (int dim) const -{ - // FIXME: this is a potential waste of memory. - - Matrix m = matrix_value (); - - return m.all (dim); -} - -octave_value -octave_range::any (int dim) const -{ - // FIXME: this is a potential waste of memory. - - Matrix m = matrix_value (); - - return m.any (dim); -} - -octave_value -octave_range::diag (octave_idx_type k) const -{ - return - (k == 0 - ? octave_value (DiagMatrix (DiagArray2<double> (matrix_value ()))) - : octave_value (m_range.diag (k))); -} - -octave_value -octave_range::diag (octave_idx_type m, octave_idx_type n) const -{ - Matrix mat = matrix_value (); - - return mat.diag (m, n); -} - -// Return true if this range has all true elements (non-zero, not NaN/NA). -// A range cannot have NaN/NA. -bool -octave_range::is_true (void) const -{ - bool retval = false; - - if (! m_range.isempty ()) - { - if (dims ().numel () > 1) - warn_array_as_logical (dims ()); - - octave::range<double> r = range_value (); - double base = r.base (); - double limit = r.limit (); - - // Can't be zero if we start and finish on the same size of 0 - if (((base > 0 && limit > 0) || (base < 0 && limit < 0)) && numel () > 0) - retval = true; - else - { - /* - // This tells us whether one element is 0, if arithmetic is exact. - double steps_to_zero = base / r.increment (); - - retval = (steps_to_zero != floor (steps_to_zero)); - */ - - // FIXME: this is a waste of memory. - Matrix m ((matrix_value ().all ()).all ()); - - retval = ! m.isempty () && m(0, 0) != 0.0; - } - } - - return retval; -} - +template <typename T> Complex -octave_range::complex_value (bool) const +ov_range<T>::complex_value (bool) const { octave_idx_type nel = numel (); @@ -319,8 +349,9 @@ return Complex (m_range.base (), 0); } +template <typename T> FloatComplex -octave_range::float_complex_value (bool) const +ov_range<T>::float_complex_value (bool) const { float tmp = lo_ieee_float_nan_value (); @@ -339,23 +370,23 @@ return retval; } +template <typename T> boolNDArray -octave_range::bool_array_value (bool warn) const +ov_range<T>::bool_array_value (bool warn) const { - Matrix m = matrix_value (); + Array<T> matrix = raw_array_value (); - if (m.any_element_is_nan ()) - octave::err_nan_to_logical_conversion (); - if (warn && m.any_element_not_one_or_zero ()) + if (warn && ! matrix.test_all (xis_one_or_zero<T>)) warn_logical_conversion (); - return boolNDArray (m); + return boolNDArray (matrix); } +template <typename T> octave_value -octave_range::resize (const dim_vector& dv, bool fill) const +ov_range<T>::resize (const dim_vector& dv, bool fill) const { - NDArray retval = array_value (); + Array<T> retval = raw_array_value (); if (fill) retval.resize (dv, 0); else @@ -363,89 +394,180 @@ return retval; } +template <typename T> +octave::range<float> +ov_range<T>::float_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::float_range_value ()", type_name ()); +} + +template <typename T> +octave::range<double> +ov_range<T>::range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::range_value()", type_name ()); +} + +template <typename T> +octave::range<octave_int8> +ov_range<T>::int8_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::int8_range_value ()", type_name ()); +} + +template <typename T> +octave::range<octave_int16> +ov_range<T>::int16_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::int16_range_value ()", type_name ()); +} + +template <typename T> +octave::range<octave_int32> +ov_range<T>::int32_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::int32_range_value ()", type_name ()); +} + +template <typename T> +octave::range<octave_int64> +ov_range<T>::int64_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::int64_range_value ()", type_name ()); +} + +template <typename T> +octave::range<octave_uint8> +ov_range<T>::uint8_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::uint8_range_value ()", type_name ()); +} + +template <typename T> +octave::range<octave_uint16> +ov_range<T>::uint16_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::uint16_range_value ()", type_name ()); +} + +template <typename T> +octave::range<octave_uint32> +ov_range<T>::uint32_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::uint32_range_value ()", type_name ()); +} + +template <typename T> +octave::range<octave_uint64> +ov_range<T>::uint64_range_value (void) const +{ + err_wrong_type_arg ("ov_range<T>::uint64_range_value ()", type_name ()); +} + +template <typename T> octave_value -octave_range::convert_to_str_internal (bool pad, bool force, char type) const +ov_range<T>::convert_to_str_internal (bool pad, bool force, char type) const { - octave_value tmp (matrix_value ()); + octave_value tmp (raw_array_value ()); return tmp.convert_to_str (pad, force, type); } +// FIXME: could most of these fucntions preserve range type now? + +template <typename T> octave_value -octave_range::as_double (void) const +ov_range<T>::as_double (void) const { - return m_range; + return NDArray (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_single (void) const +ov_range<T>::as_single (void) const { - return FloatMatrix (matrix_value ()); + return FloatMatrix (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_int8 (void) const +ov_range<T>::as_int8 (void) const { - return int8NDArray (matrix_value ()); + return int8NDArray (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_int16 (void) const +ov_range<T>::as_int16 (void) const { - return int16NDArray (matrix_value ()); + return int16NDArray (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_int32 (void) const +ov_range<T>::as_int32 (void) const { - return int32NDArray (matrix_value ()); + return int32NDArray (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_int64 (void) const +ov_range<T>::as_int64 (void) const { - return int64NDArray (matrix_value ()); + return int64NDArray (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_uint8 (void) const +ov_range<T>::as_uint8 (void) const { - return uint8NDArray (matrix_value ()); + return uint8NDArray (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_uint16 (void) const +ov_range<T>::as_uint16 (void) const { - return uint16NDArray (matrix_value ()); + return uint16NDArray (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_uint32 (void) const +ov_range<T>::as_uint32 (void) const { - return uint32NDArray (matrix_value ()); + return uint32NDArray (raw_array_value ()); } +template <typename T> octave_value -octave_range::as_uint64 (void) const +ov_range<T>::as_uint64 (void) const { - return uint64NDArray (matrix_value ()); + return uint64NDArray (raw_array_value ()); } +template <typename T> void -octave_range::print (std::ostream& os, bool pr_as_read_syntax) +ov_range<T>::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); } +template <typename T> void -octave_range::print_raw (std::ostream& os, bool pr_as_read_syntax) const +ov_range<T>::print_raw (std::ostream& os, bool pr_as_read_syntax) const { - octave_print_internal (os, m_range, pr_as_read_syntax, + // FIXME: this is a potential waste of memory. + + typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type; + typename ov_mx_type::object_type tmp (raw_array_value ()); + + octave_print_internal (os, tmp, pr_as_read_syntax, current_print_indent_level ()); } +template <typename T> bool -octave_range::print_name_tag (std::ostream& os, const std::string& name) const +ov_range<T>::print_name_tag (std::ostream& os, const std::string& name) const { bool retval = false; @@ -468,8 +590,9 @@ return retval; } +template <typename T> void -octave_range::short_disp (std::ostream& os) const +ov_range<T>::short_disp (std::ostream& os) const { octave_idx_type len = numel (); @@ -481,7 +604,7 @@ if (len > 1) { - if (m_range.increment () != 1) + if (m_range.increment () != T (1)) os << m_range.increment () << ':'; os << m_range.limit (); @@ -506,116 +629,126 @@ skip_until_newline (is, false); } +template <typename T> float_display_format -octave_range::get_edit_display_format (void) const +ov_range<T>::get_edit_display_format (void) const { - return make_format (range_value ()); + return make_format (m_range); } +template <typename T> std::string -octave_range::edit_display (const float_display_format& fmt, - octave_idx_type, octave_idx_type j) const +ov_range<T>::edit_display (const float_display_format& fmt, + octave_idx_type, octave_idx_type j) const { std::ostringstream buf; octave_print_internal (buf, fmt, m_range.elem (j)); return buf.str (); } +template <typename T> bool -octave_range::save_ascii (std::ostream& os) +ov_range<T>::save_ascii (std::ostream& os) { - octave::range<double> r = range_value (); - double base = r.base (); - double limit = r.limit (); - double inc = r.increment (); + octave::range<T> r = m_range; + T base = r.base (); + T limit = r.limit (); + T inc = r.increment (); octave_idx_type len = r.numel (); - if (inc != 0) + if (inc != T (0)) os << "# base, limit, increment\n"; else os << "# base, length, increment\n"; - octave::write_value<double> (os, base); + octave::write_value<T> (os, base); os << ' '; - if (inc != 0) - octave::write_value<double> (os, limit); + if (inc != T (0)) + octave::write_value<T> (os, limit); else os << len; os << ' '; - octave::write_value<double> (os, inc); + octave::write_value<T> (os, inc); os << "\n"; return true; } +template <typename T> bool -octave_range::load_ascii (std::istream& is) +ov_range<T>::load_ascii (std::istream& is) { // # base, limit, range comment added by save (). skip_comments (is); - double base, limit, inc; + T base, limit, inc; is >> base >> limit >> inc; if (! is) error ("load: failed to load range constant"); - if (inc != 0) - m_range = octave::range<double> (base, limit, inc); + if (inc != T (0)) + m_range = octave::range<T> (base, limit, inc); else { octave_idx_type numel = static_cast<octave_idx_type> (limit); - m_range = octave::range<double>::make_constant (base, numel); + m_range = octave::range<T>::make_constant (base, numel); } return true; } +template <typename T> bool -octave_range::save_binary (std::ostream& os, bool /* save_as_floats */) +ov_range<T>::save_binary (std::ostream& os, bool /* save_as_floats */) { + // FIXME: Not always double! + char tmp = LS_DOUBLE; os.write (reinterpret_cast<char *> (&tmp), 1); - octave::range<double> r = range_value (); - double bas = r.base (); - double lim = r.limit (); - double inc = r.increment (); - if (inc == 0) + octave::range<T> r = m_range; + T bas = r.base (); + T lim = r.limit (); + T inc = r.increment (); + if (inc == T (0)) lim = r.numel (); - os.write (reinterpret_cast<char *> (&bas), 8); - os.write (reinterpret_cast<char *> (&lim), 8); - os.write (reinterpret_cast<char *> (&inc), 8); + os.write (reinterpret_cast<char *> (&bas), sizeof (T)); + os.write (reinterpret_cast<char *> (&lim), sizeof (T)); + os.write (reinterpret_cast<char *> (&inc), sizeof (T)); return true; } +template <typename T> bool -octave_range::load_binary (std::istream& is, bool swap, - octave::mach_info::float_format /* fmt */) +ov_range<T>::load_binary (std::istream& is, bool swap, + octave::mach_info::float_format /* fmt */) { + // FIXME: Not always double! + char tmp; if (! is.read (reinterpret_cast<char *> (&tmp), 1)) return false; - double bas, lim, inc; - if (! is.read (reinterpret_cast<char *> (&bas), 8)) + T bas, lim, inc; + if (! is.read (reinterpret_cast<char *> (&bas), sizeof (T))) return false; if (swap) - swap_bytes<8> (&bas); - if (! is.read (reinterpret_cast<char *> (&lim), 8)) + swap_bytes<sizeof (T)> (&bas); + if (! is.read (reinterpret_cast<char *> (&lim), sizeof (T))) return false; if (swap) - swap_bytes<8> (&lim); - if (! is.read (reinterpret_cast<char *> (&inc), 8)) + swap_bytes<sizeof (T)> (&lim); + if (! is.read (reinterpret_cast<char *> (&inc), sizeof (T))) return false; if (swap) - swap_bytes<8> (&inc); - if (inc != 0) - m_range = octave::range<double> (bas, lim, inc); + swap_bytes<sizeof (T)> (&inc); + if (inc != T (0)) + m_range = octave::range<T> (bas, lim, inc); else { octave_idx_type numel = static_cast<octave_idx_type> (lim); - m_range = octave::range<double>::make_constant (bas, numel); + m_range = octave::range<T>::make_constant (bas, numel); } return true; @@ -629,23 +762,25 @@ // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary // conversions are handled automatically by HDF5. +template <typename T> static hid_t hdf5_make_range_type (hid_t num_type) { - hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3); + hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (T) * 3); - H5Tinsert (type_id, "base", 0 * sizeof (double), num_type); - H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type); - H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type); + H5Tinsert (type_id, "base", 0 * sizeof (T), num_type); + H5Tinsert (type_id, "limit", 1 * sizeof (T), num_type); + H5Tinsert (type_id, "increment", 2 * sizeof (T), num_type); return type_id; } #endif +template <typename T> bool -octave_range::save_hdf5 (octave_hdf5_id loc_id, const char *name, - bool /* save_as_floats */) +ov_range<T>::save_hdf5 (octave_hdf5_id loc_id, const char *name, + bool /* save_as_floats */) { bool retval = false; @@ -658,7 +793,7 @@ space_hid = H5Screate_simple (0, dimens, nullptr); if (space_hid < 0) return false; - type_hid = hdf5_make_range_type (H5T_NATIVE_DOUBLE); + type_hid = hdf5_make_range_type<T> (hdf5_save_type); if (type_hid < 0) { H5Sclose (space_hid); @@ -677,10 +812,10 @@ return false; } - octave::range<double> r = range_value (); - double range_vals[3]; + octave::range<T> r = m_range; + T range_vals[3]; range_vals[0] = r.base (); - range_vals[1] = (r.increment () != 0 ? r.limit () : r.numel ()); + range_vals[1] = (r.increment () != T (0) ? r.limit () : r.numel ()); range_vals[2] = r.increment (); if (H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, @@ -708,8 +843,9 @@ return retval; } +template <typename T> bool -octave_range::load_hdf5 (octave_hdf5_id loc_id, const char *name) +ov_range<T>::load_hdf5 (octave_hdf5_id loc_id, const char *name) { bool retval = false; @@ -722,7 +858,7 @@ #endif hid_t type_hid = H5Dget_type (data_hid); - hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE); + hid_t range_type = hdf5_make_range_type<T> (hdf5_save_type); if (! hdf5_types_compatible (type_hid, range_type)) { @@ -742,7 +878,7 @@ return false; } - double rangevals[3]; + T rangevals[3]; if (H5Dread (data_hid, range_type, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT, rangevals) >= 0) @@ -751,13 +887,12 @@ // Don't use OCTAVE_RANGE_NELEM attribute, just reconstruct the range. - if (rangevals[2] != 0) - m_range = octave::range<double> (rangevals[0], rangevals[1], - rangevals[2]); + if (rangevals[2] != T (0)) + m_range = octave::range<T> (rangevals[0], rangevals[1], rangevals[2]); else { octave_idx_type numel = static_cast<octave_idx_type> (rangevals[1]); - m_range = octave::range<double>::make_constant (rangevals[0], numel); + m_range = octave::range<T>::make_constant (rangevals[0], numel); } } @@ -775,18 +910,22 @@ return retval; } +template <typename T> mxArray * -octave_range::as_mxArray (bool interleaved) const +ov_range<T>::as_mxArray (bool interleaved) const { - mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, dims (), mxREAL); + mxClassID mx_class = mx_type_traits<T>::mx_class; - mxDouble *pd = static_cast<mxDouble *> (retval->get_data ()); + mxArray *retval = new mxArray (interleaved, mx_class, dims (), mxREAL); + + typedef typename mx_type_traits<T>::mx_type mx_type; + mx_type *pd = static_cast<mx_type *> (retval->get_data ()); mwSize nel = numel (); - Matrix m = matrix_value (); + Array<T> matrix = raw_array_value (); - const double *pdata = m.data (); + const T *pdata = matrix.data (); for (mwSize i = 0; i < nel; i++) pd[i] = pdata[i]; @@ -794,8 +933,138 @@ return retval; } +template <typename T> octave_value -octave_range::fast_elem_extract (octave_idx_type n) const +ov_range<T>::fast_elem_extract (octave_idx_type n) const { return (n < numel () ? octave_value (m_range.elem (n)) : octave_value ()); } + +// Specializations. + +template <> +octave::range<float> +ov_range<float>::float_range_value (void) const +{ + return m_range; +} + +template <> +octave::range<double> +ov_range<double>::range_value (void) const +{ + return m_range; +} + +template <> +octave::range<octave_int8> +ov_range<octave_int8>::int8_range_value (void) const +{ + return m_range; +} + +template <> +octave::range<octave_int16> +ov_range<octave_int16>::int16_range_value (void) const +{ + return m_range; +} + +template <> +octave::range<octave_int32> +ov_range<octave_int32>::int32_range_value (void) const +{ + return m_range; +} + +template <> +octave::range<octave_int64> +ov_range<octave_int64>::int64_range_value (void) const +{ + return m_range; +} + +template <> +octave::range<octave_uint8> +ov_range<octave_uint8>::uint8_range_value (void) const +{ + return m_range; +} + +template <> +octave::range<octave_uint16> +ov_range<octave_uint16>::uint16_range_value (void) const +{ + return m_range; +} + +template <> +octave::range<octave_uint32> +ov_range<octave_uint32>::uint32_range_value (void) const +{ + return m_range; +} + +template <> +octave::range<octave_uint64> +ov_range<octave_uint64>::uint64_range_value (void) const +{ + return m_range; +} + +template <> +idx_vector +ov_range<double>::index_vector (bool require_integers) const +{ + if (m_idx_cache) + return *m_idx_cache; + + if (require_integers || m_range.all_elements_are_ints ()) + return set_idx_cache (idx_vector (m_range)); + + warning_with_id ("Octave:noninteger-range-as-index", + "non-integer range used as index"); + + return octave_value (matrix_value ()).round ().index_vector (); +} + +template <> +octave_idx_type +ov_range<double>::nnz (void) const +{ + return m_range.nnz (); +} + +// The following specialization is also historical baggage. For double +// ranges, we can produce special double-valued diagnoal matrix objects +// but Octave currently provides only double and Complex diagonal matrix +// objects. + +template <> +octave_value +ov_range<double>::diag (octave_idx_type k) const +{ + // FIXME: this is a potential waste of memory. + + return + (k == 0 + ? octave_value (DiagMatrix (DiagArray2<double> (matrix_value ()))) + : octave_value (m_range.diag (k))); +} + +template <> +octave_value +ov_range<double>::diag (octave_idx_type nr, octave_idx_type nc) const +{ + Matrix mat = matrix_value (); + + return mat.diag (nr, nc); +} + +template <> +void +ov_range<double>::print_raw (std::ostream& os, bool pr_as_read_syntax) const +{ + octave_print_internal (os, m_range, pr_as_read_syntax, + current_print_indent_level ()); +}
--- a/libinterp/octave-value/ov-range.h Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/octave-value/ov-range.h Wed Aug 12 12:14:17 2020 -0400 @@ -43,6 +43,7 @@ #include "error.h" #include "oct-stream.h" #include "ov-base.h" +#include "ov-range-traits.h" #include "ov-re-mat.h" #include "ov-typeinfo.h" @@ -51,136 +52,57 @@ // Range values. template <typename T> -octave::range<double> -make_double_range (const octave::range<T>& r) -{ - return octave::range<double> (static_cast<double> (r.base ()), - static_cast<double> (r.increment ()), - static_cast<double> (r.limit ()), - static_cast<double> (r.final_value ()), - r.numel ()); -} - class -octave_range : public octave_base_value +ov_range : public octave_base_value { public: - octave_range (void) + ov_range (void) : octave_base_value (), m_range (), m_idx_cache () { } - octave_range (const octave::range<float>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave::range<double>& r) + ov_range (const octave::range<T>& r) : octave_base_value (), m_range (r), m_idx_cache () { if (numel () < 0 && numel () != -2) error ("invalid range"); } - octave_range (const octave::range<octave_int8>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave::range<octave_int16>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave::range<octave_int32>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave::range<octave_int64>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave::range<octave_uint8>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave::range<octave_uint16>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave::range<octave_uint32>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave::range<octave_uint64>& r) - : octave_base_value (), m_range (make_double_range (r)), m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (double base, double limit, double increment) - : octave_base_value (), m_range (base, limit, increment), m_idx_cache () - { - if (numel () < 0) - error ("invalid range"); - } - - octave_range (const Range& r) - : octave_base_value (), - m_range (r.base (), r.increment (), r.limit (), r.numel ()), - m_idx_cache () - { - if (numel () < 0 && numel () != -2) - error ("invalid range"); - } - - octave_range (const octave_range& r) + ov_range (const ov_range<T>& r) : octave_base_value (), m_range (r.m_range), m_idx_cache (r.m_idx_cache ? new idx_vector (*r.m_idx_cache) : nullptr) { } - octave_range (const Range& r, const idx_vector& cache) - : octave_base_value (), - m_range (r.base (), r.increment (), r.limit (), r.numel ()), - m_idx_cache () + ov_range (const octave::range<T>& r, const idx_vector& cache) + : octave_base_value (), m_range (r), m_idx_cache () { set_idx_cache (cache); } - ~octave_range (void) { clear_cached_info (); } + // No assignment. + ov_range& operator = (const ov_range&) = delete; + + ~ov_range (void) { clear_cached_info (); } - octave_base_value * clone (void) const { return new octave_range (*this); } + octave_base_value * clone (void) const + { + return new ov_range (*this); + } // A range is really just a special kind of real matrix object. In // the places where we need to call empty_clone, it makes more sense // to create an empty matrix (0x0) instead of an empty range (1x0). - octave_base_value * empty_clone (void) const { return new octave_matrix (); } + + octave_base_value * empty_clone (void) const + { + return new typename octave_value_range_traits<T>::matrix_type (); + } type_conv_info numeric_conversion_function (void) const; octave_base_value * try_narrowing_conversion (void); + builtin_type_t builtin_type (void) const { return class_to_btyp<T>::btyp; } + // We don't need to override all three forms of subsref. The using // declaration will avoid warnings about partially-overloaded virtual // functions. @@ -206,21 +128,31 @@ octave_idx_type numel (void) const { return m_range.numel (); } - octave_idx_type nnz (void) const { return m_range.nnz (); } + octave_idx_type nnz (void) const + { + // FIXME: this is a potential waste of memory. + + octave_value tmp (raw_array_value ()); + return tmp.nnz (); + } octave_value resize (const dim_vector& dv, bool fill = false) const; - size_t byte_size (void) const { return 3 * sizeof (double); } + size_t byte_size (void) const { return 3 * sizeof (T); } octave_value reshape (const dim_vector& new_dims) const - { return NDArray (array_value ().reshape (new_dims)); } + { + return raw_array_value ().reshape (new_dims); + } octave_value permute (const Array<int>& vec, bool inv = false) const - { return NDArray (array_value ().permute (vec, inv)); } + { + return raw_array_value ().permute (vec, inv); + } octave_value squeeze (void) const { return m_range; } - octave_value full_value (void) const { return matrix_value (); } + octave_value full_value (void) const { return raw_array_value (); } bool is_defined (void) const { return true; } @@ -228,69 +160,142 @@ bool is_range (void) const { return true; } - octave_value all (int dim = 0) const; + bool is_double_type (void) const { return builtin_type () == btyp_double; } + + bool is_single_type (void) const { return builtin_type () == btyp_float; } + + bool isfloat (void) const { return btyp_isfloat (builtin_type ()); } + + bool is_int8_type (void) const { return builtin_type () == btyp_int8; } + + bool is_int16_type (void) const { return builtin_type () == btyp_int16; } + + bool is_int32_type (void) const { return builtin_type () == btyp_int32; } + + bool is_int64_type (void) const { return builtin_type () == btyp_int64; } + + bool is_uint8_type (void) const { return builtin_type () == btyp_uint8; } + + bool is_uint16_type (void) const { return builtin_type () == btyp_uint16; } - octave_value any (int dim = 0) const; + bool is_uint32_type (void) const { return builtin_type () == btyp_uint32; } + + bool is_uint64_type (void) const { return builtin_type () == btyp_uint64; } + + bool isinteger (void) const + { + return btyp_isinteger (builtin_type ()); + } + + bool isreal (void) const { return isfloat (); } + + bool isnumeric (void) const + { + return btyp_isnumeric (builtin_type ()); + } + + bool is_true (void) const { return nnz () == numel (); } - octave_value diag (octave_idx_type k = 0) const; + octave_value all (int dim = 0) const + { + // FIXME: this is a potential waste of memory. + + typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type; + typename ov_mx_type::object_type m (raw_array_value ()); + + return m.all (dim); + } + + octave_value any (int dim = 0) const + { + // FIXME: this is a potential waste of memory. + + typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type; + typename ov_mx_type::object_type m (raw_array_value ()); - octave_value diag (octave_idx_type m, octave_idx_type n) const; + return m.any (dim); + } + + octave_value diag (octave_idx_type k = 0) const + { + // FIXME: this is a potential waste of memory. + + return m_range.diag (k); + } + + octave_value diag (octave_idx_type nr, octave_idx_type nc) const + { + // FIXME: this is a potential waste of memory. + + typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type; + typename ov_mx_type::object_type m (raw_array_value ()); + + return m.diag (nr, nc); + } octave_value sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const { - Matrix tmp = matrix_value (); + Array<T> tmp = raw_array_value (); return tmp.sort (dim, mode); } octave_value sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0, sortmode mode = ASCENDING) const { - Matrix tmp = matrix_value (); + Array<T> tmp = raw_array_value (); return tmp.sort (sidx, dim, mode); } sortmode issorted (sortmode mode = UNSORTED) const - { return m_range.issorted (mode); } + { + return m_range.issorted (mode); + } Array<octave_idx_type> sort_rows_idx (sortmode) const - { return Array<octave_idx_type> (dim_vector (1, 0)); } + { + return Array<octave_idx_type> (dim_vector (1, 0)); + } sortmode is_sorted_rows (sortmode mode = UNSORTED) const - { return (mode == UNSORTED) ? ASCENDING : mode; } - - builtin_type_t builtin_type (void) const { return btyp_double; } - - bool isreal (void) const { return true; } + { + return (mode == UNSORTED) ? ASCENDING : mode; + } - bool is_double_type (void) const { return true; } - - bool isfloat (void) const { return true; } - - bool isnumeric (void) const { return true; } - - bool is_true (void) const; + Array<T> raw_array_value (void) const { return m_range.array_value (); } double double_value (bool = false) const; float float_value (bool = false) const; double scalar_value (bool frc_str_conv = false) const - { return double_value (frc_str_conv); } + { + return double_value (frc_str_conv); + } float float_scalar_value (bool frc_str_conv = false) const - { return float_value (frc_str_conv); } + { + return float_value (frc_str_conv); + } Matrix matrix_value (bool = false) const - { return m_range.array_value (); } + { + return raw_array_value (); + } FloatMatrix float_matrix_value (bool = false) const - { return matrix_value (); } + { + return raw_array_value (); + } NDArray array_value (bool = false) const - { return matrix_value (); } + { + return raw_array_value (); + } FloatNDArray float_array_value (bool = false) const - { return FloatMatrix (matrix_value ()); } + { + return raw_array_value (); + } charNDArray char_array_value (bool = false) const; @@ -298,35 +303,55 @@ // functions to avoid the intermediate conversion to a matrix // object. - int8NDArray - int8_array_value (void) const { return int8NDArray (array_value ()); } + int8NDArray int8_array_value (void) const + { + return raw_array_value (); + } - int16NDArray - int16_array_value (void) const { return int16NDArray (array_value ()); } + int16NDArray int16_array_value (void) const + { + return raw_array_value (); + } - int32NDArray - int32_array_value (void) const { return int32NDArray (array_value ()); } + int32NDArray int32_array_value (void) const + { + return raw_array_value (); + } - int64NDArray - int64_array_value (void) const { return int64NDArray (array_value ()); } + int64NDArray int64_array_value (void) const + { + return raw_array_value (); + } - uint8NDArray - uint8_array_value (void) const { return uint8NDArray (array_value ()); } + uint8NDArray uint8_array_value (void) const + { + return raw_array_value (); + } - uint16NDArray - uint16_array_value (void) const { return uint16NDArray (array_value ()); } + uint16NDArray uint16_array_value (void) const + { + return raw_array_value (); + } - uint32NDArray - uint32_array_value (void) const { return uint32NDArray (array_value ()); } + uint32NDArray uint32_array_value (void) const + { + return raw_array_value (); + } - uint64NDArray - uint64_array_value (void) const { return uint64NDArray (array_value ()); } + uint64NDArray uint64_array_value (void) const + { + return raw_array_value (); + } SparseMatrix sparse_matrix_value (bool = false) const - { return SparseMatrix (matrix_value ()); } + { + return SparseMatrix (matrix_value ()); + } SparseComplexMatrix sparse_complex_matrix_value (bool = false) const - { return SparseComplexMatrix (sparse_matrix_value ()); } + { + return SparseComplexMatrix (complex_matrix_value ()); + } Complex complex_value (bool = false) const; @@ -335,18 +360,44 @@ boolNDArray bool_array_value (bool warn = false) const; ComplexMatrix complex_matrix_value (bool = false) const - { return ComplexMatrix (matrix_value ()); } + { + return raw_array_value (); + } FloatComplexMatrix float_complex_matrix_value (bool = false) const - { return FloatComplexMatrix (matrix_value ()); } + { + return raw_array_value (); + } ComplexNDArray complex_array_value (bool = false) const - { return ComplexMatrix (matrix_value ()); } + { + return raw_array_value (); + } FloatComplexNDArray float_complex_array_value (bool = false) const - { return FloatComplexMatrix (matrix_value ()); } + { + return raw_array_value (); + } + + octave::range<float> float_range_value (void) const; + + octave::range<double> range_value (void) const; + + octave::range<octave_int8> int8_range_value (void) const; + + octave::range<octave_int16> int16_range_value (void) const; - octave::range<double> range_value (void) const { return m_range; } + octave::range<octave_int32> int32_range_value (void) const; + + octave::range<octave_int64> int64_range_value (void) const; + + octave::range<octave_uint8> uint8_range_value (void) const; + + octave::range<octave_uint16> uint16_range_value (void) const; + + octave::range<octave_uint32> uint32_range_value (void) const; + + octave::range<octave_uint64> uint64_range_value (void) const; octave_value convert_to_str_internal (bool pad, bool force, char type) const; @@ -385,7 +436,7 @@ bool load_binary (std::istream& is, bool swap, octave::mach_info::float_format fmt); - bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats); + bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool flag); bool load_hdf5 (octave_hdf5_id loc_id, const char *name); @@ -403,15 +454,15 @@ octave_value map (unary_mapper_t umap) const { - octave_matrix m (matrix_value ()); - return m.map (umap); + octave_value tmp (raw_array_value ()); + return tmp.map (umap); } octave_value fast_elem_extract (octave_idx_type n) const; -private: +protected: - octave::range<double> m_range; + octave::range<T> m_range; idx_vector set_idx_cache (const idx_vector& idx) const { @@ -427,25 +478,106 @@ mutable idx_vector *m_idx_cache; - // No assignment. - - octave_range& operator = (const octave_range&); + static octave_hdf5_id hdf5_save_type; DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA }; -typedef octave_range octave_float_range; -typedef octave_range octave_double_range; +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, float) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, double) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int8) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int16) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int32) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int64) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint8) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint16) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint32) +DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint64) + +// Specializations. + +template <> +octave::range<float> +ov_range<float>::float_range_value (void) const; + +template <> +octave::range<double> +ov_range<double>::range_value (void) const; + +template <> +octave::range<octave_int8> +ov_range<octave_int8>::int8_range_value (void) const; + +template <> +octave::range<octave_int16> +ov_range<octave_int16>::int16_range_value (void) const; + +template <> +octave::range<octave_int32> +ov_range<octave_int32>::int32_range_value (void) const; + +template <> +octave::range<octave_int64> +ov_range<octave_int64>::int64_range_value (void) const; -typedef octave_range octave_int8_range; -typedef octave_range octave_int16_range; -typedef octave_range octave_int32_range; -typedef octave_range octave_int64_range; +template <> +octave::range<octave_uint8> +ov_range<octave_uint8>::uint8_range_value (void) const; + +template <> +octave::range<octave_uint16> +ov_range<octave_uint16>::uint16_range_value (void) const; + +template <> +octave::range<octave_uint32> +ov_range<octave_uint32>::uint32_range_value (void) const; + +template <> +octave::range<octave_uint64> +ov_range<octave_uint64>::uint64_range_value (void) const; + +// The following specializations are here to preserve previous Range +// performance until solutions can be generalized for other types. -typedef octave_range octave_uint8_range; -typedef octave_range octave_uint16_range; -typedef octave_range octave_uint32_range; -typedef octave_range octave_uint64_range; +template <> +idx_vector +ov_range<double>::index_vector (bool require_integers) const; + +template <> +octave_idx_type +ov_range<double>::nnz (void) const; + +// The following specialization is also historical baggage. For double +// ranges, we can produce special double-valued diagnoal matrix objects +// but Octave currently provides only double and Complex diagonal matrix +// objects. + +template <> +octave_value +ov_range<double>::diag (octave_idx_type k) const; + +template <> +octave_value +ov_range<double>::diag (octave_idx_type nr, octave_idx_type nc) const; + +template <> +void +ov_range<double>::print_raw (std::ostream& os, bool pr_as_read_syntax) const; +typedef ov_range<float> octave_float_range; +typedef ov_range<double> octave_double_range; + +typedef ov_range<octave_int8> octave_int8_range; +typedef ov_range<octave_int16> octave_int16_range; +typedef ov_range<octave_int32> octave_int32_range; +typedef ov_range<octave_int64> octave_int64_range; + +typedef ov_range<octave_uint8> octave_uint8_range; +typedef ov_range<octave_uint16> octave_uint16_range; +typedef ov_range<octave_uint32> octave_uint32_range; +typedef ov_range<octave_uint64> octave_uint64_range; + +typedef octave_double_range octave_range; + #endif
--- a/libinterp/octave-value/ov.cc Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/octave-value/ov.cc Wed Aug 12 12:14:17 2020 -0400 @@ -1069,7 +1069,7 @@ } octave_value::octave_value (double base, double limit, double inc) - : rep (new octave_range (base, limit, inc)) + : rep (new ov_range<double> (octave::range<double> (base, inc, limit))) { maybe_mutate (); } @@ -1081,7 +1081,7 @@ error ("invalid range"); if (force_range || ! Vdisable_range) - rep = dynamic_cast<octave_base_value *> (new octave_range (r)); + rep = dynamic_cast<octave_base_value *> (new ov_range<double> (octave::range<double> (r.base (), r.increment (), r.limit ()))); else rep = dynamic_cast<octave_base_value *> (new octave_matrix (r.matrix_value ())); @@ -1107,7 +1107,7 @@ octave_value::octave_value (const octave::range<float>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_float_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<float> (r)) : dynamic_cast<octave_base_value *> (new octave_float_matrix (r.array_value ()))) { maybe_mutate (); @@ -1115,7 +1115,7 @@ octave_value::octave_value (const octave::range<double>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_double_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<double> (r)) : dynamic_cast<octave_base_value *> (new octave_matrix (r.array_value ()))) { maybe_mutate (); @@ -1124,7 +1124,7 @@ octave_value::octave_value (const octave::range<octave_int8>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_int8_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<octave_int8> (r)) : dynamic_cast<octave_base_value *> (new octave_int8_matrix (r.array_value ()))) { maybe_mutate (); @@ -1133,7 +1133,7 @@ octave_value::octave_value (const octave::range<octave_int16>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_int16_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<octave_int16> (r)) : dynamic_cast<octave_base_value *> (new octave_int16_matrix (r.array_value ()))) { maybe_mutate (); @@ -1142,7 +1142,7 @@ octave_value::octave_value (const octave::range<octave_int32>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_int32_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<octave_int32> (r)) : dynamic_cast<octave_base_value *> (new octave_int32_matrix (r.array_value ()))) { maybe_mutate (); @@ -1151,7 +1151,7 @@ octave_value::octave_value (const octave::range<octave_int64>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_int64_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<octave_int64> (r)) : dynamic_cast<octave_base_value *> (new octave_int64_matrix (r.array_value ()))) { maybe_mutate (); @@ -1160,7 +1160,7 @@ octave_value::octave_value (const octave::range<octave_uint8>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_uint8_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint8> (r)) : dynamic_cast<octave_base_value *> (new octave_uint8_matrix (r.array_value ()))) { maybe_mutate (); @@ -1169,7 +1169,7 @@ octave_value::octave_value (const octave::range<octave_uint16>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_uint16_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint16> (r)) : dynamic_cast<octave_base_value *> (new octave_uint16_matrix (r.array_value ()))) { maybe_mutate (); @@ -1178,7 +1178,7 @@ octave_value::octave_value (const octave::range<octave_uint32>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_uint32_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint32> (r)) : dynamic_cast<octave_base_value *> (new octave_uint32_matrix (r.array_value ()))) { maybe_mutate (); @@ -1187,7 +1187,7 @@ octave_value::octave_value (const octave::range<octave_uint64>& r, bool force_range) : rep (force_range || ! Vdisable_range - ? dynamic_cast<octave_base_value *> (new octave_uint64_range (r)) + ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint64> (r)) : dynamic_cast<octave_base_value *> (new octave_uint64_matrix (r.array_value ()))) { maybe_mutate (); @@ -2193,7 +2193,16 @@ XVALUE_EXTRACTOR (Cell, xcell_value, cell_value) XVALUE_EXTRACTOR (Array<std::string>, xcellstr_value, cellstr_value) +XVALUE_EXTRACTOR (octave::range<float>, xfloat_range_value, float_range_value) XVALUE_EXTRACTOR (octave::range<double>, xrange_value, range_value) +XVALUE_EXTRACTOR (octave::range<octave_int8>, xint8_range_value, int8_range_value) +XVALUE_EXTRACTOR (octave::range<octave_int16>, xint16_range_value, int16_range_value) +XVALUE_EXTRACTOR (octave::range<octave_int32>, xint32_range_value, int32_range_value) +XVALUE_EXTRACTOR (octave::range<octave_int64>, xint64_range_value, int64_range_value) +XVALUE_EXTRACTOR (octave::range<octave_uint8>, xuint8_range_value, uint8_range_value) +XVALUE_EXTRACTOR (octave::range<octave_uint16>, xuint16_range_value, uint16_range_value) +XVALUE_EXTRACTOR (octave::range<octave_uint32>, xuint32_range_value, uint32_range_value) +XVALUE_EXTRACTOR (octave::range<octave_uint64>, xuint64_range_value, uint64_range_value) XVALUE_EXTRACTOR (octave_map, xmap_value, map_value) XVALUE_EXTRACTOR (octave_scalar_map, xscalar_map_value, scalar_map_value) @@ -3174,7 +3183,16 @@ octave_diag_matrix::register_type (ti); octave_complex_matrix::register_type (ti); octave_complex_diag_matrix::register_type (ti); - octave_range::register_type (ti); + ov_range<float>::register_type (ti); + ov_range<double>::register_type (ti); + ov_range<octave_int8>::register_type (ti); + ov_range<octave_int16>::register_type (ti); + ov_range<octave_int32>::register_type (ti); + ov_range<octave_int64>::register_type (ti); + ov_range<octave_uint8>::register_type (ti); + ov_range<octave_uint16>::register_type (ti); + ov_range<octave_uint32>::register_type (ti); + ov_range<octave_uint64>::register_type (ti); octave_bool::register_type (ti); octave_bool_matrix::register_type (ti); octave_char_matrix_str::register_type (ti);
--- a/libinterp/octave-value/ov.h Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/octave-value/ov.h Wed Aug 12 12:14:17 2020 -0400 @@ -950,9 +950,36 @@ Array<std::string> cellstr_value (void) const { return rep->cellstr_value (); } + octave::range<float> float_range_value (void) const + { return rep->float_range_value (); } + octave::range<double> range_value (void) const { return rep->range_value (); } + octave::range<octave_int8> int8_range_value (void) const + { return rep->int8_range_value (); } + + octave::range<octave_int16> int16_range_value (void) const + { return rep->int16_range_value (); } + + octave::range<octave_int32> int32_range_value (void) const + { return rep->int32_range_value (); } + + octave::range<octave_int64> int64_range_value (void) const + { return rep->int64_range_value (); } + + octave::range<octave_uint8> uint8_range_value (void) const + { return rep->uint8_range_value (); } + + octave::range<octave_uint16> uint16_range_value (void) const + { return rep->uint16_range_value (); } + + octave::range<octave_uint32> uint32_range_value (void) const + { return rep->uint32_range_value (); } + + octave::range<octave_uint64> uint64_range_value (void) const + { return rep->uint64_range_value (); } + octave_map map_value (void) const; octave_scalar_map scalar_map_value (void) const; @@ -1162,8 +1189,26 @@ Array<std::string> xcellstr_value (const char *fmt, ...) const; + octave::range<float> xfloat_range_value (const char *fmt, ...) const; + octave::range<double> xrange_value (const char *fmt, ...) const; + octave::range<octave_int8> xint8_range_value (const char *fmt, ...) const; + + octave::range<octave_int16> xint16_range_value (const char *fmt, ...) const; + + octave::range<octave_int32> xint32_range_value (const char *fmt, ...) const; + + octave::range<octave_int64> xint64_range_value (const char *fmt, ...) const; + + octave::range<octave_uint8> xuint8_range_value (const char *fmt, ...) const; + + octave::range<octave_uint16> xuint16_range_value (const char *fmt, ...) const; + + octave::range<octave_uint32> xuint32_range_value (const char *fmt, ...) const; + + octave::range<octave_uint64> xuint64_range_value (const char *fmt, ...) const; + octave_map xmap_value (const char *fmt, ...) const; octave_scalar_map xscalar_map_value (const char *fmt, ...) const;
--- a/libinterp/parse-tree/pt-eval.cc Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/parse-tree/pt-eval.cc Wed Aug 12 12:14:17 2020 -0400 @@ -2490,6 +2490,36 @@ } } + template <typename T> + void + tree_evaluator::execute_range_loop (const range<T>& rng, size_t line, + octave_lvalue& ult, + tree_statement_list *loop_body) + { + octave_idx_type steps = rng.numel (); + + if (octave::math::isinf (rng.limit ())) + warning_with_id ("Octave:infinite-loop", + "FOR loop limit is infinite, will stop after %" + OCTAVE_IDX_TYPE_FORMAT " steps", steps); + + for (octave_idx_type i = 0; i < steps; i++) + { + if (m_echo_state) + m_echo_file_pos = line; + + octave_value val (rng.elem (i)); + + ult.assign (octave_value::op_asn_eq, val); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + } + void tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) { @@ -2529,33 +2559,70 @@ if (rhs.is_range ()) { - octave::range<double> rng = rhs.range_value (); - - octave_idx_type steps = rng.numel (); - - if (octave::math::isinf (rng.limit ())) - warning_with_id ("Octave:infinite-loop", - "FOR loop limit is infinite, will stop after %" - OCTAVE_IDX_TYPE_FORMAT " steps", - steps); - - for (octave_idx_type i = 0; i < steps; i++) + // FIXME: is there a better way to dispatch here? + + if (rhs.is_double_type ()) + { + execute_range_loop (rhs.range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_int64_type ()) + { + execute_range_loop (rhs.int64_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_uint64_type ()) + { + execute_range_loop (rhs.uint64_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_int32_type ()) + { + execute_range_loop (rhs.int32_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_uint32_type ()) { - if (m_echo_state) - m_echo_file_pos = line; - - octave_value val (rng.elem (i)); - - ult.assign (octave_value::op_asn_eq, val); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; + execute_range_loop (rhs.uint32_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_int16_type ()) + { + execute_range_loop (rhs.int16_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_uint16_type ()) + { + execute_range_loop (rhs.uint16_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_int8_type ()) + { + execute_range_loop (rhs.int8_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_uint8_type ()) + { + execute_range_loop (rhs.uint8_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_single_type ()) + { + execute_range_loop (rhs.float_range_value (), line, ult, loop_body); + return; } } - else if (rhs.is_scalar_type ()) + + if (rhs.is_scalar_type ()) { if (m_echo_state) m_echo_file_pos = line; @@ -2567,9 +2634,15 @@ // Maybe decrement break and continue states. quit_loop_now (); + + return; } - else if (rhs.is_matrix_type () || rhs.iscell () || rhs.is_string () - || rhs.isstruct ()) + + // Also handle any range types not explicitly handled above, though + // not as efficiently as the specialized code above. + + if (rhs.is_range () || rhs.is_matrix_type () || rhs.iscell () + || rhs.is_string () || rhs.isstruct ()) { // A matrix or cell is reshaped to 2 dimensions and iterated by // columns. @@ -2624,10 +2697,12 @@ // Handle empty cases, while still assigning to loop var. ult.assign (octave_value::op_asn_eq, arg); } + + return; } - else - error ("invalid type in for loop expression near line %d, column %d", - cmd.line (), cmd.column ()); + + error ("invalid type in for loop expression near line %d, column %d", + cmd.line (), cmd.column ()); } void
--- a/libinterp/parse-tree/pt-eval.h Thu Aug 20 17:42:26 2020 -0400 +++ b/libinterp/parse-tree/pt-eval.h Wed Aug 12 12:14:17 2020 -0400 @@ -717,6 +717,11 @@ private: + template <typename T> + void execute_range_loop (const range<T>& rng, size_t line, + octave_lvalue& ult, + tree_statement_list *loop_body); + void set_echo_state (int type, const std::string& file_name, size_t pos); void maybe_set_echo_state (void);
--- a/liboctave/array/Range.h Thu Aug 20 17:42:26 2020 -0400 +++ b/liboctave/array/Range.h Wed Aug 12 12:14:17 2020 -0400 @@ -139,7 +139,7 @@ // clearer to see "make_constant" instead of puzzling over the // purpose of this strange constructor form. - T final_val = base + double (numel - 1) * increment; + T final_val = base + (numel - 1) * increment; return range<T> (base, increment, final_val, numel); } @@ -298,7 +298,7 @@ retval(0) = m_base; for (octave_idx_type i = 1; i < nel - 1; i++) - retval.xelem (i) = m_base + double (i) * m_increment; + retval.xelem (i) = m_base + i * m_increment; retval.xelem (nel - 1) = final_value (); } @@ -337,7 +337,7 @@ T get_final_value (void) const { - return m_base + double (m_numel - 1) * m_increment; + return m_base + (m_numel - 1) * m_increment; } };