// { dg-options "-std=gnu++20" } // { dg-do run { target c++20 } } #include #include template bool is_std_format_spec_for(std::string_view spec) { std::format_parse_context pc(spec); if (auto_indexing) (void) pc.next_arg_id(); else pc.check_arg_id(0); std::formatter f; try { auto end = f.parse(pc); VERIFY( end == spec.end() || *end == '}' ); return true; } catch (const std::format_error&) { return false; } } #if __cpp_lib_format_ranges constexpr bool escaped_strings_supported = true; #else constexpr bool escaped_strings_supported = false; #endif void test_char() { VERIFY( is_std_format_spec_for("") ); VERIFY( is_std_format_spec_for("<") ); VERIFY( is_std_format_spec_for(">") ); VERIFY( is_std_format_spec_for("^") ); VERIFY( is_std_format_spec_for("0<") ); VERIFY( is_std_format_spec_for("0>") ); VERIFY( is_std_format_spec_for("0^") ); VERIFY( ! is_std_format_spec_for("{^") ); VERIFY( ! is_std_format_spec_for("+") ); VERIFY( ! is_std_format_spec_for("-") ); VERIFY( ! is_std_format_spec_for(" ") ); VERIFY( ! is_std_format_spec_for("#") ); VERIFY( is_std_format_spec_for("0d") ); VERIFY( ! is_std_format_spec_for("0") ); VERIFY( ! is_std_format_spec_for("00d") ); VERIFY( is_std_format_spec_for("01d") ); VERIFY( is_std_format_spec_for("0{}d") ); VERIFY( ! is_std_format_spec_for("0{1}d") ); VERIFY(( is_std_format_spec_for("0{1}d") )); VERIFY( is_std_format_spec_for("1") ); VERIFY( ! is_std_format_spec_for("-1") ); VERIFY( is_std_format_spec_for("-1d") ); // sign and width VERIFY( ! is_std_format_spec_for(".") ); VERIFY( ! is_std_format_spec_for(".1") ); VERIFY( is_std_format_spec_for("c") ); VERIFY( is_std_format_spec_for("b") ); VERIFY( is_std_format_spec_for("B") ); VERIFY( is_std_format_spec_for("d") ); VERIFY( is_std_format_spec_for("o") ); VERIFY( is_std_format_spec_for("x") ); VERIFY( is_std_format_spec_for("X") ); VERIFY( ! is_std_format_spec_for("s") ); VERIFY( is_std_format_spec_for("?") == escaped_strings_supported ); VERIFY( ! is_std_format_spec_for("a") ); VERIFY( ! is_std_format_spec_for("A") ); VERIFY( ! is_std_format_spec_for("f") ); VERIFY( ! is_std_format_spec_for("F") ); VERIFY( ! is_std_format_spec_for("g") ); VERIFY( ! is_std_format_spec_for("G") ); VERIFY( ! is_std_format_spec_for("+c") ); VERIFY( ! is_std_format_spec_for("+?") ); VERIFY( is_std_format_spec_for("+d") ); } void test_int() { VERIFY( is_std_format_spec_for("") ); VERIFY( is_std_format_spec_for("<") ); VERIFY( is_std_format_spec_for(">") ); VERIFY( is_std_format_spec_for("^") ); VERIFY( is_std_format_spec_for("0<") ); VERIFY( is_std_format_spec_for("0>") ); VERIFY( is_std_format_spec_for("0^") ); VERIFY( ! is_std_format_spec_for("{^") ); VERIFY( is_std_format_spec_for("+") ); VERIFY( is_std_format_spec_for("-") ); VERIFY( is_std_format_spec_for(" ") ); VERIFY( is_std_format_spec_for("#") ); VERIFY( is_std_format_spec_for("0d") ); VERIFY( is_std_format_spec_for("0") ); VERIFY( ! is_std_format_spec_for("00d") ); VERIFY( is_std_format_spec_for("01d") ); VERIFY( ! is_std_format_spec_for("0{1}d") ); VERIFY(( is_std_format_spec_for("0{}d") )); VERIFY(( ! is_std_format_spec_for("0{1}d") )); VERIFY(( is_std_format_spec_for("0{1}d") )); VERIFY( is_std_format_spec_for("1") ); VERIFY( is_std_format_spec_for("-1") ); // sign and width VERIFY( ! is_std_format_spec_for(".") ); VERIFY( ! is_std_format_spec_for(".1") ); VERIFY( is_std_format_spec_for("c") ); VERIFY( is_std_format_spec_for("b") ); VERIFY( is_std_format_spec_for("B") ); VERIFY( is_std_format_spec_for("d") ); VERIFY( is_std_format_spec_for("o") ); VERIFY( is_std_format_spec_for("x") ); VERIFY( is_std_format_spec_for("X") ); VERIFY( ! is_std_format_spec_for("s") ); VERIFY( ! is_std_format_spec_for("?") ); VERIFY( ! is_std_format_spec_for("a") ); VERIFY( ! is_std_format_spec_for("A") ); VERIFY( ! is_std_format_spec_for("f") ); VERIFY( ! is_std_format_spec_for("F") ); VERIFY( ! is_std_format_spec_for("g") ); VERIFY( ! is_std_format_spec_for("G") ); VERIFY( ! is_std_format_spec_for("p") ); VERIFY( ! is_std_format_spec_for("P") ); VERIFY( is_std_format_spec_for("+c") ); // But LWG 3644 would change it. VERIFY( ! is_std_format_spec_for("+?") ); VERIFY( is_std_format_spec_for("+d") ); } void test_bool() { VERIFY( is_std_format_spec_for("") ); VERIFY( is_std_format_spec_for("<") ); VERIFY( is_std_format_spec_for(">") ); VERIFY( is_std_format_spec_for("^") ); VERIFY( is_std_format_spec_for("0<") ); VERIFY( is_std_format_spec_for("0>") ); VERIFY( is_std_format_spec_for("0^") ); VERIFY( ! is_std_format_spec_for("{^") ); VERIFY( ! is_std_format_spec_for("+") ); VERIFY( ! is_std_format_spec_for("-") ); VERIFY( ! is_std_format_spec_for(" ") ); VERIFY( ! is_std_format_spec_for("#") ); VERIFY( is_std_format_spec_for("0d") ); VERIFY( ! is_std_format_spec_for("0") ); VERIFY( ! is_std_format_spec_for("00d") ); VERIFY( is_std_format_spec_for("01d") ); VERIFY( is_std_format_spec_for("1") ); VERIFY( ! is_std_format_spec_for("-1") ); VERIFY( is_std_format_spec_for("-1d") ); // sign and width VERIFY( ! is_std_format_spec_for(".") ); VERIFY( ! is_std_format_spec_for(".1") ); VERIFY( ! is_std_format_spec_for("c") ); VERIFY( is_std_format_spec_for("b") ); VERIFY( is_std_format_spec_for("B") ); VERIFY( is_std_format_spec_for("d") ); VERIFY( is_std_format_spec_for("o") ); VERIFY( is_std_format_spec_for("x") ); VERIFY( is_std_format_spec_for("X") ); VERIFY( is_std_format_spec_for("s") ); VERIFY( ! is_std_format_spec_for("?") ); VERIFY( ! is_std_format_spec_for("a") ); VERIFY( ! is_std_format_spec_for("A") ); VERIFY( ! is_std_format_spec_for("f") ); VERIFY( ! is_std_format_spec_for("F") ); VERIFY( ! is_std_format_spec_for("g") ); VERIFY( ! is_std_format_spec_for("G") ); VERIFY( ! is_std_format_spec_for("p") ); VERIFY( ! is_std_format_spec_for("P") ); VERIFY( ! is_std_format_spec_for("+s") ); VERIFY( is_std_format_spec_for("+d") ); } void test_float() { VERIFY( is_std_format_spec_for("") ); VERIFY( is_std_format_spec_for("<") ); VERIFY( is_std_format_spec_for(">") ); VERIFY( is_std_format_spec_for("^") ); VERIFY( is_std_format_spec_for("0<") ); VERIFY( is_std_format_spec_for("0>") ); VERIFY( is_std_format_spec_for("0^") ); VERIFY( ! is_std_format_spec_for("{^") ); VERIFY( is_std_format_spec_for("+") ); VERIFY( is_std_format_spec_for("-") ); VERIFY( is_std_format_spec_for(" ") ); VERIFY( is_std_format_spec_for("#") ); VERIFY( is_std_format_spec_for("0f") ); VERIFY( is_std_format_spec_for("0") ); VERIFY( ! is_std_format_spec_for("00f") ); VERIFY( is_std_format_spec_for("01f") ); VERIFY( is_std_format_spec_for("0{}f") ); VERIFY( ! is_std_format_spec_for("0{1}f") ); VERIFY( ! is_std_format_spec_for("0{1}f") ); VERIFY(( is_std_format_spec_for("0{1}f") )); VERIFY( is_std_format_spec_for("1") ); VERIFY( is_std_format_spec_for("-1") ); // sign and width VERIFY( ! is_std_format_spec_for(".") ); VERIFY( is_std_format_spec_for(".1") ); VERIFY( is_std_format_spec_for(".{}") ); VERIFY( ! is_std_format_spec_for(".{1}") ); VERIFY(( is_std_format_spec_for(".{1}") )); VERIFY( is_std_format_spec_for("{}.{}") ); VERIFY(( is_std_format_spec_for("{1}.{1}") )); VERIFY(( is_std_format_spec_for("{2}.{1}") )); VERIFY( ! is_std_format_spec_for("c") ); VERIFY( ! is_std_format_spec_for("b") ); VERIFY( ! is_std_format_spec_for("B") ); VERIFY( ! is_std_format_spec_for("d") ); VERIFY( ! is_std_format_spec_for("o") ); VERIFY( ! is_std_format_spec_for("x") ); VERIFY( ! is_std_format_spec_for("X") ); VERIFY( ! is_std_format_spec_for("s") ); VERIFY( ! is_std_format_spec_for("?") ); VERIFY( is_std_format_spec_for("a") ); VERIFY( is_std_format_spec_for("A") ); VERIFY( is_std_format_spec_for("f") ); VERIFY( is_std_format_spec_for("F") ); VERIFY( is_std_format_spec_for("g") ); VERIFY( is_std_format_spec_for("G") ); VERIFY( ! is_std_format_spec_for("p") ); VERIFY( ! is_std_format_spec_for("P") ); VERIFY( is_std_format_spec_for("+f") ); VERIFY( is_std_format_spec_for("_<+#09.6Lf") ); VERIFY( is_std_format_spec_for("<+#09.6Lf") ); VERIFY( is_std_format_spec_for("<+#9.6Lf") ); VERIFY( is_std_format_spec_for(".0006f") ); } void test_pointer() { VERIFY( is_std_format_spec_for("") ); VERIFY( is_std_format_spec_for("<") ); VERIFY( is_std_format_spec_for(">") ); VERIFY( is_std_format_spec_for("^") ); VERIFY( is_std_format_spec_for("0<") ); VERIFY( is_std_format_spec_for("0>") ); VERIFY( is_std_format_spec_for("0^") ); VERIFY( ! is_std_format_spec_for("{^") ); VERIFY( ! is_std_format_spec_for("+") ); VERIFY( ! is_std_format_spec_for("-") ); VERIFY( ! is_std_format_spec_for(" ") ); VERIFY( ! is_std_format_spec_for("#") ); VERIFY( is_std_format_spec_for("0p") ); // P2510 VERIFY( is_std_format_spec_for("0") ); VERIFY( ! is_std_format_spec_for("00p") ); VERIFY( is_std_format_spec_for("01p") ); VERIFY( is_std_format_spec_for("1") ); VERIFY( ! is_std_format_spec_for("-1") ); VERIFY( ! is_std_format_spec_for("-1p") ); VERIFY( ! is_std_format_spec_for(".") ); VERIFY( ! is_std_format_spec_for(".1") ); VERIFY( ! is_std_format_spec_for("c") ); VERIFY( ! is_std_format_spec_for("b") ); VERIFY( ! is_std_format_spec_for("B") ); VERIFY( ! is_std_format_spec_for("d") ); VERIFY( ! is_std_format_spec_for("o") ); VERIFY( ! is_std_format_spec_for("x") ); VERIFY( ! is_std_format_spec_for("X") ); VERIFY( ! is_std_format_spec_for("s") ); VERIFY( ! is_std_format_spec_for("?") ); VERIFY( is_std_format_spec_for("p") ); VERIFY( is_std_format_spec_for("P") ); VERIFY( ! is_std_format_spec_for("a") ); VERIFY( ! is_std_format_spec_for("A") ); VERIFY( ! is_std_format_spec_for("f") ); VERIFY( ! is_std_format_spec_for("F") ); VERIFY( ! is_std_format_spec_for("g") ); VERIFY( ! is_std_format_spec_for("G") ); VERIFY( ! is_std_format_spec_for("+p") ); } void test_string() { VERIFY( is_std_format_spec_for("") ); VERIFY( is_std_format_spec_for("<") ); VERIFY( is_std_format_spec_for(">") ); VERIFY( is_std_format_spec_for("^") ); VERIFY( is_std_format_spec_for("0<") ); VERIFY( is_std_format_spec_for("0>") ); VERIFY( is_std_format_spec_for("0^") ); VERIFY( ! is_std_format_spec_for("{^") ); VERIFY( ! is_std_format_spec_for("+") ); VERIFY( ! is_std_format_spec_for("-") ); VERIFY( ! is_std_format_spec_for(" ") ); VERIFY( ! is_std_format_spec_for("#") ); VERIFY( ! is_std_format_spec_for("0") ); VERIFY( ! is_std_format_spec_for("01s") ); VERIFY( is_std_format_spec_for("1") ); VERIFY( ! is_std_format_spec_for("-1") ); VERIFY( ! is_std_format_spec_for("-1s") ); VERIFY( ! is_std_format_spec_for(".") ); VERIFY( is_std_format_spec_for(".1") ); VERIFY( is_std_format_spec_for(".{}") ); VERIFY(( is_std_format_spec_for(".{0}") )); VERIFY(( is_std_format_spec_for(".{1}") )); VERIFY( ! is_std_format_spec_for("c") ); VERIFY( ! is_std_format_spec_for("b") ); VERIFY( ! is_std_format_spec_for("B") ); VERIFY( ! is_std_format_spec_for("d") ); VERIFY( ! is_std_format_spec_for("o") ); VERIFY( ! is_std_format_spec_for("x") ); VERIFY( ! is_std_format_spec_for("X") ); VERIFY( is_std_format_spec_for("s") ); VERIFY( is_std_format_spec_for("?") == escaped_strings_supported ); VERIFY( ! is_std_format_spec_for("p") ); VERIFY( ! is_std_format_spec_for("P") ); VERIFY( ! is_std_format_spec_for("a") ); VERIFY( ! is_std_format_spec_for("A") ); VERIFY( ! is_std_format_spec_for("f") ); VERIFY( ! is_std_format_spec_for("F") ); VERIFY( ! is_std_format_spec_for("g") ); VERIFY( ! is_std_format_spec_for("G") ); VERIFY( is_std_format_spec_for("*^6s") ); VERIFY( is_std_format_spec_for(">6s") ); VERIFY( is_std_format_spec_for("_<6.4?") == escaped_strings_supported ); } struct S { }; template<> struct std::formatter { constexpr std::format_parse_context::iterator parse(std::format_parse_context& pc) { std::string_view spec(pc.begin(), pc.end()); auto p = spec.find('}'); if (p == std::string_view::npos) p = spec.size(); if (p == 0) throw std::format_error("empty format-spec"); if (spec != "custom") throw std::format_error("invalid format-spec"); return pc.begin() + p; } std::format_context::iterator format(const S&, std::format_context&) const; }; void test_custom() { VERIFY( is_std_format_spec_for("custom") ); VERIFY( ! is_std_format_spec_for("customer") ); VERIFY( ! is_std_format_spec_for("custard") ); VERIFY( ! is_std_format_spec_for("") ); } int main() { test_char(); test_int(); test_bool(); test_float(); test_string(); test_pointer(); test_custom(); }