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