changeset 30854:eba0a86471b9

maint: Merge stable to default.
author John W. Eaton <jwe@octave.org>
date Tue, 22 Mar 2022 00:06:09 -0400
parents a0e13472457d (current diff) fc3bd70cd1be (diff)
children 1be26e9c07e3
files libinterp/corefcn/data.cc libinterp/octave-value/ov-base.h libinterp/octave-value/ov-range.cc libinterp/octave-value/ov-typeinfo.cc libinterp/octave-value/ov.cc libinterp/octave-value/ov.h
diffstat 12 files changed, 477 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/data.cc	Sat Mar 19 11:00:13 2022 -0300
+++ b/libinterp/corefcn/data.cc	Tue Mar 22 00:06:09 2022 -0400
@@ -4227,14 +4227,6 @@
     case oct_data_conv::dt_double:
       if (iscomplex)
         retval = ComplexNDArray (dims, Complex (val, 0));
-      else if (dims.ndims () == 2 && dims(0) == 1)
-        {
-          // FIXME: If this optimization provides a significant
-          // benefit, then maybe there should be a special storage
-          // type for constant value arrays.
-          double dval = static_cast<double> (val);
-          retval = range<double>::make_constant (dval, dims(1));
-        }
       else
         retval = NDArray (dims, val);
       break;
@@ -4338,11 +4330,6 @@
     case oct_data_conv::dt_double:
       if (iscomplex)
         retval = ComplexNDArray (dims, Complex (val, 0));
-      else if (dims.ndims () == 2 && dims(0) == 1 && math::isfinite (val))
-        // FIXME: If this optimization provides a significant benefit,
-        // then maybe there should be a special storage type for
-        // constant value arrays.
-        retval = range<double>::make_constant (val, dims(1));
       else
         retval = NDArray (dims, val);
       break;
@@ -4407,13 +4394,7 @@
       break;
 
     case oct_data_conv::dt_double:
-      if (dims.ndims () == 2 && dims(0) == 1 && math::isfinite (val))
-        // FIXME: If this optimization provides a significant benefit,
-        // then maybe there should be a special storage type for
-        // constant value arrays.
-        retval = range<double>::make_constant (val, dims(1));
-      else
-        retval = NDArray (dims, val);
+      retval = NDArray (dims, val);
       break;
 
     default:
--- a/libinterp/octave-value/module.mk	Sat Mar 19 11:00:13 2022 -0300
+++ b/libinterp/octave-value/module.mk	Tue Mar 22 00:06:09 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 \
--- a/libinterp/octave-value/ov-base.h	Sat Mar 19 11:00:13 2022 -0300
+++ b/libinterp/octave-value/ov-base.h	Tue Mar 22 00:06:09 2022 -0400
@@ -387,6 +387,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 (); }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-legacy-range.cc	Tue Mar 22 00:06:09 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 <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 (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <istream>
+#include <ostream>
+#include <sstream>
+
+#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<const octave_legacy_range&> (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<double> (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<octave_idx_type> (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<char *> (&tmp), 1))
+    return false;
+  double bas, lim, inc;
+  if (! is.read (reinterpret_cast<char *> (&bas), 8))
+    return false;
+  if (swap)
+    swap_bytes<8> (&bas);
+  if (! is.read (reinterpret_cast<char *> (&lim), 8))
+    return false;
+  if (swap)
+    swap_bytes<8> (&lim);
+  if (! is.read (reinterpret_cast<char *> (&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<octave_idx_type> (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<octave_idx_type> (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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-legacy-range.h	Tue Mar 22 00:06:09 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 <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_legacy_range_h)
+#define octave_ov_legacy_range_h 1
+
+#include "octave-config.h"
+
+#include <cstdlib>
+
+#include <iosfwd>
+#include <string>
+
+#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
--- a/libinterp/octave-value/ov-range.cc	Sat Mar 19 11:00:13 2022 -0300
+++ b/libinterp/octave-value/ov-range.cc	Tue Mar 22 00:06:09 2022 -0400
@@ -143,7 +143,7 @@
 #endif
 
 DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<double>,
-                                              "range", "double");
+                                              "double_range", "double");
 
 // For now, disable all but ov_range<double>.
 
@@ -766,13 +766,7 @@
   if (! is)
     error ("load: failed to load range constant");
 
-  if (inc != T (0))
-    r = octave::range<T> (base, inc, limit, rev);
-  else
-    {
-      octave_idx_type numel = static_cast<octave_idx_type> (limit);
-      r = octave::range<T>::make_constant (base, numel, rev);
-    }
+  r = octave::range<T> (base, inc, limit, rev);
 
   return true;
 }
@@ -946,13 +940,8 @@
       if (swap)
         swap_bytes<sizeof (bool)> (&rev);
     }
-  if (inc != T (0))
-    r = octave::range<T> (bas, inc, lim, rev);
-  else
-    {
-      octave_idx_type numel = static_cast<octave_idx_type> (lim);
-      r = octave::range<T>::make_constant (bas, numel, rev);
-    }
+
+  r = octave::range<T> (bas, inc, lim, rev);
 
   return true;
 }
