Mercurial > octave
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 << ')'; -}