1 //===----------------------------------------------------------------------===//
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 
8 // UNSUPPORTED: c++03, c++11, c++14, c++17
9 // UNSUPPORTED: libcpp-has-no-incomplete-format
10 // TODO FMT Evaluate gcc-12 status
11 // UNSUPPORTED: gcc-12
12 // TODO FMT Investigate AppleClang ICE
13 // UNSUPPORTED: apple-clang-13
14 
15 // <format>
16 
17 // template<class Out, class... Args>
18 //   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
19 //                                       format-string<Args...> fmt, const Args&... args);
20 // template<class Out, class... Args>
21 //   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
22 //                                       wformat-string<Args...> fmt, const Args&... args);
23 
24 #include <format>
25 #include <algorithm>
26 #include <cassert>
27 #include <list>
28 #include <vector>
29 
30 #include "test_macros.h"
31 #include "format_tests.h"
32 #include "string_literal.h"
33 
34 auto test = []<string_literal fmt, class CharT, class... Args>(std::basic_string_view<CharT> expected,
35                                                                const Args&... args) constexpr {
36   {
37     std::list<CharT> out;
38     std::format_to_n_result result = std::format_to_n(std::back_inserter(out), 0, fmt.template sv<CharT>(), args...);
39     // To avoid signedness warnings make sure formatted_size uses the same type
40     // as result.size.
41     using diff_type = decltype(result.size);
42     diff_type formatted_size = std::formatted_size(fmt.template sv<CharT>(), args...);
43 
44     assert(result.size == formatted_size);
45     assert(out.empty());
46   }
47   {
48     std::vector<CharT> out;
49     std::format_to_n_result result = std::format_to_n(std::back_inserter(out), 5, fmt.template sv<CharT>(), args...);
50     using diff_type = decltype(result.size);
51     diff_type formatted_size = std::formatted_size(fmt.template sv<CharT>(), args...);
52     diff_type size = std::min<diff_type>(5, formatted_size);
53 
54     assert(result.size == formatted_size);
55     assert(std::equal(out.begin(), out.end(), expected.begin(), expected.begin() + size));
56   }
57   {
58     std::basic_string<CharT> out;
59     std::format_to_n_result result = std::format_to_n(std::back_inserter(out), 1000, fmt.template sv<CharT>(), args...);
60     using diff_type = decltype(result.size);
61     diff_type formatted_size = std::formatted_size(fmt.template sv<CharT>(), args...);
62     diff_type size = std::min<diff_type>(1000, formatted_size);
63 
64     assert(result.size == formatted_size);
65     assert(out == expected.substr(0, size));
66   }
67   {
68     // Test the returned iterator.
69     std::basic_string<CharT> out(10, CharT(' '));
70     std::format_to_n_result result = std::format_to_n(out.begin(), 10, fmt.template sv<CharT>(), args...);
71     using diff_type = decltype(result.size);
72     diff_type formatted_size = std::formatted_size(fmt.template sv<CharT>(), args...);
73     diff_type size = std::min<diff_type>(10, formatted_size);
74 
75     assert(result.size == formatted_size);
76     assert(result.out == out.begin() + size);
77     assert(out.substr(0, size) == expected.substr(0, size));
78   }
79   {
80     static_assert(std::is_signed_v<std::iter_difference_t<CharT*>>,
81                   "If the difference type isn't negative the test will fail "
82                   "due to using a large positive value.");
83     CharT buffer[1] = {CharT(0)};
84     std::format_to_n_result result = std::format_to_n(buffer, -1, fmt.template sv<CharT>(), args...);
85     using diff_type = decltype(result.size);
86     diff_type formatted_size = std::formatted_size(fmt.template sv<CharT>(), args...);
87 
88     assert(result.size == formatted_size);
89     assert(result.out == buffer);
90     assert(buffer[0] == CharT(0));
91   }
92 };
93 
94 auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
95   // After P2216 most exceptions thrown by std::format_to_n become ill-formed.
96   // Therefore this tests does nothing.
97   // A basic ill-formed test is done in format_to_n.verify.cpp
98   // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
99 };
100 
main(int,char **)101 int main(int, char**) {
102   format_tests<char>(test, test_exception);
103 
104 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
105   format_tests_char_to_wchar_t(test);
106   format_tests<wchar_t>(test, test_exception);
107 #endif
108 
109   return 0;
110 }
111