@@ -1281,13 +1270,7 @@
 
       bool rev = with_reverse ? static_cast<bool> (rangevals[3]) : false;
 
-      if (rangevals[2] != T (0))
-        r = octave::range<T> (rangevals[0], rangevals[2], rangevals[1], rev);
-      else
-        {
-          octave_idx_type numel = static_cast<octave_idx_type> (rangevals[1]);
-          r = octave::range<T>::make_constant (rangevals[0], numel, rev);
-        }
+      r = octave::range<T> (rangevals[0], rangevals[2], rangevals[1], rev);
     }
 
   H5Tclose (range_type);
--- a/libinterp/octave-value/ov-typeinfo.cc	Sat Mar 19 11:00:13 2022 -0300
+++ b/libinterp/octave-value/ov-typeinfo.cc	Tue Mar 22 00:06:09 2022 -0400
@@ -951,7 +951,7 @@
 
 %!test
 %! if (optimize_range ())
-%!   assert (typeinfo (1:2), "range")
+%!   assert (typeinfo (1:2), "double_range")
 %! else
 %!   assert (typeinfo (1:2), "matrix")
 %! endif
--- a/libinterp/octave-value/ov.cc	Sat Mar 19 11:00:13 2022 -0300
+++ b/libinterp/octave-value/ov.cc	Tue Mar 22 00:06:09 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<octave_base_value *>
-    (new ov_range<double> (octave::range<double> (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<octave_base_value *> (new octave_legacy_range (r));
   else
     return dynamic_cast<octave_base_value *> (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<double>::register_type (ti);
 
   // For now, disable all but ov_range<double>.
@@ -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")
 */
 
--- a/libinterp/octave-value/ov.h	Sat Mar 19 11:00:13 2022 -0300
+++ b/libinterp/octave-value/ov.h	Tue Mar 22 00:06:09 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,
--- a/liboctave/array/Range.h	Sat Mar 19 11:00:13 2022 -0300
+++ b/liboctave/array/Range.h	Tue Mar 22 00:06:09 2022 -0400
@@ -76,14 +76,11 @@
     }
 
     // Allow conversion from (presumably) properly constructed Range
-    // objects and to create constant ranges (see the static
-    // make_constant method).  The values of base, limit, increment,
-    // and numel must be consistent.
+    // objects.  The values of base, limit, increment, and numel must be
+    // consistent.
 
     // FIXME: Actually check that base, limit, increment, and numel are
-    // consistent.
-
-    // FIXME: Is there a way to limit this to T == double?
+    // consistent?
 
     range (const T& base, const T& increment, const T& limit,
            octave_idx_type numel, bool reverse = false)
@@ -91,26 +88,6 @@
         m_final (limit), m_numel (numel), m_reverse (reverse)
     { }
 
-    range (const T& base, const T& increment, const T& limit,
-           const T& final, octave_idx_type numel, bool reverse = false)
-      : m_base (base), m_increment (increment), m_limit (limit),
-        m_final (final), m_numel (numel), m_reverse (reverse)
-    { }
-
-    // We don't use a constructor for this because it will conflict with
-    // range<T> (base, limit) when T is octave_idx_type.
-
-    static range<T> make_constant (const T& base, octave_idx_type numel,
-                                   bool reverse = false)
-    {
-      // We could just make this constructor public, but it allows
-      // inconsistent ranges to be constructed.  And it is probably much
-      // clearer to see "make_constant" instead of puzzling over the
-      // purpose of this strange constructor form.
-
-      return range<T> (base, T (), base, numel, reverse);
-    }
-
     // We don't use a constructor for this because it will conflict with
     // range<T> (base, limit, increment) when T is octave_idx_type.
 
@@ -120,7 +97,7 @@
     {
       // We could just make this constructor public, but it allows
       // inconsistent ranges to be constructed.  And it is probably much
-      // clearer to see "make_constant" instead of puzzling over the
+      // clearer to see "make_n_element_range" instead of puzzling over the
       // purpose of this strange constructor form.
 
       T final_val = (reverse ? base - (numel - 1) * increment
@@ -423,7 +400,6 @@
 {
 public:
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
   OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (void)
     : m_base (0), m_limit (0), m_inc (0), m_numel (0)
@@ -439,7 +415,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 +422,6 @@
 
   ~Range (void) = default;
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
   OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (double b, double l)
     : m_base (b), m_limit (l), m_inc (1), m_numel (numel_internal ())
@@ -477,7 +451,6 @@
     if (! octave::math::isinf (m_limit))
       m_limit = limit_internal ();
   }
-#endif
 
   // The range has a finite number of elements.
   bool ok (void) const
--- a/test/mk-conv-tst.sh	Sat Mar 19 11:00:13 2022 -0300
+++ b/test/mk-conv-tst.sh	Tue Mar 22 00:06:09 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
--- a/test/range.tst	Sat Mar 19 11:00:13 2022 -0300
+++ b/test/range.tst	Tue Mar 22 00:06:09 2022 -0400
@@ -611,17 +611,30 @@
 %!test  # ascending ranges
 %! types = {"int8", "int16", "int32", "int64"};
 %! for i_type = 1:numel (types)
-%!   assert (intmin (types{i_type}) : double (intmax (types{i_type})) + 1 : intmax (types{i_type}), ...
+%!   assert (intmin (types{i_type}) : -double (intmin (types{i_type})) : intmax (types{i_type}), ...
 %!           [intmin(types{i_type}), 0]);
+%!   ## FIXME: This test leads to a deadlock for "int64".
+%!   ## assert (intmin (types{i_type}) : -2*double (intmin (types{i_type})) : intmax (types{i_type}), ...
+%!   ##         intmin (types{i_type}));
+%!   if (! strcmp (types, "int64"))
+%!     ## The increment cannot be represented in double precision for "int64"
+%!     assert (intmin (types{i_type}) : 2*double (intmax (types{i_type})) : intmin (types{i_type}), ...
+%!             [intmin(types{i_type}), intmax(types{i_type})-1]);
+%!   endif
 %! endfor
 %!test  # descending ranges
 %! types = {"int8", "int16", "int32", "int64"};
 %! for i_type = 1:numel (types)
 %!   assert (intmax (types{i_type}) : double (intmin (types{i_type})) : intmin (types{i_type}), ...
 %!           [intmax(types{i_type}), -1]);
-%!   ## FIXME: This leads to a deadlock for "int64".
-%!   ## assert (intmax (types{i_type}) : -2*double (intmax (types{i_type})) : intmin (types{i_type}), ...
-%!   ##         [intmax(types{i_type}), -intmax(types{i_type})]);
+%!   ## FIXME: This test leads to a deadlock for "int64".
+%!   ## assert (intmax (types{i_type}) : 2*double (intmin (types{i_type})) : intmin (types{i_type}), ...
+%!   ##         intmax (types{i_type}));
+%!   if (! strcmp (types, "int64"))
+%!     ## The increment cannot be represented in double precision for "int64"
+%!     assert (intmax (types{i_type}) : -2*double (intmax (types{i_type})) : intmin (types{i_type}), ...
+%!             [intmax(types{i_type}), -intmax(types{i_type})]);
+%!   endif
 %! endfor
 
 ## integer range near intmax