Commit | Line | Data |
---|---|---|
05aa7e19 JG |
1 | // Formatting library for C++ - experimental range support |
2 | // | |
3 | // Copyright (c) 2012 - present, Victor Zverovich | |
4 | // All rights reserved. | |
5 | // | |
6 | // For the license information refer to format.h. | |
7 | // | |
8 | // Copyright (c) 2018 - present, Remotion (Igor Schulz) | |
9 | // All Rights Reserved | |
10 | // {fmt} support for ranges, containers and types tuple interface. | |
11 | ||
12 | #ifndef FMT_RANGES_H_ | |
13 | #define FMT_RANGES_H_ | |
14 | ||
15 | #include <initializer_list> | |
16 | #include <tuple> | |
17 | #include <type_traits> | |
18 | ||
19 | #include "format.h" | |
20 | ||
21 | FMT_BEGIN_NAMESPACE | |
22 | ||
23 | namespace detail { | |
24 | ||
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) | |
28 | *out++ = *it; | |
29 | return out; | |
30 | } | |
31 | ||
32 | template <typename OutputIterator> | |
33 | OutputIterator copy(const char* str, OutputIterator out) { | |
34 | while (*str) *out++ = *str++; | |
35 | return out; | |
36 | } | |
37 | ||
38 | template <typename OutputIterator> | |
39 | OutputIterator copy(char ch, OutputIterator out) { | |
40 | *out++ = ch; | |
41 | return out; | |
42 | } | |
43 | ||
44 | template <typename OutputIterator> | |
45 | OutputIterator copy(wchar_t ch, OutputIterator out) { | |
46 | *out++ = ch; | |
47 | return out; | |
48 | } | |
49 | ||
50 | // Returns true if T has a std::string-like interface, like std::string_view. | |
51 | template <typename T> class is_std_string_like { | |
52 | template <typename U> | |
53 | static auto check(U* p) | |
54 | -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); | |
55 | template <typename> static void check(...); | |
56 | ||
57 | public: | |
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; | |
62 | }; | |
63 | ||
64 | template <typename Char> | |
65 | struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {}; | |
66 | ||
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(...); | |
70 | ||
71 | public: | |
72 | #ifdef FMT_FORMAT_MAP_AS_LIST | |
73 | static FMT_CONSTEXPR_DECL const bool value = false; | |
74 | #else | |
75 | static FMT_CONSTEXPR_DECL const bool value = | |
76 | !std::is_void<decltype(check<T>(nullptr))>::value; | |
77 | #endif | |
78 | }; | |
79 | ||
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(...); | |
83 | ||
84 | public: | |
85 | #ifdef FMT_FORMAT_SET_AS_LIST | |
86 | static FMT_CONSTEXPR_DECL const bool value = false; | |
87 | #else | |
88 | static FMT_CONSTEXPR_DECL const bool value = | |
89 | !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value; | |
90 | #endif | |
91 | }; | |
92 | ||
93 | template <typename... Ts> struct conditional_helper {}; | |
94 | ||
95 | template <typename T, typename _ = void> struct is_range_ : std::false_type {}; | |
96 | ||
97 | #if !FMT_MSC_VER || FMT_MSC_VER > 1800 | |
98 | ||
99 | # define FMT_DECLTYPE_RETURN(val) \ | |
100 | ->decltype(val) { return val; } \ | |
101 | static_assert( \ | |
102 | true, "") // This makes it so that a semicolon is required after the | |
103 | // macro, which helps clang-format handle the formatting. | |
104 | ||
105 | // C array overload | |
106 | template <typename T, std::size_t N> | |
107 | auto range_begin(const T (&arr)[N]) -> const T* { | |
108 | return arr; | |
109 | } | |
110 | template <typename T, std::size_t N> | |
111 | auto range_end(const T (&arr)[N]) -> const T* { | |
112 | return arr + N; | |
113 | } | |
114 | ||
115 | template <typename T, typename Enable = void> | |
116 | struct has_member_fn_begin_end_t : std::false_type {}; | |
117 | ||
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())>> | |
121 | : std::true_type {}; | |
122 | ||
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()); | |
128 | ||
129 | // ADL overload. Only participates in overload resolution if member functions | |
130 | // are not found. | |
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)); | |
136 | } | |
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)); | |
141 | } | |
142 | ||
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 {}; | |
147 | ||
148 | template <typename T> | |
149 | struct has_const_begin_end< | |
150 | T, | |
151 | void_t< | |
152 | decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())), | |
153 | decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>> | |
154 | : std::true_type {}; | |
155 | ||
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>>> | |
161 | : std::true_type {}; | |
162 | ||
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 | |
168 | #endif | |
169 | ||
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(...); | |
175 | ||
176 | public: | |
177 | static FMT_CONSTEXPR_DECL const bool value = | |
178 | !std::is_void<decltype(check<T>(nullptr))>::value; | |
179 | }; | |
180 | ||
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>; | |
187 | #else | |
188 | template <typename T, T... N> struct integer_sequence { | |
189 | using value_type = T; | |
190 | ||
191 | static FMT_CONSTEXPR size_t size() { return sizeof...(N); } | |
192 | }; | |
193 | ||
194 | template <size_t... N> using index_sequence = integer_sequence<size_t, N...>; | |
195 | ||
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...> {}; | |
200 | ||
201 | template <size_t N> | |
202 | using make_index_sequence = make_integer_sequence<size_t, N>; | |
203 | #endif | |
204 | ||
205 | template <class Tuple, class F, size_t... Is> | |
206 | void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT { | |
207 | using std::get; | |
208 | // using free function get<I>(T) now. | |
209 | const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; | |
210 | (void)_; // blocks warnings | |
211 | } | |
212 | ||
213 | template <class T> | |
214 | FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes( | |
215 | T const&) { | |
216 | return {}; | |
217 | } | |
218 | ||
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)); | |
222 | } | |
223 | ||
224 | template <typename Range> | |
225 | using value_type = | |
226 | remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>; | |
227 | ||
228 | template <typename OutputIt> OutputIt write_delimiter(OutputIt out) { | |
229 | *out++ = ','; | |
230 | *out++ = ' '; | |
231 | return out; | |
232 | } | |
233 | ||
234 | struct singleton { | |
235 | unsigned char upper; | |
236 | unsigned char lower_count; | |
237 | }; | |
238 | ||
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) | |
243 | -> bool { | |
244 | auto upper = x >> 8; | |
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; | |
253 | } | |
254 | } | |
255 | lower_start = lower_end; | |
256 | } | |
257 | ||
258 | auto xsigned = static_cast<int>(x); | |
259 | auto current = true; | |
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; | |
263 | xsigned -= len; | |
264 | if (xsigned < 0) break; | |
265 | current = !current; | |
266 | } | |
267 | return current; | |
268 | } | |
269 | ||
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}, | |
281 | }; | |
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, | |
307 | 0xfe, 0xff, | |
308 | }; | |
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}, | |
317 | }; | |
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, | |
334 | }; | |
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, | |
362 | }; | |
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, | |
399 | }; | |
400 | auto lower = static_cast<uint16_t>(cp); | |
401 | if (cp < 0x10000) { | |
402 | return is_printable(lower, singletons0, | |
403 | sizeof(singletons0) / sizeof(*singletons0), | |
404 | singletons0_lower, normal0, sizeof(normal0)); | |
405 | } | |
406 | if (cp < 0x20000) { | |
407 | return is_printable(lower, singletons1, | |
408 | sizeof(singletons1) / sizeof(*singletons1), | |
409 | singletons1_lower, normal1, sizeof(normal1)); | |
410 | } | |
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; | |
420 | } | |
421 | ||
422 | inline auto needs_escape(uint32_t cp) -> bool { | |
423 | return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || | |
424 | !is_printable(cp); | |
425 | } | |
426 | ||
427 | template <typename Char> struct find_escape_result { | |
428 | const Char* begin; | |
429 | const Char* end; | |
430 | uint32_t cp; | |
431 | }; | |
432 | ||
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}; | |
440 | } | |
441 | return {begin, nullptr, 0}; | |
442 | } | |
443 | ||
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}; | |
452 | return false; | |
453 | } | |
454 | return true; | |
455 | }); | |
456 | return result; | |
457 | } | |
458 | ||
459 | template <typename Char, typename OutputIt> | |
460 | auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt { | |
461 | *out++ = '"'; | |
462 | auto begin = str.begin(), end = str.end(); | |
463 | do { | |
464 | auto escape = find_escape(begin, end); | |
465 | out = copy_str<Char>(begin, escape.begin, out); | |
466 | begin = escape.end; | |
467 | if (!begin) break; | |
468 | auto c = static_cast<Char>(escape.cp); | |
469 | switch (escape.cp) { | |
470 | case '\n': | |
471 | *out++ = '\\'; | |
472 | c = 'n'; | |
473 | break; | |
474 | case '\r': | |
475 | *out++ = '\\'; | |
476 | c = 'r'; | |
477 | break; | |
478 | case '\t': | |
479 | *out++ = '\\'; | |
480 | c = 't'; | |
481 | break; | |
482 | case '"': | |
483 | FMT_FALLTHROUGH; | |
484 | case '\\': | |
485 | *out++ = '\\'; | |
486 | break; | |
487 | default: | |
488 | if (is_utf8()) { | |
489 | if (escape.cp < 0x100) { | |
490 | out = format_to(out, "\\x{:02x}", escape.cp); | |
491 | continue; | |
492 | } | |
493 | if (escape.cp < 0x10000) { | |
494 | out = format_to(out, "\\u{:04x}", escape.cp); | |
495 | continue; | |
496 | } | |
497 | if (escape.cp < 0x110000) { | |
498 | out = format_to(out, "\\U{:08x}", escape.cp); | |
499 | continue; | |
500 | } | |
501 | } | |
502 | for (Char escape_char : basic_string_view<Char>( | |
503 | escape.begin, to_unsigned(escape.end - escape.begin))) { | |
504 | out = format_to( | |
505 | out, "\\x{:02x}", | |
506 | static_cast<typename std::make_unsigned<Char>::type>(escape_char)); | |
507 | } | |
508 | continue; | |
509 | } | |
510 | *out++ = c; | |
511 | } while (begin != end); | |
512 | *out++ = '"'; | |
513 | return out; | |
514 | } | |
515 | ||
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)); | |
521 | } | |
522 | ||
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) { | |
526 | *out++ = '\''; | |
527 | *out++ = v; | |
528 | *out++ = '\''; | |
529 | return out; | |
530 | } | |
531 | ||
532 | template < | |
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); | |
538 | } | |
539 | ||
540 | } // namespace detail | |
541 | ||
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; | |
545 | }; | |
546 | ||
547 | template <typename TupleT, typename Char> | |
548 | struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> { | |
549 | private: | |
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); | |
555 | ++i; | |
556 | } | |
557 | int i; | |
558 | typename FormatContext::iterator& out; | |
559 | }; | |
560 | ||
561 | public: | |
562 | template <typename ParseContext> | |
563 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | |
564 | return ctx.begin(); | |
565 | } | |
566 | ||
567 | template <typename FormatContext = format_context> | |
568 | auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) { | |
569 | auto out = ctx.out(); | |
570 | *out++ = '('; | |
571 | detail::for_each(values, format_each<FormatContext>{0, out}); | |
572 | *out++ = ')'; | |
573 | return out; | |
574 | } | |
575 | }; | |
576 | ||
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; | |
583 | }; | |
584 | ||
585 | template <typename T, typename Char> | |
586 | struct formatter< | |
587 | T, Char, | |
588 | enable_if_t< | |
589 | fmt::is_range<T, Char>::value | |
590 | // Workaround a bug in MSVC 2019 and earlier. | |
591 | #if !FMT_MSC_VER | |
592 | && (is_formattable<detail::value_type<T>, Char>::value || | |
593 | detail::has_fallback_formatter<detail::value_type<T>, Char>::value) | |
594 | #endif | |
595 | >> { | |
596 | template <typename ParseContext> | |
597 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | |
598 | return ctx.begin(); | |
599 | } | |
600 | ||
601 | template < | |
602 | typename FormatContext, typename U, | |
603 | FMT_ENABLE_IF( | |
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 | |
608 | Char prefix = '{'; | |
609 | Char postfix = '}'; | |
610 | #else | |
611 | Char prefix = detail::is_set<T>::value ? '{' : '['; | |
612 | Char postfix = detail::is_set<T>::value ? '}' : ']'; | |
613 | #endif | |
614 | auto out = ctx.out(); | |
615 | *out++ = prefix; | |
616 | int i = 0; | |
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); | |
622 | ++i; | |
623 | } | |
624 | *out++ = postfix; | |
625 | return out; | |
626 | } | |
627 | }; | |
628 | ||
629 | template <typename T, typename Char> | |
630 | struct formatter< | |
631 | T, Char, | |
632 | enable_if_t< | |
633 | detail::is_map<T>::value | |
634 | // Workaround a bug in MSVC 2019 and earlier. | |
635 | #if !FMT_MSC_VER | |
636 | && (is_formattable<detail::value_type<T>, Char>::value || | |
637 | detail::has_fallback_formatter<detail::value_type<T>, Char>::value) | |
638 | #endif | |
639 | >> { | |
640 | template <typename ParseContext> | |
641 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | |
642 | return ctx.begin(); | |
643 | } | |
644 | ||
645 | template < | |
646 | typename FormatContext, typename U, | |
647 | FMT_ENABLE_IF( | |
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(); | |
652 | *out++ = '{'; | |
653 | int i = 0; | |
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); | |
657 | *out++ = ':'; | |
658 | *out++ = ' '; | |
659 | out = detail::write_range_entry<Char>(out, item.second); | |
660 | ++i; | |
661 | } | |
662 | *out++ = '}'; | |
663 | return out; | |
664 | } | |
665 | }; | |
666 | ||
667 | template <typename Char, typename... T> struct tuple_join_view : detail::view { | |
668 | const std::tuple<T...>& tuple; | |
669 | basic_string_view<Char> sep; | |
670 | ||
671 | tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s) | |
672 | : tuple(t), sep{s} {} | |
673 | }; | |
674 | ||
675 | template <typename Char, typename... T> | |
676 | using tuple_arg_join = tuple_join_view<Char, T...>; | |
677 | ||
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 | |
683 | #endif | |
684 | ||
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)>()); | |
690 | } | |
691 | ||
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)>()); | |
697 | } | |
698 | ||
699 | private: | |
700 | std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_; | |
701 | ||
702 | template <typename ParseContext> | |
703 | FMT_CONSTEXPR auto do_parse(ParseContext& ctx, | |
704 | std::integral_constant<size_t, 0>) | |
705 | -> decltype(ctx.begin()) { | |
706 | return ctx.begin(); | |
707 | } | |
708 | ||
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); | |
716 | if (N > 1) { | |
717 | auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>()); | |
718 | if (end != end1) | |
719 | FMT_THROW(format_error("incompatible format specs for tuple elements")); | |
720 | } | |
721 | #endif | |
722 | return end; | |
723 | } | |
724 | ||
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 { | |
729 | return ctx.out(); | |
730 | } | |
731 | ||
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); | |
738 | if (N > 1) { | |
739 | out = std::copy(value.sep.begin(), value.sep.end(), out); | |
740 | ctx.advance_to(out); | |
741 | return do_format(value, ctx, std::integral_constant<size_t, N - 1>()); | |
742 | } | |
743 | return out; | |
744 | } | |
745 | }; | |
746 | ||
747 | FMT_MODULE_EXPORT_BEGIN | |
748 | ||
749 | /** | |
750 | \rst | |
751 | Returns an object that formats `tuple` with elements separated by `sep`. | |
752 | ||
753 | **Example**:: | |
754 | ||
755 | std::tuple<int, char> t = {1, 'a'}; | |
756 | fmt::print("{}", fmt::join(t, ", ")); | |
757 | // Output: "1, a" | |
758 | \endrst | |
759 | */ | |
760 | template <typename... T> | |
761 | FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep) | |
762 | -> tuple_join_view<char, T...> { | |
763 | return {tuple, sep}; | |
764 | } | |
765 | ||
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...> { | |
770 | return {tuple, sep}; | |
771 | } | |
772 | ||
773 | /** | |
774 | \rst | |
775 | Returns an object that formats `initializer_list` with elements separated by | |
776 | `sep`. | |
777 | ||
778 | **Example**:: | |
779 | ||
780 | fmt::print("{}", fmt::join({1, 2, 3}, ", ")); | |
781 | // Output: "1, 2, 3" | |
782 | \endrst | |
783 | */ | |
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); | |
788 | } | |
789 | ||
790 | FMT_MODULE_EXPORT_END | |
791 | FMT_END_NAMESPACE | |
792 | ||
793 | #endif // FMT_RANGES_H_ |