This path add handling of p/P specifier to floating points and
integrals formatter, producing hexademical output

This is proof-of-concept patch, that includes test coverage
for the handling of _Pres_p/_Pres_P for floating-point types.

libstdc++-v3/ChangeLog:

        * include/std/format (__formatter_int, __formatter_fp):
        Parse p/P.
        * testsuite/23_containers/vector/bool/format.cc:
        Test for p/P.
        * testsuite/std/format/functions/format.cc: Change
        unsupported specifier placeholder to 'q'.
        * testsuite/std/format/ranges/sequence.c: Likewise.
        * libstdc++-v3/testsuite/std/format/parse_ctx.cc: Mark
        p/P as supported.
---
Tested on x86_64-linux locally. All *format* test passed.

 libstdc++-v3/include/std/format               | 14 +++++++
 .../23_containers/vector/bool/format.cc       |  2 +-
 .../testsuite/std/format/functions/format.cc  | 38 ++++++++++++-------
 .../testsuite/std/format/parse_ctx.cc         | 14 ++++---
 .../testsuite/std/format/ranges/sequence.cc   | 18 ++++-----
 5 files changed, 56 insertions(+), 30 deletions(-)

diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index a469ead08b4..33c45d96a27 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -1623,10 +1623,16 @@ namespace __format
            __spec._M_type = _Pres_o;
            ++__first;
            break;
+         case 'p':
+           __spec._M_alt = true;
+           [[fallthrough]];
          case 'x':
            __spec._M_type = _Pres_x;
            ++__first;
            break;
+         case 'P':
+           __spec._M_alt = true;
+           [[fallthrough]];
          case 'X':
            __spec._M_type = _Pres_X;
            ++__first;
@@ -2080,6 +2086,14 @@ namespace __format
            __spec._M_type = _Pres_A;
            ++__first;
            break;
+         case 'p':
+           __spec._M_type = _Pres_p;
+           ++__first;
+           break;
+         case 'P':
+           __spec._M_type = _Pres_P;
+           ++__first;
+           break;
          case 'e':
            __spec._M_type = _Pres_e;
            ++__first;
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc 
b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc
index 833727f4b41..c483d17f48c 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc
@@ -29,7 +29,7 @@ test_format_string()
 {
   std::vector<bool> v(1, true);
   VERIFY( !is_format_string_for("{:?}", v[0]) );
-  VERIFY( !is_format_string_for("{:P}", v[0]) );
+  VERIFY( !is_format_string_for("{:Q}", v[0]) );
 
   // width needs to be integer type
   VERIFY( !is_format_string_for("{:{}}", v[0], 1.0f) );
diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc 
b/libstdc++-v3/testsuite/std/format/functions/format.cc
index 88e95a788b5..38a0ff9fdc8 100644
--- a/libstdc++-v3/testsuite/std/format/functions/format.cc
+++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
@@ -159,16 +159,16 @@ test_std_examples()
 
       string s0 = format("{}", 42);
       VERIFY(s0 == "42");
-      string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42);
-      VERIFY(s1 == "101010 42 52 2a");
-      string s2 = format("{0:#x} {0:#X}", 42);
-      VERIFY(s2 == "0x2a 0X2A");
+      string s1 = format("{0:b} {0:d} {0:o} {0:x} {0:X} {0:p} {0:P}", 42);
+      VERIFY(s1 == "101010 42 52 2a 2A 0x2a 0X2A");
+      string s2 = format("{0:#x} {0:#X} {0:#p} {0:#P}", 42);
+      VERIFY(s2 == "0x2a 0X2A 0x2a 0X2A");
       string s3 = format("{:L}", 1234);
       VERIFY(s3 == "1,234");
 
       // Test locale's "byte-and-a-half" grouping (Imperial word? tribble?).
-      string s4 = format("{:#Lx}", 0xfffff);
-      VERIFY(s4 == "0xff,fff");
+      string s4 = format("{0:Lx} {0:#Lx} {0:Lp}", 0xfffff);
+      VERIFY(s4 == "ff,fff 0xff,fff 0xff,fff");
 
       // Restore
       std::locale::global(std::locale::classic());
@@ -204,6 +204,11 @@ test_alternate_forms()
       s = std::format("{0:#.0} {0:#.1} {0:#.0g}", 10.0);
       VERIFY( s == "1.e+01 1.e+01 1.e+01" );
 
