changeset 28628:83172e1c77f2

refactor octave_read_* and octave_write_* functions * lo-utils.h, lo-utils.cc (read_value): Define inside octave namespace and rename from octave_read_value. (write_value): New template. (octave_read_double, octave_read_float, octave_read_complex, octave_read_float_complex, octave_write_double, octave_write_float, octave_write_complex, octave_write_float_complex): Deprecate. Change all uses to use octave::read_value<T> and octave::write_value<T> functions instead.
author John W. Eaton <jwe@octave.org>
date Tue, 11 Aug 2020 15:20:01 -0400
parents 0da2fbd3a642
children af361aea02e0
files libinterp/corefcn/dlmread.cc libinterp/corefcn/ls-mat-ascii.cc libinterp/corefcn/oct-stream.cc libinterp/octave-value/ov-bool.cc libinterp/octave-value/ov-complex.cc libinterp/octave-value/ov-float.cc libinterp/octave-value/ov-flt-complex.cc libinterp/octave-value/ov-range.cc libinterp/octave-value/ov-scalar.cc liboctave/array/CMatrix.cc liboctave/array/CNDArray.cc liboctave/array/CSparse.cc liboctave/array/Range.cc liboctave/array/boolSparse.cc liboctave/array/dMatrix.cc liboctave/array/dNDArray.cc liboctave/array/dSparse.cc liboctave/array/fCMatrix.cc liboctave/array/fCNDArray.cc liboctave/array/fMatrix.cc liboctave/array/fNDArray.cc liboctave/util/lo-utils.cc liboctave/util/lo-utils.h
diffstat 23 files changed, 340 insertions(+), 294 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/dlmread.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/corefcn/dlmread.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -443,7 +443,7 @@
           tmp_stream.str (str);
           tmp_stream.clear ();
 
