diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv index 10463c44ef8fe..d80346e9d68c5 100644 --- a/libcxx/docs/Status/FormatPaper.csv +++ b/libcxx/docs/Status/FormatPaper.csv @@ -34,4 +34,4 @@ Section,Description,Dependencies,Assignee,Status,First released version `[format.range] `_,"Formatting for ranges: associative",,Mark de Wever,, `[format.range] `_,"Formatting for ranges: container adaptors",,Mark de Wever,|Complete|,Clang 16 `[format.range] `_,"Formatting for ranges: ``pair`` and ``tuple``",,Mark de Wever,|Complete|,Clang 16 -`[format.range] `_,"Formatting for ranges: ``vector``",,Mark de Wever,, +`[format.range] `_,"Formatting for ranges: ``vector``",,Mark de Wever,|Complete|,Clang 16 diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index b954c10493778..26657491393dd 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -55,6 +55,8 @@ class __bit_reference friend class __bit_const_reference<_Cp>; friend class __bit_iterator<_Cp, false>; public: + using __container = typename _Cp::__self; + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_reference(const __bit_reference&) = default; diff --git a/libcxx/include/vector b/libcxx/include/vector index e9d1b72171e7f..4c939806dc12b 100644 --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -267,6 +267,13 @@ template typename vector::size_type erase_if(vector& c, Predicate pred); // C++20 + +template + inline constexpr bool is-vector-bool-reference = see below; // exposition only, since C++23 + +template requires is-vector-bool-reference // Since C++23 + struct formatter; + } // std */ @@ -281,9 +288,11 @@ erase_if(vector& c, Predicate pred); // C++20 #include <__algorithm/unwrap_iter.h> #include <__assert> // all public C++ headers provide the assertion handler #include <__bit_reference> +#include <__concepts/same_as.h> #include <__config> #include <__debug> #include <__format/enable_insertable.h> +#include <__format/formatter.h> #include <__functional/hash.h> #include <__functional/unary_function.h> #include <__iterator/advance.h> @@ -3312,6 +3321,27 @@ inline constexpr bool __format::__enable_insertable> = true; #endif // _LIBCPP_STD_VER > 17 +#if _LIBCPP_STD_VER > 20 +template +// Since is-vector-bool-reference is only used once it's inlined here. + requires same_as> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<_Tp, CharT> { +private: + formatter __underlying_; + +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return __underlying_.parse(__ctx); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _Tp& __ref, _FormatContext& __ctx) const { + return __underlying_.format(__ref, __ctx); + } +}; +#endif // _LIBCPP_STD_VER > 20 + _LIBCPP_END_NAMESPACE_STD #if _LIBCPP_STD_VER > 14 diff --git a/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.format.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.format.pass.cpp new file mode 100644 index 0000000000000..61cbfea76de7f --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.format.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// 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, c++20 +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// + +// template +// requires is-vector-bool-reference +// struct formatter + +// template +// string format(format_string fmt, Args&&... args); +// template +// wstring format(wformat_string fmt, Args&&... args); + +#include +#include + +#include "format.functions.tests.h" +#include "test_format_string.h" +#include "test_macros.h" +#include "assert_macros.h" + +auto test = []( + std::basic_string_view expected, test_format_string fmt, Args&&... args) { + std::basic_string out = std::format(fmt, std::forward(args)...); + TEST_REQUIRE( + out == expected, + test_concat_message("\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n')); +}; + +auto test_exception = [](std::string_view, std::basic_string_view, Args&&...) { + // After P2216 most exceptions thrown by std::format become ill-formed. + // Therefore this tests does nothing. +}; + +int main(int, char**) { + format_tests(test, test_exception); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + format_tests(test, test_exception); +#endif + + return 0; +} diff --git a/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.tests.h b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.tests.h new file mode 100644 index 0000000000000..32b68b85f85ab --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.tests.h @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// 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 TEST_STD_CONTAINERS_SEQUENCES_VECTOR_BOOL_VECTOR_BOOL_FMT_FORMAT_FUNCTIONS_TESTS_H +#define TEST_STD_CONTAINERS_SEQUENCES_VECTOR_BOOL_VECTOR_BOOL_FMT_FORMAT_FUNCTIONS_TESTS_H + +#include + +#include "format.functions.common.h" +#include "test_macros.h" + +template +void format_tests(TestFunction check, ExceptionTest check_exception) { + std::vector input{true, true, false}; + + check(SV("[true, true, false]"), SV("{}"), input); + + // ***** underlying has no format-spec + + // *** align-fill & width *** + check(SV("[true, true, false] "), SV("{:24}"), input); + check(SV("[true, true, false]*****"), SV("{:*<24}"), input); + check(SV("__[true, true, false]___"), SV("{:_^24}"), input); + check(SV("#####[true, true, false]"), SV("{:#>24}"), input); + + check(SV("[true, true, false] "), SV("{:{}}"), input, 24); + check(SV("[true, true, false]*****"), SV("{:*<{}}"), input, 24); + check(SV("__[true, true, false]___"), SV("{:_^{}}"), input, 24); + check(SV("#####[true, true, false]"), SV("{:#>{}}"), input, 24); + + check_exception("The format-spec range-fill field contains an invalid character", SV("{:}<}"), input); + check_exception("The format-spec range-fill field contains an invalid character", SV("{:{<}"), input); + check_exception("The format-spec range-fill field contains an invalid character", SV("{::<}"), input); + + // *** sign *** + check_exception("The format-spec should consume the input or end with a '}'", SV("{:-}"), input); + check_exception("The format-spec should consume the input or end with a '}'", SV("{:+}"), input); + check_exception("The format-spec should consume the input or end with a '}'", SV("{: }"), input); + + // *** alternate form *** + check_exception("The format-spec should consume the input or end with a '}'", SV("{:#}"), input); + + // *** zero-padding *** + check_exception("A format-spec width field shouldn't have a leading zero", SV("{:0}"), input); + + // *** precision *** + check_exception("The format-spec should consume the input or end with a '}'", SV("{:.}"), input); + + // *** locale-specific form *** + check_exception("The format-spec should consume the input or end with a '}'", SV("{:L}"), input); + + // *** n + check(SV("__true, true, false___"), SV("{:_^22n}"), input); + + // *** type *** + check_exception("The range-format-spec type m requires two elements for a pair or tuple", SV("{:m}"), input); + check_exception("The range-format-spec type s requires formatting a character type", SV("{:s}"), input); + check_exception("The range-format-spec type ?s requires formatting a character type", SV("{:?s}"), input); + + for (std::basic_string_view fmt : fmt_invalid_types("s")) + check_exception("The format-spec should consume the input or end with a '}'", fmt, input); + + // ***** Only underlying has a format-spec + check(SV("[true , true , false ]"), SV("{::7}"), input); + check(SV("[true***, true***, false**]"), SV("{::*<7}"), input); + check(SV("[_true__, _true__, _false_]"), SV("{::_^7}"), input); + check(SV("[:::true, :::true, ::false]"), SV("{:::>7}"), input); + + check(SV("[true , true , false ]"), SV("{::{}}"), input, 7); + check(SV("[true***, true***, false**]"), SV("{::*<{}}"), input, 7); + check(SV("[_true__, _true__, _false_]"), SV("{::_^{}}"), input, 7); + check(SV("[:::true, :::true, ::false]"), SV("{:::>{}}"), input, 7); + + check_exception("The format-spec fill field contains an invalid character", SV("{::}<}"), input); + check_exception("The format-spec fill field contains an invalid character", SV("{::{<}"), input); + + // *** sign *** + check_exception("A sign field isn't allowed in this format-spec", SV("{::-}"), input); + check_exception("A sign field isn't allowed in this format-spec", SV("{::+}"), input); + check_exception("A sign field isn't allowed in this format-spec", SV("{:: }"), input); + + check(SV("[1, 1, 0]"), SV("{::-d}"), input); + check(SV("[+1, +1, +0]"), SV("{::+d}"), input); + check(SV("[ 1, 1, 0]"), SV("{:: d}"), input); + + // *** alternate form *** + check_exception("An alternate form field isn't allowed in this format-spec", SV("{::#}"), input); + + check(SV("[0x1, 0x1, 0x0]"), SV("{::#x}"), input); + + // *** zero-padding *** + check_exception("A zero-padding field isn't allowed in this format-spec", SV("{::05}"), input); + + check(SV("[00001, 00001, 00000]"), SV("{::05o}"), input); + + // *** precision *** + check_exception("The format-spec should consume the input or end with a '}'", SV("{::.}"), input); + + // *** type *** + for (std::basic_string_view fmt : fmt_invalid_nested_types("bBdosxX")) + check_exception("The format-spec type has a type not supported for a bool argument", fmt, input); + + // ***** Both have a format-spec + check(SV("^^[:::true, :::true, ::false]^^^"), SV("{:^^32::>7}"), input); + check(SV("^^[:::true, :::true, ::false]^^^"), SV("{:^^{}::>7}"), input, 32); + check(SV("^^[:::true, :::true, ::false]^^^"), SV("{:^^{}::>{}}"), input, 32, 7); + + check_exception("Argument index out of bounds", SV("{:^^{}::>5}"), input); + check_exception("Argument index out of bounds", SV("{:^^{}::>{}}"), input, 32); +} + +#endif // TEST_STD_CONTAINERS_SEQUENCES_VECTOR_BOOL_VECTOR_BOOL_FMT_FORMAT_FUNCTIONS_TESTS_H diff --git a/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.vformat.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.vformat.pass.cpp new file mode 100644 index 0000000000000..9e6db80cf9890 --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.vformat.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// 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, c++20 +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// This test requires the dylib support introduced in D92214. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}} +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}} + +// + +// template +// requires is-vector-bool-reference +// struct formatter + +// string vformat(string_view fmt, format_args args); +// wstring vformat(wstring_view fmt, wformat_args args); + +#include +#include + +#include "format.functions.tests.h" +#include "test_macros.h" +#include "assert_macros.h" + +auto test = []( + std::basic_string_view expected, std::basic_string_view fmt, Args&&... args) { + std::basic_string out = std::vformat(fmt, std::make_format_args>(args...)); + TEST_REQUIRE( + out == expected, + test_concat_message("\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n')); +}; + +auto test_exception = + []( + [[maybe_unused]] std::string_view what, + [[maybe_unused]] std::basic_string_view fmt, + [[maybe_unused]] Args&&... args) { +#ifndef TEST_HAS_NO_EXCEPTIONS + try { + TEST_IGNORE_NODISCARD std::vformat(fmt, std::make_format_args>(args...)); + TEST_FAIL(test_concat_message("\nFormat string ", fmt, "\nDidn't throw an exception.\n")); + } catch (const std::format_error& e) { + TEST_LIBCPP_REQUIRE( + e.what() == what, + test_concat_message( + "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); + + return; + } + assert(false); +#endif + }; + +int main(int, char**) { + format_tests(test, test_exception); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + format_tests(test, test_exception); +#endif + + return 0; +} diff --git a/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.pass.cpp new file mode 100644 index 0000000000000..bb29081dfb898 --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/format.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// 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, c++20 +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// This test requires the dylib support introduced in D92214. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}} +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}} + +// + +// template +// requires is-vector-bool-reference +// struct formatter + +// template +// typename FormatContext::iterator +// format(const T& r, FormatContext& ctx) const; + +// Note this tests the basics of this function. It's tested in more detail in +// the format functions test. + +#include +#include +#include +#include + +#include "test_format_context.h" +#include "test_macros.h" +#include "make_string.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +void test_format(StringViewT expected, std::vector::reference arg) { + using CharT = typename StringViewT::value_type; + using String = std::basic_string; + using OutIt = std::back_insert_iterator; + using FormatCtxT = std::basic_format_context; + + const std::formatter::reference, CharT> formatter; + + String result; + OutIt out = std::back_inserter(result); + FormatCtxT format_ctx = test_format_context_create(out, std::make_format_args(arg)); + formatter.format(arg, format_ctx); + assert(result == expected); +} + +template +void test_fmt() { + test_format(SV("true"), std::vector{true}[0]); + test_format(SV("false"), std::vector{false}[0]); +} + +void test() { + test_fmt(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_fmt(); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/parse.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/parse.pass.cpp new file mode 100644 index 0000000000000..c711e25d1cd06 --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector.bool/vector.bool.fmt/parse.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// 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, c++20 +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// This test requires the dylib support introduced in D92214. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}} +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}} + +// + +// template +// requires is-vector-bool-reference +// struct formatter + +// template +// constexpr typename ParseContext::iterator +// parse(ParseContext& ctx); + +// Note this tests the basics of this function. It's tested in more detail in +// the format functions test. + +#include +#include +#include +#include + +#include "test_format_context.h" +#include "test_macros.h" +#include "make_string.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +constexpr void test_parse(StringViewT fmt) { + using CharT = typename StringViewT::value_type; + auto parse_ctx = std::basic_format_parse_context(fmt); + std::formatter>::reference, CharT> formatter; + static_assert(std::semiregular); + + std::same_as auto it = formatter.parse(parse_ctx); + assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}')); +} + +template +constexpr void test_fmt() { + test_parse(SV("")); + test_parse(SV("b")); + + test_parse(SV("}")); + test_parse(SV("b}")); +} + +constexpr bool test() { + test_fmt(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_fmt(); +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp index 06a29502a9724..cef22792f3aa6 100644 --- a/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp +++ b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp @@ -38,6 +38,7 @@ #include #include "test_macros.h" +#include "min_allocator.h" #ifndef TEST_HAS_NO_FILESYSTEM_LIBRARY # include @@ -194,6 +195,12 @@ void test_P1636() { assert_is_not_formattable, CharT>(); } +template +void test_P2286_vector_bool() { + assert_is_formattable(); + assert_is_formattable(); +} + // Tests for P2286 Formatting ranges template void test_P2286() { @@ -223,6 +230,10 @@ void test_P2286() { assert_is_formattable, CharT>(); assert_is_formattable, CharT>(); + + test_P2286_vector_bool>(); + test_P2286_vector_bool>>(); + test_P2286_vector_bool>>(); } class c {