1 // Formatting library for C++ - experimental range support
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
8 // Copyright (c) 2018 - present, Remotion (Igor Schulz)
10 // {fmt} support for ranges, containers and types tuple interface.
15 #include <initializer_list>
17 #include <type_traits>
25 template <typename RangeT
, typename OutputIterator
>
26 OutputIterator
copy(const RangeT
& range
, OutputIterator out
) {
27 for (auto it
= range
.begin(), end
= range
.end(); it
!= end
; ++it
)
32 template <typename OutputIterator
>
33 OutputIterator
copy(const char* str
, OutputIterator out
) {
34 while (*str
) *out
++ = *str
++;
38 template <typename OutputIterator
>
39 OutputIterator
copy(char ch
, OutputIterator out
) {
44 template <typename OutputIterator
>
45 OutputIterator
copy(wchar_t ch
, OutputIterator out
) {
50 // Returns true if T has a std::string-like interface, like std::string_view.
51 template <typename T
> class is_std_string_like
{
53 static auto check(U
* p
)
54 -> decltype((void)p
->find('a'), p
->length(), (void)p
->data(), int());
55 template <typename
> static void check(...);
58 static FMT_CONSTEXPR_DECL
const bool value
=
59 is_string
<T
>::value
||
60 std::is_convertible
<T
, std_string_view
<char>>::value
||
61 !std::is_void
<decltype(check
<T
>(nullptr))>::value
;
64 template <typename Char
>
65 struct is_std_string_like
<fmt::basic_string_view
<Char
>> : std::true_type
{};
67 template <typename T
> class is_map
{
68 template <typename U
> static auto check(U
*) -> typename
U::mapped_type
;
69 template <typename
> static void check(...);
72 #ifdef FMT_FORMAT_MAP_AS_LIST
73 static FMT_CONSTEXPR_DECL
const bool value
= false;
75 static FMT_CONSTEXPR_DECL
const bool value
=
76 !std::is_void
<decltype(check
<T
>(nullptr))>::value
;
80 template <typename T
> class is_set
{
81 template <typename U
> static auto check(U
*) -> typename
U::key_type
;
82 template <typename
> static void check(...);
85 #ifdef FMT_FORMAT_SET_AS_LIST
86 static FMT_CONSTEXPR_DECL
const bool value
= false;
88 static FMT_CONSTEXPR_DECL
const bool value
=
89 !std::is_void
<decltype(check
<T
>(nullptr))>::value
&& !is_map
<T
>::value
;
93 template <typename
... Ts
> struct conditional_helper
{};
95 template <typename T
, typename _
= void> struct is_range_
: std::false_type
{};
97 #if !FMT_MSC_VER || FMT_MSC_VER > 1800
99 # define FMT_DECLTYPE_RETURN(val) \
100 ->decltype(val) { return val; } \
102 true, "") // This makes it so that a semicolon is required after the
103 // macro, which helps clang-format handle the formatting.
106 template <typename T
, std::size_t N
>
107 auto range_begin(const T (&arr
)[N
]) -> const T
* {
110 template <typename T
, std::size_t N
>
111 auto range_end(const T (&arr
)[N
]) -> const T
* {
115 template <typename T
, typename Enable
= void>
116 struct has_member_fn_begin_end_t
: std::false_type
{};
118 template <typename T
>
119 struct has_member_fn_begin_end_t
<T
, void_t
<decltype(std::declval
<T
>().begin()),
120 decltype(std::declval
<T
>().end())>>
123 // Member function overload
124 template <typename T
>
125 auto range_begin(T
&& rng
) FMT_DECLTYPE_RETURN(static_cast<T
&&>(rng
).begin());
126 template <typename T
>
127 auto range_end(T
&& rng
) FMT_DECLTYPE_RETURN(static_cast<T
&&>(rng
).end());
129 // ADL overload. Only participates in overload resolution if member functions
131 template <typename T
>
132 auto range_begin(T
&& rng
)
133 -> enable_if_t
<!has_member_fn_begin_end_t
<T
&&>::value
,
134 decltype(begin(static_cast<T
&&>(rng
)))> {
135 return begin(static_cast<T
&&>(rng
));
137 template <typename T
>
138 auto range_end(T
&& rng
) -> enable_if_t
<!has_member_fn_begin_end_t
<T
&&>::value
,
139 decltype(end(static_cast<T
&&>(rng
)))> {
140 return end(static_cast<T
&&>(rng
));
143 template <typename T
, typename Enable
= void>
144 struct has_const_begin_end
: std::false_type
{};
145 template <typename T
, typename Enable
= void>
146 struct has_mutable_begin_end
: std::false_type
{};
148 template <typename T
>
149 struct has_const_begin_end
<
152 decltype(detail::range_begin(std::declval
<const remove_cvref_t
<T
>&>())),
153 decltype(detail::range_end(std::declval
<const remove_cvref_t
<T
>&>()))>>
156 template <typename T
>
157 struct has_mutable_begin_end
<
158 T
, void_t
<decltype(detail::range_begin(std::declval
<T
>())),
159 decltype(detail::range_end(std::declval
<T
>())),
160 enable_if_t
<std::is_copy_constructible
<T
>::value
>>>
163 template <typename T
>
164 struct is_range_
<T
, void>
165 : std::integral_constant
<bool, (has_const_begin_end
<T
>::value
||
166 has_mutable_begin_end
<T
>::value
)> {};
167 # undef FMT_DECLTYPE_RETURN
170 // tuple_size and tuple_element check.
171 template <typename T
> class is_tuple_like_
{
172 template <typename U
>
173 static auto check(U
* p
) -> decltype(std::tuple_size
<U
>::value
, int());
174 template <typename
> static void check(...);
177 static FMT_CONSTEXPR_DECL
const bool value
=
178 !std::is_void
<decltype(check
<T
>(nullptr))>::value
;
181 // Check for integer_sequence
182 #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
183 template <typename T
, T
... N
>
184 using integer_sequence
= std::integer_sequence
<T
, N
...>;
185 template <size_t... N
> using index_sequence
= std::index_sequence
<N
...>;
186 template <size_t N
> using make_index_sequence
= std::make_index_sequence
<N
>;
188 template <typename T
, T
... N
> struct integer_sequence
{
189 using value_type
= T
;
191 static FMT_CONSTEXPR
size_t size() { return sizeof...(N
); }
194 template <size_t... N
> using index_sequence
= integer_sequence
<size_t, N
...>;
196 template <typename T
, size_t N
, T
... Ns
>
197 struct make_integer_sequence
: make_integer_sequence
<T
, N
- 1, N
- 1, Ns
...> {};
198 template <typename T
, T
... Ns
>
199 struct make_integer_sequence
<T
, 0, Ns
...> : integer_sequence
<T
, Ns
...> {};
202 using make_index_sequence
= make_integer_sequence
<size_t, N
>;
205 template <class Tuple
, class F
, size_t... Is
>
206 void for_each(index_sequence
<Is
...>, Tuple
&& tup
, F
&& f
) FMT_NOEXCEPT
{
208 // using free function get<I>(T) now.
209 const int _
[] = {0, ((void)f(get
<Is
>(tup
)), 0)...};
210 (void)_
; // blocks warnings
214 FMT_CONSTEXPR make_index_sequence
<std::tuple_size
<T
>::value
> get_indexes(
219 template <class Tuple
, class F
> void for_each(Tuple
&& tup
, F
&& f
) {
220 const auto indexes
= get_indexes(tup
);
221 for_each(indexes
, std::forward
<Tuple
>(tup
), std::forward
<F
>(f
));
224 template <typename Range
>
226 remove_cvref_t
<decltype(*detail::range_begin(std::declval
<Range
>()))>;
228 template <typename OutputIt
> OutputIt
write_delimiter(OutputIt out
) {
236 unsigned char lower_count
;
239 inline auto is_printable(uint16_t x
, const singleton
* singletons
,
240 size_t singletons_size
,
241 const unsigned char* singleton_lowers
,
242 const unsigned char* normal
, size_t normal_size
)
245 auto lower_start
= 0;
246 for (size_t i
= 0; i
< singletons_size
; ++i
) {
247 auto s
= singletons
[i
];
248 auto lower_end
= lower_start
+ s
.lower_count
;
249 if (upper
< s
.upper
) break;
250 if (upper
== s
.upper
) {
251 for (auto j
= lower_start
; j
< lower_end
; ++j
) {
252 if (singleton_lowers
[j
] == (x
& 0xff)) return false;
255 lower_start
= lower_end
;
258 auto xsigned
= static_cast<int>(x
);
260 for (size_t i
= 0; i
< normal_size
; ++i
) {
261 auto v
= static_cast<int>(normal
[i
]);
262 auto len
= (v
& 0x80) != 0 ? (v
& 0x7f) << 8 | normal
[++i
] : v
;
264 if (xsigned
< 0) break;
270 // Returns true iff the code point cp is printable.
271 // This code is generated by support/printable.py.
272 inline auto is_printable(uint32_t cp
) -> bool {
273 static constexpr singleton singletons0
[] = {
274 {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8},
275 {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13},
276 {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5},
277 {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22},
278 {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3},
279 {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8},
280 {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9},
282 static constexpr unsigned char singletons0_lower
[] = {
283 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90,
284 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f,
285 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1,
286 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04,
287 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d,
288 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf,
289 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
290 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d,
291 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d,
292 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d,
293 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
294 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7,
295 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
296 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7,
297 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
298 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e,
299 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16,
300 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e,
301 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f,
302 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
303 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0,
304 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
305 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91,
306 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
309 static constexpr singleton singletons1
[] = {
310 {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2},
311 {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5},
312 {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5},
313 {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2},
314 {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5},
315 {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2},
316 {0xfa, 2}, {0xfb, 1},
318 static constexpr unsigned char singletons1_lower
[] = {
319 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07,
320 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36,
321 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87,
322 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
323 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b,
324 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9,
325 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
326 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27,
327 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc,
328 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7,
329 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6,
330 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c,
331 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66,
332 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0,
333 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93,
335 static constexpr unsigned char normal0
[] = {
336 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04,
337 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0,
338 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01,
339 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03,
340 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03,
341 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a,
342 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15,
343 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f,
344 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80,
345 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07,
346 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06,
347 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04,
348 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac,
349 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c,
350 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11,
351 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c,
352 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b,
353 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6,
354 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03,
355 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80,
356 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06,
357 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c,
358 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17,
359 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80,
360 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80,
361 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d,
363 static constexpr unsigned char normal1
[] = {
364 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f,
365 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e,
366 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04,
367 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09,
368 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16,
369 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f,
370 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36,
371 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33,
372 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08,
373 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e,
374 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41,
375 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03,
376 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22,
377 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04,
378 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45,
379 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03,
380 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81,
381 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75,
382 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1,
383 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a,
384 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11,
385 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09,
386 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89,
387 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6,
388 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09,
389 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50,
390 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05,
391 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83,
392 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05,
393 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80,
394 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80,
395 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07,
396 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e,
397 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07,
398 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06,
400 auto lower
= static_cast<uint16_t>(cp
);
402 return is_printable(lower
, singletons0
,
403 sizeof(singletons0
) / sizeof(*singletons0
),
404 singletons0_lower
, normal0
, sizeof(normal0
));
407 return is_printable(lower
, singletons1
,
408 sizeof(singletons1
) / sizeof(*singletons1
),
409 singletons1_lower
, normal1
, sizeof(normal1
));
411 if (0x2a6de <= cp
&& cp
< 0x2a700) return false;
412 if (0x2b735 <= cp
&& cp
< 0x2b740) return false;
413 if (0x2b81e <= cp
&& cp
< 0x2b820) return false;
414 if (0x2cea2 <= cp
&& cp
< 0x2ceb0) return false;
415 if (0x2ebe1 <= cp
&& cp
< 0x2f800) return false;
416 if (0x2fa1e <= cp
&& cp
< 0x30000) return false;
417 if (0x3134b <= cp
&& cp
< 0xe0100) return false;
418 if (0xe01f0 <= cp
&& cp
< 0x110000) return false;
419 return cp
< 0x110000;
422 inline auto needs_escape(uint32_t cp
) -> bool {
423 return cp
< 0x20 || cp
== 0x7f || cp
== '"' || cp
== '\\' ||
427 template <typename Char
> struct find_escape_result
{
433 template <typename Char
>
434 auto find_escape(const Char
* begin
, const Char
* end
)
435 -> find_escape_result
<Char
> {
436 for (; begin
!= end
; ++begin
) {
437 auto cp
= static_cast<typename
std::make_unsigned
<Char
>::type
>(*begin
);
438 if (sizeof(Char
) == 1 && cp
>= 0x80) continue;
439 if (needs_escape(cp
)) return {begin
, begin
+ 1, cp
};
441 return {begin
, nullptr, 0};
444 inline auto find_escape(const char* begin
, const char* end
)
445 -> find_escape_result
<char> {
446 if (!is_utf8()) return find_escape
<char>(begin
, end
);
447 auto result
= find_escape_result
<char>{end
, nullptr, 0};
448 for_each_codepoint(string_view(begin
, to_unsigned(end
- begin
)),
449 [&](uint32_t cp
, string_view sv
) {
450 if (needs_escape(cp
)) {
451 result
= {sv
.begin(), sv
.end(), cp
};
459 template <typename Char
, typename OutputIt
>
460 auto write_range_entry(OutputIt out
, basic_string_view
<Char
> str
) -> OutputIt
{
462 auto begin
= str
.begin(), end
= str
.end();
464 auto escape
= find_escape(begin
, end
);
465 out
= copy_str
<Char
>(begin
, escape
.begin
, out
);
468 auto c
= static_cast<Char
>(escape
.cp
);
489 if (escape
.cp
< 0x100) {
490 out
= format_to(out
, "\\x{:02x}", escape
.cp
);
493 if (escape
.cp
< 0x10000) {
494 out
= format_to(out
, "\\u{:04x}", escape
.cp
);
497 if (escape
.cp
< 0x110000) {
498 out
= format_to(out
, "\\U{:08x}", escape
.cp
);
502 for (Char escape_char
: basic_string_view
<Char
>(
503 escape
.begin
, to_unsigned(escape
.end
- escape
.begin
))) {
506 static_cast<typename
std::make_unsigned
<Char
>::type
>(escape_char
));
511 } while (begin
!= end
);
516 template <typename Char
, typename OutputIt
, typename T
,
517 FMT_ENABLE_IF(std::is_convertible
<T
, std_string_view
<char>>::value
)>
518 inline auto write_range_entry(OutputIt out
, const T
& str
) -> OutputIt
{
519 auto sv
= std_string_view
<Char
>(str
);
520 return write_range_entry
<Char
>(out
, basic_string_view
<Char
>(sv
));
523 template <typename Char
, typename OutputIt
, typename Arg
,
524 FMT_ENABLE_IF(std::is_same
<Arg
, Char
>::value
)>
525 OutputIt
write_range_entry(OutputIt out
, const Arg v
) {
533 typename Char
, typename OutputIt
, typename Arg
,
534 FMT_ENABLE_IF(!is_std_string_like
<typename
std::decay
<Arg
>::type
>::value
&&
535 !std::is_same
<Arg
, Char
>::value
)>
536 OutputIt
write_range_entry(OutputIt out
, const Arg
& v
) {
537 return write
<Char
>(out
, v
);
540 } // namespace detail
542 template <typename T
> struct is_tuple_like
{
543 static FMT_CONSTEXPR_DECL
const bool value
=
544 detail::is_tuple_like_
<T
>::value
&& !detail::is_range_
<T
>::value
;
547 template <typename TupleT
, typename Char
>
548 struct formatter
<TupleT
, Char
, enable_if_t
<fmt::is_tuple_like
<TupleT
>::value
>> {
550 // C++11 generic lambda for format().
551 template <typename FormatContext
> struct format_each
{
552 template <typename T
> void operator()(const T
& v
) {
553 if (i
> 0) out
= detail::write_delimiter(out
);
554 out
= detail::write_range_entry
<Char
>(out
, v
);
558 typename
FormatContext::iterator
& out
;
562 template <typename ParseContext
>
563 FMT_CONSTEXPR
auto parse(ParseContext
& ctx
) -> decltype(ctx
.begin()) {
567 template <typename FormatContext
= format_context
>
568 auto format(const TupleT
& values
, FormatContext
& ctx
) -> decltype(ctx
.out()) {
569 auto out
= ctx
.out();
571 detail::for_each(values
, format_each
<FormatContext
>{0, out
});
577 template <typename T
, typename Char
> struct is_range
{
578 static FMT_CONSTEXPR_DECL
const bool value
=
579 detail::is_range_
<T
>::value
&& !detail::is_std_string_like
<T
>::value
&&
580 !detail::is_map
<T
>::value
&&
581 !std::is_convertible
<T
, std::basic_string
<Char
>>::value
&&
582 !std::is_constructible
<detail::std_string_view
<Char
>, T
>::value
;
585 template <typename T
, typename Char
>
589 fmt::is_range
<T
, Char
>::value
590 // Workaround a bug in MSVC 2019 and earlier.
592 && (is_formattable
<detail::value_type
<T
>, Char
>::value
||
593 detail::has_fallback_formatter
<detail::value_type
<T
>, Char
>::value
)
596 template <typename ParseContext
>
597 FMT_CONSTEXPR
auto parse(ParseContext
& ctx
) -> decltype(ctx
.begin()) {
602 typename FormatContext
, typename U
,
604 std::is_same
<U
, conditional_t
<detail::has_const_begin_end
<T
>::value
,
605 const T
, T
>>::value
)>
606 auto format(U
& range
, FormatContext
& ctx
) -> decltype(ctx
.out()) {
607 #ifdef FMT_DEPRECATED_BRACED_RANGES
611 Char prefix
= detail::is_set
<T
>::value
? '{' : '[';
612 Char postfix
= detail::is_set
<T
>::value
? '}' : ']';
614 auto out
= ctx
.out();
617 auto it
= std::begin(range
);
618 auto end
= std::end(range
);
619 for (; it
!= end
; ++it
) {
620 if (i
> 0) out
= detail::write_delimiter(out
);
621 out
= detail::write_range_entry
<Char
>(out
, *it
);
629 template <typename T
, typename Char
>
633 detail::is_map
<T
>::value
634 // Workaround a bug in MSVC 2019 and earlier.
636 && (is_formattable
<detail::value_type
<T
>, Char
>::value
||
637 detail::has_fallback_formatter
<detail::value_type
<T
>, Char
>::value
)
640 template <typename ParseContext
>
641 FMT_CONSTEXPR
auto parse(ParseContext
& ctx
) -> decltype(ctx
.begin()) {
646 typename FormatContext
, typename U
,
648 std::is_same
<U
, conditional_t
<detail::has_const_begin_end
<T
>::value
,
649 const T
, T
>>::value
)>
650 auto format(U
& map
, FormatContext
& ctx
) -> decltype(ctx
.out()) {
651 auto out
= ctx
.out();
654 for (const auto& item
: map
) {
655 if (i
> 0) out
= detail::write_delimiter(out
);
656 out
= detail::write_range_entry
<Char
>(out
, item
.first
);
659 out
= detail::write_range_entry
<Char
>(out
, item
.second
);
667 template <typename Char
, typename
... T
> struct tuple_join_view
: detail::view
{
668 const std::tuple
<T
...>& tuple
;
669 basic_string_view
<Char
> sep
;
671 tuple_join_view(const std::tuple
<T
...>& t
, basic_string_view
<Char
> s
)
672 : tuple(t
), sep
{s
} {}
675 template <typename Char
, typename
... T
>
676 using tuple_arg_join
= tuple_join_view
<Char
, T
...>;
678 // Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
679 // support in tuple_join. It is disabled by default because of issues with
680 // the dynamic width and precision.
681 #ifndef FMT_TUPLE_JOIN_SPECIFIERS
682 # define FMT_TUPLE_JOIN_SPECIFIERS 0
685 template <typename Char
, typename
... T
>
686 struct formatter
<tuple_join_view
<Char
, T
...>, Char
> {
687 template <typename ParseContext
>
688 FMT_CONSTEXPR
auto parse(ParseContext
& ctx
) -> decltype(ctx
.begin()) {
689 return do_parse(ctx
, std::integral_constant
<size_t, sizeof...(T
)>());
692 template <typename FormatContext
>
693 auto format(const tuple_join_view
<Char
, T
...>& value
,
694 FormatContext
& ctx
) const -> typename
FormatContext::iterator
{
695 return do_format(value
, ctx
,
696 std::integral_constant
<size_t, sizeof...(T
)>());
700 std::tuple
<formatter
<typename
std::decay
<T
>::type
, Char
>...> formatters_
;
702 template <typename ParseContext
>
703 FMT_CONSTEXPR
auto do_parse(ParseContext
& ctx
,
704 std::integral_constant
<size_t, 0>)
705 -> decltype(ctx
.begin()) {
709 template <typename ParseContext
, size_t N
>
710 FMT_CONSTEXPR
auto do_parse(ParseContext
& ctx
,
711 std::integral_constant
<size_t, N
>)
712 -> decltype(ctx
.begin()) {
713 auto end
= ctx
.begin();
714 #if FMT_TUPLE_JOIN_SPECIFIERS
715 end
= std::get
<sizeof...(T
) - N
>(formatters_
).parse(ctx
);
717 auto end1
= do_parse(ctx
, std::integral_constant
<size_t, N
- 1>());
719 FMT_THROW(format_error("incompatible format specs for tuple elements"));
725 template <typename FormatContext
>
726 auto do_format(const tuple_join_view
<Char
, T
...>&, FormatContext
& ctx
,
727 std::integral_constant
<size_t, 0>) const ->
728 typename
FormatContext::iterator
{
732 template <typename FormatContext
, size_t N
>
733 auto do_format(const tuple_join_view
<Char
, T
...>& value
, FormatContext
& ctx
,
734 std::integral_constant
<size_t, N
>) const ->
735 typename
FormatContext::iterator
{
736 auto out
= std::get
<sizeof...(T
) - N
>(formatters_
)
737 .format(std::get
<sizeof...(T
) - N
>(value
.tuple
), ctx
);
739 out
= std::copy(value
.sep
.begin(), value
.sep
.end(), out
);
741 return do_format(value
, ctx
, std::integral_constant
<size_t, N
- 1>());
747 FMT_MODULE_EXPORT_BEGIN
751 Returns an object that formats `tuple` with elements separated by `sep`.
755 std::tuple<int, char> t = {1, 'a'};
756 fmt::print("{}", fmt::join(t, ", "));
760 template <typename
... T
>
761 FMT_CONSTEXPR
auto join(const std::tuple
<T
...>& tuple
, string_view sep
)
762 -> tuple_join_view
<char, T
...> {
766 template <typename
... T
>
767 FMT_CONSTEXPR
auto join(const std::tuple
<T
...>& tuple
,
768 basic_string_view
<wchar_t> sep
)
769 -> tuple_join_view
<wchar_t, T
...> {
775 Returns an object that formats `initializer_list` with elements separated by
780 fmt::print("{}", fmt::join({1, 2, 3}, ", "));
784 template <typename T
>
785 auto join(std::initializer_list
<T
> list
, string_view sep
)
786 -> join_view
<const T
*, const T
*> {
787 return join(std::begin(list
), std::end(list
), sep
);
790 FMT_MODULE_EXPORT_END
793 #endif // FMT_RANGES_H_