-          double x = octave_read_double (tmp_stream);
+          double x = octave::read_value<double> (tmp_stream);
           if (tmp_stream)
             {
               if (tmp_stream.eof ())
@@ -485,7 +485,7 @@
                     }
                   else
                     {
-                      double y = octave_read_double (tmp_stream);
+                      double y = octave::read_value<double> (tmp_stream);
 
                       if (! iscmplx && y != 0.0)
                         {
@@ -502,7 +502,7 @@
             }
           else
             {
-              // octave_read_double() parsing failed
+              // octave::read_value<double>() parsing failed
               j++;  // Leave data initialized to empty_value
             }
 
--- a/libinterp/corefcn/ls-mat-ascii.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/corefcn/ls-mat-ascii.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -154,7 +154,7 @@
                 {
                   std::istringstream tmp_stream (buf.substr (beg, end-beg));
 
-                  octave_read_double (tmp_stream);
+                  octave::read_value<double> (tmp_stream);
 
                   if (tmp_stream.fail ())
                     {
@@ -285,7 +285,7 @@
         {
           octave_quit ();
 
-          d = octave_read_value<double> (tmp_stream);
+          d = octave::read_value<double> (tmp_stream);
 
           if (! tmp_stream && ! tmp_stream.eof ())
             error ("load: failed to read matrix from file '%s'",
@@ -381,7 +381,7 @@
                 {
                   // Omit leading tabs.
                   if (j != 0) os << '\t';
-                  octave_write_double (os, m(i, j));
+                  octave::write_value<double> (os, m(i, j));
                 }
               os << "\n";
             }
--- a/libinterp/corefcn/oct-stream.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/corefcn/oct-stream.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -2960,7 +2960,7 @@
       {
         char *pos = is.tellg ();
         std::ios::iostate state = is.rdstate ();
-        //re = octave_read_value<double> (is);
+        //re = octave::read_value<double> (is);
         re = read_double (is, fmt);
 
         // check for "treat as empty" string
@@ -3025,7 +3025,7 @@
                 pos   = is.tellg ();
                 state = is.rdstate ();
 
-                //im = octave_read_value<double> (is);
+                //im = octave::read_value<double> (is);
                 im = read_double (is, fmt);
                 if (is.fail ())
                   im = 1;
@@ -4370,7 +4370,7 @@
             {
               is.putback (c1);
 
-              ref = octave_read_value<double> (is);
+              ref = octave::read_value<double> (is);
             }
         }
         break;
--- a/libinterp/octave-value/ov-bool.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/octave-value/ov-bool.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -188,7 +188,7 @@
 {
   double d = double_value ();
 
-  octave_write_double (os, d);
+  octave::write_value<double> (os, d);
   os << "\n";
 
   return true;
@@ -197,7 +197,7 @@
 bool
 octave_bool::load_ascii (std::istream& is)
 {
-  scalar = (octave_read_value<double> (is) != 0.0);
+  scalar = (octave::read_value<double> (is) != 0.0);
 
   if (! is)
     error ("load: failed to load scalar constant");
--- a/libinterp/octave-value/ov-complex.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/octave-value/ov-complex.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -313,7 +313,7 @@
 {
   Complex c = complex_value ();
 
-  octave_write_complex (os, c);
+  octave::write_value<Complex> (os, c);
 
   os << "\n";
 
@@ -323,7 +323,7 @@
 bool
 octave_complex::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<Complex> (is);
+  scalar = octave::read_value<Complex> (is);
 
   if (! is)
     error ("load: failed to load complex scalar constant");
--- a/libinterp/octave-value/ov-float.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/octave-value/ov-float.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -200,7 +200,7 @@
 {
   float d = float_value ();
 
-  octave_write_float (os, d);
+  octave::write_value<float> (os, d);
 
   os << "\n";
 
@@ -210,7 +210,7 @@
 bool
 octave_float_scalar::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<float> (is);
+  scalar = octave::read_value<float> (is);
   if (! is)
     error ("load: failed to load scalar constant");
 
--- a/libinterp/octave-value/ov-flt-complex.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/octave-value/ov-flt-complex.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -254,7 +254,7 @@
 {
   FloatComplex c = float_complex_value ();
 
-  octave_write_float_complex (os, c);
+  octave::write_value<FloatComplex> (os, c);
 
   os << "\n";
 
@@ -264,7 +264,7 @@
 bool
 octave_float_complex::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<FloatComplex> (is);
+  scalar = octave::read_value<FloatComplex> (is);
 
   if (! is)
     error ("load: failed to load complex scalar constant");
--- a/libinterp/octave-value/ov-range.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/octave-value/ov-range.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -535,14 +535,14 @@
   else
     os << "# base, length, increment\n";
 
-  octave_write_double (os, base);
+  octave::write_value<double> (os, base);
   os << ' ';
   if (inc != 0)
-    octave_write_double (os, limit);
+    octave::write_value<double> (os, limit);
   else
     os << len;
   os << ' ';
-  octave_write_double (os, inc);
+  octave::write_value<double> (os, inc);
   os << "\n";
 
   return true;
--- a/libinterp/octave-value/ov-scalar.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/libinterp/octave-value/ov-scalar.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -219,7 +219,7 @@
 {
   double d = double_value ();
 
-  octave_write_double (os, d);
+  octave::write_value<double> (os, d);
 
   os << "\n";
 
@@ -229,7 +229,7 @@
 bool
 octave_scalar::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<double> (is);
+  scalar = octave::read_value<double> (is);
 
   if (! is)
     error ("load: failed to load scalar constant");
--- a/liboctave/array/CMatrix.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/CMatrix.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -3168,7 +3168,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_complex (os, a.elem (i, j));
+          octave::write_value<Complex> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -3187,7 +3187,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<Complex> (is);
+            tmp = octave::read_value<Complex> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/CNDArray.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/CNDArray.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -601,7 +601,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_complex (os, a.elem (i));
+      octave::write_value<Complex> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -617,7 +617,7 @@
       Complex tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<Complex> (is);
+          tmp = octave::read_value<Complex> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/CSparse.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/CSparse.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -7487,7 +7487,7 @@
       for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++)
         {
           os << a.ridx (i) + 1 << ' '  << j + 1 << ' ';
-          octave_write_complex (os, a.data (i));
+          octave::write_value<Complex> (os, a.data (i));
           os << "\n";
         }
     }
@@ -7500,7 +7500,7 @@
 {
   typedef SparseComplexMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<Complex>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<Complex>);
 }
 
 SparseComplexMatrix
--- a/liboctave/array/Range.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/Range.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -91,16 +91,19 @@
 {
   Matrix retval (1, m_numel);
 
-  // The first element must always be *exactly* the base.
-  // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
-  retval(0) = m_base;
+  if (m_numel > 0)
+    {
+      // The first element must always be *exactly* the base.
+      // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
+      retval(0) = m_base;
 
-  double b = m_base;
-  double increment = m_inc;
-  for (octave_idx_type i = 1; i < m_numel - 1; i++)
-    retval.xelem (i) = b + i * increment;
+      double b = m_base;
+      double increment = m_inc;
+      for (octave_idx_type i = 1; i < m_numel - 1; i++)
+        retval.xelem (i) = b + i * increment;
 
-  retval.xelem (m_numel - 1) = m_limit;
+      retval.xelem (m_numel - 1) = m_limit;
+    }
 
   return retval;
 }
--- a/liboctave/array/boolSparse.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/boolSparse.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -282,7 +282,7 @@
 {
   typedef SparseBoolMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<bool>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<bool>);
 }
 
 SparseBoolMatrix
--- a/liboctave/array/dMatrix.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/dMatrix.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -2637,7 +2637,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_double (os, a.elem (i, j));
+          octave::write_value<double> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -2656,7 +2656,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<double> (is);
+            tmp = octave::read_value<double> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/dNDArray.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/dNDArray.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -626,7 +626,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_double (os, a.elem (i));
+      octave::write_value<double> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -642,7 +642,7 @@
       double tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<double> (is);
+          tmp = octave::read_value<double> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/dSparse.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/dSparse.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -7493,7 +7493,7 @@
       for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++)
         {
           os << a.ridx (i) + 1 << ' '  << j + 1 << ' ';
-          octave_write_double (os, a.data (i));
+          octave::write_value<double> (os, a.data (i));
           os << "\n";
         }
     }
@@ -7506,7 +7506,7 @@
 {
   typedef SparseMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<double>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<double>);
 }
 
 SparseMatrix
--- a/liboctave/array/fCMatrix.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/fCMatrix.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -3200,7 +3200,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_complex (os, a.elem (i, j));
+          octave::write_value<Complex> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -3219,7 +3219,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<FloatComplex> (is);
+            tmp = octave::read_value<FloatComplex> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/fCNDArray.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/fCNDArray.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -616,7 +616,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_complex (os, a.elem (i));
+      octave::write_value<Complex> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -632,7 +632,7 @@
       FloatComplex tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<FloatComplex> (is);
+          tmp = octave::read_value<FloatComplex> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/fMatrix.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/fMatrix.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -2647,7 +2647,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_float (os, a.elem (i, j));
+          octave::write_value<float> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -2666,7 +2666,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<float> (is);
+            tmp = octave::read_value<float> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/fNDArray.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/array/fNDArray.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -594,7 +594,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_float (os, a.elem (i));
+      octave::write_value<float> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -610,7 +610,7 @@
       float tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<float> (is);
+          tmp = octave::read_value<float> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/util/lo-utils.cc	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/util/lo-utils.cc	Tue Aug 11 15:20:01 2020 -0400
@@ -187,244 +187,253 @@
   return retval;
 }
 
-// Note that the caller is responsible for repositioning the stream on failure.
+namespace octave
+{
+  // Note that the caller is responsible for repositioning the stream on
+  // failure.
+
+  template <typename T>
+  T
+  read_inf_nan_na (std::istream& is, char c0)
+  {
+    T val = 0.0;
+
+    switch (c0)
+      {
+      case 'i': case 'I':
+        {
+          char c1 = is.get ();
+          if (c1 == 'n' || c1 == 'N')
+            {
+              char c2 = is.get ();
+              if (c2 == 'f' || c2 == 'F')
+                val = std::numeric_limits<T>::infinity ();
+              else
+                is.setstate (std::ios::failbit);
+            }
+          else
+            is.setstate (std::ios::failbit);
+        }
+        break;
 
-template <typename T>
-T
-read_inf_nan_na (std::istream& is, char c0)
-{
-  T val = 0.0;
+      case 'n': case 'N':
+        {
+          char c1 = is.get ();
+          if (c1 == 'a' || c1 == 'A')
+            {
+              char c2 = is.get ();
+              if (c2 == 'n' || c2 == 'N')
+                val = std::numeric_limits<T>::quiet_NaN ();
+              else
+                {
+                  val = octave::numeric_limits<T>::NA ();
+                  if (c2 != std::istream::traits_type::eof ())
+                    is.putback (c2);
+                  else
+                    is.clear (is.rdstate () & ~std::ios::failbit);
+                }
+            }
+          else
+            is.setstate (std::ios::failbit);
+        }
+        break;
+
+      default:
+        (*current_liboctave_error_handler)
+          ("read_inf_nan_na: invalid character '%c'", c0);
+      }
+
+    return val;
+  }
+
+  // Read a double value.  Discard any sign on NaN and NA.
+
+  template <typename T>
+  double
+  read_fp_value (std::istream& is)
+  {
+    T val = 0.0;
+
+    // FIXME: resetting stream position is likely to fail unless we are
+    // reading from a file.
+    std::streampos pos = is.tellg ();
+
+    char c1 = ' ';
+
+    while (isspace (c1))
+      c1 = is.get ();
+
+    bool neg = false;
 
-  switch (c0)
-    {
-    case 'i': case 'I':
+    switch (c1)
+      {
+      case '-':
+        neg = true;
+        OCTAVE_FALLTHROUGH;
+
+      case '+':
+        {
+          char c2 = 0;
+          c2 = is.get ();
+          if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
+            val = read_inf_nan_na<T> (is, c2);
+          else
+            {
+              is.putback (c2);
+              is >> val;
+            }
+
+          if (neg && ! is.fail ())
+            val = -val;
+        }
+        break;
+
+      case 'i': case 'I':
+      case 'n': case 'N':
+        val = read_inf_nan_na<T> (is, c1);
+        break;
+
+      default:
+        is.putback (c1);
+        is >> val;
+        break;
+      }
+
+    std::ios::iostate status = is.rdstate ();
+    if (status & std::ios::failbit)
       {
-        char c1 = is.get ();
-        if (c1 == 'n' || c1 == 'N')
+        // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
+        if (val == std::numeric_limits<T>::max ())
+          {
+            if (neg)
+              val = -std::numeric_limits<T>::infinity ();
+            else
+              val = std::numeric_limits<T>::infinity ();
+            is.clear (status & ~std::ios::failbit);
+          }
+        else
           {
-            char c2 = is.get ();
-            if (c2 == 'f' || c2 == 'F')
-              val = std::numeric_limits<T>::infinity ();
+            // True error.  Reset stream to original position and pass status on.
+            is.clear ();
+            is.seekg (pos);
+            is.setstate (status);
+          }
+      }
+
+    return val;
+  }
+
+  template <typename T>
+  std::complex<T>
+  read_cx_fp_value (std::istream& is)
+  {
+    T re = 0.0;
+    T im = 0.0;
+
+    std::complex<T> cx = 0.0;
+
+    char ch = ' ';
+
+    while (isspace (ch))
+      ch = is.get ();
+
+    if (ch == '(')
+      {
+        re = read_value<T> (is);
+        ch = is.get ();
+
+        if (ch == ',')
+          {
+            im = read_value<T> (is);
+            ch = is.get ();
+
+            if (ch == ')')
+              cx = std::complex<T> (re, im);
             else
               is.setstate (std::ios::failbit);
           }
-        else
-          is.setstate (std::ios::failbit);
-      }
-      break;
-
-    case 'n': case 'N':
-      {
-        char c1 = is.get ();
-        if (c1 == 'a' || c1 == 'A')
-          {
-            char c2 = is.get ();
-            if (c2 == 'n' || c2 == 'N')
-              val = std::numeric_limits<T>::quiet_NaN ();
-            else
-              {
-                val = octave::numeric_limits<T>::NA ();
-                if (c2 != std::istream::traits_type::eof ())
-                  is.putback (c2);
-                else
-                  is.clear (is.rdstate () & ~std::ios::failbit);
-              }
-          }
+        else if (ch == ')')
+          cx = re;
         else
           is.setstate (std::ios::failbit);
       }
-      break;
-
-    default:
-      (*current_liboctave_error_handler)
-        ("read_inf_nan_na: invalid character '%c'", c0);
-    }
-
-  return val;
-}
-
-// Read a double value.  Discard any sign on NaN and NA.
-
-template <typename T>
-double
-octave_read_fp_value (std::istream& is)
-{
-  T val = 0.0;
-
-  // FIXME: resetting stream position is likely to fail unless we are
-  // reading from a file.
-  std::streampos pos = is.tellg ();
+    else
+      {
+        is.putback (ch);
+        cx = read_value<T> (is);
+      }
 
-  char c1 = ' ';
-
-  while (isspace (c1))
-    c1 = is.get ();
-
-  bool neg = false;
+    return cx;
+  }
 
-  switch (c1)
-    {
-    case '-':
-      neg = true;
-      OCTAVE_FALLTHROUGH;
+  // FIXME: Could we use traits and enable_if to avoid duplication in the
+  // following specializations?
 
-    case '+':
-      {
-        char c2 = 0;
-        c2 = is.get ();
-        if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          val = read_inf_nan_na<T> (is, c2);
-        else
-          {
-            is.putback (c2);
-            is >> val;
-          }
+  template <> double read_value (std::istream& is)
+  {
+    return read_fp_value<double> (is);
+  }
 
-        if (neg && ! is.fail ())
-          val = -val;
-      }
-      break;
-
-    case 'i': case 'I':
-    case 'n': case 'N':
-      val = read_inf_nan_na<T> (is, c1);
-      break;
-
-    default:
-      is.putback (c1);
-      is >> val;
-      break;
-    }
+  template <> Complex read_value (std::istream& is)
+  {
+    return read_cx_fp_value<double> (is);
+  }
 
-  std::ios::iostate status = is.rdstate ();
-  if (status & std::ios::failbit)
-    {
-      // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
-      if (val == std::numeric_limits<T>::max ())
-        {
-          if (neg)
-            val = -std::numeric_limits<T>::infinity ();
-          else
-            val = std::numeric_limits<T>::infinity ();
-          is.clear (status & ~std::ios::failbit);
-        }
-      else
-        {
-          // True error.  Reset stream to original position and pass status on.
-          is.clear ();
-          is.seekg (pos);
-          is.setstate (status);
-        }
-    }
+  template <> float read_value (std::istream& is)
+  {
+    return read_fp_value<float> (is);
+  }
 
-  return val;
-}
+  template <> FloatComplex read_value (std::istream& is)
+  {
+    return read_cx_fp_value<float> (is);
+  }
 
-template <typename T>
-std::complex<T>
-octave_read_cx_fp_value (std::istream& is)
-{
-  T re = 0.0;
-  T im = 0.0;
-
-  std::complex<T> cx = 0.0;
-
-  char ch = ' ';
+  // Note: precision is supposed to be managed outside of this function by
+  // setting stream parameters.
 
-  while (isspace (ch))
-    ch = is.get ();
-
-  if (ch == '(')
-    {
-      re = octave_read_value<T> (is);
-      ch = is.get ();
-
-      if (ch == ',')
-        {
-          im = octave_read_value<T> (is);
-          ch = is.get ();
+  template <> void write_value (std::ostream& os, const double& value)
+  {
+    if (lo_ieee_is_NA (value))
+      os << "NA";
+    else if (lo_ieee_isnan (value))
+      os << "NaN";
+    else if (lo_ieee_isinf (value))
+      os << (value < 0 ? "-Inf" : "Inf");
+    else
+      os << value;
+  }
 
-          if (ch == ')')
-            cx = std::complex<T> (re, im);
-          else
-            is.setstate (std::ios::failbit);
-        }
-      else if (ch == ')')
-        cx = re;
-      else
-        is.setstate (std::ios::failbit);
-    }
-  else
-    {
-      is.putback (ch);
-      cx = octave_read_value<double> (is);
-    }
-
-  return cx;
-}
-
-template <> OCTAVE_API double octave_read_value (std::istream& is)
-{
-  return octave_read_fp_value<double> (is);
-}
-
-template <> OCTAVE_API Complex octave_read_value (std::istream& is)
-{
-  return octave_read_cx_fp_value<double> (is);
-}
-
-template <> OCTAVE_API float octave_read_value (std::istream& is)
-{
-  return octave_read_fp_value<float> (is);
-}
+  template <> void write_value (std::ostream& os, const Complex& value)
+  {
+    os << '(';
+    write_value<double> (os, real (value));
+    os << ',';
+    write_value<double> (os, imag (value));
+    os << ')';
+  }
 
-template <> OCTAVE_API FloatComplex octave_read_value (std::istream& is)
-{
-  return octave_read_cx_fp_value<float> (is);
-}
-
-void
-octave_write_double (std::ostream& os, double d)
-{
-  if (lo_ieee_is_NA (d))
-    os << "NA";
-  else if (lo_ieee_isnan (d))
-    os << "NaN";
-  else if (lo_ieee_isinf (d))
-    os << (d < 0 ? "-Inf" : "Inf");
-  else
-    os << d;
-}
+  // Note: precision is supposed to be managed outside of this function by
+  // setting stream parameters.
 
-void
-octave_write_complex (std::ostream& os, const Complex& c)
-{
-  os << '(';
-  octave_write_double (os, real (c));
-  os << ',';
-  octave_write_double (os, imag (c));
-  os << ')';
-}
+  template <> void write_value (std::ostream& os, const float& value)
+  {
+    if (lo_ieee_is_NA (value))
+      os << "NA";
+    else if (lo_ieee_isnan (value))
+      os << "NaN";
+    else if (lo_ieee_isinf (value))
+      os << (value < 0 ? "-Inf" : "Inf");
+    else
+      os << value;
+  }
 
-void
-octave_write_float (std::ostream& os, float d)
-{
-  if (lo_ieee_is_NA (d))
-    os << "NA";
-  else if (lo_ieee_isnan (d))
-    os << "NaN";
-  else if (lo_ieee_isinf (d))
-    os << (d < 0 ? "-Inf" : "Inf");
-  else
-    os << d;
+  template <> void write_value (std::ostream& os, const FloatComplex& value)
+  {
+    os << '(';
+    write_value<float> (os, real (value));
+    os << ',';
+    write_value<float> (os, imag (value));
+    os << ')';
+  }
 }
-
-void
-octave_write_float_complex (std::ostream& os, const FloatComplex& c)
-{
-  os << '(';
-  octave_write_float (os, real (c));
-  os << ',';
-  octave_write_float (os, imag (c));
-  os << ')';
-}
--- a/liboctave/util/lo-utils.h	Thu Aug 20 23:12:47 2020 +0900
+++ b/liboctave/util/lo-utils.h	Tue Aug 11 15:20:01 2020 -0400
@@ -85,55 +85,89 @@
 extern OCTAVE_API std::string octave_fgets (std::FILE *, bool& eof);
 extern OCTAVE_API std::string octave_fgetl (std::FILE *, bool& eof);
 
-template <typename T>
-T
-octave_read_value (std::istream& is)
+namespace octave
 {
-  T retval;
-  is >> retval;
-  return retval;
+  template <typename T>
+  T
+  read_value (std::istream& is)
+  {
+    T retval;
+    is >> retval;
+    return retval;
+  }
+
+  template <> double read_value (std::istream& is);
+  template <> Complex read_value (std::istream& is);
+  template <> float read_value (std::istream& is);
+  template <> FloatComplex read_value (std::istream& is);
+
+  template <typename T>
+  void
+  write_value (std::ostream& os, const T& value)
+  {
+    os << value;
+  }
+
+  template <> void write_value (std::ostream& os, const double& value);
+  template <> void write_value (std::ostream& os, const Complex& value);
+  template <> void write_value (std::ostream& os, const float& value);
+  template <> void write_value (std::ostream& os, const FloatComplex& value);
 }
 
-template <> OCTAVE_API double octave_read_value (std::istream& is);
-template <> OCTAVE_API Complex octave_read_value (std::istream& is);
-template <> OCTAVE_API float octave_read_value (std::istream& is);
-template <> OCTAVE_API FloatComplex octave_read_value (std::istream& is);
-
-// The next four functions are provided for backward compatibility.
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline double
 octave_read_double (std::istream& is)
 {
-  return octave_read_value<double> (is);
+  return octave::read_value<double> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline Complex
 octave_read_complex (std::istream& is)
 {
-  return octave_read_value<Complex> (is);
+  return octave::read_value<Complex> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline float
 octave_read_float (std::istream& is)
 {
-  return octave_read_value<float> (is);
+  return octave::read_value<float> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline FloatComplex
 octave_read_float_complex (std::istream& is)
 {
-  return octave_read_value<FloatComplex> (is);
+  return octave::read_value<FloatComplex> (is);
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_double (std::ostream& os, double value)
+{
+  octave::write_value<double> (os, value);
 }
 
-extern OCTAVE_API void
-octave_write_double (std::ostream& os, double dval);
-
-extern OCTAVE_API void
-octave_write_complex (std::ostream& os, const Complex& cval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_complex (std::ostream& os, const Complex& value)
+{
+  octave::write_value<Complex> (os, value);
+}
 
-extern OCTAVE_API void
-octave_write_float (std::ostream& os, float dval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_float (std::ostream& os, float value)
+{
+  octave::write_value<float> (os, value);
+}
 
-extern OCTAVE_API void
-octave_write_float_complex (std::ostream& os, const FloatComplex& cval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_float_complex (std::ostream& os, const FloatComplex& value)
+{
+  octave::write_value<FloatComplex> (os, value);
+}
 
 #endif