diff mbox

libstdc++: Add hexfloat/defaultfloat io manipulators.

Message ID 2874621.ncaCZN6kVT@descartes
State New
Headers show

Commit Message

Rüdiger Sonderfeld March 27, 2014, 11:52 a.m. UTC
* include/bits/ios_base.h (hexfloat): New function.
(defaultfloat): New function.
* src/c++98/locale_facets.cc (__num_base::_S_format_float):
Support hexadecimal floating point format.
* testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc:
New file.

hexfloat/defaultfloat are new iostream manipulators introduced in C++11.
See the changes in [locale.nm.put] (§22.4.2.2) and
[floatfield.manip] (§27.5.6.4).  This patch does not add input support
for hexfloats.  The effect of outputting hexadecimal floating points by
setting both fixed and scientific is also added in C++98.  I am not sure
how to change this except for adding a C++11 specific implementation of
`__num_base::_S_format_float'.  But since the C++11 standard explicitly
says that "C++2003 gives no meaning to the combination of fixed and
scientific," this might be acceptable anyway.

I have signed the FSF papers.

Signed-off-by: Rüdiger Sonderfeld <ruediger@c-plusplus.de>
---
 libstdc++-v3/ChangeLog                             |   9 ++
 libstdc++-v3/include/bits/ios_base.h               |  20 +++
 libstdc++-v3/src/c++98/locale_facets.cc            |   2 +
 .../inserters_arithmetic/char/hexfloat.cc          | 141 
+++++++++++++++++++++
 4 files changed, 172 insertions(+)
 create mode 100644 libstdc++-
v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc

diff --git a/libstdc++-
v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc 
b/libstdc++-
v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc
new file mode 100644
index 0000000..b0f5724
--- /dev/null
+++ b/libstdc++-
v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc
@@ -0,0 +1,141 @@
+// { dg-options "-std=gnu++0x" }
+
+// 2014-03-27 Rüdiger Sonderfeld
+// test the hexadecimal floating point inserters (facet num_put)
+
+// Copyright (C) 2014 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
+// any later version.
+
+// This library 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 this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <limits>
+#include <testsuite_hooks.h>
+
+using namespace std;
+
+//#ifndef _GLIBCXX_ASSERT
+#  define TEST_NUMPUT_VERBOSE 1
+//#endif
+
+void
+test01()
+{
+  {
+    ostringstream os;
+    double d = 272.; // 0x1.1p+8;
+    cout << os.precision() << endl;
+    os << hexfloat << setprecision(1);
+    os << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "0x1.1p+8" );
+    os.str("");
+    os << uppercase << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "0X1.1P+8" );
+    os << nouppercase;
+    os.str("");
+    os << defaultfloat << setprecision(6);
+    os << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "272" );
+
+    os.str("");
+    d = 15.; //0x1.ep+3;
+    os << hexfloat << setprecision(1);
+    os << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "0x1.ep+3" );
+    os.str("");
+    os << uppercase << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "0X1.EP+3" );
+    os << nouppercase;
+    os.str("");
+    os << defaultfloat << setprecision(6);
+    os << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "15" );
+  }
+
+  {
+    ostringstream os;
+    long double d = 272.L; // 0x1.1p+8L;
+    os << hexfloat << setprecision(1);
+    os << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "0x8.8p+5" );
+    os.str("");
+    os << uppercase << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "0X8.8P+5" );
+    os << nouppercase;
+    os.str("");
+    os << defaultfloat << setprecision(6);
+    os << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "272" );
+
+    os.str("");
+    os << hexfloat << setprecision(1);
+    d = 15.; //0x1.ep+3;
+    os << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "0xf.0p+0" );
+    os.str("");
+    os << uppercase << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "0XF.0P+0" );
+    os << nouppercase;
+    os.str("");
+    os << defaultfloat << setprecision(6);
+    os << d;
+#ifdef TEST_NUMPUT_VERBOSE
+    cout << "got: " << os.str() << endl;
+#endif
+    VERIFY( os && os.str() == "15" );
+  }
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}

Comments

Jonathan Wakely March 27, 2014, 1:37 p.m. UTC | #1
On 27/03/14 12:52 +0100, Rüdiger Sonderfeld wrote:
>* include/bits/ios_base.h (hexfloat): New function.
>(defaultfloat): New function.
>* src/c++98/locale_facets.cc (__num_base::_S_format_float):
>Support hexadecimal floating point format.
>* testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc:
>New file.

Thanks for the patch. I have a few comments inline below.

With a few tweaks I think this can be committed once the trunk
re-opens for stage 1 <http://gcc.gnu.org/develop.html#stage1>

>hexfloat/defaultfloat are new iostream manipulators introduced in C++11.
>See the changes in [locale.nm.put] (§22.4.2.2) and
>[floatfield.manip] (§27.5.6.4).  This patch does not add input support
>for hexfloats.  The effect of outputting hexadecimal floating points by
>setting both fixed and scientific is also added in C++98.  I am not sure
>how to change this except for adding a C++11 specific implementation of
>`__num_base::_S_format_float'.  But since the C++11 standard explicitly
>says that "C++2003 gives no meaning to the combination of fixed and
>scientific," this might be acceptable anyway.

Yes, I think that's OK, thanks for explaining it.

We could document that (fixed|scientific) has that effect in c++98
mode. I'll also need to update the C++11 status table in the manual to
note std::hexfloat works for output streams.

>I have signed the FSF papers.

Excellent, that's the hardest part of contributing.

>+2014-03-27  Rüdiger Sonderfeld  <ruediger@c-plusplus.de>
>+
>+	* include/bits/ios_base.h (hexfloat): New function.
>+	(defaultfloat): New function.
>+	* src/c++98/locale_facets.cc (__num_base::_S_format_float):
>+	Support hexadecimal floating point format.
>+	* testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc:
>+	New file.

