# HG changeset patch # User John W. Eaton # Date 1647921515 14400 # Node ID 95725e6ad9c12beb8eb3ce1234c2bf18c9dd1c9f # Parent 82c1554c4a643716c54a52aecade370fb8432f53 restore part of the old octave_range class as octave_legacy_range This change allows old range objects to be loaded from data files and then converted to the new range type or other numeric types. * libinterp/octave-value/ov-legacy-range.h, libinterp/octave-value/ov-legacy-range.cc: New files restored from old versions of ov-range.h and ov-range.cc. Only provide enough support to load "range" objects from data files. * libinterp/octave-value/module.mk: Update. * ov.h, ov.cc: Update tests. (octave_value::is_legacy_object): New function. (octave_value::load_ascii, octave_value::load_binary, octave_value::load_hdf5): If loaded value is a legacy object, call maybe_mutate to allow conversion to a currently supported data type. (install_types): Register octave_legacy_range objects. (octave_value::make_range_rep_deprecated): Convert to Don't allow (const Range& r, bool force_range) (octave_value::make_range_rep_deprecated): Use Range constructor. Allow mutation to handle conversion to new range object or other numeric types. * ov-base.h (octave_base_value::is_legacy_object): New function * ov-range.cc: Rename ov_range data type from "range" to "double_range". * Range.h (Range::Range): Always provide deprecated Range constructors. * ov-typeinfo.cc: Update test. * mk-conv-tst.sh: Update tests. diff -r 82c1554c4a64 -r 95725e6ad9c1 libinterp/octave-value/module.mk --- a/libinterp/octave-value/module.mk Sat Mar 19 16:55:30 2022 +0100 +++ b/libinterp/octave-value/module.mk Mon Mar 21 23:58:35 2022 -0400 @@ -53,6 +53,7 @@ %reldir%/ov-flt-re-mat.h \ %reldir%/ov-java.h \ %reldir%/ov-lazy-idx.h \ + %reldir%/ov-legacy-range.h \ %reldir%/ov-magic-int.h \ %reldir%/ov-mex-fcn.h \ %reldir%/ov-null-mat.h \ @@ -119,6 +120,7 @@ %reldir%/ov-flt-re-mat.cc \ %reldir%/ov-java.cc \ %reldir%/ov-lazy-idx.cc \ + %reldir%/ov-legacy-range.cc \ %reldir%/ov-magic-int.cc \ %reldir%/ov-mex-fcn.cc \ %reldir%/ov-null-mat.cc \ diff -r 82c1554c4a64 -r 95725e6ad9c1 libinterp/octave-value/ov-base.h --- a/libinterp/octave-value/ov-base.h Sat Mar 19 16:55:30 2022 +0100 +++ b/libinterp/octave-value/ov-base.h Mon Mar 21 23:58:35 2022 -0400 @@ -386,6 +386,8 @@ virtual bool is_storable (void) const { return true; } + virtual bool is_legacy_object (void) const { return false; } + bool isempty (void) const { return (dims ().any_zero ()); } bool is_zero_by_zero (void) const { return dims().zero_by_zero (); } diff -r 82c1554c4a64 -r 95725e6ad9c1 libinterp/octave-value/ov-legacy-range.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-legacy-range.cc Mon Mar 21 23:58:35 2022 -0400 @@ -0,0 +1,275 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 1996-2022 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or . +// +// 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 +// . +// +//////////////////////////////////////////////////////////////////////// + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#include +#include +#include + +#include "lo-ieee.h" +#include "lo-utils.h" + +#include "variables.h" +#include "error.h" +#include "ovl.h" +#include "oct-hdf5.h" +#include "ov-legacy-range.h" +#include "ov-range.h" +#include "ov-re-mat.h" +#include "ov-scalar.h" +#include "pr-output.h" + +#include "byte-swap.h" +#include "ls-ascii-helper.h" +#include "ls-hdf5.h" +#include "ls-utils.h" + +#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_legacy_range, "range", "double"); + +octave_legacy_range::octave_legacy_range (void) + : octave_base_value (), range () { } + +octave_legacy_range::octave_legacy_range (const Range& r) + : octave_base_value (), range (r) +{ + if (range.numel () < 0 && range.numel () != -2) + error ("invalid range"); +} + +static octave_base_value * +default_numeric_conversion_function (const octave_base_value& a) +{ + const octave_legacy_range& v = dynamic_cast (a); + + return new octave_matrix (v.matrix_value ()); +} + +octave_base_value::type_conv_info +octave_legacy_range::numeric_conversion_function (void) const +{ + return octave_base_value::type_conv_info (default_numeric_conversion_function, + octave_matrix::static_type_id ()); +} + +octave_base_value * +octave_legacy_range::try_narrowing_conversion (void) +{ + octave_base_value *retval = nullptr; + + switch (range.numel ()) + { + case 1: + retval = new octave_scalar (range.base ()); + break; + + case 0: + retval = new octave_matrix (Matrix (1, 0)); + break; + + case -2: + retval = new octave_matrix (range.matrix_value ()); + break; + + default: + { + if (range.increment () == 0) + retval = new octave_matrix (range.matrix_value ()); + else + retval = new octave_range + (octave::range (range.base (), range.increment (), + range.limit (), range.numel ())); + } + break; + } + + return retval; +} + +// Skip white space and comments on stream IS. + +static void +skip_comments (std::istream& is) +{ + char c = '\0'; + while (is.get (c)) + { + if (c == ' ' || c == '\t' || c == '\n') + ; // Skip whitespace on way to beginning of next line. + else + break; + } + + octave::skip_until_newline (is, false); +} + +bool +octave_legacy_range::load_ascii (std::istream& is) +{ + // # base, limit, range comment added by save (). + skip_comments (is); + + double base, limit, inc; + is >> base >> limit >> inc; + + if (! is) + error ("load: failed to load range constant"); + + if (inc != 0) + range = Range (base, limit, inc); + else + range = Range (base, inc, static_cast (limit)); + + return true; +} + +bool +octave_legacy_range::load_binary (std::istream& is, bool swap, + octave::mach_info::float_format /* fmt */) +{ + char tmp; + if (! is.read (reinterpret_cast (&tmp), 1)) + return false; + double bas, lim, inc; + if (! is.read (reinterpret_cast (&bas), 8)) + return false; + if (swap) + swap_bytes<8> (&bas); + if (! is.read (reinterpret_cast (&lim), 8)) + return false; + if (swap) + swap_bytes<8> (&lim); + if (! is.read (reinterpret_cast (&inc), 8)) + return false; + if (swap) + swap_bytes<8> (&inc); + if (inc != 0) + range = Range (bas, lim, inc); + else + range = Range (bas, inc, static_cast (lim)); + + return true; +} + +#if defined (HAVE_HDF5) + +// The following subroutines creates an HDF5 representation of the way +// we will store Octave range types (triplets of floating-point numbers). +// NUM_TYPE is the HDF5 numeric type to use for storage (e.g. +// H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary +// conversions are handled automatically by HDF5. + +static hid_t +hdf5_make_range_type (hid_t num_type) +{ + hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 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); + + return type_id; +} + +#endif + +bool +octave_legacy_range::load_hdf5 (octave_hdf5_id loc_id, const char *name) +{ + bool retval = false; + +#if defined (HAVE_HDF5) + +#if defined (HAVE_HDF5_18) + hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT); +#else + hid_t data_hid = H5Dopen (loc_id, name); +#endif + hid_t type_hid = H5Dget_type (data_hid); + + hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE); + + if (! hdf5_types_compatible (type_hid, range_type)) + { + H5Tclose (range_type); + H5Dclose (data_hid); + return false; + } + + hid_t space_hid = H5Dget_space (data_hid); + hsize_t rank = H5Sget_simple_extent_ndims (space_hid); + + if (rank != 0) + { + H5Tclose (range_type); + H5Sclose (space_hid); + H5Dclose (data_hid); + return false; + } + + double rangevals[3]; + if (H5Dread (data_hid, range_type, octave_H5S_ALL, octave_H5S_ALL, + octave_H5P_DEFAULT, rangevals) + >= 0) + { + retval = true; + octave_idx_type nel; + if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX, + "OCTAVE_RANGE_NELEM", &nel)) + range = Range (rangevals[0], rangevals[2], nel); + else + { + if (rangevals[2] != 0) + range = Range (rangevals[0], rangevals[1], rangevals[2]); + else + range = Range (rangevals[0], rangevals[2], + static_cast (rangevals[1])); + } + } + + H5Tclose (range_type); + H5Sclose (space_hid); + H5Dclose (data_hid); + +#else + octave_unused_parameter (loc_id); + octave_unused_parameter (name); + + warn_load ("hdf5"); +#endif + + return retval; +} + +#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) +# pragma GCC diagnostic pop +#endif diff -r 82c1554c4a64 -r 95725e6ad9c1 libinterp/octave-value/ov-legacy-range.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-legacy-range.h Mon Mar 21 23:58:35 2022 -0400 @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 1996-2022 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or . +// +// 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 +// . +// +//////////////////////////////////////////////////////////////////////// + +#if ! defined (octave_ov_legacy_range_h) +#define octave_ov_legacy_range_h 1 + +#include "octave-config.h" + +#include + +#include +#include + +#include "Range.h" + +#include "lo-mappers.h" +#include "lo-utils.h" +#include "mx-base.h" + +#include "error.h" +#include "oct-stream.h" +#include "ov-base.h" +#include "ov-re-mat.h" +#include "ov-typeinfo.h" + +class octave_value_list; + +// Legacy Range values. + +// Provide enough of the old octave_range class to allow Range objects +// to be loaded from files. After loading, they are converted to some +// other type by a call to octave_value::maybe_mutate in +// load_save_system::load_vars so there should no longer be any values +// of this type used by the interpreter. The action of maybe_mutate is +// performed by octave_legacy_range::try_narrowing_conversion. + +class +octave_legacy_range : public octave_base_value +{ +public: + + octave_legacy_range (void); + + octave_legacy_range (const Range& r); + + octave_legacy_range (const octave_legacy_range& r) = default; + + // No assignment. + + octave_legacy_range& operator = (const octave_legacy_range&) = delete; + + ~octave_legacy_range (void) { } + + octave_base_value * clone (void) const + { + return new octave_legacy_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 (); } + + type_conv_info numeric_conversion_function (void) const; + + octave_base_value * try_narrowing_conversion (void); + + bool is_defined (void) const { return true; } + + bool is_legacy_object (void) const { return true; } + + bool is_constant (void) const { return true; } + + bool load_ascii (std::istream& is); + + bool load_binary (std::istream& is, bool swap, + octave::mach_info::float_format fmt); + + bool load_hdf5 (octave_hdf5_id loc_id, const char *name); + +private: + + Range range; + + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA +}; + +#endif diff -r 82c1554c4a64 -r 95725e6ad9c1 libinterp/octave-value/ov-range.cc --- a/libinterp/octave-value/ov-range.cc Sat Mar 19 16:55:30 2022 +0100 +++ b/libinterp/octave-value/ov-range.cc Mon Mar 21 23:58:35 2022 -0400 @@ -143,7 +143,7 @@ #endif DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range, - "range", "double"); + "double_range", "double"); // For now, disable all but ov_range. diff -r 82c1554c4a64 -r 95725e6ad9c1 libinterp/octave-value/ov-typeinfo.cc --- a/libinterp/octave-value/ov-typeinfo.cc Sat Mar 19 16:55:30 2022 +0100 +++ b/libinterp/octave-value/ov-typeinfo.cc Mon Mar 21 23:58:35 2022 -0400 @@ -948,7 +948,7 @@ %!test %! if (optimize_range ()) -%! assert (typeinfo (1:2), "range") +%! assert (typeinfo (1:2), "double_range") %! else %! assert (typeinfo (1:2), "matrix") %! endif diff -r 82c1554c4a64 -r 95725e6ad9c1 libinterp/octave-value/ov.cc --- a/libinterp/octave-value/ov.cc Sat Mar 19 16:55:30 2022 +0100 +++ b/libinterp/octave-value/ov.cc Mon Mar 21 23:58:35 2022 -0400 @@ -48,6 +48,7 @@ #include "ov-flt-re-mat.h" #include "ov-re-diag.h" #include "ov-flt-re-diag.h" +#include "ov-legacy-range.h" #include "ov-perm.h" #include "ov-bool-sparse.h" #include "ov-cx-sparse.h" @@ -1076,8 +1077,17 @@ octave_base_value * octave_value::make_range_rep_deprecated (double base, double inc, double limit) { +#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + return dynamic_cast - (new ov_range (octave::range (base, inc, limit))); + (new octave_legacy_range (Range (base, inc, limit))); + +#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) +# pragma GCC diagnostic pop +#endif } // Remove when public constructor that uses this function is removed. @@ -1087,8 +1097,8 @@ if (! force_range && ! r.ok ()) error ("invalid range"); - if (force_range || Voptimize_range) - return make_range_rep_deprecated (r.base (), r.increment (), r.limit ()); + if ((force_range || Voptimize_range)) + return dynamic_cast (new octave_legacy_range (r)); else return dynamic_cast (new octave_matrix (r.matrix_value ())); } @@ -2350,6 +2360,39 @@ m_rep->print_info (os, prefix + ' '); } +bool octave_value::load_ascii (std::istream& is) +{ + bool status = m_rep->load_ascii (is); + + // Force conversion of legacy objects. + if (is_legacy_object ()) + maybe_mutate (); + + return status; +} +bool octave_value::load_binary (std::istream& is, bool swap, + octave::mach_info::float_format fmt) +{ + bool status = m_rep->load_binary (is, swap, fmt); + + // Force conversion of legacy objects. + if (is_legacy_object ()) + maybe_mutate (); + + return status; +} + +bool octave_value::load_hdf5 (octave_hdf5_id loc_id, const char *name) +{ + bool status = m_rep->load_hdf5 (loc_id, name); + + // Force conversion of legacy objects. + if (is_legacy_object ()) + maybe_mutate (); + + return status; +} + const void * octave_value::mex_get_data (mxClassID class_id, mxComplexity complexity) const { @@ -3595,6 +3638,11 @@ octave_diag_matrix::register_type (ti); octave_complex_matrix::register_type (ti); octave_complex_diag_matrix::register_type (ti); + + // Legacy range type, preserved to allow loading "constant" ranges + // from data files. + octave_legacy_range::register_type (ti); + ov_range::register_type (ti); // For now, disable all but ov_range. @@ -4078,7 +4126,7 @@ %! r = base:limit; %!endfunction -%!assert (typeinfo (__test_dr__ (true)), "range") +%!assert (typeinfo (__test_dr__ (true)), "double_range") %!assert (typeinfo (__test_dr__ (false)), "matrix") */ diff -r 82c1554c4a64 -r 95725e6ad9c1 libinterp/octave-value/ov.h --- a/libinterp/octave-value/ov.h Sat Mar 19 16:55:30 2022 +0100 +++ b/libinterp/octave-value/ov.h Mon Mar 21 23:58:35 2022 -0400 @@ -640,6 +640,9 @@ bool is_undefined (void) const { return ! is_defined (); } + bool is_legacy_object (void) const + { return m_rep->is_legacy_object (); } + bool isempty (void) const { return m_rep->isempty (); } @@ -1483,21 +1486,19 @@ bool save_ascii (std::ostream& os) { return m_rep->save_ascii (os); } - bool load_ascii (std::istream& is) { return m_rep->load_ascii (is); } + OCTINTERP_API bool load_ascii (std::istream& is); bool save_binary (std::ostream& os, bool save_as_floats) { return m_rep->save_binary (os, save_as_floats); } - bool load_binary (std::istream& is, bool swap, - octave::mach_info::float_format fmt) - { return m_rep->load_binary (is, swap, fmt); } + OCTINTERP_API 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) { return m_rep->save_hdf5 (loc_id, name, save_as_floats); } - bool load_hdf5 (octave_hdf5_id loc_id, const char *name) - { return m_rep->load_hdf5 (loc_id, name); } + OCTINTERP_API bool load_hdf5 (octave_hdf5_id loc_id, const char *name); OCTINTERP_API int write (octave::stream& os, int block_size, diff -r 82c1554c4a64 -r 95725e6ad9c1 liboctave/array/Range.h --- a/liboctave/array/Range.h Sat Mar 19 16:55:30 2022 +0100 +++ b/liboctave/array/Range.h Mon Mar 21 23:58:35 2022 -0400 @@ -423,7 +423,6 @@ { public: -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) OCTAVE_DEPRECATED (7, "use the 'octave::range' class instead") Range (void) : m_base (0), m_limit (0), m_inc (0), m_numel (0) @@ -439,7 +438,6 @@ : m_base (r.base ()), m_limit (r.final_value ()), m_inc (r.increment ()), m_numel (r.numel ()) { } -#endif Range (const Range& r) = default; @@ -447,7 +445,6 @@ ~Range (void) = default; -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) OCTAVE_DEPRECATED (7, "use the 'octave::range' class instead") Range (double b, double l) : m_base (b), m_limit (l), m_inc (1), m_numel (numel_internal ()) @@ -477,7 +474,6 @@ if (! octave::math::isinf (m_limit)) m_limit = limit_internal (); } -#endif // The range has a finite number of elements. bool ok (void) const diff -r 82c1554c4a64 -r 95725e6ad9c1 test/mk-conv-tst.sh --- a/test/mk-conv-tst.sh Sat Mar 19 16:55:30 2022 +0100 +++ b/test/mk-conv-tst.sh Mon Mar 21 23:58:35 2022 -0400 @@ -73,7 +73,7 @@ %! %!test %! if (optimize_range ()) -%! assert (typeinfo (r), "range") +%! assert (typeinfo (r), "double_range") %! else %! assert (typeinfo (r), "matrix") %! endif