[libcxx-commits] [libcxx] 7fb9f99 - [libc++][format] Adds bool formatter.
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Oct 7 08:17:35 PDT 2021
Author: Mark de Wever
Date: 2021-10-07T17:17:27+02:00
New Revision: 7fb9f99f3bb645337b4f4e6a2a3515219be82011
URL: https://github.com/llvm/llvm-project/commit/7fb9f99f3bb645337b4f4e6a2a3515219be82011
DIFF: https://github.com/llvm/llvm-project/commit/7fb9f99f3bb645337b4f4e6a2a3515219be82011.diff
LOG: [libc++][format] Adds bool formatter.
Implements the formatter for Boolean types.
[format.formatter.spec]/2.3
For each charT, for each cv-unqualified arithmetic type ArithmeticT other
than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
```
template<> struct formatter<ArithmeticT, charT>;
```
This removes the stub implemented in D96664.
Implements parts of:
- P0645 Text Formatting
- P1652 Printf corner cases in std::format
Completes:
- P1868 width: clarifying units of width and precision in std::format
Reviewed By: #libc, ldionne
Differential Revision: https://reviews.llvm.org/D103670
Added:
libcxx/include/__format/formatter_bool.h
libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_bool.module.verify.cpp
libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_bool.pass.cpp
Modified:
libcxx/docs/Status/Cxx20Papers.csv
libcxx/include/CMakeLists.txt
libcxx/include/format
libcxx/include/module.modulemap
libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.pass.cpp
libcxx/test/std/utilities/format/format.functions/format_tests.h
libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index 18acdf922437f..a4dd75c5ca039 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -171,7 +171,7 @@
"`P1460 <https://wg21.link/P1460>`__","LWG","Mandating the Standard Library: Clause 20 - Utilities library","Prague","* *",""
"`P1739 <https://wg21.link/P1739>`__","LWG","Avoid template bloat for safe_ranges in combination with ""subrange-y"" view adaptors","Prague","* *",""
"`P1831 <https://wg21.link/P1831>`__","LWG","Deprecating volatile: library","Prague","* *",""
-"`P1868 <https://wg21.link/P1868>`__","LWG","width: clarifying units of width and precision in std::format","Prague","|In Progress|",""
+"`P1868 <https://wg21.link/P1868>`__","LWG","width: clarifying units of width and precision in std::format","Prague","|Complete|","14.0"
"`P1908 <https://wg21.link/P1908>`__","CWG","Reserving Attribute Namespaces for Future Use","Prague","* *",""
"`P1937 <https://wg21.link/P1937>`__","CWG","Fixing inconsistencies between constexpr and consteval functions","Prague","* *",""
"`P1956 <https://wg21.link/P1956>`__","LWG","On the names of low-level bit manipulation functions","Prague","|Complete|","12.0"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 568f06bda4812..3460f72f80000 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -140,6 +140,7 @@ set(files
__format/format_parse_context.h
__format/format_string.h
__format/formatter.h
+ __format/formatter_bool.h
__format/formatter_char.h
__format/formatter_integer.h
__format/formatter_integral.h
diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h
new file mode 100644
index 0000000000000..8d9a1d26a4e22
--- /dev/null
+++ b/libcxx/include/__format/formatter_bool.h
@@ -0,0 +1,145 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FORMAT_FORMATTER_BOOL_H
+#define _LIBCPP___FORMAT_FORMATTER_BOOL_H
+
+#include <__availability>
+#include <__config>
+#include <__format/format_error.h>
+#include <__format/format_fwd.h>
+#include <__format/formatter.h>
+#include <__format/formatter_integral.h>
+#include <__format/parser_std_format_spec.h>
+#include <string_view>
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+#include <locale>
+#endif
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17
+
+// TODO FMT Remove this once we require compilers with proper C++20 support.
+// If the compiler has no concepts support, the format header will be disabled.
+// Without concepts support enable_if needs to be used and that too much effort
+// to support compilers with partial C++20 support.
+#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+namespace __format_spec {
+
+template <class _CharT>
+class _LIBCPP_TEMPLATE_VIS __parser_bool : public __parser_integral<_CharT> {
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr auto parse(auto& __parse_ctx)
+ -> decltype(__parse_ctx.begin()) {
+ auto __it = __parser_integral<_CharT>::__parse(__parse_ctx);
+
+ switch (this->__type) {
+ case _Flags::_Type::__default:
+ this->__type = _Flags::_Type::__string;
+ [[fallthrough]];
+ case _Flags::_Type::__string:
+ this->__handle_bool();
+ break;
+
+ case _Flags::_Type::__char:
+ this->__handle_char();
+ break;
+
+ case _Flags::_Type::__binary_lower_case:
+ case _Flags::_Type::__binary_upper_case:
+ case _Flags::_Type::__octal:
+ case _Flags::_Type::__decimal:
+ case _Flags::_Type::__hexadecimal_lower_case:
+ case _Flags::_Type::__hexadecimal_upper_case:
+ this->__handle_integer();
+ break;
+
+ default:
+ __throw_format_error(
+ "The format-spec type has a type not supported for a bool argument");
+ }
+
+ return __it;
+ }
+};
+
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __bool_strings;
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS __bool_strings<char> {
+ static constexpr string_view __true{"true"};
+ static constexpr string_view __false{"false"};
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS __bool_strings<wchar_t> {
+ static constexpr wstring_view __true{L"true"};
+ static constexpr wstring_view __false{L"false"};
+};
+
+template <class _CharT>
+using __formatter_bool = __formatter_integral<__parser_bool<_CharT>>;
+
+} //namespace __format_spec
+
+// [format.formatter.spec]/2.3
+// For each charT, for each cv-unqualified arithmetic type ArithmeticT other
+// than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
+
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<bool, _CharT>
+ : public __format_spec::__formatter_bool<_CharT> {
+ using _Base = __format_spec::__formatter_bool<_CharT>;
+
+ _LIBCPP_HIDE_FROM_ABI auto format(bool __value, auto& __ctx)
+ -> decltype(__ctx.out()) {
+ if (this->__type != __format_spec::_Flags::_Type::__string)
+ return _Base::format(static_cast<unsigned char>(__value), __ctx);
+
+ if (this->__width_needs_substitution())
+ this->__substitute_width_arg_id(__ctx.arg(this->__width));
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+ if (this->__locale_specific_form) {
+ const auto& __np = use_facet<numpunct<_CharT>>(__ctx.locale());
+ basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename();
+ return __formatter::__write_unicode(
+ __ctx.out(), basic_string_view<_CharT>{__str}, this->__width, -1,
+ this->__fill, this->__alignment);
+ }
+#endif
+ basic_string_view<_CharT> __str =
+ __value ? __format_spec::__bool_strings<_CharT>::__true
+ : __format_spec::__bool_strings<_CharT>::__false;
+
+ // The output only uses ASCII so every character is one column.
+ unsigned __size = __str.size();
+ if (__size >= this->__width)
+ return _VSTD::copy(__str.begin(), __str.end(), __ctx.out());
+
+ return __formatter::__write(__ctx.out(), __str.begin(), __str.end(), __size,
+ this->__width, this->__fill, this->__alignment);
+ }
+};
+
+#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FORMAT_FORMATTER_BOOL_H
diff --git a/libcxx/include/format b/libcxx/include/format
index d4e24b6c30fcf..91160151489aa 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -279,6 +279,7 @@ namespace std {
#include <__format/format_parse_context.h>
#include <__format/format_string.h>
#include <__format/formatter.h>
+#include <__format/formatter_bool.h>
#include <__format/formatter_char.h>
#include <__format/formatter_integer.h>
#include <__format/formatter_string.h>
@@ -389,28 +390,6 @@ private:
// These specializations are helper stubs and not proper formatters.
// TODO FMT Implement the proper formatter specializations.
-// [format.formatter.spec]/2.3
-// For each charT, for each cv-unqualified arithmetic type ArithmeticT other
-// than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
-
-// Boolean.
-template <class _CharT>
-struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> {
- _LIBCPP_HIDE_FROM_ABI
- auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
- // TODO FMT Implement
- return __parse_ctx.begin();
- }
-
- _LIBCPP_HIDE_FROM_ABI
- auto format(bool __b, auto& __ctx) -> decltype(__ctx.out()) {
- // TODO FMT Implement using formatting arguments
- auto __out_it = __ctx.out();
- *__out_it++ = _CharT('0') + __b;
- return __out_it;
- }
-};
-
// Floating point types.
// TODO FMT There are no replacements for the floating point stubs due to not
// having floating point support in std::to_chars yet. These stubs aren't
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 4f107738313fe..5abe2431300a7 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -450,6 +450,7 @@ module std [system] {
module format_parse_context { private header "__format/format_parse_context.h" }
module format_string { private header "__format/format_string.h" }
module formatter { private header "__format/formatter.h" }
+ module formatter_bool { private header "__format/formatter_bool.h" }
module formatter_char { private header "__format/formatter_char.h" }
module formatter_integer { private header "__format/formatter_integer.h" }
module formatter_integral { private header "__format/formatter_integral.h" }
diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_bool.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_bool.module.verify.cpp
new file mode 100644
index 0000000000000..9cd9dfa37a16f
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_bool.module.verify.cpp
@@ -0,0 +1,16 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__format/formatter_bool.h'}}
+#include <__format/formatter_bool.h>
diff --git a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_bool.pass.cpp b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_bool.pass.cpp
new file mode 100644
index 0000000000000..c6fdbee325320
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_bool.pass.cpp
@@ -0,0 +1,452 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// <format>
+
+// Tests the parsing of the format string as specified in [format.string.std].
+// It validates whether the std-format-spec is valid for a boolean type.
+
+#include <format>
+#include <cassert>
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+# include <iostream>
+#endif
+
+#include "concepts_precision.h"
+#include "test_macros.h"
+#include "make_string.h"
+#include "test_exception.h"
+
+#define CSTR(S) MAKE_CSTRING(CharT, S)
+
+using namespace std::__format_spec;
+
+template <class CharT>
+using Parser = __parser_bool<CharT>;
+
+template <class CharT>
+struct Expected {
+ CharT fill = CharT(' ');
+ _Flags::_Alignment alignment = _Flags::_Alignment::__left;
+ _Flags::_Sign sign = _Flags::_Sign::__default;
+ bool alternate_form = false;
+ bool zero_padding = false;
+ uint32_t width = 0;
+ bool width_as_arg = false;
+ bool locale_specific_form = false;
+ _Flags::_Type type = _Flags::_Type::__string;
+};
+
+template <class CharT>
+constexpr void test(Expected<CharT> expected, size_t size,
+ std::basic_string_view<CharT> fmt) {
+ // Initialize parser with sufficient arguments to avoid the parsing to fail
+ // due to insufficient arguments.
+ std::basic_format_parse_context<CharT> parse_ctx(fmt,
+ std::__format::__number_max);
+ auto begin = parse_ctx.begin();
+ auto end = parse_ctx.end();
+ Parser<CharT> parser;
+ auto it = parser.parse(parse_ctx);
+
+ assert(begin == parse_ctx.begin());
+ assert(end == parse_ctx.end());
+
+ assert(begin + size == it);
+ assert(parser.__fill == expected.fill);
+ assert(parser.__alignment == expected.alignment);
+ assert(parser.__sign == expected.sign);
+ assert(parser.__alternate_form == expected.alternate_form);
+ assert(parser.__zero_padding == expected.zero_padding);
+ assert(parser.__width == expected.width);
+ assert(parser.__width_as_arg == expected.width_as_arg);
+ assert(parser.__locale_specific_form == expected.locale_specific_form);
+ assert(parser.__type == expected.type);
+}
+
+template <class CharT>
+constexpr void test(Expected<CharT> expected, size_t size, const CharT* f) {
+ // The format-spec is valid if completely consumed or terminates at a '}'.
+ // The valid inputs all end with a '}'. The test is executed twice:
+ // - first with the terminating '}',
+ // - second consuming the entire input.
+ std::basic_string_view<CharT> fmt{f};
+ assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+ test(expected, size, fmt);
+ fmt.remove_suffix(1);
+ test(expected, size, fmt);
+}
+
+template <class CharT>
+constexpr void test_as_string() {
+
+ test({}, 1, CSTR("s}"));
+
+ // *** Align-fill ***
+ test({.alignment = _Flags::_Alignment::__left}, 1, CSTR("<}"));
+ test({.alignment = _Flags::_Alignment::__center}, 1, "^}");
+ test({.alignment = _Flags::_Alignment::__right}, 1, ">}");
+
+ test({.alignment = _Flags::_Alignment::__left}, 2, CSTR("<s}"));
+ test({.alignment = _Flags::_Alignment::__center}, 2, "^s}");
+ test({.alignment = _Flags::_Alignment::__right}, 2, ">s}");
+
+ test({.fill = CharT('L'), .alignment = _Flags::_Alignment::__left}, 2,
+ CSTR("L<}"));
+ test({.fill = CharT('#'), .alignment = _Flags::_Alignment::__center}, 2,
+ CSTR("#^}"));
+ test({.fill = CharT('0'), .alignment = _Flags::_Alignment::__right}, 2,
+ CSTR("0>}"));
+
+ test({.fill = CharT('L'), .alignment = _Flags::_Alignment::__left}, 3,
+ CSTR("L<s}"));
+ test({.fill = CharT('#'), .alignment = _Flags::_Alignment::__center}, 3,
+ CSTR("#^s}"));
+ test({.fill = CharT('0'), .alignment = _Flags::_Alignment::__right}, 3,
+ CSTR("0>s}"));
+
+ // *** Sign ***
+ test_exception<Parser<CharT>>(
+ "A sign field isn't allowed in this format-spec", CSTR("-}"));
+ test_exception<Parser<CharT>>(
+ "A sign field isn't allowed in this format-spec", CSTR("-s}"));
+
+ // *** Alternate form ***
+ test_exception<Parser<CharT>>(
+ "An alternate form field isn't allowed in this format-spec", CSTR("#}"));
+ test_exception<Parser<CharT>>(
+ "An alternate form field isn't allowed in this format-spec", CSTR("#s}"));
+
+ // *** Zero padding ***
+ test_exception<Parser<CharT>>(
+ "A zero-padding field isn't allowed in this format-spec", CSTR("0}"));
+ test_exception<Parser<CharT>>(
+ "A zero-padding field isn't allowed in this format-spec", CSTR("0s}"));
+
+ // *** Width ***
+ test({.width = 0, .width_as_arg = false}, 0, CSTR("}"));
+ test({.width = 1, .width_as_arg = false}, 1, CSTR("1}"));
+ test({.width = 10, .width_as_arg = false}, 2, CSTR("10}"));
+ test({.width = 1000, .width_as_arg = false}, 4, CSTR("1000}"));
+ test({.width = 1000000, .width_as_arg = false}, 7, CSTR("1000000}"));
+
+ test({.width = 0, .width_as_arg = true}, 2, CSTR("{}}"));
+ test({.width = 0, .width_as_arg = true}, 3, CSTR("{0}}"));
+ test({.width = 1, .width_as_arg = true}, 3, CSTR("{1}}"));
+
+ test_exception<Parser<CharT>>(
+ "A format-spec width field shouldn't have a leading zero", CSTR("00"));
+
+ static_assert(std::__format::__number_max == 2'147'483'647,
+ "Update the assert and the test.");
+ test({.width = 2'147'483'647, .width_as_arg = false}, 10,
+ CSTR("2147483647}"));
+ test_exception<Parser<CharT>>(
+ "The numeric value of the format-spec is too large", CSTR("2147483648"));
+ test_exception<Parser<CharT>>(
+ "The numeric value of the format-spec is too large", CSTR("5000000000"));
+ test_exception<Parser<CharT>>(
+ "The numeric value of the format-spec is too large", CSTR("10000000000"));
+
+ test_exception<Parser<CharT>>("End of input while parsing format-spec arg-id",
+ CSTR("{"));
+ test_exception<Parser<CharT>>(
+ "A format-spec arg-id should terminate at a '}'", CSTR("{0"));
+ test_exception<Parser<CharT>>(
+ "The arg-id of the format-spec starts with an invalid character",
+ CSTR("{a"));
+ test_exception<Parser<CharT>>(
+ "A format-spec arg-id should terminate at a '}'", CSTR("{1"));
+ test_exception<Parser<CharT>>(
+ "A format-spec arg-id should terminate at a '}'", CSTR("{9"));
+ test_exception<Parser<CharT>>(
+ "A format-spec arg-id should terminate at a '}'", CSTR("{9:"));
+ test_exception<Parser<CharT>>(
+ "A format-spec arg-id should terminate at a '}'", CSTR("{9a"));
+
+ static_assert(std::__format::__number_max == 2'147'483'647,
+ "Update the assert and the test.");
+ // Note the static_assert tests whether the arg-id is valid.
+ // Therefore the following should be true arg-id < __format::__number_max.
+ test({.width = 2'147'483'646, .width_as_arg = true}, 12,
+ CSTR("{2147483646}}"));
+ test_exception<Parser<CharT>>(
+ "The numeric value of the format-spec is too large",
+ CSTR("{2147483648}"));
+ test_exception<Parser<CharT>>(
+ "The numeric value of the format-spec is too large",
+ CSTR("{5000000000}"));
+ test_exception<Parser<CharT>>(
+ "The numeric value of the format-spec is too large",
+ CSTR("{10000000000}"));
+
+ // *** Precision ***
+ test_exception<Parser<CharT>>(
+ "The format-spec should consume the input or end with a '}'", CSTR("."));
+ test_exception<Parser<CharT>>(
+ "The format-spec should consume the input or end with a '}'", CSTR(".1"));
+
+ // *** Locale-specific form ***
+ test({.locale_specific_form = true}, 1, CSTR("L}"));
+ test({.locale_specific_form = true}, 2, CSTR("Ls}"));
+}
+
+template <class CharT>
+constexpr void test_as_char() {
+
+ test({.type = _Flags::_Type::__char}, 1, CSTR("c}"));
+
+ // *** Align-fill ***
+ test({.alignment = _Flags::_Alignment::__left, .type = _Flags::_Type::__char},
+ 2, CSTR("<c}"));
+ test({.alignment = _Flags::_Alignment::__center,
+ .type = _Flags::_Type::__char},
+ 2, "^c}");
+ test(
+ {.alignment = _Flags::_Alignment::__right, .type = _Flags::_Type::__char},
+ 2, ">c}");
+
+ test({.fill = CharT('L'),
+ .alignment = _Flags::_Alignment::__left,
+ .type = _Flags::_Type::__char},
+ 3, CSTR("L<c}"));
+ test({.fill = CharT('#'),
+ .alignment = _Flags::_Alignment::__center,
+ .type = _Flags::_Type::__char},
+ 3, CSTR("#^c}"));
+ test({.fill = CharT('0'),
+ .alignment = _Flags::_Alignment::__right,
+ .type = _Flags::_Type::__char},
+ 3, CSTR("0>c}"));
+
+ // *** Sign ***
+ test_exception<Parser<CharT>>(
+ "A sign field isn't allowed in this format-spec", CSTR("-c}"));
+
+ // *** Alternate form ***
+ test_exception<Parser<CharT>>(
+ "An alternate form field isn't allowed in this format-spec", CSTR("#c}"));
+
+ // *** Zero padding ***
+ test_exception<Parser<CharT>>(
+ "A zero-padding field isn't allowed in this format-spec", CSTR("0c}"));
+
+ // *** Width ***
+ test({.width = 0, .width_as_arg = false, .type = _Flags::_Type::__char}, 1,
+ CSTR("c}"));
+ test({.width = 1, .width_as_arg = false, .type = _Flags::_Type::__char}, 2,
+ CSTR("1c}"));
+ test({.width = 10, .width_as_arg = false, .type = _Flags::_Type::__char}, 3,
+ CSTR("10c}"));
+ test({.width = 1000, .width_as_arg = false, .type = _Flags::_Type::__char}, 5,
+ CSTR("1000c}"));
+ test({.width = 1000000, .width_as_arg = false, .type = _Flags::_Type::__char},
+ 8, CSTR("1000000c}"));
+
+ test({.width = 0, .width_as_arg = true, .type = _Flags::_Type::__char}, 3,
+ CSTR("{}c}"));
+ test({.width = 0, .width_as_arg = true, .type = _Flags::_Type::__char}, 4,
+ CSTR("{0}c}"));
+ test({.width = 1, .width_as_arg = true, .type = _Flags::_Type::__char}, 4,
+ CSTR("{1}c}"));
+
+ // *** Precision ***
+ test_exception<Parser<CharT>>(
+ "The format-spec should consume the input or end with a '}'", CSTR("."));
+ test_exception<Parser<CharT>>(
+ "The format-spec should consume the input or end with a '}'", CSTR(".1"));
+
+ // *** Locale-specific form ***
+ test({.locale_specific_form = true, .type = _Flags::_Type::__char}, 2,
+ CSTR("Lc}"));
+}
+
+template <class CharT>
+constexpr void test_as_integer() {
+
+ test({.alignment = _Flags::_Alignment::__right,
+ .type = _Flags::_Type::__decimal},
+ 1, CSTR("d}"));
+
+ // *** Align-fill ***
+ test({.alignment = _Flags::_Alignment::__left,
+ .type = _Flags::_Type::__decimal},
+ 2, CSTR("<d}"));
+ test({.alignment = _Flags::_Alignment::__center,
+ .type = _Flags::_Type::__decimal},
+ 2, "^d}");
+ test({.alignment = _Flags::_Alignment::__right,
+ .type = _Flags::_Type::__decimal},
+ 2, ">d}");
+
+ test({.fill = CharT('L'),
+ .alignment = _Flags::_Alignment::__left,
+ .type = _Flags::_Type::__decimal},
+ 3, CSTR("L<d}"));
+ test({.fill = CharT('#'),
+ .alignment = _Flags::_Alignment::__center,
+ .type = _Flags::_Type::__decimal},
+ 3, CSTR("#^d}"));
+ test({.fill = CharT('0'),
+ .alignment = _Flags::_Alignment::__right,
+ .type = _Flags::_Type::__decimal},
+ 3, CSTR("0>d}"));
+
+ // *** Sign ***
+ test({.alignment = _Flags::_Alignment::__right,
+ .sign = _Flags::_Sign::__minus,
+ .type = _Flags::_Type::__decimal},
+ 2, CSTR("-d}"));
+ test({.alignment = _Flags::_Alignment::__right,
+ .sign = _Flags::_Sign::__plus,
+ .type = _Flags::_Type::__decimal},
+ 2, CSTR("+d}"));
+ test({.alignment = _Flags::_Alignment::__right,
+ .sign = _Flags::_Sign::__space,
+ .type = _Flags::_Type::__decimal},
+ 2, CSTR(" d}"));
+
+ // *** Alternate form ***
+ test({.alignment = _Flags::_Alignment::__right,
+ .alternate_form = true,
+ .type = _Flags::_Type::__decimal},
+ 2, CSTR("#d}"));
+
+ // *** Zero padding ***
+ test({.alignment = _Flags::_Alignment::__default,
+ .zero_padding = true,
+ .type = _Flags::_Type::__decimal},
+ 2, CSTR("0d}"));
+ test({.alignment = _Flags::_Alignment::__center,
+ .type = _Flags::_Type::__decimal},
+ 3, CSTR("^0d}"));
+
+ // *** Width ***
+ test({.alignment = _Flags::_Alignment::__right,
+ .width = 0,
+ .width_as_arg = false,
+ .type = _Flags::_Type::__decimal},
+ 1, CSTR("d}"));
+ test({.alignment = _Flags::_Alignment::__right,
+ .width = 1,
+ .width_as_arg = false,
+ .type = _Flags::_Type::__decimal},
+ 2, CSTR("1d}"));
+ test({.alignment = _Flags::_Alignment::__right,
+ .width = 10,
+ .width_as_arg = false,
+ .type = _Flags::_Type::__decimal},
+ 3, CSTR("10d}"));
+ test({.alignment = _Flags::_Alignment::__right,
+ .width = 1000,
+ .width_as_arg = false,
+ .type = _Flags::_Type::__decimal},
+ 5, CSTR("1000d}"));
+ test({.alignment = _Flags::_Alignment::__right,
+ .width = 1000000,
+ .width_as_arg = false,
+ .type = _Flags::_Type::__decimal},
+ 8, CSTR("1000000d}"));
+
+ test({.alignment = _Flags::_Alignment::__right,
+ .width = 0,
+ .width_as_arg = true,
+ .type = _Flags::_Type::__decimal},
+ 3, CSTR("{}d}"));
+ test({.alignment = _Flags::_Alignment::__right,
+ .width = 0,
+ .width_as_arg = true,
+ .type = _Flags::_Type::__decimal},
+ 4, CSTR("{0}d}"));
+ test({.alignment = _Flags::_Alignment::__right,
+ .width = 1,
+ .width_as_arg = true,
+ .type = _Flags::_Type::__decimal},
+ 4, CSTR("{1}d}"));
+
+ // *** Precision ***
+ test_exception<Parser<CharT>>(
+ "The format-spec should consume the input or end with a '}'", CSTR("."));
+ test_exception<Parser<CharT>>(
+ "The format-spec should consume the input or end with a '}'", CSTR(".1"));
+
+ // *** Locale-specific form ***
+ test({.alignment = _Flags::_Alignment::__right,
+ .locale_specific_form = true,
+ .type = _Flags::_Type::__decimal},
+ 2, CSTR("Ld}"));
+}
+
+template <class CharT>
+constexpr void test() {
+ Parser<CharT> parser;
+
+ assert(parser.__fill == CharT(' '));
+ assert(parser.__alignment == _Flags::_Alignment::__default);
+ assert(parser.__sign == _Flags::_Sign::__default);
+ assert(parser.__alternate_form == false);
+ assert(parser.__zero_padding == false);
+ assert(parser.__width == 0);
+ assert(parser.__width_as_arg == false);
+ static_assert(!has_precision<decltype(parser)>);
+ static_assert(!has_precision_as_arg<decltype(parser)>);
+ assert(parser.__locale_specific_form == false);
+ assert(parser.__type == _Flags::_Type::__default);
+
+ test({}, 0, CSTR("}"));
+
+ test_as_string<CharT>();
+ test_as_char<CharT>();
+ test_as_integer<CharT>();
+
+ // *** Type ***
+ {
+ const char* expected =
+ "The format-spec type has a type not supported for a bool argument";
+ test_exception<Parser<CharT>>(expected, CSTR("A}"));
+ test_exception<Parser<CharT>>(expected, CSTR("E}"));
+ test_exception<Parser<CharT>>(expected, CSTR("F}"));
+ test_exception<Parser<CharT>>(expected, CSTR("G}"));
+ test_exception<Parser<CharT>>(expected, CSTR("a}"));
+ test_exception<Parser<CharT>>(expected, CSTR("e}"));
+ test_exception<Parser<CharT>>(expected, CSTR("f}"));
+ test_exception<Parser<CharT>>(expected, CSTR("g}"));
+ test_exception<Parser<CharT>>(expected, CSTR("p}"));
+ }
+
+ // **** General ***
+ test_exception<Parser<CharT>>(
+ "The format-spec should consume the input or end with a '}'", CSTR("ss"));
+}
+
+constexpr bool test() {
+ test<char>();
+ test<wchar_t>();
+
+ return true;
+}
+
+int main(int, char**) {
+#ifndef _WIN32
+ // Make sure the parsers match the expectations. The layout of the
+ // subobjects is chosen to minimize the size required.
+ static_assert(sizeof(Parser<char>) == 2 * sizeof(uint32_t));
+ static_assert(
+ sizeof(Parser<wchar_t>) ==
+ (sizeof(wchar_t) <= 2 ? 2 * sizeof(uint32_t) : 3 * sizeof(uint32_t)));
+#endif
+
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.pass.cpp
index 9a62d04be37f4..41b6f1246945f 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.pass.cpp
@@ -67,8 +67,8 @@ void test_termination_condition(StringT expected, StringT f, bool arg) {
template <class CharT>
void test_boolean() {
- test_termination_condition(STR("1"), STR("}"), true);
- test_termination_condition(STR("0"), STR("}"), false);
+ test_termination_condition(STR("true"), STR("}"), true);
+ test_termination_condition(STR("false"), STR("}"), false);
}
int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h b/libcxx/test/std/utilities/format/format.functions/format_tests.h
index 1478288b8c976..3da2edfbf066b 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_tests.h
+++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h
@@ -15,6 +15,7 @@
// ExceptionTest must be callable as check_exception(expected-exception, string-to-format, args-to-format...)
#define STR(S) MAKE_STRING(CharT, S)
+#define CSTR(S) MAKE_CSTRING(CharT, S)
template <class CharT>
std::vector<std::basic_string<CharT>> invalid_types(std::string valid) {
@@ -260,6 +261,238 @@ void format_string_tests(TestFunction check, ExceptionTest check_exception) {
format_test_string_unicode<CharT>(check);
}
+template <class CharT, class TestFunction, class ExceptionTest>
+void format_test_bool(TestFunction check, ExceptionTest check_exception) {
+
+ // *** align-fill & width ***
+ check(STR("answer is 'true '"), STR("answer is '{:7}'"), true);
+ check(STR("answer is ' true'"), STR("answer is '{:>7}'"), true);
+ check(STR("answer is 'true '"), STR("answer is '{:<7}'"), true);
+ check(STR("answer is ' true '"), STR("answer is '{:^7}'"), true);
+
+ check(STR("answer is 'false '"), STR("answer is '{:8s}'"), false);
+ check(STR("answer is ' false'"), STR("answer is '{:>8s}'"), false);
+ check(STR("answer is 'false '"), STR("answer is '{:<8s}'"), false);
+ check(STR("answer is ' false '"), STR("answer is '{:^8s}'"), false);
+
+ check(STR("answer is '---true'"), STR("answer is '{:->7}'"), true);
+ check(STR("answer is 'true---'"), STR("answer is '{:-<7}'"), true);
+ check(STR("answer is '-true--'"), STR("answer is '{:-^7}'"), true);
+
+ check(STR("answer is '---false'"), STR("answer is '{:->8s}'"), false);
+ check(STR("answer is 'false---'"), STR("answer is '{:-<8s}'"), false);
+ check(STR("answer is '-false--'"), STR("answer is '{:-^8s}'"), false);
+
+ // *** Sign ***
+ check_exception("A sign field isn't allowed in this format-spec", STR("{:-}"),
+ true);
+ check_exception("A sign field isn't allowed in this format-spec", STR("{:+}"),
+ true);
+ check_exception("A sign field isn't allowed in this format-spec", STR("{: }"),
+ true);
+
+ check_exception("A sign field isn't allowed in this format-spec",
+ STR("{:-s}"), true);
+ check_exception("A sign field isn't allowed in this format-spec",
+ STR("{:+s}"), true);
+ check_exception("A sign field isn't allowed in this format-spec",
+ STR("{: s}"), true);
+
+ // *** alternate form ***
+ check_exception("An alternate form field isn't allowed in this format-spec",
+ STR("{:#}"), true);
+ check_exception("An alternate form field isn't allowed in this format-spec",
+ STR("{:#s}"), true);
+
+ // *** zero-padding ***
+ check_exception("A zero-padding field isn't allowed in this format-spec",
+ STR("{:0}"), true);
+ check_exception("A zero-padding field isn't allowed in this format-spec",
+ STR("{:0s}"), true);
+
+ // *** precision ***
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.}"), true);
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.0}"), true);
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.42}"), true);
+
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.s}"), true);
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.0s}"), true);
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.42s}"), true);
+
+ // *** locale-specific form ***
+ // See locale-specific_form.pass.cpp
+
+ // *** type ***
+ for (const auto& fmt : invalid_types<CharT>("bBcdosxX"))
+ check_exception(
+ "The format-spec type has a type not supported for a bool argument",
+ fmt, true);
+}
+
+template <class CharT, class TestFunction, class ExceptionTest>
+void format_test_bool_as_char(TestFunction check,
+ ExceptionTest check_exception) {
+ // *** align-fill & width ***
+ check(STR("answer is '\1 '"), STR("answer is '{:6c}'"), true);
+ check(STR("answer is ' \1'"), STR("answer is '{:>6c}'"), true);
+ check(STR("answer is '\1 '"), STR("answer is '{:<6c}'"), true);
+ check(STR("answer is ' \1 '"), STR("answer is '{:^6c}'"), true);
+
+ check(STR("answer is '-----\1'"), STR("answer is '{:->6c}'"), true);
+ check(STR("answer is '\1-----'"), STR("answer is '{:-<6c}'"), true);
+ check(STR("answer is '--\1---'"), STR("answer is '{:-^6c}'"), true);
+
+ check(std::basic_string<CharT>(CSTR("answer is '\0 '"), 18),
+ STR("answer is '{:6c}'"), false);
+ check(std::basic_string<CharT>(CSTR("answer is '\0 '"), 18),
+ STR("answer is '{:6c}'"), false);
+ check(std::basic_string<CharT>(CSTR("answer is ' \0'"), 18),
+ STR("answer is '{:>6c}'"), false);
+ check(std::basic_string<CharT>(CSTR("answer is '\0 '"), 18),
+ STR("answer is '{:<6c}'"), false);
+ check(std::basic_string<CharT>(CSTR("answer is ' \0 '"), 18),
+ STR("answer is '{:^6c}'"), false);
+
+ check(std::basic_string<CharT>(CSTR("answer is '-----\0'"), 18),
+ STR("answer is '{:->6c}'"), false);
+ check(std::basic_string<CharT>(CSTR("answer is '\0-----'"), 18),
+ STR("answer is '{:-<6c}'"), false);
+ check(std::basic_string<CharT>(CSTR("answer is '--\0---'"), 18),
+ STR("answer is '{:-^6c}'"), false);
+
+ // *** Sign ***
+ check_exception("A sign field isn't allowed in this format-spec",
+ STR("{:-c}"), true);
+ check_exception("A sign field isn't allowed in this format-spec",
+ STR("{:+c}"), true);
+ check_exception("A sign field isn't allowed in this format-spec",
+ STR("{: c}"), true);
+
+ // *** alternate form ***
+ check_exception("An alternate form field isn't allowed in this format-spec",
+ STR("{:#c}"), true);
+
+ // *** zero-padding ***
+ check_exception("A zero-padding field isn't allowed in this format-spec",
+ STR("{:0c}"), true);
+
+ // *** precision ***
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.c}"), true);
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.0c}"), true);
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.42c}"), true);
+
+ // *** locale-specific form ***
+ // Note it has no effect but it's allowed.
+ check(STR("answer is '*'"), STR("answer is '{:Lc}'"), '*');
+
+ // *** type ***
+ for (const auto& fmt : invalid_types<CharT>("bBcdosxX"))
+ check_exception(
+ "The format-spec type has a type not supported for a bool argument",
+ fmt, true);
+}
+
+template <class CharT, class TestFunction, class ExceptionTest>
+void format_test_bool_as_integer(TestFunction check,
+ ExceptionTest check_exception) {
+ // *** align-fill & width ***
+ check(STR("answer is '1'"), STR("answer is '{:<1d}'"), true);
+ check(STR("answer is '1 '"), STR("answer is '{:<2d}'"), true);
+ check(STR("answer is '0 '"), STR("answer is '{:<2d}'"), false);
+
+ check(STR("answer is ' 1'"), STR("answer is '{:6d}'"), true);
+ check(STR("answer is ' 1'"), STR("answer is '{:>6d}'"), true);
+ check(STR("answer is '1 '"), STR("answer is '{:<6d}'"), true);
+ check(STR("answer is ' 1 '"), STR("answer is '{:^6d}'"), true);
+
+ check(STR("answer is '*****0'"), STR("answer is '{:*>6d}'"), false);
+ check(STR("answer is '0*****'"), STR("answer is '{:*<6d}'"), false);
+ check(STR("answer is '**0***'"), STR("answer is '{:*^6d}'"), false);
+
+ // Test whether zero padding is ignored
+ check(STR("answer is ' 1'"), STR("answer is '{:>06d}'"), true);
+ check(STR("answer is '1 '"), STR("answer is '{:<06d}'"), true);
+ check(STR("answer is ' 1 '"), STR("answer is '{:^06d}'"), true);
+
+ // *** Sign ***
+ check(STR("answer is 1"), STR("answer is {:d}"), true);
+ check(STR("answer is 0"), STR("answer is {:-d}"), false);
+ check(STR("answer is +1"), STR("answer is {:+d}"), true);
+ check(STR("answer is 0"), STR("answer is {: d}"), false);
+
+ // *** alternate form ***
+ check(STR("answer is +1"), STR("answer is {:+#d}"), true);
+ check(STR("answer is +1"), STR("answer is {:+b}"), true);
+ check(STR("answer is +0b1"), STR("answer is {:+#b}"), true);
+ check(STR("answer is +0B1"), STR("answer is {:+#B}"), true);
+ check(STR("answer is +1"), STR("answer is {:+o}"), true);
+ check(STR("answer is +01"), STR("answer is {:+#o}"), true);
+ check(STR("answer is +1"), STR("answer is {:+x}"), true);
+ check(STR("answer is +0x1"), STR("answer is {:+#x}"), true);
+ check(STR("answer is +1"), STR("answer is {:+X}"), true);
+ check(STR("answer is +0X1"), STR("answer is {:+#X}"), true);
+
+ check(STR("answer is 0"), STR("answer is {:#d}"), false);
+ check(STR("answer is 0"), STR("answer is {:b}"), false);
+ check(STR("answer is 0b0"), STR("answer is {:#b}"), false);
+ check(STR("answer is 0B0"), STR("answer is {:#B}"), false);
+ check(STR("answer is 0"), STR("answer is {:o}"), false);
+ check(STR("answer is 0"), STR("answer is {:#o}"), false);
+ check(STR("answer is 0"), STR("answer is {:x}"), false);
+ check(STR("answer is 0x0"), STR("answer is {:#x}"), false);
+ check(STR("answer is 0"), STR("answer is {:X}"), false);
+ check(STR("answer is 0X0"), STR("answer is {:#X}"), false);
+
+ // *** zero-padding & width ***
+ check(STR("answer is +00000000001"), STR("answer is {:+#012d}"), true);
+ check(STR("answer is +00000000001"), STR("answer is {:+012b}"), true);
+ check(STR("answer is +0b000000001"), STR("answer is {:+#012b}"), true);
+ check(STR("answer is +0B000000001"), STR("answer is {:+#012B}"), true);
+ check(STR("answer is +00000000001"), STR("answer is {:+012o}"), true);
+ check(STR("answer is +00000000001"), STR("answer is {:+#012o}"), true);
+ check(STR("answer is +00000000001"), STR("answer is {:+012x}"), true);
+ check(STR("answer is +0x000000001"), STR("answer is {:+#012x}"), true);
+ check(STR("answer is +00000000001"), STR("answer is {:+012X}"), true);
+ check(STR("answer is +0X000000001"), STR("answer is {:+#012X}"), true);
+
+ check(STR("answer is 000000000000"), STR("answer is {:#012d}"), false);
+ check(STR("answer is 000000000000"), STR("answer is {:012b}"), false);
+ check(STR("answer is 0b0000000000"), STR("answer is {:#012b}"), false);
+ check(STR("answer is 0B0000000000"), STR("answer is {:#012B}"), false);
+ check(STR("answer is 000000000000"), STR("answer is {:012o}"), false);
+ check(STR("answer is 000000000000"), STR("answer is {:#012o}"), false);
+ check(STR("answer is 000000000000"), STR("answer is {:012x}"), false);
+ check(STR("answer is 0x0000000000"), STR("answer is {:#012x}"), false);
+ check(STR("answer is 000000000000"), STR("answer is {:012X}"), false);
+ check(STR("answer is 0X0000000000"), STR("answer is {:#012X}"), false);
+
+ // *** precision ***
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.}"), true);
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.0}"), true);
+ check_exception("The format-spec should consume the input or end with a '}'",
+ STR("{:.42}"), true);
+
+ // *** locale-specific form ***
+ // See locale-specific_form.pass.cpp
+
+ // *** type ***
+ for (const auto& fmt : invalid_types<CharT>("bBcdosxX"))
+ check_exception(
+ "The format-spec type has a type not supported for a bool argument",
+ fmt, true);
+}
+
template <class I, class CharT, class TestFunction, class ExceptionTest>
void format_test_integer_as_integer(TestFunction check,
ExceptionTest check_exception) {
@@ -743,8 +976,8 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
check(STR("}"), STR("}}"));
// *** Test argument ID ***
- check(STR("hello 01"), STR("hello {0:}{1:}"), false, true);
- check(STR("hello 10"), STR("hello {1:}{0:}"), false, true);
+ check(STR("hello false true"), STR("hello {0:} {1:}"), false, true);
+ check(STR("hello true false"), STR("hello {1:} {0:}"), false, true);
// ** Test invalid format strings ***
check_exception("The format string terminates at a '{'", STR("{"));
@@ -799,7 +1032,11 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
format_string_tests<CharT>(check, check_exception);
// *** Test Boolean format argument ***
- check(STR("hello 01"), STR("hello {}{}"), false, true);
+ check(STR("hello false true"), STR("hello {} {}"), false, true);
+
+ format_test_bool<CharT>(check, check_exception);
+ format_test_bool_as_char<CharT>(check, check_exception);
+ format_test_bool_as_integer<CharT>(check, check_exception);
// *** Test signed integral format argument ***
check(STR("hello 42"), STR("hello {}"), static_cast<signed char>(42));
diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
index 9598bea7076da..461f541c73750 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
@@ -56,8 +56,8 @@ auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
CharT out[4096];
CharT* it = std::format_to(out, std::locale(), fmt, args...);
assert(std::distance(out, it) == int(expected.size()));
- *it = '\0';
- assert(out == expected);
+ // Convert to std::string since output contains '\0' for boolean tests.
+ assert(std::basic_string<CharT>(out, it) == expected);
}
};
diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
index 795587cb4f993..fc988beaca97e 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
@@ -57,8 +57,8 @@ auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
CharT out[4096];
CharT* it = std::format_to(out, fmt, args...);
assert(std::distance(out, it) == int(expected.size()));
- *it = '\0';
- assert(out == expected);
+ // Convert to std::string since output contains '\0' for boolean tests.
+ assert(std::basic_string<CharT>(out, it) == expected);
}
};
diff --git a/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp b/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
index b32f22a5020b2..eda372310ac8d 100644
--- a/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
@@ -227,6 +227,56 @@ void test(std::basic_string<CharT> expected, std::locale loc,
}
}
+#ifndef _LIBCPP_HAS_NO_UNICODE
+template <class CharT>
+struct numpunct_unicode;
+
+template <>
+struct numpunct_unicode<char> : std::numpunct<char> {
+ string_type do_truename() const override { return "gültig"; }
+ string_type do_falsename() const override { return "ungültig"; }
+};
+
+template <>
+struct numpunct_unicode<wchar_t> : std::numpunct<wchar_t> {
+ string_type do_truename() const override { return L"gültig"; }
+ string_type do_falsename() const override { return L"ungültig"; }
+};
+#endif
+
+template <class CharT>
+void test_bool() {
+ std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+
+ std::locale::global(std::locale(LOCALE_en_US_UTF_8));
+ assert(std::locale().name() == LOCALE_en_US_UTF_8);
+ test(STR("true"), STR("{:L}"), true);
+ test(STR("false"), STR("{:L}"), false);
+
+ test(STR("yes"), loc, STR("{:L}"), true);
+ test(STR("no"), loc, STR("{:L}"), false);
+
+ std::locale::global(loc);
+ test(STR("yes"), STR("{:L}"), true);
+ test(STR("no"), STR("{:L}"), false);
+
+ test(STR("true"), std::locale(LOCALE_en_US_UTF_8), STR("{:L}"), true);
+ test(STR("false"), std::locale(LOCALE_en_US_UTF_8), STR("{:L}"), false);
+
+#ifndef _LIBCPP_HAS_NO_UNICODE
+ std::locale loc_unicode =
+ std::locale(std::locale(), new numpunct_unicode<CharT>());
+
+ test(STR("gültig"), loc_unicode, STR("{:L}"), true);
+ test(STR("ungültig"), loc_unicode, STR("{:L}"), false);
+
+ test(STR("gültig "), loc_unicode, STR("{:9L}"), true);
+ test(STR("gültig!!!"), loc_unicode, STR("{:!<9L}"), true);
+ test(STR("_gültig__"), loc_unicode, STR("{:_^9L}"), true);
+ test(STR(" gültig"), loc_unicode, STR("{:>9L}"), true);
+#endif
+}
+
template <class CharT>
void test_integer() {
std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
@@ -557,6 +607,7 @@ void test_integer() {
template <class CharT>
void test() {
+ test_bool<CharT>();
test_integer<CharT>();
}
diff --git a/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
index 6569934bec767..a006a2b686c08 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
@@ -68,8 +68,8 @@ auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
std::make_format_args<std::basic_format_context<CharT*, CharT>>(
args...));
assert(std::distance(out, it) == int(expected.size()));
- *it = '\0';
- assert(out == expected);
+ // Convert to std::string since output contains '\0' for boolean tests.
+ assert(std::basic_string<CharT>(out, it) == expected);
}
};
diff --git a/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
index 179776a7f0760..1c243e68d493e 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
@@ -71,8 +71,8 @@ auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
std::make_format_args<std::basic_format_context<CharT*, CharT>>(
args...));
assert(std::distance(out, it) == int(expected.size()));
- *it = '\0';
- assert(out == expected);
+ // Convert to std::string since output contains '\0' for boolean tests.
+ assert(std::basic_string<CharT>(out, it) == expected);
}
};
More information about the libcxx-commits
mailing list