N.B. patches to the ChangeLog rarely apply cleanly (because someone
else may have changed the ChangeLog since the patch was created) so
the convention is to send the ChangeLog entry in the email body, or as
a separate attachment, or by using 'git log -p @{u}..' so the commit
log shows it, rather than as part of the patch.

>diff --git a/libstdc++-v3/include/bits/ios_base.h b/libstdc++-
>v3/include/bits/ios_base.h
>index ae856de..8f263c1 100644
>--- a/libstdc++-v3/include/bits/ios_base.h
>+++ b/libstdc++-v3/include/bits/ios_base.h
>@@ -969,6 +969,26 @@ namespace std _GLIBCXX_VISIBILITY(default)
>     return __base;
>   }
>
>+#if __cplusplus >= 201103L
>+  // New floatingfield manipulators

It's only a comment, but that should be "floatfield"

>+
>+  /// Calls base.setf(ios_base::fixed|
>ios_base::scientific,ios_base::floatfield)

Does this line exceed 80 characters?

>diff --git a/libstdc++-v3/src/c++98/locale_facets.cc b/libstdc++-
>v3/src/c++98/locale_facets.cc
>index 3669acb..9455f42 100644
>--- a/libstdc++-v3/src/c++98/locale_facets.cc
>+++ b/libstdc++-v3/src/c++98/locale_facets.cc
>@@ -82,6 +82,8 @@ namespace std _GLIBCXX_VISIBILITY(default)
>       *__fptr++ = 'f';
>     else if (__fltfield == ios_base::scientific)
>       *__fptr++ = (__flags & ios_base::uppercase) ? 'E' : 'e';
>+    else if (__fltfield == (ios_base::fixed | ios_base::scientific))
>+      *__fptr++ = (__flags & ios_base::uppercase) ? 'A' : 'a';
>     else
>       *__fptr++ = (__flags & ios_base::uppercase) ? 'G' : 'g';
>     *__fptr = '\0';

I wonder if we need a config macro to test whether the libc's
vsnprintf supports the A conversion specifier. You could do:

#ifdef _GLIBCXX_USE_C99
     else if (__fltfield == (ios_base::fixed | ios_base::scientific))
       *__fptr++ = (__flags & ios_base::uppercase) ? 'A' : 'a';
#endif

which I think would be correct for now (I'm planning to overhaul how we
use _GLIBCXX_USE_C99 later this year).


>diff --git a/libstdc++-
>v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc
>b/libstdc++-
>v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc
>new file mode 100644
>index 0000000..b0f5724
>--- /dev/null
>+++ b/libstdc++-
>v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc
>@@ -0,0 +1,141 @@
>+// { dg-options "-std=gnu++0x" }

New tests should use -std=gnu++11, the gnu++0x option is deprecated so
will stop working at some point (and we'll have to update the existing
tests using it).

>+//#ifndef _GLIBCXX_ASSERT
>+#  define TEST_NUMPUT_VERBOSE 1
>+//#endif

This appears to make the test write to std::cout by default, did you
mean to remove that before submitting the patch?

Thanks again for contributing this to the library!
diff mbox

Patch

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index f6008d1..3345d12 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,12 @@ 
+2014-03-27  Rüdiger Sonderfeld  <ruediger@c-plusplus.de>
+
+	* include/bits/ios_base.h (hexfloat): New function.
+	(defaultfloat): New function.
+	* src/c++98/locale_facets.cc (__num_base::_S_format_float):
+	Support hexadecimal floating point format.
+	* testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc:
+	New file.
+
 2014-03-25  Jonathan Wakely  <jwakely@redhat.com>
 
 	PR libstdc++/60658
diff --git a/libstdc++-v3/include/bits/ios_base.h b/libstdc++-
v3/include/bits/ios_base.h
index ae856de..8f263c1 100644
--- a/libstdc++-v3/include/bits/ios_base.h
+++ b/libstdc++-v3/include/bits/ios_base.h
@@ -969,6 +969,26 @@  namespace std _GLIBCXX_VISIBILITY(default)
     return __base;
   }
 
+#if __cplusplus >= 201103L
+  // New floatingfield manipulators
+
+  /// Calls base.setf(ios_base::fixed|
ios_base::scientific,ios_base::floatfield)
+  inline ios_base&
+  hexfloat(ios_base& __base)
+  {
+    __base.setf(ios_base::fixed | ios_base::scientific, 
ios_base::floatfield);
+    return __base;
+  }
+
+  /// Calls base.unsetf(ios_base::floatfield)
+  inline ios_base&
+  defaultfloat(ios_base& __base)
+  {
+    __base.unsetf(ios_base::floatfield);
+    return __base;
+  }
+#endif // __cplusplus >= 201103L
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
diff --git a/libstdc++-v3/src/c++98/locale_facets.cc b/libstdc++-
v3/src/c++98/locale_facets.cc
index 3669acb..9455f42 100644
--- a/libstdc++-v3/src/c++98/locale_facets.cc
+++ b/libstdc++-v3/src/c++98/locale_facets.cc
@@ -82,6 +82,8 @@  namespace std _GLIBCXX_VISIBILITY(default)
       *__fptr++ = 'f';
     else if (__fltfield == ios_base::scientific)
       *__fptr++ = (__flags & ios_base::uppercase) ? 'E' : 'e';
+    else if (__fltfield == (ios_base::fixed | ios_base::scientific))
+      *__fptr++ = (__flags & ios_base::uppercase) ? 'A' : 'a';
     else
       *__fptr++ = (__flags & ios_base::uppercase) ? 'G' : 'g';
     *__fptr = '\0';