diff liboctave/util/lo-utils.cc @ 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 bd51beb6205e
children a2cb3dec4bc5
line wrap: on
line diff
--- 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 << ')';
-}