+      s = std::format("{0:a} {0:A} {1:p} {1:P}", 1.0, -1.0);
+      VERIFY( s == "1p+0 1P+0 -0x1p+0 -0X1P+0" );
+      s = std::format("{1:#a} {1:#A} {0:#p} {0:#P}", 1.0, -1.0);
+      VERIFY( s == "-1.p+0 -1.P+0 0x1.p+0 0X1.P+0" );
+
       // PR libstdc++/113512
       s = std::format("{:#.3g}", 0.025);
       VERIFY( s == "0.0250" );
@@ -218,10 +223,10 @@ test_infnan()
   double inf = std::numeric_limits<double>::infinity();
   double nan = std::numeric_limits<double>::quiet_NaN();
   std::string s;
-  s = std::format("{0} {0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:a} {0:A}", inf);
-  VERIFY( s == "inf inf INF inf INF inf INF inf INF" );
-  s = std::format("{0} {0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:a} {0:A}", nan);
-  VERIFY( s == "nan nan NAN nan NAN nan NAN nan NAN" );
+  s = std::format("{0} {0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:a} {0:A} {0:p} 
{0:P}", inf);
+  VERIFY( s == "inf inf INF inf INF inf INF inf INF inf INF" );
+  s = std::format("{0} {0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:a} {0:A} {0:p} 
{0:P}", nan);
+  VERIFY( s == "nan nan NAN nan NAN nan NAN nan NAN nan NAN" );
 }
 
 struct euro_punc : std::numpunct<char>
@@ -248,8 +253,8 @@ test_locale()
   // Format using the global locale:
   s = std::format("{0:L} {0:Lx} {0:Lb}", 12345);
   VERIFY( s == "12,345 3,039 11,000,000,111,001" );
-  s = std::format("{0:L} {0:.7Lg} {0:La}", 12345.6789);
-  VERIFY( s == "12,345.6789 12,345.68 1.81cd6e631f8a1p+13" );
+  s = std::format("{0:L} {0:.7Lg} {0:La} {0:Lp}", 12345.6789);
+  VERIFY( s == "12,345.6789 12,345.68 1.81cd6e631f8a1p+13 
0x1.81cd6e631f8a1p+13" );
 
   s = std::format("{0:s} {0:L} {1:Ls} {0:Ld}", true, false);
   VERIFY( s == "true yes mate nah bruv 1" );
@@ -257,8 +262,8 @@ test_locale()
   // Format using a specific locale:
   s = std::format(eloc, "{0:L} {0:Lx} {0:Lb}", 12345);
   VERIFY( s == "12.345 3.039 11.000.000.111.001" );
-  s = std::format(eloc, "{0:L} {0:.7LG} {0:La}", 12345.6789);
-  VERIFY( s == "12.345,6789 12.345,68 1,81cd6e631f8a1p+13" );
+  s = std::format(eloc, "{0:L} {0:.7LG} {0:La} {0:Lp}", 12345.6789);
+  VERIFY( s == "12.345,6789 12.345,68 1,81cd6e631f8a1p+13 
0x1,81cd6e631f8a1p+13" );
 
   s = std::format(eloc, "{0:#Lg} {0:+#.3Lg} {0:#08.4Lg}", -1234.);
   VERIFY( s == "-1.234,00 -1,23e+03 -01.234," );
@@ -353,6 +358,9 @@ test_char()
   s = std::format("{:x} {:#x} {:#X}", '\x12', '\x34', '\x45');
   VERIFY( s == "12 0x34 0X45" );
 
+  s = std::format("{:p} {:P} {:#p} {:#P}", '\x1a', '\x2b', '\x3c', '\x4d');
+  VERIFY( s == "0x1a 0X2B 0x3c 0X4D" );
+
   // P2909R4 Fix formatting of code units as integers (Dude, where’s my char?)
   // char and wchar_t should be converted to unsigned when formatting them
   // with an integer presentation type.
@@ -384,6 +392,8 @@ test_wchar()
       VERIFY( s == L"0.25" );
       s = std::format(L"{:+a} {:A}", 0x1.23p45, -0x1.abcdefp-15);
       VERIFY( s == L"+1.23p+45 -1.ABCDEFP-15" );
+      s = std::format(L"{:+p} {:P}", 0x1.23p45, -0x1.abcdefp-15);
+      VERIFY( s == L"+0x1.23p+45 -0X1.ABCDEFP-15" );
 
       double inf = std::numeric_limits<double>::infinity();
       double nan = std::numeric_limits<double>::quiet_NaN();
diff --git a/libstdc++-v3/testsuite/std/format/parse_ctx.cc 
b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
index 6294dcf43f5..a5e84d1da9c 100644
--- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc
+++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
@@ -156,6 +156,8 @@ test_char()
   VERIFY( ! is_std_format_spec_for<char>("F") );
   VERIFY( ! is_std_format_spec_for<char>("g") );
   VERIFY( ! is_std_format_spec_for<char>("G") );
+  VERIFY( is_std_format_spec_for<char>("p") );
+  VERIFY( is_std_format_spec_for<char>("P") );
   VERIFY( ! is_std_format_spec_for<char>("+c") );
   VERIFY( ! is_std_format_spec_for<char>("+?") );
   VERIFY( is_std_format_spec_for<char>("+d") );
@@ -203,8 +205,8 @@ test_int()
   VERIFY( ! is_std_format_spec_for<int>("F") );
   VERIFY( ! is_std_format_spec_for<int>("g") );
   VERIFY( ! is_std_format_spec_for<int>("G") );
-  VERIFY( ! is_std_format_spec_for<int>("p") );
-  VERIFY( ! is_std_format_spec_for<int>("P") );
+  VERIFY( is_std_format_spec_for<int>("p") );
+  VERIFY( is_std_format_spec_for<int>("P") );
   VERIFY( is_std_format_spec_for<int>("+c") ); // But LWG 3644 would change it.
   VERIFY( ! is_std_format_spec_for<int>("+?") );
   VERIFY( is_std_format_spec_for<int>("+d") );
@@ -249,8 +251,8 @@ test_bool()
   VERIFY( ! is_std_format_spec_for<bool>("F") );
   VERIFY( ! is_std_format_spec_for<bool>("g") );
   VERIFY( ! is_std_format_spec_for<bool>("G") );
-  VERIFY( ! is_std_format_spec_for<bool>("p") );
-  VERIFY( ! is_std_format_spec_for<bool>("P") );
+  VERIFY( is_std_format_spec_for<bool>("p") );
+  VERIFY( is_std_format_spec_for<bool>("P") );
   VERIFY( ! is_std_format_spec_for<bool>("+s") );
   VERIFY( is_std_format_spec_for<bool>("+d") );
 }
@@ -303,8 +305,8 @@ test_float()
   VERIFY( is_std_format_spec_for<float>("F") );
   VERIFY( is_std_format_spec_for<float>("g") );
   VERIFY( is_std_format_spec_for<float>("G") );
-  VERIFY( ! is_std_format_spec_for<float>("p") );
-  VERIFY( ! is_std_format_spec_for<float>("P") );
+  VERIFY( is_std_format_spec_for<float>("p") );
+  VERIFY( is_std_format_spec_for<float>("P") );
   VERIFY( is_std_format_spec_for<float>("+f") );
 
   VERIFY( is_std_format_spec_for<float>("_<+#09.6Lf") );
diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc 
b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
index cba53b46270..bc902548009 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
@@ -66,20 +66,20 @@ is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
 CONSTEXPR void
 test_format_string()
 {
-  // invalid format spec 'p'
-  VERIFY( !is_range_formatter_spec_for("p", std::vector<int>()) );
-  VERIFY( !is_format_string_for("{:p}", std::vector<int>()) );
-  VERIFY( !is_range_formatter_spec_for("np", std::vector<int>()) );
-  VERIFY( !is_format_string_for("{:np}", std::vector<int>()) );
+  // invalid format spec 'q'
+  VERIFY( !is_range_formatter_spec_for("q", std::vector<int>()) );
+  VERIFY( !is_format_string_for("{:q}", std::vector<int>()) );
+  VERIFY( !is_range_formatter_spec_for("nq", std::vector<int>()) );
+  VERIFY( !is_format_string_for("{:nq}", std::vector<int>()) );
 
   // width needs to be integer type
   VERIFY( !is_format_string_for("{:{}}", std::vector<int>(), 1.0f) );
 
   // element format needs to be valid
-  VERIFY( !is_range_formatter_spec_for(":p", std::vector<int>()) );
-  VERIFY( !is_format_string_for("{::p}", std::vector<int>()) );
-  VERIFY( !is_range_formatter_spec_for("n:p", std::vector<int>()) );
-  VERIFY( !is_format_string_for("{:n:p}", std::vector<int>()) );
+  VERIFY( !is_range_formatter_spec_for(":q", std::vector<int>()) );
+  VERIFY( !is_format_string_for("{::q}", std::vector<int>()) );
+  VERIFY( !is_range_formatter_spec_for("n:q", std::vector<int>()) );
+  VERIFY( !is_format_string_for("{:n:q}", std::vector<int>()) );
 }
 
 #define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
-- 
2.54.0

Reply via email to