1 | /* |
2 | Formatting library for C++ |
3 | |
4 | Copyright (c) 2012 - present, Victor Zverovich |
5 | |
6 | Permission is hereby granted, free of charge, to any person obtaining |
7 | a copy of this software and associated documentation files (the |
8 | "Software"), to deal in the Software without restriction, including |
9 | without limitation the rights to use, copy, modify, merge, publish, |
10 | distribute, sublicense, and/or sell copies of the Software, and to |
11 | permit persons to whom the Software is furnished to do so, subject to |
12 | the following conditions: |
13 | |
14 | The above copyright notice and this permission notice shall be |
15 | included in all copies or substantial portions of the Software. |
16 | |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
24 | |
25 | --- Optional exception to the license --- |
26 | |
27 | As an exception, if, as a result of your compiling your source code, portions |
28 | of this Software are embedded into a machine-executable object form of such |
29 | source code, you may redistribute such embedded portions in such object form |
30 | without including the above copyright and permission notices. |
31 | */ |
32 | |
33 | #ifndef FMT_FORMAT_H_ |
34 | #define FMT_FORMAT_H_ |
35 | |
36 | #include "core.h" |
37 | |
38 | #include <algorithm> |
39 | #include <cerrno> |
40 | #include <cmath> |
41 | #include <cstdint> |
42 | #include <limits> |
43 | #include <memory> |
44 | #include <stdexcept> |
45 | |
46 | #ifdef __clang__ |
47 | # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) |
48 | #else |
49 | # define FMT_CLANG_VERSION 0 |
50 | #endif |
51 | |
52 | #ifdef __INTEL_COMPILER |
53 | # define FMT_ICC_VERSION __INTEL_COMPILER |
54 | #elif defined(__ICL) |
55 | # define FMT_ICC_VERSION __ICL |
56 | #else |
57 | # define FMT_ICC_VERSION 0 |
58 | #endif |
59 | |
60 | #ifdef __NVCC__ |
61 | # define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) |
62 | #else |
63 | # define FMT_CUDA_VERSION 0 |
64 | #endif |
65 | |
66 | #ifdef __has_builtin |
67 | # define FMT_HAS_BUILTIN(x) __has_builtin(x) |
68 | #else |
69 | # define FMT_HAS_BUILTIN(x) 0 |
70 | #endif |
71 | |
72 | #if FMT_HAS_CPP_ATTRIBUTE(fallthrough) && \ |
73 | (__cplusplus >= 201703 || FMT_GCC_VERSION != 0) |
74 | # define FMT_FALLTHROUGH [[fallthrough]] |
75 | #else |
76 | # define FMT_FALLTHROUGH |
77 | #endif |
78 | |
79 | #ifndef FMT_THROW |
80 | # if FMT_EXCEPTIONS |
81 | # if FMT_MSC_VER |
82 | FMT_BEGIN_NAMESPACE |
83 | namespace internal { |
84 | template <typename Exception> inline void do_throw(const Exception& x) { |
85 | // Silence unreachable code warnings in MSVC because these are nearly |
86 | // impossible to fix in a generic code. |
87 | volatile bool b = true; |
88 | if (b) throw x; |
89 | } |
90 | } // namespace internal |
91 | FMT_END_NAMESPACE |
92 | # define FMT_THROW(x) internal::do_throw(x) |
93 | # else |
94 | # define FMT_THROW(x) throw x |
95 | # endif |
96 | # else |
97 | # define FMT_THROW(x) \ |
98 | do { \ |
99 | static_cast<void>(sizeof(x)); \ |
100 | FMT_ASSERT(false, ""); \ |
101 | } while (false) |
102 | # endif |
103 | #endif |
104 | |
105 | #ifndef FMT_USE_USER_DEFINED_LITERALS |
106 | // For Intel and NVIDIA compilers both they and the system gcc/msc support UDLs. |
107 | # if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ |
108 | FMT_MSC_VER >= 1900) && \ |
109 | (!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || FMT_ICC_VERSION >= 1500 || \ |
110 | FMT_CUDA_VERSION >= 700) |
111 | # define FMT_USE_USER_DEFINED_LITERALS 1 |
112 | # else |
113 | # define FMT_USE_USER_DEFINED_LITERALS 0 |
114 | # endif |
115 | #endif |
116 | |
117 | #ifndef FMT_USE_UDL_TEMPLATE |
118 | // EDG front end based compilers (icc, nvcc) do not support UDL templates yet |
119 | // and GCC 9 warns about them. |
120 | # if FMT_USE_USER_DEFINED_LITERALS && FMT_ICC_VERSION == 0 && \ |
121 | FMT_CUDA_VERSION == 0 && \ |
122 | ((FMT_GCC_VERSION >= 600 && FMT_GCC_VERSION <= 900 && \ |
123 | __cplusplus >= 201402L) || \ |
124 | FMT_CLANG_VERSION >= 304) |
125 | # define FMT_USE_UDL_TEMPLATE 1 |
126 | # else |
127 | # define FMT_USE_UDL_TEMPLATE 0 |
128 | # endif |
129 | #endif |
130 | |
131 | // __builtin_clz is broken in clang with Microsoft CodeGen: |
132 | // https://github.com/fmtlib/fmt/issues/519 |
133 | #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER |
134 | # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) |
135 | #endif |
136 | #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER |
137 | # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) |
138 | #endif |
139 | |
140 | // Some compilers masquerade as both MSVC and GCC-likes or otherwise support |
141 | // __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the |
142 | // MSVC intrinsics if the clz and clzll builtins are not available. |
143 | #if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) |
144 | # include <intrin.h> // _BitScanReverse, _BitScanReverse64 |
145 | |
146 | FMT_BEGIN_NAMESPACE |
147 | namespace internal { |
148 | // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. |
149 | # ifndef __clang__ |
150 | # pragma intrinsic(_BitScanReverse) |
151 | # endif |
152 | inline uint32_t clz(uint32_t x) { |
153 | unsigned long r = 0; |
154 | _BitScanReverse(&r, x); |
155 | |
156 | FMT_ASSERT(x != 0, "" ); |
157 | // Static analysis complains about using uninitialized data |
158 | // "r", but the only way that can happen is if "x" is 0, |
159 | // which the callers guarantee to not happen. |
160 | # pragma warning(suppress : 6102) |
161 | return 31 - r; |
162 | } |
163 | # define FMT_BUILTIN_CLZ(n) internal::clz(n) |
164 | |
165 | # if defined(_WIN64) && !defined(__clang__) |
166 | # pragma intrinsic(_BitScanReverse64) |
167 | # endif |
168 | |
169 | inline uint32_t clzll(uint64_t x) { |
170 | unsigned long r = 0; |
171 | # ifdef _WIN64 |
172 | _BitScanReverse64(&r, x); |
173 | # else |
174 | // Scan the high 32 bits. |
175 | if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) return 63 - (r + 32); |
176 | |
177 | // Scan the low 32 bits. |
178 | _BitScanReverse(&r, static_cast<uint32_t>(x)); |
179 | # endif |
180 | |
181 | FMT_ASSERT(x != 0, "" ); |
182 | // Static analysis complains about using uninitialized data |
183 | // "r", but the only way that can happen is if "x" is 0, |
184 | // which the callers guarantee to not happen. |
185 | # pragma warning(suppress : 6102) |
186 | return 63 - r; |
187 | } |
188 | # define FMT_BUILTIN_CLZLL(n) internal::clzll(n) |
189 | } // namespace internal |
190 | FMT_END_NAMESPACE |
191 | #endif |
192 | |
193 | // Enable the deprecated numeric alignment. |
194 | #ifndef FMT_NUMERIC_ALIGN |
195 | # define FMT_NUMERIC_ALIGN 1 |
196 | #endif |
197 | |
198 | // Enable the deprecated percent specifier. |
199 | #ifndef FMT_DEPRECATED_PERCENT |
200 | # define FMT_DEPRECATED_PERCENT 0 |
201 | #endif |
202 | |
203 | FMT_BEGIN_NAMESPACE |
204 | namespace internal { |
205 | |
206 | // A helper function to suppress bogus "conditional expression is constant" |
207 | // warnings. |
208 | template <typename T> inline T const_check(T value) { return value; } |
209 | |
210 | // An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have |
211 | // undefined behavior (e.g. due to type aliasing). |
212 | // Example: uint64_t d = bit_cast<uint64_t>(2.718); |
213 | template <typename Dest, typename Source> |
214 | inline Dest bit_cast(const Source& source) { |
215 | static_assert(sizeof(Dest) == sizeof(Source), "size mismatch" ); |
216 | Dest dest; |
217 | std::memcpy(&dest, &source, sizeof(dest)); |
218 | return dest; |
219 | } |
220 | |
221 | inline bool is_big_endian() { |
222 | auto u = 1u; |
223 | struct bytes { |
224 | char data[sizeof(u)]; |
225 | }; |
226 | return bit_cast<bytes>(u).data[0] == 0; |
227 | } |
228 | |
229 | // A fallback implementation of uintptr_t for systems that lack it. |
230 | struct fallback_uintptr { |
231 | unsigned char value[sizeof(void*)]; |
232 | |
233 | fallback_uintptr() = default; |
234 | explicit fallback_uintptr(const void* p) { |
235 | *this = bit_cast<fallback_uintptr>(p); |
236 | if (is_big_endian()) { |
237 | for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j) |
238 | std::swap(value[i], value[j]); |
239 | } |
240 | } |
241 | }; |
242 | #ifdef UINTPTR_MAX |
243 | using uintptr_t = ::uintptr_t; |
244 | inline uintptr_t to_uintptr(const void* p) { return bit_cast<uintptr_t>(p); } |
245 | #else |
246 | using uintptr_t = fallback_uintptr; |
247 | inline fallback_uintptr to_uintptr(const void* p) { |
248 | return fallback_uintptr(p); |
249 | } |
250 | #endif |
251 | |
252 | // Returns the largest possible value for type T. Same as |
253 | // std::numeric_limits<T>::max() but shorter and not affected by the max macro. |
254 | template <typename T> constexpr T max_value() { |
255 | return (std::numeric_limits<T>::max)(); |
256 | } |
257 | template <typename T> constexpr int num_bits() { |
258 | return std::numeric_limits<T>::digits; |
259 | } |
260 | template <> constexpr int num_bits<fallback_uintptr>() { |
261 | return static_cast<int>(sizeof(void*) * |
262 | std::numeric_limits<unsigned char>::digits); |
263 | } |
264 | |
265 | // An approximation of iterator_t for pre-C++20 systems. |
266 | template <typename T> |
267 | using iterator_t = decltype(std::begin(std::declval<T&>())); |
268 | |
269 | // Detect the iterator category of *any* given type in a SFINAE-friendly way. |
270 | // Unfortunately, older implementations of std::iterator_traits are not safe |
271 | // for use in a SFINAE-context. |
272 | template <typename It, typename Enable = void> |
273 | struct iterator_category : std::false_type {}; |
274 | |
275 | template <typename T> struct iterator_category<T*> { |
276 | using type = std::random_access_iterator_tag; |
277 | }; |
278 | |
279 | template <typename It> |
280 | struct iterator_category<It, void_t<typename It::iterator_category>> { |
281 | using type = typename It::iterator_category; |
282 | }; |
283 | |
284 | // Detect if *any* given type models the OutputIterator concept. |
285 | template <typename It> class is_output_iterator { |
286 | // Check for mutability because all iterator categories derived from |
287 | // std::input_iterator_tag *may* also meet the requirements of an |
288 | // OutputIterator, thereby falling into the category of 'mutable iterators' |
289 | // [iterator.requirements.general] clause 4. The compiler reveals this |
290 | // property only at the point of *actually dereferencing* the iterator! |
291 | template <typename U> |
292 | static decltype(*(std::declval<U>())) test(std::input_iterator_tag); |
293 | template <typename U> static char& test(std::output_iterator_tag); |
294 | template <typename U> static const char& test(...); |
295 | |
296 | using type = decltype(test<It>(typename iterator_category<It>::type{})); |
297 | |
298 | public: |
299 | static const bool value = !std::is_const<remove_reference_t<type>>::value; |
300 | }; |
301 | |
302 | // A workaround for std::string not having mutable data() until C++17. |
303 | template <typename Char> inline Char* get_data(std::basic_string<Char>& s) { |
304 | return &s[0]; |
305 | } |
306 | template <typename Container> |
307 | inline typename Container::value_type* get_data(Container& c) { |
308 | return c.data(); |
309 | } |
310 | |
311 | #ifdef _SECURE_SCL |
312 | // Make a checked iterator to avoid MSVC warnings. |
313 | template <typename T> using checked_ptr = stdext::checked_array_iterator<T*>; |
314 | template <typename T> checked_ptr<T> make_checked(T* p, std::size_t size) { |
315 | return {p, size}; |
316 | } |
317 | #else |
318 | template <typename T> using checked_ptr = T*; |
319 | template <typename T> inline T* make_checked(T* p, std::size_t) { return p; } |
320 | #endif |
321 | |
322 | template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)> |
323 | inline checked_ptr<typename Container::value_type> reserve( |
324 | std::back_insert_iterator<Container>& it, std::size_t n) { |
325 | Container& c = get_container(it); |
326 | std::size_t size = c.size(); |
327 | c.resize(size + n); |
328 | return make_checked(get_data(c) + size, n); |
329 | } |
330 | |
331 | template <typename Iterator> |
332 | inline Iterator& reserve(Iterator& it, std::size_t) { |
333 | return it; |
334 | } |
335 | |
336 | // An output iterator that counts the number of objects written to it and |
337 | // discards them. |
338 | class counting_iterator { |
339 | private: |
340 | std::size_t count_; |
341 | |
342 | public: |
343 | using iterator_category = std::output_iterator_tag; |
344 | using difference_type = std::ptrdiff_t; |
345 | using pointer = void; |
346 | using reference = void; |
347 | using _Unchecked_type = counting_iterator; // Mark iterator as checked. |
348 | |
349 | struct value_type { |
350 | template <typename T> void operator=(const T&) {} |
351 | }; |
352 | |
353 | counting_iterator() : count_(0) {} |
354 | |
355 | std::size_t count() const { return count_; } |
356 | |
357 | counting_iterator& operator++() { |
358 | ++count_; |
359 | return *this; |
360 | } |
361 | |
362 | counting_iterator operator++(int) { |
363 | auto it = *this; |
364 | ++*this; |
365 | return it; |
366 | } |
367 | |
368 | value_type operator*() const { return {}; } |
369 | }; |
370 | |
371 | template <typename OutputIt> class truncating_iterator_base { |
372 | protected: |
373 | OutputIt out_; |
374 | std::size_t limit_; |
375 | std::size_t count_; |
376 | |
377 | truncating_iterator_base(OutputIt out, std::size_t limit) |
378 | : out_(out), limit_(limit), count_(0) {} |
379 | |
380 | public: |
381 | using iterator_category = std::output_iterator_tag; |
382 | using difference_type = void; |
383 | using pointer = void; |
384 | using reference = void; |
385 | using _Unchecked_type = |
386 | truncating_iterator_base; // Mark iterator as checked. |
387 | |
388 | OutputIt base() const { return out_; } |
389 | std::size_t count() const { return count_; } |
390 | }; |
391 | |
392 | // An output iterator that truncates the output and counts the number of objects |
393 | // written to it. |
394 | template <typename OutputIt, |
395 | typename Enable = typename std::is_void< |
396 | typename std::iterator_traits<OutputIt>::value_type>::type> |
397 | class truncating_iterator; |
398 | |
399 | template <typename OutputIt> |
400 | class truncating_iterator<OutputIt, std::false_type> |
401 | : public truncating_iterator_base<OutputIt> { |
402 | using traits = std::iterator_traits<OutputIt>; |
403 | |
404 | mutable typename traits::value_type blackhole_; |
405 | |
406 | public: |
407 | using value_type = typename traits::value_type; |
408 | |
409 | truncating_iterator(OutputIt out, std::size_t limit) |
410 | : truncating_iterator_base<OutputIt>(out, limit) {} |
411 | |
412 | truncating_iterator& operator++() { |
413 | if (this->count_++ < this->limit_) ++this->out_; |
414 | return *this; |
415 | } |
416 | |
417 | truncating_iterator operator++(int) { |
418 | auto it = *this; |
419 | ++*this; |
420 | return it; |
421 | } |
422 | |
423 | value_type& operator*() const { |
424 | return this->count_ < this->limit_ ? *this->out_ : blackhole_; |
425 | } |
426 | }; |
427 | |
428 | template <typename OutputIt> |
429 | class truncating_iterator<OutputIt, std::true_type> |
430 | : public truncating_iterator_base<OutputIt> { |
431 | public: |
432 | using value_type = typename OutputIt::container_type::value_type; |
433 | |
434 | truncating_iterator(OutputIt out, std::size_t limit) |
435 | : truncating_iterator_base<OutputIt>(out, limit) {} |
436 | |
437 | truncating_iterator& operator=(value_type val) { |
438 | if (this->count_++ < this->limit_) this->out_ = val; |
439 | return *this; |
440 | } |
441 | |
442 | truncating_iterator& operator++() { return *this; } |
443 | truncating_iterator& operator++(int) { return *this; } |
444 | truncating_iterator& operator*() { return *this; } |
445 | }; |
446 | |
447 | // A range with the specified output iterator and value type. |
448 | template <typename OutputIt, typename T = typename OutputIt::value_type> |
449 | class output_range { |
450 | private: |
451 | OutputIt it_; |
452 | |
453 | public: |
454 | using value_type = T; |
455 | using iterator = OutputIt; |
456 | struct sentinel {}; |
457 | |
458 | explicit output_range(OutputIt it) : it_(it) {} |
459 | OutputIt begin() const { return it_; } |
460 | sentinel end() const { return {}; } // Sentinel is not used yet. |
461 | }; |
462 | |
463 | template <typename Char> |
464 | inline size_t count_code_points(basic_string_view<Char> s) { |
465 | return s.size(); |
466 | } |
467 | |
468 | // Counts the number of code points in a UTF-8 string. |
469 | inline size_t count_code_points(basic_string_view<char8_t> s) { |
470 | const char8_t* data = s.data(); |
471 | size_t num_code_points = 0; |
472 | for (size_t i = 0, size = s.size(); i != size; ++i) { |
473 | if ((data[i] & 0xc0) != 0x80) ++num_code_points; |
474 | } |
475 | return num_code_points; |
476 | } |
477 | |
478 | template <typename Char> |
479 | inline size_t code_point_index(basic_string_view<Char> s, size_t n) { |
480 | size_t size = s.size(); |
481 | return n < size ? n : size; |
482 | } |
483 | |
484 | // Calculates the index of the nth code point in a UTF-8 string. |
485 | inline size_t code_point_index(basic_string_view<char8_t> s, size_t n) { |
486 | const char8_t* data = s.data(); |
487 | size_t num_code_points = 0; |
488 | for (size_t i = 0, size = s.size(); i != size; ++i) { |
489 | if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) { |
490 | return i; |
491 | } |
492 | } |
493 | return s.size(); |
494 | } |
495 | |
496 | inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); } |
497 | |
498 | template <typename InputIt, typename OutChar> |
499 | using needs_conversion = bool_constant< |
500 | std::is_same<typename std::iterator_traits<InputIt>::value_type, |
501 | char>::value && |
502 | std::is_same<OutChar, char8_t>::value>; |
503 | |
504 | template <typename OutChar, typename InputIt, typename OutputIt, |
505 | FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)> |
506 | OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { |
507 | return std::copy(begin, end, it); |
508 | } |
509 | |
510 | template <typename OutChar, typename InputIt, typename OutputIt, |
511 | FMT_ENABLE_IF(needs_conversion<InputIt, OutChar>::value)> |
512 | OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { |
513 | return std::transform(begin, end, it, to_char8_t); |
514 | } |
515 | |
516 | #ifndef FMT_USE_GRISU |
517 | # define FMT_USE_GRISU 1 |
518 | #endif |
519 | |
520 | template <typename T> constexpr bool use_grisu() { |
521 | return FMT_USE_GRISU && std::numeric_limits<double>::is_iec559 && |
522 | sizeof(T) <= sizeof(double); |
523 | } |
524 | |
525 | template <typename T> |
526 | template <typename U> |
527 | void buffer<T>::append(const U* begin, const U* end) { |
528 | std::size_t new_size = size_ + to_unsigned(end - begin); |
529 | reserve(new_size); |
530 | std::uninitialized_copy(begin, end, make_checked(ptr_, capacity_) + size_); |
531 | size_ = new_size; |
532 | } |
533 | } // namespace internal |
534 | |
535 | // A range with an iterator appending to a buffer. |
536 | template <typename T> |
537 | class buffer_range : public internal::output_range< |
538 | std::back_insert_iterator<internal::buffer<T>>, T> { |
539 | public: |
540 | using iterator = std::back_insert_iterator<internal::buffer<T>>; |
541 | using internal::output_range<iterator, T>::output_range; |
542 | buffer_range(internal::buffer<T>& buf) |
543 | : internal::output_range<iterator, T>(std::back_inserter(buf)) {} |
544 | }; |
545 | |
546 | // A UTF-8 string view. |
547 | class u8string_view : public basic_string_view<char8_t> { |
548 | public: |
549 | u8string_view(const char* s) |
550 | : basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s)) {} |
551 | u8string_view(const char* s, size_t count) FMT_NOEXCEPT |
552 | : basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s), count) { |
553 | } |
554 | }; |
555 | |
556 | #if FMT_USE_USER_DEFINED_LITERALS |
557 | inline namespace literals { |
558 | inline u8string_view operator"" _u(const char* s, std::size_t n) { |
559 | return {s, n}; |
560 | } |
561 | } // namespace literals |
562 | #endif |
563 | |
564 | // The number of characters to store in the basic_memory_buffer object itself |
565 | // to avoid dynamic memory allocation. |
566 | enum { inline_buffer_size = 500 }; |
567 | |
568 | /** |
569 | \rst |
570 | A dynamically growing memory buffer for trivially copyable/constructible types |
571 | with the first ``SIZE`` elements stored in the object itself. |
572 | |
573 | You can use one of the following type aliases for common character types: |
574 | |
575 | +----------------+------------------------------+ |
576 | | Type | Definition | |
577 | +================+==============================+ |
578 | | memory_buffer | basic_memory_buffer<char> | |
579 | +----------------+------------------------------+ |
580 | | wmemory_buffer | basic_memory_buffer<wchar_t> | |
581 | +----------------+------------------------------+ |
582 | |
583 | **Example**:: |
584 | |
585 | fmt::memory_buffer out; |
586 | format_to(out, "The answer is {}.", 42); |
587 | |
588 | This will append the following output to the ``out`` object: |
589 | |
590 | .. code-block:: none |
591 | |
592 | The answer is 42. |
593 | |
594 | The output can be converted to an ``std::string`` with ``to_string(out)``. |
595 | \endrst |
596 | */ |
597 | template <typename T, std::size_t SIZE = inline_buffer_size, |
598 | typename Allocator = std::allocator<T>> |
599 | class basic_memory_buffer : private Allocator, public internal::buffer<T> { |
600 | private: |
601 | T store_[SIZE]; |
602 | |
603 | // Deallocate memory allocated by the buffer. |
604 | void deallocate() { |
605 | T* data = this->data(); |
606 | if (data != store_) Allocator::deallocate(data, this->capacity()); |
607 | } |
608 | |
609 | protected: |
610 | void grow(std::size_t size) FMT_OVERRIDE; |
611 | |
612 | public: |
613 | using value_type = T; |
614 | using const_reference = const T&; |
615 | |
616 | explicit basic_memory_buffer(const Allocator& alloc = Allocator()) |
617 | : Allocator(alloc) { |
618 | this->set(store_, SIZE); |
619 | } |
620 | ~basic_memory_buffer() FMT_OVERRIDE { deallocate(); } |
621 | |
622 | private: |
623 | // Move data from other to this buffer. |
624 | void move(basic_memory_buffer& other) { |
625 | Allocator &this_alloc = *this, &other_alloc = other; |
626 | this_alloc = std::move(other_alloc); |
627 | T* data = other.data(); |
628 | std::size_t size = other.size(), capacity = other.capacity(); |
629 | if (data == other.store_) { |
630 | this->set(store_, capacity); |
631 | std::uninitialized_copy(other.store_, other.store_ + size, |
632 | internal::make_checked(store_, capacity)); |
633 | } else { |
634 | this->set(data, capacity); |
635 | // Set pointer to the inline array so that delete is not called |
636 | // when deallocating. |
637 | other.set(other.store_, 0); |
638 | } |
639 | this->resize(size); |
640 | } |
641 | |
642 | public: |
643 | /** |
644 | \rst |
645 | Constructs a :class:`fmt::basic_memory_buffer` object moving the content |
646 | of the other object to it. |
647 | \endrst |
648 | */ |
649 | basic_memory_buffer(basic_memory_buffer&& other) FMT_NOEXCEPT { move(other); } |
650 | |
651 | /** |
652 | \rst |
653 | Moves the content of the other ``basic_memory_buffer`` object to this one. |
654 | \endrst |
655 | */ |
656 | basic_memory_buffer& operator=(basic_memory_buffer&& other) FMT_NOEXCEPT { |
657 | FMT_ASSERT(this != &other, "" ); |
658 | deallocate(); |
659 | move(other); |
660 | return *this; |
661 | } |
662 | |
663 | // Returns a copy of the allocator associated with this buffer. |
664 | Allocator get_allocator() const { return *this; } |
665 | }; |
666 | |
667 | template <typename T, std::size_t SIZE, typename Allocator> |
668 | void basic_memory_buffer<T, SIZE, Allocator>::grow(std::size_t size) { |
669 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
670 | if (size > 1000) throw std::runtime_error("fuzz mode - won't grow that much" ); |
671 | #endif |
672 | std::size_t old_capacity = this->capacity(); |
673 | std::size_t new_capacity = old_capacity + old_capacity / 2; |
674 | if (size > new_capacity) new_capacity = size; |
675 | T* old_data = this->data(); |
676 | T* new_data = std::allocator_traits<Allocator>::allocate(*this, new_capacity); |
677 | // The following code doesn't throw, so the raw pointer above doesn't leak. |
678 | std::uninitialized_copy(old_data, old_data + this->size(), |
679 | internal::make_checked(new_data, new_capacity)); |
680 | this->set(new_data, new_capacity); |
681 | // deallocate must not throw according to the standard, but even if it does, |
682 | // the buffer already uses the new storage and will deallocate it in |
683 | // destructor. |
684 | if (old_data != store_) Allocator::deallocate(old_data, old_capacity); |
685 | } |
686 | |
687 | using memory_buffer = basic_memory_buffer<char>; |
688 | using wmemory_buffer = basic_memory_buffer<wchar_t>; |
689 | |
690 | /** A formatting error such as invalid format string. */ |
691 | class FMT_API format_error : public std::runtime_error { |
692 | public: |
693 | explicit format_error(const char* message) : std::runtime_error(message) {} |
694 | explicit format_error(const std::string& message) |
695 | : std::runtime_error(message) {} |
696 | format_error(const format_error&) = default; |
697 | format_error& operator=(const format_error&) = default; |
698 | format_error(format_error&&) = default; |
699 | format_error& operator=(format_error&&) = default; |
700 | ~format_error() FMT_NOEXCEPT FMT_OVERRIDE; |
701 | }; |
702 | |
703 | namespace internal { |
704 | |
705 | // Returns true if value is negative, false otherwise. |
706 | // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. |
707 | template <typename T, FMT_ENABLE_IF(std::numeric_limits<T>::is_signed)> |
708 | FMT_CONSTEXPR bool is_negative(T value) { |
709 | return value < 0; |
710 | } |
711 | template <typename T, FMT_ENABLE_IF(!std::numeric_limits<T>::is_signed)> |
712 | FMT_CONSTEXPR bool is_negative(T) { |
713 | return false; |
714 | } |
715 | |
716 | // Smallest of uint32_t, uint64_t, uint128_t that is large enough to |
717 | // represent all values of T. |
718 | template <typename T> |
719 | using uint32_or_64_or_128_t = conditional_t< |
720 | std::numeric_limits<T>::digits <= 32, uint32_t, |
721 | conditional_t<std::numeric_limits<T>::digits <= 64, uint64_t, uint128_t>>; |
722 | |
723 | // Static data is placed in this class template for the header-only config. |
724 | template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data { |
725 | static const uint64_t powers_of_10_64[]; |
726 | static const uint32_t zero_or_powers_of_10_32[]; |
727 | static const uint64_t zero_or_powers_of_10_64[]; |
728 | static const uint64_t pow10_significands[]; |
729 | static const int16_t pow10_exponents[]; |
730 | static const char digits[]; |
731 | static const char hex_digits[]; |
732 | static const char foreground_color[]; |
733 | static const char background_color[]; |
734 | static const char reset_color[5]; |
735 | static const wchar_t wreset_color[5]; |
736 | static const char signs[]; |
737 | }; |
738 | |
739 | FMT_EXTERN template struct basic_data<void>; |
740 | |
741 | // This is a struct rather than an alias to avoid shadowing warnings in gcc. |
742 | struct data : basic_data<> {}; |
743 | |
744 | #ifdef FMT_BUILTIN_CLZLL |
745 | // Returns the number of decimal digits in n. Leading zeros are not counted |
746 | // except for n == 0 in which case count_digits returns 1. |
747 | inline int count_digits(uint64_t n) { |
748 | // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 |
749 | // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. |
750 | int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; |
751 | return t - (n < data::zero_or_powers_of_10_64[t]) + 1; |
752 | } |
753 | #else |
754 | // Fallback version of count_digits used when __builtin_clz is not available. |
755 | inline int count_digits(uint64_t n) { |
756 | int count = 1; |
757 | for (;;) { |
758 | // Integer division is slow so do it for a group of four digits instead |
759 | // of for every digit. The idea comes from the talk by Alexandrescu |
760 | // "Three Optimization Tips for C++". See speed-test for a comparison. |
761 | if (n < 10) return count; |
762 | if (n < 100) return count + 1; |
763 | if (n < 1000) return count + 2; |
764 | if (n < 10000) return count + 3; |
765 | n /= 10000u; |
766 | count += 4; |
767 | } |
768 | } |
769 | #endif |
770 | |
771 | #if FMT_USE_INT128 |
772 | inline int count_digits(uint128_t n) { |
773 | int count = 1; |
774 | for (;;) { |
775 | // Integer division is slow so do it for a group of four digits instead |
776 | // of for every digit. The idea comes from the talk by Alexandrescu |
777 | // "Three Optimization Tips for C++". See speed-test for a comparison. |
778 | if (n < 10) return count; |
779 | if (n < 100) return count + 1; |
780 | if (n < 1000) return count + 2; |
781 | if (n < 10000) return count + 3; |
782 | n /= 10000U; |
783 | count += 4; |
784 | } |
785 | } |
786 | #endif |
787 | |
788 | // Counts the number of digits in n. BITS = log2(radix). |
789 | template <unsigned BITS, typename UInt> inline int count_digits(UInt n) { |
790 | int num_digits = 0; |
791 | do { |
792 | ++num_digits; |
793 | } while ((n >>= BITS) != 0); |
794 | return num_digits; |
795 | } |
796 | |
797 | template <> int count_digits<4>(internal::fallback_uintptr n); |
798 | |
799 | #if FMT_GCC_VERSION || FMT_CLANG_VERSION |
800 | # define FMT_ALWAYS_INLINE inline __attribute__((always_inline)) |
801 | #else |
802 | # define FMT_ALWAYS_INLINE |
803 | #endif |
804 | |
805 | #ifdef FMT_BUILTIN_CLZ |
806 | // Optional version of count_digits for better performance on 32-bit platforms. |
807 | inline int count_digits(uint32_t n) { |
808 | int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; |
809 | return t - (n < data::zero_or_powers_of_10_32[t]) + 1; |
810 | } |
811 | #endif |
812 | |
813 | template <typename Char> FMT_API std::string grouping_impl(locale_ref loc); |
814 | template <typename Char> inline std::string grouping(locale_ref loc) { |
815 | return grouping_impl<char>(loc); |
816 | } |
817 | template <> inline std::string grouping<wchar_t>(locale_ref loc) { |
818 | return grouping_impl<wchar_t>(loc); |
819 | } |
820 | |
821 | template <typename Char> FMT_API Char thousands_sep_impl(locale_ref loc); |
822 | template <typename Char> inline Char thousands_sep(locale_ref loc) { |
823 | return Char(thousands_sep_impl<char>(loc)); |
824 | } |
825 | template <> inline wchar_t thousands_sep(locale_ref loc) { |
826 | return thousands_sep_impl<wchar_t>(loc); |
827 | } |
828 | |
829 | template <typename Char> FMT_API Char decimal_point_impl(locale_ref loc); |
830 | template <typename Char> inline Char decimal_point(locale_ref loc) { |
831 | return Char(decimal_point_impl<char>(loc)); |
832 | } |
833 | template <> inline wchar_t decimal_point(locale_ref loc) { |
834 | return decimal_point_impl<wchar_t>(loc); |
835 | } |
836 | |
837 | // Formats a decimal unsigned integer value writing into buffer. |
838 | // add_thousands_sep is called after writing each char to add a thousands |
839 | // separator if necessary. |
840 | template <typename UInt, typename Char, typename F> |
841 | inline Char* format_decimal(Char* buffer, UInt value, int num_digits, |
842 | F add_thousands_sep) { |
843 | FMT_ASSERT(num_digits >= 0, "invalid digit count" ); |
844 | buffer += num_digits; |
845 | Char* end = buffer; |
846 | while (value >= 100) { |
847 | // Integer division is slow so do it for a group of two digits instead |
848 | // of for every digit. The idea comes from the talk by Alexandrescu |
849 | // "Three Optimization Tips for C++". See speed-test for a comparison. |
850 | auto index = static_cast<unsigned>((value % 100) * 2); |
851 | value /= 100; |
852 | *--buffer = static_cast<Char>(data::digits[index + 1]); |
853 | add_thousands_sep(buffer); |
854 | *--buffer = static_cast<Char>(data::digits[index]); |
855 | add_thousands_sep(buffer); |
856 | } |
857 | if (value < 10) { |
858 | *--buffer = static_cast<Char>('0' + value); |
859 | return end; |
860 | } |
861 | auto index = static_cast<unsigned>(value * 2); |
862 | *--buffer = static_cast<Char>(data::digits[index + 1]); |
863 | add_thousands_sep(buffer); |
864 | *--buffer = static_cast<Char>(data::digits[index]); |
865 | return end; |
866 | } |
867 | |
868 | template <typename Int> constexpr int digits10() noexcept { |
869 | return std::numeric_limits<Int>::digits10; |
870 | } |
871 | template <> constexpr int digits10<int128_t>() noexcept { return 38; } |
872 | template <> constexpr int digits10<uint128_t>() noexcept { return 38; } |
873 | |
874 | template <typename Char, typename UInt, typename Iterator, typename F> |
875 | inline Iterator format_decimal(Iterator out, UInt value, int num_digits, |
876 | F add_thousands_sep) { |
877 | FMT_ASSERT(num_digits >= 0, "invalid digit count" ); |
878 | // Buffer should be large enough to hold all digits (<= digits10 + 1). |
879 | enum { max_size = digits10<UInt>() + 1 }; |
880 | Char buffer[2 * max_size]; |
881 | auto end = format_decimal(buffer, value, num_digits, add_thousands_sep); |
882 | return internal::copy_str<Char>(buffer, end, out); |
883 | } |
884 | |
885 | template <typename Char, typename It, typename UInt> |
886 | inline It format_decimal(It out, UInt value, int num_digits) { |
887 | return format_decimal<Char>(out, value, num_digits, [](Char*) {}); |
888 | } |
889 | |
890 | template <unsigned BASE_BITS, typename Char, typename UInt> |
891 | inline Char* format_uint(Char* buffer, UInt value, int num_digits, |
892 | bool upper = false) { |
893 | buffer += num_digits; |
894 | Char* end = buffer; |
895 | do { |
896 | const char* digits = upper ? "0123456789ABCDEF" : data::hex_digits; |
897 | unsigned digit = (value & ((1 << BASE_BITS) - 1)); |
898 | *--buffer = static_cast<Char>(BASE_BITS < 4 ? static_cast<char>('0' + digit) |
899 | : digits[digit]); |
900 | } while ((value >>= BASE_BITS) != 0); |
901 | return end; |
902 | } |
903 | |
904 | template <unsigned BASE_BITS, typename Char> |
905 | Char* format_uint(Char* buffer, internal::fallback_uintptr n, int num_digits, |
906 | bool = false) { |
907 | auto char_digits = std::numeric_limits<unsigned char>::digits / 4; |
908 | int start = (num_digits + char_digits - 1) / char_digits - 1; |
909 | if (int start_digits = num_digits % char_digits) { |
910 | unsigned value = n.value[start--]; |
911 | buffer = format_uint<BASE_BITS>(buffer, value, start_digits); |
912 | } |
913 | for (; start >= 0; --start) { |
914 | unsigned value = n.value[start]; |
915 | buffer += char_digits; |
916 | auto p = buffer; |
917 | for (int i = 0; i < char_digits; ++i) { |
918 | unsigned digit = (value & ((1 << BASE_BITS) - 1)); |
919 | *--p = static_cast<Char>(data::hex_digits[digit]); |
920 | value >>= BASE_BITS; |
921 | } |
922 | } |
923 | return buffer; |
924 | } |
925 | |
926 | template <unsigned BASE_BITS, typename Char, typename It, typename UInt> |
927 | inline It format_uint(It out, UInt value, int num_digits, bool upper = false) { |
928 | // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). |
929 | char buffer[num_bits<UInt>() / BASE_BITS + 1]; |
930 | format_uint<BASE_BITS>(buffer, value, num_digits, upper); |
931 | return internal::copy_str<Char>(buffer, buffer + num_digits, out); |
932 | } |
933 | |
934 | #ifndef _WIN32 |
935 | # define FMT_USE_WINDOWS_H 0 |
936 | #elif !defined(FMT_USE_WINDOWS_H) |
937 | # define FMT_USE_WINDOWS_H 1 |
938 | #endif |
939 | |
940 | // Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. |
941 | // All the functionality that relies on it will be disabled too. |
942 | #if FMT_USE_WINDOWS_H |
943 | // A converter from UTF-8 to UTF-16. |
944 | // It is only provided for Windows since other systems support UTF-8 natively. |
945 | class utf8_to_utf16 { |
946 | private: |
947 | wmemory_buffer buffer_; |
948 | |
949 | public: |
950 | FMT_API explicit utf8_to_utf16(string_view s); |
951 | operator wstring_view() const { return wstring_view(&buffer_[0], size()); } |
952 | size_t size() const { return buffer_.size() - 1; } |
953 | const wchar_t* c_str() const { return &buffer_[0]; } |
954 | std::wstring str() const { return std::wstring(&buffer_[0], size()); } |
955 | }; |
956 | |
957 | // A converter from UTF-16 to UTF-8. |
958 | // It is only provided for Windows since other systems support UTF-8 natively. |
959 | class utf16_to_utf8 { |
960 | private: |
961 | memory_buffer buffer_; |
962 | |
963 | public: |
964 | utf16_to_utf8() {} |
965 | FMT_API explicit utf16_to_utf8(wstring_view s); |
966 | operator string_view() const { return string_view(&buffer_[0], size()); } |
967 | size_t size() const { return buffer_.size() - 1; } |
968 | const char* c_str() const { return &buffer_[0]; } |
969 | std::string str() const { return std::string(&buffer_[0], size()); } |
970 | |
971 | // Performs conversion returning a system error code instead of |
972 | // throwing exception on conversion error. This method may still throw |
973 | // in case of memory allocation error. |
974 | FMT_API int convert(wstring_view s); |
975 | }; |
976 | |
977 | FMT_API void format_windows_error(internal::buffer<char>& out, int error_code, |
978 | string_view message) FMT_NOEXCEPT; |
979 | #endif |
980 | |
981 | template <typename T = void> struct null {}; |
982 | |
983 | // Workaround an array initialization issue in gcc 4.8. |
984 | template <typename Char> struct fill_t { |
985 | private: |
986 | Char data_[6]; |
987 | |
988 | public: |
989 | FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; } |
990 | FMT_CONSTEXPR const Char& operator[](size_t index) const { |
991 | return data_[index]; |
992 | } |
993 | |
994 | static FMT_CONSTEXPR fill_t<Char> make() { |
995 | auto fill = fill_t<Char>(); |
996 | fill[0] = Char(' '); |
997 | return fill; |
998 | } |
999 | }; |
1000 | } // namespace internal |
1001 | |
1002 | // We cannot use enum classes as bit fields because of a gcc bug |
1003 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. |
1004 | namespace align { |
1005 | enum type { none, left, right, center, numeric }; |
1006 | } |
1007 | using align_t = align::type; |
1008 | |
1009 | namespace sign { |
1010 | enum type { none, minus, plus, space }; |
1011 | } |
1012 | using sign_t = sign::type; |
1013 | |
1014 | // Format specifiers for built-in and string types. |
1015 | template <typename Char> struct basic_format_specs { |
1016 | int width; |
1017 | int precision; |
1018 | char type; |
1019 | align_t align : 4; |
1020 | sign_t sign : 3; |
1021 | bool alt : 1; // Alternate form ('#'). |
1022 | internal::fill_t<Char> fill; |
1023 | |
1024 | constexpr basic_format_specs() |
1025 | : width(0), |
1026 | precision(-1), |
1027 | type(0), |
1028 | align(align::none), |
1029 | sign(sign::none), |
1030 | alt(false), |
1031 | fill(internal::fill_t<Char>::make()) {} |
1032 | }; |
1033 | |
1034 | using format_specs = basic_format_specs<char>; |
1035 | |
1036 | namespace internal { |
1037 | |
1038 | // A floating-point presentation format. |
1039 | enum class float_format : unsigned char { |
1040 | general, // General: exponent notation or fixed point based on magnitude. |
1041 | exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. |
1042 | fixed, // Fixed point with the default precision of 6, e.g. 0.0012. |
1043 | hex |
1044 | }; |
1045 | |
1046 | struct float_specs { |
1047 | int precision; |
1048 | float_format format : 8; |
1049 | sign_t sign : 8; |
1050 | bool upper : 1; |
1051 | bool locale : 1; |
1052 | bool percent : 1; |
1053 | bool binary32 : 1; |
1054 | bool use_grisu : 1; |
1055 | bool trailing_zeros : 1; |
1056 | }; |
1057 | |
1058 | // Writes the exponent exp in the form "[+-]d{2,3}" to buffer. |
1059 | template <typename Char, typename It> It write_exponent(int exp, It it) { |
1060 | FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range" ); |
1061 | if (exp < 0) { |
1062 | *it++ = static_cast<Char>('-'); |
1063 | exp = -exp; |
1064 | } else { |
1065 | *it++ = static_cast<Char>('+'); |
1066 | } |
1067 | if (exp >= 100) { |
1068 | const char* top = data::digits + (exp / 100) * 2; |
1069 | if (exp >= 1000) *it++ = static_cast<Char>(top[0]); |
1070 | *it++ = static_cast<Char>(top[1]); |
1071 | exp %= 100; |
1072 | } |
1073 | const char* d = data::digits + exp * 2; |
1074 | *it++ = static_cast<Char>(d[0]); |
1075 | *it++ = static_cast<Char>(d[1]); |
1076 | return it; |
1077 | } |
1078 | |
1079 | template <typename Char> class float_writer { |
1080 | private: |
1081 | // The number is given as v = digits_ * pow(10, exp_). |
1082 | const char* digits_; |
1083 | int num_digits_; |
1084 | int exp_; |
1085 | size_t size_; |
1086 | float_specs specs_; |
1087 | Char decimal_point_; |
1088 | |
1089 | template <typename It> It prettify(It it) const { |
1090 | // pow(10, full_exp - 1) <= v <= pow(10, full_exp). |
1091 | int full_exp = num_digits_ + exp_; |
1092 | if (specs_.format == float_format::exp) { |
1093 | // Insert a decimal point after the first digit and add an exponent. |
1094 | *it++ = static_cast<Char>(*digits_); |
1095 | int num_zeros = specs_.precision - num_digits_; |
1096 | bool trailing_zeros = num_zeros > 0 && specs_.trailing_zeros; |
1097 | if (num_digits_ > 1 || trailing_zeros) *it++ = decimal_point_; |
1098 | it = copy_str<Char>(digits_ + 1, digits_ + num_digits_, it); |
1099 | if (trailing_zeros) |
1100 | it = std::fill_n(it, num_zeros, static_cast<Char>('0')); |
1101 | *it++ = static_cast<Char>(specs_.upper ? 'E' : 'e'); |
1102 | return write_exponent<Char>(full_exp - 1, it); |
1103 | } |
1104 | if (num_digits_ <= full_exp) { |
1105 | // 1234e7 -> 12340000000[.0+] |
1106 | it = copy_str<Char>(digits_, digits_ + num_digits_, it); |
1107 | it = std::fill_n(it, full_exp - num_digits_, static_cast<Char>('0')); |
1108 | if (specs_.trailing_zeros) { |
1109 | *it++ = decimal_point_; |
1110 | int num_zeros = specs_.precision - full_exp; |
1111 | if (num_zeros <= 0) { |
1112 | if (specs_.format != float_format::fixed) |
1113 | *it++ = static_cast<Char>('0'); |
1114 | return it; |
1115 | } |
1116 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
1117 | if (num_zeros > 1000) |
1118 | throw std::runtime_error("fuzz mode - avoiding excessive cpu use" ); |
1119 | #endif |
1120 | it = std::fill_n(it, num_zeros, static_cast<Char>('0')); |
1121 | } |
1122 | } else if (full_exp > 0) { |
1123 | // 1234e-2 -> 12.34[0+] |
1124 | it = copy_str<Char>(digits_, digits_ + full_exp, it); |
1125 | if (!specs_.trailing_zeros) { |
1126 | // Remove trailing zeros. |
1127 | int num_digits = num_digits_; |
1128 | while (num_digits > full_exp && digits_[num_digits - 1] == '0') |
1129 | --num_digits; |
1130 | if (num_digits != full_exp) *it++ = decimal_point_; |
1131 | return copy_str<Char>(digits_ + full_exp, digits_ + num_digits, it); |
1132 | } |
1133 | *it++ = decimal_point_; |
1134 | it = copy_str<Char>(digits_ + full_exp, digits_ + num_digits_, it); |
1135 | if (specs_.precision > num_digits_) { |
1136 | // Add trailing zeros. |
1137 | int num_zeros = specs_.precision - num_digits_; |
1138 | it = std::fill_n(it, num_zeros, static_cast<Char>('0')); |
1139 | } |
1140 | } else { |
1141 | // 1234e-6 -> 0.001234 |
1142 | *it++ = static_cast<Char>('0'); |
1143 | int num_zeros = -full_exp; |
1144 | if (specs_.precision >= 0 && specs_.precision < num_zeros) |
1145 | num_zeros = specs_.precision; |
1146 | int num_digits = num_digits_; |
1147 | if (!specs_.trailing_zeros) |
1148 | while (num_digits > 0 && digits_[num_digits - 1] == '0') --num_digits; |
1149 | if (num_zeros != 0 || num_digits != 0) { |
1150 | *it++ = decimal_point_; |
1151 | it = std::fill_n(it, num_zeros, static_cast<Char>('0')); |
1152 | it = copy_str<Char>(digits_, digits_ + num_digits, it); |
1153 | } |
1154 | } |
1155 | return it; |
1156 | } |
1157 | |
1158 | public: |
1159 | float_writer(const char* digits, int num_digits, int exp, float_specs specs, |
1160 | Char decimal_point) |
1161 | : digits_(digits), |
1162 | num_digits_(num_digits), |
1163 | exp_(exp), |
1164 | specs_(specs), |
1165 | decimal_point_(decimal_point) { |
1166 | int full_exp = num_digits + exp - 1; |
1167 | int precision = specs.precision > 0 ? specs.precision : 16; |
1168 | if (specs_.format == float_format::general && |
1169 | !(full_exp >= -4 && full_exp < precision)) { |
1170 | specs_.format = float_format::exp; |
1171 | } |
1172 | size_ = prettify(counting_iterator()).count(); |
1173 | size_ += specs.sign ? 1 : 0; |
1174 | } |
1175 | |
1176 | size_t size() const { return size_; } |
1177 | size_t width() const { return size(); } |
1178 | |
1179 | template <typename It> void operator()(It&& it) { |
1180 | if (specs_.sign) *it++ = static_cast<Char>(data::signs[specs_.sign]); |
1181 | it = prettify(it); |
1182 | } |
1183 | }; |
1184 | |
1185 | template <typename T> |
1186 | int format_float(T value, int precision, float_specs specs, buffer<char>& buf); |
1187 | |
1188 | // Formats a floating-point number with snprintf. |
1189 | template <typename T> |
1190 | int snprintf_float(T value, int precision, float_specs specs, |
1191 | buffer<char>& buf); |
1192 | |
1193 | template <typename T> T promote_float(T value) { return value; } |
1194 | inline double promote_float(float value) { return value; } |
1195 | |
1196 | template <typename Handler> |
1197 | FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) { |
1198 | switch (spec) { |
1199 | case 0: |
1200 | case 'd': |
1201 | handler.on_dec(); |
1202 | break; |
1203 | case 'x': |
1204 | case 'X': |
1205 | handler.on_hex(); |
1206 | break; |
1207 | case 'b': |
1208 | case 'B': |
1209 | handler.on_bin(); |
1210 | break; |
1211 | case 'o': |
1212 | handler.on_oct(); |
1213 | break; |
1214 | case 'n': |
1215 | handler.on_num(); |
1216 | break; |
1217 | default: |
1218 | handler.on_error(); |
1219 | } |
1220 | } |
1221 | |
1222 | template <typename ErrorHandler = error_handler, typename Char> |
1223 | FMT_CONSTEXPR float_specs parse_float_type_spec( |
1224 | const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) { |
1225 | auto result = float_specs(); |
1226 | result.trailing_zeros = specs.alt; |
1227 | switch (specs.type) { |
1228 | case 0: |
1229 | result.format = float_format::general; |
1230 | result.trailing_zeros |= specs.precision != 0; |
1231 | break; |
1232 | case 'G': |
1233 | result.upper = true; |
1234 | FMT_FALLTHROUGH; |
1235 | case 'g': |
1236 | result.format = float_format::general; |
1237 | break; |
1238 | case 'E': |
1239 | result.upper = true; |
1240 | FMT_FALLTHROUGH; |
1241 | case 'e': |
1242 | result.format = float_format::exp; |
1243 | result.trailing_zeros |= specs.precision != 0; |
1244 | break; |
1245 | case 'F': |
1246 | result.upper = true; |
1247 | FMT_FALLTHROUGH; |
1248 | case 'f': |
1249 | result.format = float_format::fixed; |
1250 | result.trailing_zeros |= specs.precision != 0; |
1251 | break; |
1252 | #if FMT_DEPRECATED_PERCENT |
1253 | case '%': |
1254 | result.format = float_format::fixed; |
1255 | result.percent = true; |
1256 | break; |
1257 | #endif |
1258 | case 'A': |
1259 | result.upper = true; |
1260 | FMT_FALLTHROUGH; |
1261 | case 'a': |
1262 | result.format = float_format::hex; |
1263 | break; |
1264 | case 'n': |
1265 | result.locale = true; |
1266 | break; |
1267 | default: |
1268 | eh.on_error("invalid type specifier" ); |
1269 | break; |
1270 | } |
1271 | return result; |
1272 | } |
1273 | |
1274 | template <typename Char, typename Handler> |
1275 | FMT_CONSTEXPR void handle_char_specs(const basic_format_specs<Char>* specs, |
1276 | Handler&& handler) { |
1277 | if (!specs) return handler.on_char(); |
1278 | if (specs->type && specs->type != 'c') return handler.on_int(); |
1279 | if (specs->align == align::numeric || specs->sign != sign::none || specs->alt) |
1280 | handler.on_error("invalid format specifier for char" ); |
1281 | handler.on_char(); |
1282 | } |
1283 | |
1284 | template <typename Char, typename Handler> |
1285 | FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler&& handler) { |
1286 | if (spec == 0 || spec == 's') |
1287 | handler.on_string(); |
1288 | else if (spec == 'p') |
1289 | handler.on_pointer(); |
1290 | else |
1291 | handler.on_error("invalid type specifier" ); |
1292 | } |
1293 | |
1294 | template <typename Char, typename ErrorHandler> |
1295 | FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) { |
1296 | if (spec != 0 && spec != 's') eh.on_error("invalid type specifier" ); |
1297 | } |
1298 | |
1299 | template <typename Char, typename ErrorHandler> |
1300 | FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) { |
1301 | if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier" ); |
1302 | } |
1303 | |
1304 | template <typename ErrorHandler> class int_type_checker : private ErrorHandler { |
1305 | public: |
1306 | FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} |
1307 | |
1308 | FMT_CONSTEXPR void on_dec() {} |
1309 | FMT_CONSTEXPR void on_hex() {} |
1310 | FMT_CONSTEXPR void on_bin() {} |
1311 | FMT_CONSTEXPR void on_oct() {} |
1312 | FMT_CONSTEXPR void on_num() {} |
1313 | |
1314 | FMT_CONSTEXPR void on_error() { |
1315 | ErrorHandler::on_error("invalid type specifier" ); |
1316 | } |
1317 | }; |
1318 | |
1319 | template <typename ErrorHandler> |
1320 | class char_specs_checker : public ErrorHandler { |
1321 | private: |
1322 | char type_; |
1323 | |
1324 | public: |
1325 | FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh) |
1326 | : ErrorHandler(eh), type_(type) {} |
1327 | |
1328 | FMT_CONSTEXPR void on_int() { |
1329 | handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this)); |
1330 | } |
1331 | FMT_CONSTEXPR void on_char() {} |
1332 | }; |
1333 | |
1334 | template <typename ErrorHandler> |
1335 | class cstring_type_checker : public ErrorHandler { |
1336 | public: |
1337 | FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh) |
1338 | : ErrorHandler(eh) {} |
1339 | |
1340 | FMT_CONSTEXPR void on_string() {} |
1341 | FMT_CONSTEXPR void on_pointer() {} |
1342 | }; |
1343 | |
1344 | template <typename Context> |
1345 | void arg_map<Context>::init(const basic_format_args<Context>& args) { |
1346 | if (map_) return; |
1347 | map_ = new entry[internal::to_unsigned(args.max_size())]; |
1348 | if (args.is_packed()) { |
1349 | for (int i = 0;; ++i) { |
1350 | internal::type arg_type = args.type(i); |
1351 | if (arg_type == internal::none_type) return; |
1352 | if (arg_type == internal::named_arg_type) push_back(args.values_[i]); |
1353 | } |
1354 | } |
1355 | for (int i = 0, n = args.max_size(); i < n; ++i) { |
1356 | auto type = args.args_[i].type_; |
1357 | if (type == internal::named_arg_type) push_back(args.args_[i].value_); |
1358 | } |
1359 | } |
1360 | |
1361 | template <typename Char> struct nonfinite_writer { |
1362 | sign_t sign; |
1363 | const char* str; |
1364 | static constexpr size_t str_size = 3; |
1365 | |
1366 | size_t size() const { return str_size + (sign ? 1 : 0); } |
1367 | size_t width() const { return size(); } |
1368 | |
1369 | template <typename It> void operator()(It&& it) const { |
1370 | if (sign) *it++ = static_cast<Char>(data::signs[sign]); |
1371 | it = copy_str<Char>(str, str + str_size, it); |
1372 | } |
1373 | }; |
1374 | |
1375 | // This template provides operations for formatting and writing data into a |
1376 | // character range. |
1377 | template <typename Range> class basic_writer { |
1378 | public: |
1379 | using char_type = typename Range::value_type; |
1380 | using iterator = typename Range::iterator; |
1381 | using format_specs = basic_format_specs<char_type>; |
1382 | |
1383 | private: |
1384 | iterator out_; // Output iterator. |
1385 | locale_ref locale_; |
1386 | |
1387 | // Attempts to reserve space for n extra characters in the output range. |
1388 | // Returns a pointer to the reserved range or a reference to out_. |
1389 | auto reserve(std::size_t n) -> decltype(internal::reserve(out_, n)) { |
1390 | return internal::reserve(out_, n); |
1391 | } |
1392 | |
1393 | template <typename F> struct padded_int_writer { |
1394 | size_t size_; |
1395 | string_view prefix; |
1396 | char_type fill; |
1397 | std::size_t padding; |
1398 | F f; |
1399 | |
1400 | size_t size() const { return size_; } |
1401 | size_t width() const { return size_; } |
1402 | |
1403 | template <typename It> void operator()(It&& it) const { |
1404 | if (prefix.size() != 0) |
1405 | it = copy_str<char_type>(prefix.begin(), prefix.end(), it); |
1406 | it = std::fill_n(it, padding, fill); |
1407 | f(it); |
1408 | } |
1409 | }; |
1410 | |
1411 | // Writes an integer in the format |
1412 | // <left-padding><prefix><numeric-padding><digits><right-padding> |
1413 | // where <digits> are written by f(it). |
1414 | template <typename F> |
1415 | void write_int(int num_digits, string_view prefix, format_specs specs, F f) { |
1416 | std::size_t size = prefix.size() + to_unsigned(num_digits); |
1417 | char_type fill = specs.fill[0]; |
1418 | std::size_t padding = 0; |
1419 | if (specs.align == align::numeric) { |
1420 | auto unsiged_width = to_unsigned(specs.width); |
1421 | if (unsiged_width > size) { |
1422 | padding = unsiged_width - size; |
1423 | size = unsiged_width; |
1424 | } |
1425 | } else if (specs.precision > num_digits) { |
1426 | size = prefix.size() + to_unsigned(specs.precision); |
1427 | padding = to_unsigned(specs.precision - num_digits); |
1428 | fill = static_cast<char_type>('0'); |
1429 | } |
1430 | if (specs.align == align::none) specs.align = align::right; |
1431 | write_padded(specs, padded_int_writer<F>{size, prefix, fill, padding, f}); |
1432 | } |
1433 | |
1434 | // Writes a decimal integer. |
1435 | template <typename Int> void write_decimal(Int value) { |
1436 | auto abs_value = static_cast<uint32_or_64_or_128_t<Int>>(value); |
1437 | bool negative = is_negative(value); |
1438 | // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. |
1439 | if (negative) abs_value = ~abs_value + 1; |
1440 | int num_digits = count_digits(abs_value); |
1441 | auto&& it = reserve((negative ? 1 : 0) + static_cast<size_t>(num_digits)); |
1442 | if (negative) *it++ = static_cast<char_type>('-'); |
1443 | it = format_decimal<char_type>(it, abs_value, num_digits); |
1444 | } |
1445 | |
1446 | // The handle_int_type_spec handler that writes an integer. |
1447 | template <typename Int, typename Specs> struct int_writer { |
1448 | using unsigned_type = uint32_or_64_or_128_t<Int>; |
1449 | |
1450 | basic_writer<Range>& writer; |
1451 | const Specs& specs; |
1452 | unsigned_type abs_value; |
1453 | char prefix[4]; |
1454 | unsigned prefix_size; |
1455 | |
1456 | string_view get_prefix() const { return string_view(prefix, prefix_size); } |
1457 | |
1458 | int_writer(basic_writer<Range>& w, Int value, const Specs& s) |
1459 | : writer(w), |
1460 | specs(s), |
1461 | abs_value(static_cast<unsigned_type>(value)), |
1462 | prefix_size(0) { |
1463 | if (is_negative(value)) { |
1464 | prefix[0] = '-'; |
1465 | ++prefix_size; |
1466 | abs_value = 0 - abs_value; |
1467 | } else if (specs.sign != sign::none && specs.sign != sign::minus) { |
1468 | prefix[0] = specs.sign == sign::plus ? '+' : ' '; |
1469 | ++prefix_size; |
1470 | } |
1471 | } |
1472 | |
1473 | struct dec_writer { |
1474 | unsigned_type abs_value; |
1475 | int num_digits; |
1476 | |
1477 | template <typename It> void operator()(It&& it) const { |
1478 | it = internal::format_decimal<char_type>(it, abs_value, num_digits); |
1479 | } |
1480 | }; |
1481 | |
1482 | void on_dec() { |
1483 | int num_digits = count_digits(abs_value); |
1484 | writer.write_int(num_digits, get_prefix(), specs, |
1485 | dec_writer{abs_value, num_digits}); |
1486 | } |
1487 | |
1488 | struct hex_writer { |
1489 | int_writer& self; |
1490 | int num_digits; |
1491 | |
1492 | template <typename It> void operator()(It&& it) const { |
1493 | it = format_uint<4, char_type>(it, self.abs_value, num_digits, |
1494 | self.specs.type != 'x'); |
1495 | } |
1496 | }; |
1497 | |
1498 | void on_hex() { |
1499 | if (specs.alt) { |
1500 | prefix[prefix_size++] = '0'; |
1501 | prefix[prefix_size++] = specs.type; |
1502 | } |
1503 | int num_digits = count_digits<4>(abs_value); |
1504 | writer.write_int(num_digits, get_prefix(), specs, |
1505 | hex_writer{*this, num_digits}); |
1506 | } |
1507 | |
1508 | template <int BITS> struct bin_writer { |
1509 | unsigned_type abs_value; |
1510 | int num_digits; |
1511 | |
1512 | template <typename It> void operator()(It&& it) const { |
1513 | it = format_uint<BITS, char_type>(it, abs_value, num_digits); |
1514 | } |
1515 | }; |
1516 | |
1517 | void on_bin() { |
1518 | if (specs.alt) { |
1519 | prefix[prefix_size++] = '0'; |
1520 | prefix[prefix_size++] = static_cast<char>(specs.type); |
1521 | } |
1522 | int num_digits = count_digits<1>(abs_value); |
1523 | writer.write_int(num_digits, get_prefix(), specs, |
1524 | bin_writer<1>{abs_value, num_digits}); |
1525 | } |
1526 | |
1527 | void on_oct() { |
1528 | int num_digits = count_digits<3>(abs_value); |
1529 | if (specs.alt && specs.precision <= num_digits && abs_value != 0) { |
1530 | // Octal prefix '0' is counted as a digit, so only add it if precision |
1531 | // is not greater than the number of digits. |
1532 | prefix[prefix_size++] = '0'; |
1533 | } |
1534 | writer.write_int(num_digits, get_prefix(), specs, |
1535 | bin_writer<3>{abs_value, num_digits}); |
1536 | } |
1537 | |
1538 | enum { sep_size = 1 }; |
1539 | |
1540 | struct num_writer { |
1541 | unsigned_type abs_value; |
1542 | int size; |
1543 | const std::string& groups; |
1544 | char_type sep; |
1545 | |
1546 | template <typename It> void operator()(It&& it) const { |
1547 | basic_string_view<char_type> s(&sep, sep_size); |
1548 | // Index of a decimal digit with the least significant digit having |
1549 | // index 0. |
1550 | int digit_index = 0; |
1551 | std::string::const_iterator group = groups.cbegin(); |
1552 | it = format_decimal<char_type>( |
1553 | it, abs_value, size, |
1554 | [this, s, &group, &digit_index](char_type*& buffer) { |
1555 | if (*group <= 0 || ++digit_index % *group != 0 || |
1556 | *group == max_value<char>()) |
1557 | return; |
1558 | if (group + 1 != groups.cend()) { |
1559 | digit_index = 0; |
1560 | ++group; |
1561 | } |
1562 | buffer -= s.size(); |
1563 | std::uninitialized_copy(s.data(), s.data() + s.size(), |
1564 | make_checked(buffer, s.size())); |
1565 | }); |
1566 | } |
1567 | }; |
1568 | |
1569 | void on_num() { |
1570 | std::string groups = grouping<char_type>(writer.locale_); |
1571 | if (groups.empty()) return on_dec(); |
1572 | auto sep = thousands_sep<char_type>(writer.locale_); |
1573 | if (!sep) return on_dec(); |
1574 | int num_digits = count_digits(abs_value); |
1575 | int size = num_digits; |
1576 | std::string::const_iterator group = groups.cbegin(); |
1577 | while (group != groups.cend() && num_digits > *group && *group > 0 && |
1578 | *group != max_value<char>()) { |
1579 | size += sep_size; |
1580 | num_digits -= *group; |
1581 | ++group; |
1582 | } |
1583 | if (group == groups.cend()) |
1584 | size += sep_size * ((num_digits - 1) / groups.back()); |
1585 | writer.write_int(size, get_prefix(), specs, |
1586 | num_writer{abs_value, size, groups, sep}); |
1587 | } |
1588 | |
1589 | FMT_NORETURN void on_error() { |
1590 | FMT_THROW(format_error("invalid type specifier" )); |
1591 | } |
1592 | }; |
1593 | |
1594 | template <typename Char> struct str_writer { |
1595 | const Char* s; |
1596 | size_t size_; |
1597 | |
1598 | size_t size() const { return size_; } |
1599 | size_t width() const { |
1600 | return count_code_points(basic_string_view<Char>(s, size_)); |
1601 | } |
1602 | |
1603 | template <typename It> void operator()(It&& it) const { |
1604 | it = copy_str<char_type>(s, s + size_, it); |
1605 | } |
1606 | }; |
1607 | |
1608 | template <typename UIntPtr> struct pointer_writer { |
1609 | UIntPtr value; |
1610 | int num_digits; |
1611 | |
1612 | size_t size() const { return to_unsigned(num_digits) + 2; } |
1613 | size_t width() const { return size(); } |
1614 | |
1615 | template <typename It> void operator()(It&& it) const { |
1616 | *it++ = static_cast<char_type>('0'); |
1617 | *it++ = static_cast<char_type>('x'); |
1618 | it = format_uint<4, char_type>(it, value, num_digits); |
1619 | } |
1620 | }; |
1621 | |
1622 | public: |
1623 | explicit basic_writer(Range out, locale_ref loc = locale_ref()) |
1624 | : out_(out.begin()), locale_(loc) {} |
1625 | |
1626 | iterator out() const { return out_; } |
1627 | |
1628 | // Writes a value in the format |
1629 | // <left-padding><value><right-padding> |
1630 | // where <value> is written by f(it). |
1631 | template <typename F> void write_padded(const format_specs& specs, F&& f) { |
1632 | // User-perceived width (in code points). |
1633 | unsigned width = to_unsigned(specs.width); |
1634 | size_t size = f.size(); // The number of code units. |
1635 | size_t num_code_points = width != 0 ? f.width() : size; |
1636 | if (width <= num_code_points) return f(reserve(size)); |
1637 | auto&& it = reserve(width + (size - num_code_points)); |
1638 | char_type fill = specs.fill[0]; |
1639 | std::size_t padding = width - num_code_points; |
1640 | if (specs.align == align::right) { |
1641 | it = std::fill_n(it, padding, fill); |
1642 | f(it); |
1643 | } else if (specs.align == align::center) { |
1644 | std::size_t left_padding = padding / 2; |
1645 | it = std::fill_n(it, left_padding, fill); |
1646 | f(it); |
1647 | it = std::fill_n(it, padding - left_padding, fill); |
1648 | } else { |
1649 | f(it); |
1650 | it = std::fill_n(it, padding, fill); |
1651 | } |
1652 | } |
1653 | |
1654 | void write(int value) { write_decimal(value); } |
1655 | void write(long value) { write_decimal(value); } |
1656 | void write(long long value) { write_decimal(value); } |
1657 | |
1658 | void write(unsigned value) { write_decimal(value); } |
1659 | void write(unsigned long value) { write_decimal(value); } |
1660 | void write(unsigned long long value) { write_decimal(value); } |
1661 | |
1662 | #if FMT_USE_INT128 |
1663 | void write(int128_t value) { write_decimal(value); } |
1664 | void write(uint128_t value) { write_decimal(value); } |
1665 | #endif |
1666 | |
1667 | template <typename T, typename Spec> |
1668 | void write_int(T value, const Spec& spec) { |
1669 | handle_int_type_spec(spec.type, int_writer<T, Spec>(*this, value, spec)); |
1670 | } |
1671 | |
1672 | template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> |
1673 | void write(T value, format_specs specs = {}) { |
1674 | float_specs fspecs = parse_float_type_spec(specs); |
1675 | fspecs.sign = specs.sign; |
1676 | if (std::signbit(value)) { // value < 0 is false for NaN so use signbit. |
1677 | fspecs.sign = sign::minus; |
1678 | value = -value; |
1679 | } else if (fspecs.sign == sign::minus) { |
1680 | fspecs.sign = sign::none; |
1681 | } |
1682 | |
1683 | if (!std::isfinite(value)) { |
1684 | auto str = std::isinf(value) ? (fspecs.upper ? "INF" : "inf" ) |
1685 | : (fspecs.upper ? "NAN" : "nan" ); |
1686 | return write_padded(specs, nonfinite_writer<char_type>{fspecs.sign, str}); |
1687 | } |
1688 | |
1689 | if (specs.align == align::none) { |
1690 | specs.align = align::right; |
1691 | } else if (specs.align == align::numeric) { |
1692 | if (fspecs.sign) { |
1693 | auto&& it = reserve(1); |
1694 | *it++ = static_cast<char_type>(data::signs[fspecs.sign]); |
1695 | fspecs.sign = sign::none; |
1696 | if (specs.width != 0) --specs.width; |
1697 | } |
1698 | specs.align = align::right; |
1699 | } |
1700 | |
1701 | memory_buffer buffer; |
1702 | if (fspecs.format == float_format::hex) { |
1703 | if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]); |
1704 | snprintf_float(promote_float(value), specs.precision, fspecs, buffer); |
1705 | write_padded(specs, str_writer<char>{buffer.data(), buffer.size()}); |
1706 | return; |
1707 | } |
1708 | int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; |
1709 | if (fspecs.format == float_format::exp) ++precision; |
1710 | if (const_check(std::is_same<T, float>())) fspecs.binary32 = true; |
1711 | fspecs.use_grisu = use_grisu<T>(); |
1712 | if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) value *= 100; |
1713 | int exp = format_float(promote_float(value), precision, fspecs, buffer); |
1714 | if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) { |
1715 | buffer.push_back('%'); |
1716 | --exp; // Adjust decimal place position. |
1717 | } |
1718 | fspecs.precision = precision; |
1719 | char_type point = fspecs.locale ? decimal_point<char_type>(locale_) |
1720 | : static_cast<char_type>('.'); |
1721 | write_padded(specs, float_writer<char_type>(buffer.data(), |
1722 | static_cast<int>(buffer.size()), |
1723 | exp, fspecs, point)); |
1724 | } |
1725 | |
1726 | void write(char value) { |
1727 | auto&& it = reserve(1); |
1728 | *it++ = value; |
1729 | } |
1730 | |
1731 | template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char_type>::value)> |
1732 | void write(Char value) { |
1733 | auto&& it = reserve(1); |
1734 | *it++ = value; |
1735 | } |
1736 | |
1737 | void write(string_view value) { |
1738 | auto&& it = reserve(value.size()); |
1739 | it = copy_str<char_type>(value.begin(), value.end(), it); |
1740 | } |
1741 | void write(wstring_view value) { |
1742 | static_assert(std::is_same<char_type, wchar_t>::value, "" ); |
1743 | auto&& it = reserve(value.size()); |
1744 | it = std::copy(value.begin(), value.end(), it); |
1745 | } |
1746 | |
1747 | template <typename Char> |
1748 | void write(const Char* s, std::size_t size, const format_specs& specs) { |
1749 | write_padded(specs, str_writer<Char>{s, size}); |
1750 | } |
1751 | |
1752 | template <typename Char> |
1753 | void write(basic_string_view<Char> s, const format_specs& specs = {}) { |
1754 | const Char* data = s.data(); |
1755 | std::size_t size = s.size(); |
1756 | if (specs.precision >= 0 && to_unsigned(specs.precision) < size) |
1757 | size = code_point_index(s, to_unsigned(specs.precision)); |
1758 | write(data, size, specs); |
1759 | } |
1760 | |
1761 | template <typename UIntPtr> |
1762 | void write_pointer(UIntPtr value, const format_specs* specs) { |
1763 | int num_digits = count_digits<4>(value); |
1764 | auto pw = pointer_writer<UIntPtr>{value, num_digits}; |
1765 | if (!specs) return pw(reserve(to_unsigned(num_digits) + 2)); |
1766 | format_specs specs_copy = *specs; |
1767 | if (specs_copy.align == align::none) specs_copy.align = align::right; |
1768 | write_padded(specs_copy, pw); |
1769 | } |
1770 | }; |
1771 | |
1772 | using writer = basic_writer<buffer_range<char>>; |
1773 | |
1774 | template <typename T> struct is_integral : std::is_integral<T> {}; |
1775 | template <> struct is_integral<int128_t> : std::true_type {}; |
1776 | template <> struct is_integral<uint128_t> : std::true_type {}; |
1777 | |
1778 | template <typename Range, typename ErrorHandler = internal::error_handler> |
1779 | class arg_formatter_base { |
1780 | public: |
1781 | using char_type = typename Range::value_type; |
1782 | using iterator = typename Range::iterator; |
1783 | using format_specs = basic_format_specs<char_type>; |
1784 | |
1785 | private: |
1786 | using writer_type = basic_writer<Range>; |
1787 | writer_type writer_; |
1788 | format_specs* specs_; |
1789 | |
1790 | struct char_writer { |
1791 | char_type value; |
1792 | |
1793 | size_t size() const { return 1; } |
1794 | size_t width() const { return 1; } |
1795 | |
1796 | template <typename It> void operator()(It&& it) const { *it++ = value; } |
1797 | }; |
1798 | |
1799 | void write_char(char_type value) { |
1800 | if (specs_) |
1801 | writer_.write_padded(*specs_, char_writer{value}); |
1802 | else |
1803 | writer_.write(value); |
1804 | } |
1805 | |
1806 | void write_pointer(const void* p) { |
1807 | writer_.write_pointer(internal::to_uintptr(p), specs_); |
1808 | } |
1809 | |
1810 | protected: |
1811 | writer_type& writer() { return writer_; } |
1812 | FMT_DEPRECATED format_specs* spec() { return specs_; } |
1813 | format_specs* specs() { return specs_; } |
1814 | iterator out() { return writer_.out(); } |
1815 | |
1816 | void write(bool value) { |
1817 | string_view sv(value ? "true" : "false" ); |
1818 | specs_ ? writer_.write(sv, *specs_) : writer_.write(sv); |
1819 | } |
1820 | |
1821 | void write(const char_type* value) { |
1822 | if (!value) { |
1823 | FMT_THROW(format_error("string pointer is null" )); |
1824 | } else { |
1825 | auto length = std::char_traits<char_type>::length(value); |
1826 | basic_string_view<char_type> sv(value, length); |
1827 | specs_ ? writer_.write(sv, *specs_) : writer_.write(sv); |
1828 | } |
1829 | } |
1830 | |
1831 | public: |
1832 | arg_formatter_base(Range r, format_specs* s, locale_ref loc) |
1833 | : writer_(r, loc), specs_(s) {} |
1834 | |
1835 | iterator operator()(monostate) { |
1836 | FMT_ASSERT(false, "invalid argument type" ); |
1837 | return out(); |
1838 | } |
1839 | |
1840 | template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> |
1841 | iterator operator()(T value) { |
1842 | if (specs_) |
1843 | writer_.write_int(value, *specs_); |
1844 | else |
1845 | writer_.write(value); |
1846 | return out(); |
1847 | } |
1848 | |
1849 | iterator operator()(char_type value) { |
1850 | internal::handle_char_specs( |
1851 | specs_, char_spec_handler(*this, static_cast<char_type>(value))); |
1852 | return out(); |
1853 | } |
1854 | |
1855 | iterator operator()(bool value) { |
1856 | if (specs_ && specs_->type) return (*this)(value ? 1 : 0); |
1857 | write(value != 0); |
1858 | return out(); |
1859 | } |
1860 | |
1861 | template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> |
1862 | iterator operator()(T value) { |
1863 | writer_.write(value, specs_ ? *specs_ : format_specs()); |
1864 | return out(); |
1865 | } |
1866 | |
1867 | struct char_spec_handler : ErrorHandler { |
1868 | arg_formatter_base& formatter; |
1869 | char_type value; |
1870 | |
1871 | char_spec_handler(arg_formatter_base& f, char_type val) |
1872 | : formatter(f), value(val) {} |
1873 | |
1874 | void on_int() { |
1875 | if (formatter.specs_) |
1876 | formatter.writer_.write_int(value, *formatter.specs_); |
1877 | else |
1878 | formatter.writer_.write(value); |
1879 | } |
1880 | void on_char() { formatter.write_char(value); } |
1881 | }; |
1882 | |
1883 | struct cstring_spec_handler : internal::error_handler { |
1884 | arg_formatter_base& formatter; |
1885 | const char_type* value; |
1886 | |
1887 | cstring_spec_handler(arg_formatter_base& f, const char_type* val) |
1888 | : formatter(f), value(val) {} |
1889 | |
1890 | void on_string() { formatter.write(value); } |
1891 | void on_pointer() { formatter.write_pointer(value); } |
1892 | }; |
1893 | |
1894 | iterator operator()(const char_type* value) { |
1895 | if (!specs_) return write(value), out(); |
1896 | internal::handle_cstring_type_spec(specs_->type, |
1897 | cstring_spec_handler(*this, value)); |
1898 | return out(); |
1899 | } |
1900 | |
1901 | iterator operator()(basic_string_view<char_type> value) { |
1902 | if (specs_) { |
1903 | internal::check_string_type_spec(specs_->type, internal::error_handler()); |
1904 | writer_.write(value, *specs_); |
1905 | } else { |
1906 | writer_.write(value); |
1907 | } |
1908 | return out(); |
1909 | } |
1910 | |
1911 | iterator operator()(const void* value) { |
1912 | if (specs_) |
1913 | check_pointer_type_spec(specs_->type, internal::error_handler()); |
1914 | write_pointer(value); |
1915 | return out(); |
1916 | } |
1917 | }; |
1918 | |
1919 | template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) { |
1920 | return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; |
1921 | } |
1922 | |
1923 | // Parses the range [begin, end) as an unsigned integer. This function assumes |
1924 | // that the range is non-empty and the first character is a digit. |
1925 | template <typename Char, typename ErrorHandler> |
1926 | FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end, |
1927 | ErrorHandler&& eh) { |
1928 | FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "" ); |
1929 | if (*begin == '0') { |
1930 | ++begin; |
1931 | return 0; |
1932 | } |
1933 | unsigned value = 0; |
1934 | // Convert to unsigned to prevent a warning. |
1935 | constexpr unsigned max_int = max_value<int>(); |
1936 | unsigned big = max_int / 10; |
1937 | do { |
1938 | // Check for overflow. |
1939 | if (value > big) { |
1940 | value = max_int + 1; |
1941 | break; |
1942 | } |
1943 | value = value * 10 + unsigned(*begin - '0'); |
1944 | ++begin; |
1945 | } while (begin != end && '0' <= *begin && *begin <= '9'); |
1946 | if (value > max_int) eh.on_error("number is too big" ); |
1947 | return static_cast<int>(value); |
1948 | } |
1949 | |
1950 | template <typename Context> class custom_formatter { |
1951 | private: |
1952 | using char_type = typename Context::char_type; |
1953 | |
1954 | basic_format_parse_context<char_type>& parse_ctx_; |
1955 | Context& ctx_; |
1956 | |
1957 | public: |
1958 | explicit custom_formatter(basic_format_parse_context<char_type>& parse_ctx, |
1959 | Context& ctx) |
1960 | : parse_ctx_(parse_ctx), ctx_(ctx) {} |
1961 | |
1962 | bool operator()(typename basic_format_arg<Context>::handle h) const { |
1963 | h.format(parse_ctx_, ctx_); |
1964 | return true; |
1965 | } |
1966 | |
1967 | template <typename T> bool operator()(T) const { return false; } |
1968 | }; |
1969 | |
1970 | template <typename T> |
1971 | using is_integer = |
1972 | bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value && |
1973 | !std::is_same<T, char>::value && |
1974 | !std::is_same<T, wchar_t>::value>; |
1975 | |
1976 | template <typename ErrorHandler> class width_checker { |
1977 | public: |
1978 | explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} |
1979 | |
1980 | template <typename T, FMT_ENABLE_IF(is_integer<T>::value)> |
1981 | FMT_CONSTEXPR unsigned long long operator()(T value) { |
1982 | if (is_negative(value)) handler_.on_error("negative width" ); |
1983 | return static_cast<unsigned long long>(value); |
1984 | } |
1985 | |
1986 | template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)> |
1987 | FMT_CONSTEXPR unsigned long long operator()(T) { |
1988 | handler_.on_error("width is not integer" ); |
1989 | return 0; |
1990 | } |
1991 | |
1992 | private: |
1993 | ErrorHandler& handler_; |
1994 | }; |
1995 | |
1996 | template <typename ErrorHandler> class precision_checker { |
1997 | public: |
1998 | explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} |
1999 | |
2000 | template <typename T, FMT_ENABLE_IF(is_integer<T>::value)> |
2001 | FMT_CONSTEXPR unsigned long long operator()(T value) { |
2002 | if (is_negative(value)) handler_.on_error("negative precision" ); |
2003 | return static_cast<unsigned long long>(value); |
2004 | } |
2005 | |
2006 | template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)> |
2007 | FMT_CONSTEXPR unsigned long long operator()(T) { |
2008 | handler_.on_error("precision is not integer" ); |
2009 | return 0; |
2010 | } |
2011 | |
2012 | private: |
2013 | ErrorHandler& handler_; |
2014 | }; |
2015 | |
2016 | // A format specifier handler that sets fields in basic_format_specs. |
2017 | template <typename Char> class specs_setter { |
2018 | public: |
2019 | explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs) |
2020 | : specs_(specs) {} |
2021 | |
2022 | FMT_CONSTEXPR specs_setter(const specs_setter& other) |
2023 | : specs_(other.specs_) {} |
2024 | |
2025 | FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; } |
2026 | FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill[0] = fill; } |
2027 | FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; } |
2028 | FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; } |
2029 | FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; } |
2030 | FMT_CONSTEXPR void on_hash() { specs_.alt = true; } |
2031 | |
2032 | FMT_CONSTEXPR void on_zero() { |
2033 | specs_.align = align::numeric; |
2034 | specs_.fill[0] = Char('0'); |
2035 | } |
2036 | |
2037 | FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } |
2038 | FMT_CONSTEXPR void on_precision(int precision) { |
2039 | specs_.precision = precision; |
2040 | } |
2041 | FMT_CONSTEXPR void end_precision() {} |
2042 | |
2043 | FMT_CONSTEXPR void on_type(Char type) { |
2044 | specs_.type = static_cast<char>(type); |
2045 | } |
2046 | |
2047 | protected: |
2048 | basic_format_specs<Char>& specs_; |
2049 | }; |
2050 | |
2051 | template <typename ErrorHandler> class numeric_specs_checker { |
2052 | public: |
2053 | FMT_CONSTEXPR numeric_specs_checker(ErrorHandler& eh, internal::type arg_type) |
2054 | : error_handler_(eh), arg_type_(arg_type) {} |
2055 | |
2056 | FMT_CONSTEXPR void require_numeric_argument() { |
2057 | if (!is_arithmetic_type(arg_type_)) |
2058 | error_handler_.on_error("format specifier requires numeric argument" ); |
2059 | } |
2060 | |
2061 | FMT_CONSTEXPR void check_sign() { |
2062 | require_numeric_argument(); |
2063 | if (is_integral_type(arg_type_) && arg_type_ != int_type && |
2064 | arg_type_ != long_long_type && arg_type_ != internal::char_type) { |
2065 | error_handler_.on_error("format specifier requires signed argument" ); |
2066 | } |
2067 | } |
2068 | |
2069 | FMT_CONSTEXPR void check_precision() { |
2070 | if (is_integral_type(arg_type_) || arg_type_ == internal::pointer_type) |
2071 | error_handler_.on_error("precision not allowed for this argument type" ); |
2072 | } |
2073 | |
2074 | private: |
2075 | ErrorHandler& error_handler_; |
2076 | internal::type arg_type_; |
2077 | }; |
2078 | |
2079 | // A format specifier handler that checks if specifiers are consistent with the |
2080 | // argument type. |
2081 | template <typename Handler> class specs_checker : public Handler { |
2082 | public: |
2083 | FMT_CONSTEXPR specs_checker(const Handler& handler, internal::type arg_type) |
2084 | : Handler(handler), checker_(*this, arg_type) {} |
2085 | |
2086 | FMT_CONSTEXPR specs_checker(const specs_checker& other) |
2087 | : Handler(other), checker_(*this, other.arg_type_) {} |
2088 | |
2089 | FMT_CONSTEXPR void on_align(align_t align) { |
2090 | if (align == align::numeric) checker_.require_numeric_argument(); |
2091 | Handler::on_align(align); |
2092 | } |
2093 | |
2094 | FMT_CONSTEXPR void on_plus() { |
2095 | checker_.check_sign(); |
2096 | Handler::on_plus(); |
2097 | } |
2098 | |
2099 | FMT_CONSTEXPR void on_minus() { |
2100 | checker_.check_sign(); |
2101 | Handler::on_minus(); |
2102 | } |
2103 | |
2104 | FMT_CONSTEXPR void on_space() { |
2105 | checker_.check_sign(); |
2106 | Handler::on_space(); |
2107 | } |
2108 | |
2109 | FMT_CONSTEXPR void on_hash() { |
2110 | checker_.require_numeric_argument(); |
2111 | Handler::on_hash(); |
2112 | } |
2113 | |
2114 | FMT_CONSTEXPR void on_zero() { |
2115 | checker_.require_numeric_argument(); |
2116 | Handler::on_zero(); |
2117 | } |
2118 | |
2119 | FMT_CONSTEXPR void end_precision() { checker_.check_precision(); } |
2120 | |
2121 | private: |
2122 | numeric_specs_checker<Handler> checker_; |
2123 | }; |
2124 | |
2125 | template <template <typename> class Handler, typename FormatArg, |
2126 | typename ErrorHandler> |
2127 | FMT_CONSTEXPR int get_dynamic_spec(FormatArg arg, ErrorHandler eh) { |
2128 | unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg); |
2129 | if (value > to_unsigned(max_value<int>())) eh.on_error("number is too big" ); |
2130 | return static_cast<int>(value); |
2131 | } |
2132 | |
2133 | struct auto_id {}; |
2134 | |
2135 | template <typename Context> |
2136 | FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, int id) { |
2137 | auto arg = ctx.arg(id); |
2138 | if (!arg) ctx.on_error("argument index out of range" ); |
2139 | return arg; |
2140 | } |
2141 | |
2142 | // The standard format specifier handler with checking. |
2143 | template <typename ParseContext, typename Context> |
2144 | class specs_handler : public specs_setter<typename Context::char_type> { |
2145 | public: |
2146 | using char_type = typename Context::char_type; |
2147 | |
2148 | FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs, |
2149 | ParseContext& parse_ctx, Context& ctx) |
2150 | : specs_setter<char_type>(specs), |
2151 | parse_context_(parse_ctx), |
2152 | context_(ctx) {} |
2153 | |
2154 | template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { |
2155 | this->specs_.width = get_dynamic_spec<width_checker>( |
2156 | get_arg(arg_id), context_.error_handler()); |
2157 | } |
2158 | |
2159 | template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { |
2160 | this->specs_.precision = get_dynamic_spec<precision_checker>( |
2161 | get_arg(arg_id), context_.error_handler()); |
2162 | } |
2163 | |
2164 | void on_error(const char* message) { context_.on_error(message); } |
2165 | |
2166 | private: |
2167 | // This is only needed for compatibility with gcc 4.4. |
2168 | using format_arg = typename Context::format_arg; |
2169 | |
2170 | FMT_CONSTEXPR format_arg get_arg(auto_id) { |
2171 | return internal::get_arg(context_, parse_context_.next_arg_id()); |
2172 | } |
2173 | |
2174 | FMT_CONSTEXPR format_arg get_arg(int arg_id) { |
2175 | parse_context_.check_arg_id(arg_id); |
2176 | return internal::get_arg(context_, arg_id); |
2177 | } |
2178 | |
2179 | FMT_CONSTEXPR format_arg get_arg(basic_string_view<char_type> arg_id) { |
2180 | parse_context_.check_arg_id(arg_id); |
2181 | return context_.arg(arg_id); |
2182 | } |
2183 | |
2184 | ParseContext& parse_context_; |
2185 | Context& context_; |
2186 | }; |
2187 | |
2188 | enum class arg_id_kind { none, index, name }; |
2189 | |
2190 | // An argument reference. |
2191 | template <typename Char> struct arg_ref { |
2192 | FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} |
2193 | FMT_CONSTEXPR explicit arg_ref(int index) |
2194 | : kind(arg_id_kind::index), val(index) {} |
2195 | FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name) |
2196 | : kind(arg_id_kind::name), val(name) {} |
2197 | |
2198 | FMT_CONSTEXPR arg_ref& operator=(int idx) { |
2199 | kind = arg_id_kind::index; |
2200 | val.index = idx; |
2201 | return *this; |
2202 | } |
2203 | |
2204 | arg_id_kind kind; |
2205 | union value { |
2206 | FMT_CONSTEXPR value(int id = 0) : index{id} {} |
2207 | FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {} |
2208 | |
2209 | int index; |
2210 | basic_string_view<Char> name; |
2211 | } val; |
2212 | }; |
2213 | |
2214 | // Format specifiers with width and precision resolved at formatting rather |
2215 | // than parsing time to allow re-using the same parsed specifiers with |
2216 | // different sets of arguments (precompilation of format strings). |
2217 | template <typename Char> |
2218 | struct dynamic_format_specs : basic_format_specs<Char> { |
2219 | arg_ref<Char> width_ref; |
2220 | arg_ref<Char> precision_ref; |
2221 | }; |
2222 | |
2223 | // Format spec handler that saves references to arguments representing dynamic |
2224 | // width and precision to be resolved at formatting time. |
2225 | template <typename ParseContext> |
2226 | class dynamic_specs_handler |
2227 | : public specs_setter<typename ParseContext::char_type> { |
2228 | public: |
2229 | using char_type = typename ParseContext::char_type; |
2230 | |
2231 | FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs, |
2232 | ParseContext& ctx) |
2233 | : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {} |
2234 | |
2235 | FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other) |
2236 | : specs_setter<char_type>(other), |
2237 | specs_(other.specs_), |
2238 | context_(other.context_) {} |
2239 | |
2240 | template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { |
2241 | specs_.width_ref = make_arg_ref(arg_id); |
2242 | } |
2243 | |
2244 | template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { |
2245 | specs_.precision_ref = make_arg_ref(arg_id); |
2246 | } |
2247 | |
2248 | FMT_CONSTEXPR void on_error(const char* message) { |
2249 | context_.on_error(message); |
2250 | } |
2251 | |
2252 | private: |
2253 | using arg_ref_type = arg_ref<char_type>; |
2254 | |
2255 | FMT_CONSTEXPR arg_ref_type make_arg_ref(int arg_id) { |
2256 | context_.check_arg_id(arg_id); |
2257 | return arg_ref_type(arg_id); |
2258 | } |
2259 | |
2260 | FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) { |
2261 | return arg_ref_type(context_.next_arg_id()); |
2262 | } |
2263 | |
2264 | FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<char_type> arg_id) { |
2265 | context_.check_arg_id(arg_id); |
2266 | basic_string_view<char_type> format_str( |
2267 | context_.begin(), to_unsigned(context_.end() - context_.begin())); |
2268 | return arg_ref_type(arg_id); |
2269 | } |
2270 | |
2271 | dynamic_format_specs<char_type>& specs_; |
2272 | ParseContext& context_; |
2273 | }; |
2274 | |
2275 | template <typename Char, typename IDHandler> |
2276 | FMT_CONSTEXPR const Char* parse_arg_id(const Char* begin, const Char* end, |
2277 | IDHandler&& handler) { |
2278 | FMT_ASSERT(begin != end, "" ); |
2279 | Char c = *begin; |
2280 | if (c == '}' || c == ':') { |
2281 | handler(); |
2282 | return begin; |
2283 | } |
2284 | if (c >= '0' && c <= '9') { |
2285 | int index = parse_nonnegative_int(begin, end, handler); |
2286 | if (begin == end || (*begin != '}' && *begin != ':')) |
2287 | handler.on_error("invalid format string" ); |
2288 | else |
2289 | handler(index); |
2290 | return begin; |
2291 | } |
2292 | if (!is_name_start(c)) { |
2293 | handler.on_error("invalid format string" ); |
2294 | return begin; |
2295 | } |
2296 | auto it = begin; |
2297 | do { |
2298 | ++it; |
2299 | } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); |
2300 | handler(basic_string_view<Char>(begin, to_unsigned(it - begin))); |
2301 | return it; |
2302 | } |
2303 | |
2304 | // Adapts SpecHandler to IDHandler API for dynamic width. |
2305 | template <typename SpecHandler, typename Char> struct width_adapter { |
2306 | explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {} |
2307 | |
2308 | FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); } |
2309 | FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); } |
2310 | FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { |
2311 | handler.on_dynamic_width(id); |
2312 | } |
2313 | |
2314 | FMT_CONSTEXPR void on_error(const char* message) { |
2315 | handler.on_error(message); |
2316 | } |
2317 | |
2318 | SpecHandler& handler; |
2319 | }; |
2320 | |
2321 | // Adapts SpecHandler to IDHandler API for dynamic precision. |
2322 | template <typename SpecHandler, typename Char> struct precision_adapter { |
2323 | explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {} |
2324 | |
2325 | FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); } |
2326 | FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); } |
2327 | FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { |
2328 | handler.on_dynamic_precision(id); |
2329 | } |
2330 | |
2331 | FMT_CONSTEXPR void on_error(const char* message) { |
2332 | handler.on_error(message); |
2333 | } |
2334 | |
2335 | SpecHandler& handler; |
2336 | }; |
2337 | |
2338 | // Parses fill and alignment. |
2339 | template <typename Char, typename Handler> |
2340 | FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end, |
2341 | Handler&& handler) { |
2342 | FMT_ASSERT(begin != end, "" ); |
2343 | auto align = align::none; |
2344 | int i = 0; |
2345 | if (begin + 1 != end) ++i; |
2346 | do { |
2347 | switch (static_cast<char>(begin[i])) { |
2348 | case '<': |
2349 | align = align::left; |
2350 | break; |
2351 | case '>': |
2352 | align = align::right; |
2353 | break; |
2354 | #if FMT_NUMERIC_ALIGN |
2355 | case '=': |
2356 | align = align::numeric; |
2357 | break; |
2358 | #endif |
2359 | case '^': |
2360 | align = align::center; |
2361 | break; |
2362 | } |
2363 | if (align != align::none) { |
2364 | if (i > 0) { |
2365 | auto c = *begin; |
2366 | if (c == '{') |
2367 | return handler.on_error("invalid fill character '{'" ), begin; |
2368 | begin += 2; |
2369 | handler.on_fill(c); |
2370 | } else |
2371 | ++begin; |
2372 | handler.on_align(align); |
2373 | break; |
2374 | } |
2375 | } while (i-- > 0); |
2376 | return begin; |
2377 | } |
2378 | |
2379 | template <typename Char, typename Handler> |
2380 | FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end, |
2381 | Handler&& handler) { |
2382 | FMT_ASSERT(begin != end, "" ); |
2383 | if ('0' <= *begin && *begin <= '9') { |
2384 | handler.on_width(parse_nonnegative_int(begin, end, handler)); |
2385 | } else if (*begin == '{') { |
2386 | ++begin; |
2387 | if (begin != end) |
2388 | begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler)); |
2389 | if (begin == end || *begin != '}') |
2390 | return handler.on_error("invalid format string" ), begin; |
2391 | ++begin; |
2392 | } |
2393 | return begin; |
2394 | } |
2395 | |
2396 | template <typename Char, typename Handler> |
2397 | FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end, |
2398 | Handler&& handler) { |
2399 | ++begin; |
2400 | auto c = begin != end ? *begin : Char(); |
2401 | if ('0' <= c && c <= '9') { |
2402 | handler.on_precision(parse_nonnegative_int(begin, end, handler)); |
2403 | } else if (c == '{') { |
2404 | ++begin; |
2405 | if (begin != end) { |
2406 | begin = |
2407 | parse_arg_id(begin, end, precision_adapter<Handler, Char>(handler)); |
2408 | } |
2409 | if (begin == end || *begin++ != '}') |
2410 | return handler.on_error("invalid format string" ), begin; |
2411 | } else { |
2412 | return handler.on_error("missing precision specifier" ), begin; |
2413 | } |
2414 | handler.end_precision(); |
2415 | return begin; |
2416 | } |
2417 | |
2418 | // Parses standard format specifiers and sends notifications about parsed |
2419 | // components to handler. |
2420 | template <typename Char, typename SpecHandler> |
2421 | FMT_CONSTEXPR const Char* parse_format_specs(const Char* begin, const Char* end, |
2422 | SpecHandler&& handler) { |
2423 | if (begin == end || *begin == '}') return begin; |
2424 | |
2425 | begin = parse_align(begin, end, handler); |
2426 | if (begin == end) return begin; |
2427 | |
2428 | // Parse sign. |
2429 | switch (static_cast<char>(*begin)) { |
2430 | case '+': |
2431 | handler.on_plus(); |
2432 | ++begin; |
2433 | break; |
2434 | case '-': |
2435 | handler.on_minus(); |
2436 | ++begin; |
2437 | break; |
2438 | case ' ': |
2439 | handler.on_space(); |
2440 | ++begin; |
2441 | break; |
2442 | } |
2443 | if (begin == end) return begin; |
2444 | |
2445 | if (*begin == '#') { |
2446 | handler.on_hash(); |
2447 | if (++begin == end) return begin; |
2448 | } |
2449 | |
2450 | // Parse zero flag. |
2451 | if (*begin == '0') { |
2452 | handler.on_zero(); |
2453 | if (++begin == end) return begin; |
2454 | } |
2455 | |
2456 | begin = parse_width(begin, end, handler); |
2457 | if (begin == end) return begin; |
2458 | |
2459 | // Parse precision. |
2460 | if (*begin == '.') { |
2461 | begin = parse_precision(begin, end, handler); |
2462 | } |
2463 | |
2464 | // Parse type. |
2465 | if (begin != end && *begin != '}') handler.on_type(*begin++); |
2466 | return begin; |
2467 | } |
2468 | |
2469 | // Return the result via the out param to workaround gcc bug 77539. |
2470 | template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*> |
2471 | FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr& out) { |
2472 | for (out = first; out != last; ++out) { |
2473 | if (*out == value) return true; |
2474 | } |
2475 | return false; |
2476 | } |
2477 | |
2478 | template <> |
2479 | inline bool find<false, char>(const char* first, const char* last, char value, |
2480 | const char*& out) { |
2481 | out = static_cast<const char*>( |
2482 | std::memchr(first, value, internal::to_unsigned(last - first))); |
2483 | return out != nullptr; |
2484 | } |
2485 | |
2486 | template <typename Handler, typename Char> struct id_adapter { |
2487 | FMT_CONSTEXPR void operator()() { handler.on_arg_id(); } |
2488 | FMT_CONSTEXPR void operator()(int id) { handler.on_arg_id(id); } |
2489 | FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { |
2490 | handler.on_arg_id(id); |
2491 | } |
2492 | FMT_CONSTEXPR void on_error(const char* message) { |
2493 | handler.on_error(message); |
2494 | } |
2495 | Handler& handler; |
2496 | }; |
2497 | |
2498 | template <bool IS_CONSTEXPR, typename Char, typename Handler> |
2499 | FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str, |
2500 | Handler&& handler) { |
2501 | struct pfs_writer { |
2502 | FMT_CONSTEXPR void operator()(const Char* begin, const Char* end) { |
2503 | if (begin == end) return; |
2504 | for (;;) { |
2505 | const Char* p = nullptr; |
2506 | if (!find<IS_CONSTEXPR>(begin, end, '}', p)) |
2507 | return handler_.on_text(begin, end); |
2508 | ++p; |
2509 | if (p == end || *p != '}') |
2510 | return handler_.on_error("unmatched '}' in format string" ); |
2511 | handler_.on_text(begin, p); |
2512 | begin = p + 1; |
2513 | } |
2514 | } |
2515 | Handler& handler_; |
2516 | } write{handler}; |
2517 | auto begin = format_str.data(); |
2518 | auto end = begin + format_str.size(); |
2519 | while (begin != end) { |
2520 | // Doing two passes with memchr (one for '{' and another for '}') is up to |
2521 | // 2.5x faster than the naive one-pass implementation on big format strings. |
2522 | const Char* p = begin; |
2523 | if (*begin != '{' && !find<IS_CONSTEXPR>(begin, end, '{', p)) |
2524 | return write(begin, end); |
2525 | write(begin, p); |
2526 | ++p; |
2527 | if (p == end) return handler.on_error("invalid format string" ); |
2528 | if (static_cast<char>(*p) == '}') { |
2529 | handler.on_arg_id(); |
2530 | handler.on_replacement_field(p); |
2531 | } else if (*p == '{') { |
2532 | handler.on_text(p, p + 1); |
2533 | } else { |
2534 | p = parse_arg_id(p, end, id_adapter<Handler, Char>{handler}); |
2535 | Char c = p != end ? *p : Char(); |
2536 | if (c == '}') { |
2537 | handler.on_replacement_field(p); |
2538 | } else if (c == ':') { |
2539 | p = handler.on_format_specs(p + 1, end); |
2540 | if (p == end || *p != '}') |
2541 | return handler.on_error("unknown format specifier" ); |
2542 | } else { |
2543 | return handler.on_error("missing '}' in format string" ); |
2544 | } |
2545 | } |
2546 | begin = p + 1; |
2547 | } |
2548 | } |
2549 | |
2550 | template <typename T, typename ParseContext> |
2551 | FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs( |
2552 | ParseContext& ctx) { |
2553 | using char_type = typename ParseContext::char_type; |
2554 | using context = buffer_context<char_type>; |
2555 | using mapped_type = |
2556 | conditional_t<internal::mapped_type_constant<T, context>::value != |
2557 | internal::custom_type, |
2558 | decltype(arg_mapper<context>().map(std::declval<T>())), T>; |
2559 | auto f = conditional_t<has_formatter<mapped_type, context>::value, |
2560 | formatter<mapped_type, char_type>, |
2561 | internal::fallback_formatter<T, char_type>>(); |
2562 | return f.parse(ctx); |
2563 | } |
2564 | |
2565 | template <typename Char, typename ErrorHandler, typename... Args> |
2566 | class format_string_checker { |
2567 | public: |
2568 | explicit FMT_CONSTEXPR format_string_checker( |
2569 | basic_string_view<Char> format_str, ErrorHandler eh) |
2570 | : arg_id_(-1), |
2571 | context_(format_str, eh), |
2572 | parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {} |
2573 | |
2574 | FMT_CONSTEXPR void on_text(const Char*, const Char*) {} |
2575 | |
2576 | FMT_CONSTEXPR void on_arg_id() { |
2577 | arg_id_ = context_.next_arg_id(); |
2578 | check_arg_id(); |
2579 | } |
2580 | FMT_CONSTEXPR void on_arg_id(int id) { |
2581 | arg_id_ = id; |
2582 | context_.check_arg_id(id); |
2583 | check_arg_id(); |
2584 | } |
2585 | FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) { |
2586 | on_error("compile-time checks don't support named arguments" ); |
2587 | } |
2588 | |
2589 | FMT_CONSTEXPR void on_replacement_field(const Char*) {} |
2590 | |
2591 | FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, const Char*) { |
2592 | advance_to(context_, begin); |
2593 | return arg_id_ < num_args ? parse_funcs_[arg_id_](context_) : begin; |
2594 | } |
2595 | |
2596 | FMT_CONSTEXPR void on_error(const char* message) { |
2597 | context_.on_error(message); |
2598 | } |
2599 | |
2600 | private: |
2601 | using parse_context_type = basic_format_parse_context<Char, ErrorHandler>; |
2602 | enum { num_args = sizeof...(Args) }; |
2603 | |
2604 | FMT_CONSTEXPR void check_arg_id() { |
2605 | if (arg_id_ >= num_args) context_.on_error("argument index out of range" ); |
2606 | } |
2607 | |
2608 | // Format specifier parsing function. |
2609 | using parse_func = const Char* (*)(parse_context_type&); |
2610 | |
2611 | int arg_id_; |
2612 | parse_context_type context_; |
2613 | parse_func parse_funcs_[num_args > 0 ? num_args : 1]; |
2614 | }; |
2615 | |
2616 | template <typename Char, typename ErrorHandler, typename... Args> |
2617 | FMT_CONSTEXPR bool do_check_format_string(basic_string_view<Char> s, |
2618 | ErrorHandler eh = ErrorHandler()) { |
2619 | format_string_checker<Char, ErrorHandler, Args...> checker(s, eh); |
2620 | parse_format_string<true>(s, checker); |
2621 | return true; |
2622 | } |
2623 | |
2624 | template <typename... Args, typename S, |
2625 | enable_if_t<(is_compile_string<S>::value), int>> |
2626 | void check_format_string(S format_str) { |
2627 | FMT_CONSTEXPR_DECL bool invalid_format = |
2628 | internal::do_check_format_string<typename S::char_type, |
2629 | internal::error_handler, Args...>( |
2630 | to_string_view(format_str)); |
2631 | (void)invalid_format; |
2632 | } |
2633 | |
2634 | template <template <typename> class Handler, typename Context> |
2635 | void handle_dynamic_spec(int& value, arg_ref<typename Context::char_type> ref, |
2636 | Context& ctx) { |
2637 | switch (ref.kind) { |
2638 | case arg_id_kind::none: |
2639 | break; |
2640 | case arg_id_kind::index: |
2641 | value = internal::get_dynamic_spec<Handler>(ctx.arg(ref.val.index), |
2642 | ctx.error_handler()); |
2643 | break; |
2644 | case arg_id_kind::name: |
2645 | value = internal::get_dynamic_spec<Handler>(ctx.arg(ref.val.name), |
2646 | ctx.error_handler()); |
2647 | break; |
2648 | } |
2649 | } |
2650 | } // namespace internal |
2651 | |
2652 | template <typename Range> |
2653 | using basic_writer FMT_DEPRECATED_ALIAS = internal::basic_writer<Range>; |
2654 | using writer FMT_DEPRECATED_ALIAS = internal::writer; |
2655 | using wwriter FMT_DEPRECATED_ALIAS = |
2656 | internal::basic_writer<buffer_range<wchar_t>>; |
2657 | |
2658 | /** The default argument formatter. */ |
2659 | template <typename Range> |
2660 | class arg_formatter : public internal::arg_formatter_base<Range> { |
2661 | private: |
2662 | using char_type = typename Range::value_type; |
2663 | using base = internal::arg_formatter_base<Range>; |
2664 | using context_type = basic_format_context<typename base::iterator, char_type>; |
2665 | |
2666 | context_type& ctx_; |
2667 | basic_format_parse_context<char_type>* parse_ctx_; |
2668 | |
2669 | public: |
2670 | using range = Range; |
2671 | using iterator = typename base::iterator; |
2672 | using format_specs = typename base::format_specs; |
2673 | |
2674 | /** |
2675 | \rst |
2676 | Constructs an argument formatter object. |
2677 | *ctx* is a reference to the formatting context, |
2678 | *specs* contains format specifier information for standard argument types. |
2679 | \endrst |
2680 | */ |
2681 | explicit arg_formatter( |
2682 | context_type& ctx, |
2683 | basic_format_parse_context<char_type>* parse_ctx = nullptr, |
2684 | format_specs* specs = nullptr) |
2685 | : base(Range(ctx.out()), specs, ctx.locale()), |
2686 | ctx_(ctx), |
2687 | parse_ctx_(parse_ctx) {} |
2688 | |
2689 | using base::operator(); |
2690 | |
2691 | /** Formats an argument of a user-defined type. */ |
2692 | iterator operator()(typename basic_format_arg<context_type>::handle handle) { |
2693 | handle.format(*parse_ctx_, ctx_); |
2694 | return ctx_.out(); |
2695 | } |
2696 | }; |
2697 | |
2698 | /** |
2699 | An error returned by an operating system or a language runtime, |
2700 | for example a file opening error. |
2701 | */ |
2702 | class FMT_API system_error : public std::runtime_error { |
2703 | private: |
2704 | void init(int err_code, string_view format_str, format_args args); |
2705 | |
2706 | protected: |
2707 | int error_code_; |
2708 | |
2709 | system_error() : std::runtime_error("" ), error_code_(0) {} |
2710 | |
2711 | public: |
2712 | /** |
2713 | \rst |
2714 | Constructs a :class:`fmt::system_error` object with a description |
2715 | formatted with `fmt::format_system_error`. *message* and additional |
2716 | arguments passed into the constructor are formatted similarly to |
2717 | `fmt::format`. |
2718 | |
2719 | **Example**:: |
2720 | |
2721 | // This throws a system_error with the description |
2722 | // cannot open file 'madeup': No such file or directory |
2723 | // or similar (system message may vary). |
2724 | const char *filename = "madeup"; |
2725 | std::FILE *file = std::fopen(filename, "r"); |
2726 | if (!file) |
2727 | throw fmt::system_error(errno, "cannot open file '{}'", filename); |
2728 | \endrst |
2729 | */ |
2730 | template <typename... Args> |
2731 | system_error(int error_code, string_view message, const Args&... args) |
2732 | : std::runtime_error("" ) { |
2733 | init(error_code, message, make_format_args(args...)); |
2734 | } |
2735 | system_error(const system_error&) = default; |
2736 | system_error& operator=(const system_error&) = default; |
2737 | system_error(system_error&&) = default; |
2738 | system_error& operator=(system_error&&) = default; |
2739 | ~system_error() FMT_NOEXCEPT FMT_OVERRIDE; |
2740 | |
2741 | int error_code() const { return error_code_; } |
2742 | }; |
2743 | |
2744 | /** |
2745 | \rst |
2746 | Formats an error returned by an operating system or a language runtime, |
2747 | for example a file opening error, and writes it to *out* in the following |
2748 | form: |
2749 | |
2750 | .. parsed-literal:: |
2751 | *<message>*: *<system-message>* |
2752 | |
2753 | where *<message>* is the passed message and *<system-message>* is |
2754 | the system message corresponding to the error code. |
2755 | *error_code* is a system error code as given by ``errno``. |
2756 | If *error_code* is not a valid error code such as -1, the system message |
2757 | may look like "Unknown error -1" and is platform-dependent. |
2758 | \endrst |
2759 | */ |
2760 | FMT_API void format_system_error(internal::buffer<char>& out, int error_code, |
2761 | string_view message) FMT_NOEXCEPT; |
2762 | |
2763 | // Reports a system error without throwing an exception. |
2764 | // Can be used to report errors from destructors. |
2765 | FMT_API void report_system_error(int error_code, |
2766 | string_view message) FMT_NOEXCEPT; |
2767 | |
2768 | #if FMT_USE_WINDOWS_H |
2769 | |
2770 | /** A Windows error. */ |
2771 | class windows_error : public system_error { |
2772 | private: |
2773 | FMT_API void init(int error_code, string_view format_str, format_args args); |
2774 | |
2775 | public: |
2776 | /** |
2777 | \rst |
2778 | Constructs a :class:`fmt::windows_error` object with the description |
2779 | of the form |
2780 | |
2781 | .. parsed-literal:: |
2782 | *<message>*: *<system-message>* |
2783 | |
2784 | where *<message>* is the formatted message and *<system-message>* is the |
2785 | system message corresponding to the error code. |
2786 | *error_code* is a Windows error code as given by ``GetLastError``. |
2787 | If *error_code* is not a valid error code such as -1, the system message |
2788 | will look like "error -1". |
2789 | |
2790 | **Example**:: |
2791 | |
2792 | // This throws a windows_error with the description |
2793 | // cannot open file 'madeup': The system cannot find the file specified. |
2794 | // or similar (system message may vary). |
2795 | const char *filename = "madeup"; |
2796 | LPOFSTRUCT of = LPOFSTRUCT(); |
2797 | HFILE file = OpenFile(filename, &of, OF_READ); |
2798 | if (file == HFILE_ERROR) { |
2799 | throw fmt::windows_error(GetLastError(), |
2800 | "cannot open file '{}'", filename); |
2801 | } |
2802 | \endrst |
2803 | */ |
2804 | template <typename... Args> |
2805 | windows_error(int error_code, string_view message, const Args&... args) { |
2806 | init(error_code, message, make_format_args(args...)); |
2807 | } |
2808 | }; |
2809 | |
2810 | // Reports a Windows error without throwing an exception. |
2811 | // Can be used to report errors from destructors. |
2812 | FMT_API void report_windows_error(int error_code, |
2813 | string_view message) FMT_NOEXCEPT; |
2814 | |
2815 | #endif |
2816 | |
2817 | /** Fast integer formatter. */ |
2818 | class format_int { |
2819 | private: |
2820 | // Buffer should be large enough to hold all digits (digits10 + 1), |
2821 | // a sign and a null character. |
2822 | enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 }; |
2823 | mutable char buffer_[buffer_size]; |
2824 | char* str_; |
2825 | |
2826 | // Formats value in reverse and returns a pointer to the beginning. |
2827 | char* format_decimal(unsigned long long value) { |
2828 | char* ptr = buffer_ + (buffer_size - 1); // Parens to workaround MSVC bug. |
2829 | while (value >= 100) { |
2830 | // Integer division is slow so do it for a group of two digits instead |
2831 | // of for every digit. The idea comes from the talk by Alexandrescu |
2832 | // "Three Optimization Tips for C++". See speed-test for a comparison. |
2833 | auto index = static_cast<unsigned>((value % 100) * 2); |
2834 | value /= 100; |
2835 | *--ptr = internal::data::digits[index + 1]; |
2836 | *--ptr = internal::data::digits[index]; |
2837 | } |
2838 | if (value < 10) { |
2839 | *--ptr = static_cast<char>('0' + value); |
2840 | return ptr; |
2841 | } |
2842 | auto index = static_cast<unsigned>(value * 2); |
2843 | *--ptr = internal::data::digits[index + 1]; |
2844 | *--ptr = internal::data::digits[index]; |
2845 | return ptr; |
2846 | } |
2847 | |
2848 | void format_signed(long long value) { |
2849 | auto abs_value = static_cast<unsigned long long>(value); |
2850 | bool negative = value < 0; |
2851 | if (negative) abs_value = 0 - abs_value; |
2852 | str_ = format_decimal(abs_value); |
2853 | if (negative) *--str_ = '-'; |
2854 | } |
2855 | |
2856 | public: |
2857 | explicit format_int(int value) { format_signed(value); } |
2858 | explicit format_int(long value) { format_signed(value); } |
2859 | explicit format_int(long long value) { format_signed(value); } |
2860 | explicit format_int(unsigned value) : str_(format_decimal(value)) {} |
2861 | explicit format_int(unsigned long value) : str_(format_decimal(value)) {} |
2862 | explicit format_int(unsigned long long value) : str_(format_decimal(value)) {} |
2863 | |
2864 | /** Returns the number of characters written to the output buffer. */ |
2865 | std::size_t size() const { |
2866 | return internal::to_unsigned(buffer_ - str_ + buffer_size - 1); |
2867 | } |
2868 | |
2869 | /** |
2870 | Returns a pointer to the output buffer content. No terminating null |
2871 | character is appended. |
2872 | */ |
2873 | const char* data() const { return str_; } |
2874 | |
2875 | /** |
2876 | Returns a pointer to the output buffer content with terminating null |
2877 | character appended. |
2878 | */ |
2879 | const char* c_str() const { |
2880 | buffer_[buffer_size - 1] = '\0'; |
2881 | return str_; |
2882 | } |
2883 | |
2884 | /** |
2885 | \rst |
2886 | Returns the content of the output buffer as an ``std::string``. |
2887 | \endrst |
2888 | */ |
2889 | std::string str() const { return std::string(str_, size()); } |
2890 | }; |
2891 | |
2892 | // A formatter specialization for the core types corresponding to internal::type |
2893 | // constants. |
2894 | template <typename T, typename Char> |
2895 | struct formatter<T, Char, |
2896 | enable_if_t<internal::type_constant<T, Char>::value != |
2897 | internal::custom_type>> { |
2898 | FMT_CONSTEXPR formatter() = default; |
2899 | |
2900 | // Parses format specifiers stopping either at the end of the range or at the |
2901 | // terminating '}'. |
2902 | template <typename ParseContext> |
2903 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
2904 | using handler_type = internal::dynamic_specs_handler<ParseContext>; |
2905 | auto type = internal::type_constant<T, Char>::value; |
2906 | internal::specs_checker<handler_type> handler(handler_type(specs_, ctx), |
2907 | type); |
2908 | auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); |
2909 | auto eh = ctx.error_handler(); |
2910 | switch (type) { |
2911 | case internal::none_type: |
2912 | case internal::named_arg_type: |
2913 | FMT_ASSERT(false, "invalid argument type" ); |
2914 | break; |
2915 | case internal::int_type: |
2916 | case internal::uint_type: |
2917 | case internal::long_long_type: |
2918 | case internal::ulong_long_type: |
2919 | case internal::int128_type: |
2920 | case internal::uint128_type: |
2921 | case internal::bool_type: |
2922 | handle_int_type_spec(specs_.type, |
2923 | internal::int_type_checker<decltype(eh)>(eh)); |
2924 | break; |
2925 | case internal::char_type: |
2926 | handle_char_specs( |
2927 | &specs_, internal::char_specs_checker<decltype(eh)>(specs_.type, eh)); |
2928 | break; |
2929 | case internal::float_type: |
2930 | case internal::double_type: |
2931 | case internal::long_double_type: |
2932 | internal::parse_float_type_spec(specs_, eh); |
2933 | break; |
2934 | case internal::cstring_type: |
2935 | internal::handle_cstring_type_spec( |
2936 | specs_.type, internal::cstring_type_checker<decltype(eh)>(eh)); |
2937 | break; |
2938 | case internal::string_type: |
2939 | internal::check_string_type_spec(specs_.type, eh); |
2940 | break; |
2941 | case internal::pointer_type: |
2942 | internal::check_pointer_type_spec(specs_.type, eh); |
2943 | break; |
2944 | case internal::custom_type: |
2945 | // Custom format specifiers should be checked in parse functions of |
2946 | // formatter specializations. |
2947 | break; |
2948 | } |
2949 | return it; |
2950 | } |
2951 | |
2952 | template <typename FormatContext> |
2953 | auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { |
2954 | internal::handle_dynamic_spec<internal::width_checker>( |
2955 | specs_.width, specs_.width_ref, ctx); |
2956 | internal::handle_dynamic_spec<internal::precision_checker>( |
2957 | specs_.precision, specs_.precision_ref, ctx); |
2958 | using range_type = |
2959 | internal::output_range<typename FormatContext::iterator, |
2960 | typename FormatContext::char_type>; |
2961 | return visit_format_arg(arg_formatter<range_type>(ctx, nullptr, &specs_), |
2962 | internal::make_arg<FormatContext>(val)); |
2963 | } |
2964 | |
2965 | private: |
2966 | internal::dynamic_format_specs<Char> specs_; |
2967 | }; |
2968 | |
2969 | #define FMT_FORMAT_AS(Type, Base) \ |
2970 | template <typename Char> \ |
2971 | struct formatter<Type, Char> : formatter<Base, Char> { \ |
2972 | template <typename FormatContext> \ |
2973 | auto format(const Type& val, FormatContext& ctx) -> decltype(ctx.out()) { \ |
2974 | return formatter<Base, Char>::format(val, ctx); \ |
2975 | } \ |
2976 | } |
2977 | |
2978 | FMT_FORMAT_AS(signed char, int); |
2979 | FMT_FORMAT_AS(unsigned char, unsigned); |
2980 | FMT_FORMAT_AS(short, int); |
2981 | FMT_FORMAT_AS(unsigned short, unsigned); |
2982 | FMT_FORMAT_AS(long, long long); |
2983 | FMT_FORMAT_AS(unsigned long, unsigned long long); |
2984 | FMT_FORMAT_AS(Char*, const Char*); |
2985 | FMT_FORMAT_AS(std::basic_string<Char>, basic_string_view<Char>); |
2986 | FMT_FORMAT_AS(std::nullptr_t, const void*); |
2987 | FMT_FORMAT_AS(internal::std_string_view<Char>, basic_string_view<Char>); |
2988 | |
2989 | template <typename Char> |
2990 | struct formatter<void*, Char> : formatter<const void*, Char> { |
2991 | template <typename FormatContext> |
2992 | auto format(void* val, FormatContext& ctx) -> decltype(ctx.out()) { |
2993 | return formatter<const void*, Char>::format(val, ctx); |
2994 | } |
2995 | }; |
2996 | |
2997 | template <typename Char, size_t N> |
2998 | struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> { |
2999 | template <typename FormatContext> |
3000 | auto format(const Char* val, FormatContext& ctx) -> decltype(ctx.out()) { |
3001 | return formatter<basic_string_view<Char>, Char>::format(val, ctx); |
3002 | } |
3003 | }; |
3004 | |
3005 | // A formatter for types known only at run time such as variant alternatives. |
3006 | // |
3007 | // Usage: |
3008 | // using variant = std::variant<int, std::string>; |
3009 | // template <> |
3010 | // struct formatter<variant>: dynamic_formatter<> { |
3011 | // void format(buffer &buf, const variant &v, context &ctx) { |
3012 | // visit([&](const auto &val) { format(buf, val, ctx); }, v); |
3013 | // } |
3014 | // }; |
3015 | template <typename Char = char> class dynamic_formatter { |
3016 | private: |
3017 | struct null_handler : internal::error_handler { |
3018 | void on_align(align_t) {} |
3019 | void on_plus() {} |
3020 | void on_minus() {} |
3021 | void on_space() {} |
3022 | void on_hash() {} |
3023 | }; |
3024 | |
3025 | public: |
3026 | template <typename ParseContext> |
3027 | auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
3028 | format_str_ = ctx.begin(); |
3029 | // Checks are deferred to formatting time when the argument type is known. |
3030 | internal::dynamic_specs_handler<ParseContext> handler(specs_, ctx); |
3031 | return parse_format_specs(ctx.begin(), ctx.end(), handler); |
3032 | } |
3033 | |
3034 | template <typename T, typename FormatContext> |
3035 | auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { |
3036 | handle_specs(ctx); |
3037 | internal::specs_checker<null_handler> checker( |
3038 | null_handler(), |
3039 | internal::mapped_type_constant<T, FormatContext>::value); |
3040 | checker.on_align(specs_.align); |
3041 | switch (specs_.sign) { |
3042 | case sign::none: |
3043 | break; |
3044 | case sign::plus: |
3045 | checker.on_plus(); |
3046 | break; |
3047 | case sign::minus: |
3048 | checker.on_minus(); |
3049 | break; |
3050 | case sign::space: |
3051 | checker.on_space(); |
3052 | break; |
3053 | } |
3054 | if (specs_.alt) checker.on_hash(); |
3055 | if (specs_.precision >= 0) checker.end_precision(); |
3056 | using range = internal::output_range<typename FormatContext::iterator, |
3057 | typename FormatContext::char_type>; |
3058 | visit_format_arg(arg_formatter<range>(ctx, nullptr, &specs_), |
3059 | internal::make_arg<FormatContext>(val)); |
3060 | return ctx.out(); |
3061 | } |
3062 | |
3063 | private: |
3064 | template <typename Context> void handle_specs(Context& ctx) { |
3065 | internal::handle_dynamic_spec<internal::width_checker>( |
3066 | specs_.width, specs_.width_ref, ctx); |
3067 | internal::handle_dynamic_spec<internal::precision_checker>( |
3068 | specs_.precision, specs_.precision_ref, ctx); |
3069 | } |
3070 | |
3071 | internal::dynamic_format_specs<Char> specs_; |
3072 | const Char* format_str_; |
3073 | }; |
3074 | |
3075 | template <typename Range, typename Char> |
3076 | typename basic_format_context<Range, Char>::format_arg |
3077 | basic_format_context<Range, Char>::arg(basic_string_view<char_type> name) { |
3078 | map_.init(args_); |
3079 | format_arg arg = map_.find(name); |
3080 | if (arg.type() == internal::none_type) this->on_error("argument not found" ); |
3081 | return arg; |
3082 | } |
3083 | |
3084 | template <typename Char, typename ErrorHandler> |
3085 | FMT_CONSTEXPR void advance_to( |
3086 | basic_format_parse_context<Char, ErrorHandler>& ctx, const Char* p) { |
3087 | ctx.advance_to(ctx.begin() + (p - &*ctx.begin())); |
3088 | } |
3089 | |
3090 | template <typename ArgFormatter, typename Char, typename Context> |
3091 | struct format_handler : internal::error_handler { |
3092 | using range = typename ArgFormatter::range; |
3093 | |
3094 | format_handler(range r, basic_string_view<Char> str, |
3095 | basic_format_args<Context> format_args, |
3096 | internal::locale_ref loc) |
3097 | : parse_context(str), context(r.begin(), format_args, loc) {} |
3098 | |
3099 | void on_text(const Char* begin, const Char* end) { |
3100 | auto size = internal::to_unsigned(end - begin); |
3101 | auto out = context.out(); |
3102 | auto&& it = internal::reserve(out, size); |
3103 | it = std::copy_n(begin, size, it); |
3104 | context.advance_to(out); |
3105 | } |
3106 | |
3107 | void get_arg(int id) { arg = internal::get_arg(context, id); } |
3108 | |
3109 | void on_arg_id() { get_arg(parse_context.next_arg_id()); } |
3110 | void on_arg_id(int id) { |
3111 | parse_context.check_arg_id(id); |
3112 | get_arg(id); |
3113 | } |
3114 | void on_arg_id(basic_string_view<Char> id) { arg = context.arg(id); } |
3115 | |
3116 | void on_replacement_field(const Char* p) { |
3117 | advance_to(parse_context, p); |
3118 | context.advance_to( |
3119 | visit_format_arg(ArgFormatter(context, &parse_context), arg)); |
3120 | } |
3121 | |
3122 | const Char* on_format_specs(const Char* begin, const Char* end) { |
3123 | advance_to(parse_context, begin); |
3124 | internal::custom_formatter<Context> f(parse_context, context); |
3125 | if (visit_format_arg(f, arg)) return parse_context.begin(); |
3126 | basic_format_specs<Char> specs; |
3127 | using internal::specs_handler; |
3128 | using parse_context_t = basic_format_parse_context<Char>; |
3129 | internal::specs_checker<specs_handler<parse_context_t, Context>> handler( |
3130 | specs_handler<parse_context_t, Context>(specs, parse_context, context), |
3131 | arg.type()); |
3132 | begin = parse_format_specs(begin, end, handler); |
3133 | if (begin == end || *begin != '}') on_error("missing '}' in format string" ); |
3134 | advance_to(parse_context, begin); |
3135 | context.advance_to( |
3136 | visit_format_arg(ArgFormatter(context, &parse_context, &specs), arg)); |
3137 | return begin; |
3138 | } |
3139 | |
3140 | basic_format_parse_context<Char> parse_context; |
3141 | Context context; |
3142 | basic_format_arg<Context> arg; |
3143 | }; |
3144 | |
3145 | /** Formats arguments and writes the output to the range. */ |
3146 | template <typename ArgFormatter, typename Char, typename Context> |
3147 | typename Context::iterator vformat_to( |
3148 | typename ArgFormatter::range out, basic_string_view<Char> format_str, |
3149 | basic_format_args<Context> args, |
3150 | internal::locale_ref loc = internal::locale_ref()) { |
3151 | format_handler<ArgFormatter, Char, Context> h(out, format_str, args, loc); |
3152 | internal::parse_format_string<false>(format_str, h); |
3153 | return h.context.out(); |
3154 | } |
3155 | |
3156 | // Casts ``p`` to ``const void*`` for pointer formatting. |
3157 | // Example: |
3158 | // auto s = format("{}", ptr(p)); |
3159 | template <typename T> inline const void* ptr(const T* p) { return p; } |
3160 | template <typename T> inline const void* ptr(const std::unique_ptr<T>& p) { |
3161 | return p.get(); |
3162 | } |
3163 | template <typename T> inline const void* ptr(const std::shared_ptr<T>& p) { |
3164 | return p.get(); |
3165 | } |
3166 | |
3167 | template <typename It, typename Char> struct arg_join : internal::view { |
3168 | It begin; |
3169 | It end; |
3170 | basic_string_view<Char> sep; |
3171 | |
3172 | arg_join(It b, It e, basic_string_view<Char> s) : begin(b), end(e), sep(s) {} |
3173 | }; |
3174 | |
3175 | template <typename It, typename Char> |
3176 | struct formatter<arg_join<It, Char>, Char> |
3177 | : formatter<typename std::iterator_traits<It>::value_type, Char> { |
3178 | template <typename FormatContext> |
3179 | auto format(const arg_join<It, Char>& value, FormatContext& ctx) |
3180 | -> decltype(ctx.out()) { |
3181 | using base = formatter<typename std::iterator_traits<It>::value_type, Char>; |
3182 | auto it = value.begin; |
3183 | auto out = ctx.out(); |
3184 | if (it != value.end) { |
3185 | out = base::format(*it++, ctx); |
3186 | while (it != value.end) { |
3187 | out = std::copy(value.sep.begin(), value.sep.end(), out); |
3188 | ctx.advance_to(out); |
3189 | out = base::format(*it++, ctx); |
3190 | } |
3191 | } |
3192 | return out; |
3193 | } |
3194 | }; |
3195 | |
3196 | /** |
3197 | Returns an object that formats the iterator range `[begin, end)` with elements |
3198 | separated by `sep`. |
3199 | */ |
3200 | template <typename It> |
3201 | arg_join<It, char> join(It begin, It end, string_view sep) { |
3202 | return {begin, end, sep}; |
3203 | } |
3204 | |
3205 | template <typename It> |
3206 | arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) { |
3207 | return {begin, end, sep}; |
3208 | } |
3209 | |
3210 | /** |
3211 | \rst |
3212 | Returns an object that formats `range` with elements separated by `sep`. |
3213 | |
3214 | **Example**:: |
3215 | |
3216 | std::vector<int> v = {1, 2, 3}; |
3217 | fmt::print("{}", fmt::join(v, ", ")); |
3218 | // Output: "1, 2, 3" |
3219 | \endrst |
3220 | */ |
3221 | template <typename Range> |
3222 | arg_join<internal::iterator_t<const Range>, char> join(const Range& range, |
3223 | string_view sep) { |
3224 | return join(std::begin(range), std::end(range), sep); |
3225 | } |
3226 | |
3227 | template <typename Range> |
3228 | arg_join<internal::iterator_t<const Range>, wchar_t> join(const Range& range, |
3229 | wstring_view sep) { |
3230 | return join(std::begin(range), std::end(range), sep); |
3231 | } |
3232 | |
3233 | /** |
3234 | \rst |
3235 | Converts *value* to ``std::string`` using the default format for type *T*. |
3236 | It doesn't support user-defined types with custom formatters. |
3237 | |
3238 | **Example**:: |
3239 | |
3240 | #include <fmt/format.h> |
3241 | |
3242 | std::string answer = fmt::to_string(42); |
3243 | \endrst |
3244 | */ |
3245 | template <typename T> inline std::string to_string(const T& value) { |
3246 | return format("{}" , value); |
3247 | } |
3248 | |
3249 | /** |
3250 | Converts *value* to ``std::wstring`` using the default format for type *T*. |
3251 | */ |
3252 | template <typename T> inline std::wstring to_wstring(const T& value) { |
3253 | return format(L"{}" , value); |
3254 | } |
3255 | |
3256 | template <typename Char, std::size_t SIZE> |
3257 | std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) { |
3258 | return std::basic_string<Char>(buf.data(), buf.size()); |
3259 | } |
3260 | |
3261 | template <typename Char> |
3262 | typename buffer_context<Char>::iterator internal::vformat_to( |
3263 | internal::buffer<Char>& buf, basic_string_view<Char> format_str, |
3264 | basic_format_args<buffer_context<Char>> args) { |
3265 | using range = buffer_range<Char>; |
3266 | return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), |
3267 | args); |
3268 | } |
3269 | |
3270 | template <typename S, typename Char = char_t<S>, |
3271 | FMT_ENABLE_IF(internal::is_string<S>::value)> |
3272 | inline typename buffer_context<Char>::iterator vformat_to( |
3273 | internal::buffer<Char>& buf, const S& format_str, |
3274 | basic_format_args<buffer_context<Char>> args) { |
3275 | return internal::vformat_to(buf, to_string_view(format_str), args); |
3276 | } |
3277 | |
3278 | template <typename S, typename... Args, std::size_t SIZE = inline_buffer_size, |
3279 | typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>> |
3280 | inline typename buffer_context<Char>::iterator format_to( |
3281 | basic_memory_buffer<Char, SIZE>& buf, const S& format_str, Args&&... args) { |
3282 | internal::check_format_string<Args...>(format_str); |
3283 | using context = buffer_context<Char>; |
3284 | return internal::vformat_to(buf, to_string_view(format_str), |
3285 | {make_format_args<context>(args...)}); |
3286 | } |
3287 | |
3288 | template <typename OutputIt, typename Char = char> |
3289 | using format_context_t = basic_format_context<OutputIt, Char>; |
3290 | |
3291 | template <typename OutputIt, typename Char = char> |
3292 | using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>; |
3293 | |
3294 | template <typename S, typename OutputIt, typename... Args, |
3295 | FMT_ENABLE_IF( |
3296 | internal::is_output_iterator<OutputIt>::value && |
3297 | !internal::is_contiguous_back_insert_iterator<OutputIt>::value)> |
3298 | inline OutputIt vformat_to(OutputIt out, const S& format_str, |
3299 | format_args_t<OutputIt, char_t<S>> args) { |
3300 | using range = internal::output_range<OutputIt, char_t<S>>; |
3301 | return vformat_to<arg_formatter<range>>(range(out), |
3302 | to_string_view(format_str), args); |
3303 | } |
3304 | |
3305 | /** |
3306 | \rst |
3307 | Formats arguments, writes the result to the output iterator ``out`` and returns |
3308 | the iterator past the end of the output range. |
3309 | |
3310 | **Example**:: |
3311 | |
3312 | std::vector<char> out; |
3313 | fmt::format_to(std::back_inserter(out), "{}", 42); |
3314 | \endrst |
3315 | */ |
3316 | template <typename OutputIt, typename S, typename... Args, |
3317 | FMT_ENABLE_IF( |
3318 | internal::is_output_iterator<OutputIt>::value && |
3319 | !internal::is_contiguous_back_insert_iterator<OutputIt>::value && |
3320 | internal::is_string<S>::value)> |
3321 | inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) { |
3322 | internal::check_format_string<Args...>(format_str); |
3323 | using context = format_context_t<OutputIt, char_t<S>>; |
3324 | return vformat_to(out, to_string_view(format_str), |
3325 | {make_format_args<context>(args...)}); |
3326 | } |
3327 | |
3328 | template <typename OutputIt> struct format_to_n_result { |
3329 | /** Iterator past the end of the output range. */ |
3330 | OutputIt out; |
3331 | /** Total (not truncated) output size. */ |
3332 | std::size_t size; |
3333 | }; |
3334 | |
3335 | template <typename OutputIt, typename Char = typename OutputIt::value_type> |
3336 | using format_to_n_context = |
3337 | format_context_t<internal::truncating_iterator<OutputIt>, Char>; |
3338 | |
3339 | template <typename OutputIt, typename Char = typename OutputIt::value_type> |
3340 | using format_to_n_args = basic_format_args<format_to_n_context<OutputIt, Char>>; |
3341 | |
3342 | template <typename OutputIt, typename Char, typename... Args> |
3343 | inline format_arg_store<format_to_n_context<OutputIt, Char>, Args...> |
3344 | make_format_to_n_args(const Args&... args) { |
3345 | return format_arg_store<format_to_n_context<OutputIt, Char>, Args...>( |
3346 | args...); |
3347 | } |
3348 | |
3349 | template <typename OutputIt, typename Char, typename... Args, |
3350 | FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)> |
3351 | inline format_to_n_result<OutputIt> vformat_to_n( |
3352 | OutputIt out, std::size_t n, basic_string_view<Char> format_str, |
3353 | format_to_n_args<OutputIt, Char> args) { |
3354 | auto it = vformat_to(internal::truncating_iterator<OutputIt>(out, n), |
3355 | format_str, args); |
3356 | return {it.base(), it.count()}; |
3357 | } |
3358 | |
3359 | /** |
3360 | \rst |
3361 | Formats arguments, writes up to ``n`` characters of the result to the output |
3362 | iterator ``out`` and returns the total output size and the iterator past the |
3363 | end of the output range. |
3364 | \endrst |
3365 | */ |
3366 | template <typename OutputIt, typename S, typename... Args, |
3367 | FMT_ENABLE_IF(internal::is_string<S>::value&& |
3368 | internal::is_output_iterator<OutputIt>::value)> |
3369 | inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n, |
3370 | const S& format_str, |
3371 | const Args&... args) { |
3372 | internal::check_format_string<Args...>(format_str); |
3373 | using context = format_to_n_context<OutputIt, char_t<S>>; |
3374 | return vformat_to_n(out, n, to_string_view(format_str), |
3375 | {make_format_args<context>(args...)}); |
3376 | } |
3377 | |
3378 | template <typename Char> |
3379 | inline std::basic_string<Char> internal::vformat( |
3380 | basic_string_view<Char> format_str, |
3381 | basic_format_args<buffer_context<Char>> args) { |
3382 | basic_memory_buffer<Char> buffer; |
3383 | internal::vformat_to(buffer, format_str, args); |
3384 | return to_string(buffer); |
3385 | } |
3386 | |
3387 | /** |
3388 | Returns the number of characters in the output of |
3389 | ``format(format_str, args...)``. |
3390 | */ |
3391 | template <typename... Args> |
3392 | inline std::size_t formatted_size(string_view format_str, const Args&... args) { |
3393 | return format_to(internal::counting_iterator(), format_str, args...).count(); |
3394 | } |
3395 | |
3396 | template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)> |
3397 | void vprint(std::FILE* f, basic_string_view<Char> format_str, |
3398 | wformat_args args) { |
3399 | wmemory_buffer buffer; |
3400 | internal::vformat_to(buffer, format_str, args); |
3401 | buffer.push_back(L'\0'); |
3402 | if (std::fputws(buffer.data(), f) == -1) |
3403 | FMT_THROW(system_error(errno, "cannot write to file" )); |
3404 | } |
3405 | |
3406 | template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)> |
3407 | void vprint(basic_string_view<Char> format_str, wformat_args args) { |
3408 | vprint(stdout, format_str, args); |
3409 | } |
3410 | |
3411 | #if FMT_USE_USER_DEFINED_LITERALS |
3412 | namespace internal { |
3413 | |
3414 | # if FMT_USE_UDL_TEMPLATE |
3415 | template <typename Char, Char... CHARS> class udl_formatter { |
3416 | public: |
3417 | template <typename... Args> |
3418 | std::basic_string<Char> operator()(Args&&... args) const { |
3419 | FMT_CONSTEXPR_DECL Char s[] = {CHARS..., '\0'}; |
3420 | FMT_CONSTEXPR_DECL bool invalid_format = |
3421 | do_check_format_string<Char, error_handler, remove_cvref_t<Args>...>( |
3422 | basic_string_view<Char>(s, sizeof...(CHARS))); |
3423 | (void)invalid_format; |
3424 | return format(s, std::forward<Args>(args)...); |
3425 | } |
3426 | }; |
3427 | # else |
3428 | template <typename Char> struct udl_formatter { |
3429 | basic_string_view<Char> str; |
3430 | |
3431 | template <typename... Args> |
3432 | std::basic_string<Char> operator()(Args&&... args) const { |
3433 | return format(str, std::forward<Args>(args)...); |
3434 | } |
3435 | }; |
3436 | # endif // FMT_USE_UDL_TEMPLATE |
3437 | |
3438 | template <typename Char> struct udl_arg { |
3439 | basic_string_view<Char> str; |
3440 | |
3441 | template <typename T> named_arg<T, Char> operator=(T&& value) const { |
3442 | return {str, std::forward<T>(value)}; |
3443 | } |
3444 | }; |
3445 | |
3446 | } // namespace internal |
3447 | |
3448 | inline namespace literals { |
3449 | # if FMT_USE_UDL_TEMPLATE |
3450 | # pragma GCC diagnostic push |
3451 | # if FMT_CLANG_VERSION |
3452 | # pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" |
3453 | # endif |
3454 | template <typename Char, Char... CHARS> |
3455 | FMT_CONSTEXPR internal::udl_formatter<Char, CHARS...> operator""_format () { |
3456 | return {}; |
3457 | } |
3458 | # pragma GCC diagnostic pop |
3459 | # else |
3460 | /** |
3461 | \rst |
3462 | User-defined literal equivalent of :func:`fmt::format`. |
3463 | |
3464 | **Example**:: |
3465 | |
3466 | using namespace fmt::literals; |
3467 | std::string message = "The answer is {}"_format(42); |
3468 | \endrst |
3469 | */ |
3470 | FMT_CONSTEXPR internal::udl_formatter<char> operator"" _format(const char* s, |
3471 | std::size_t n) { |
3472 | return {{s, n}}; |
3473 | } |
3474 | FMT_CONSTEXPR internal::udl_formatter<wchar_t> operator"" _format( |
3475 | const wchar_t* s, std::size_t n) { |
3476 | return {{s, n}}; |
3477 | } |
3478 | # endif // FMT_USE_UDL_TEMPLATE |
3479 | |
3480 | /** |
3481 | \rst |
3482 | User-defined literal equivalent of :func:`fmt::arg`. |
3483 | |
3484 | **Example**:: |
3485 | |
3486 | using namespace fmt::literals; |
3487 | fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); |
3488 | \endrst |
3489 | */ |
3490 | FMT_CONSTEXPR internal::udl_arg<char> operator"" _a(const char* s, |
3491 | std::size_t n) { |
3492 | return {{s, n}}; |
3493 | } |
3494 | FMT_CONSTEXPR internal::udl_arg<wchar_t> operator"" _a(const wchar_t* s, |
3495 | std::size_t n) { |
3496 | return {{s, n}}; |
3497 | } |
3498 | } // namespace literals |
3499 | #endif // FMT_USE_USER_DEFINED_LITERALS |
3500 | FMT_END_NAMESPACE |
3501 | |
3502 | #define FMT_STRING_IMPL(s, ...) \ |
3503 | [] { \ |
3504 | struct str : fmt::compile_string { \ |
3505 | using char_type = typename std::remove_cv<std::remove_pointer< \ |
3506 | typename std::decay<decltype(s)>::type>::type>::type; \ |
3507 | __VA_ARGS__ FMT_CONSTEXPR \ |
3508 | operator fmt::basic_string_view<char_type>() const { \ |
3509 | return {s, sizeof(s) / sizeof(char_type) - 1}; \ |
3510 | } \ |
3511 | } result; \ |
3512 | /* Suppress Qt Creator warning about unused operator. */ \ |
3513 | (void)static_cast<fmt::basic_string_view<typename str::char_type>>( \ |
3514 | result); \ |
3515 | return result; \ |
3516 | }() |
3517 | |
3518 | /** |
3519 | \rst |
3520 | Constructs a compile-time format string. |
3521 | |
3522 | **Example**:: |
3523 | |
3524 | // A compile-time error because 'd' is an invalid specifier for strings. |
3525 | std::string s = format(FMT_STRING("{:d}"), "foo"); |
3526 | \endrst |
3527 | */ |
3528 | #define FMT_STRING(s) FMT_STRING_IMPL(s, ) |
3529 | |
3530 | #if defined(FMT_STRING_ALIAS) && FMT_STRING_ALIAS |
3531 | # define fmt(s) FMT_STRING_IMPL(s, [[deprecated]]) |
3532 | #endif |
3533 | |
3534 | #ifdef FMT_HEADER_ONLY |
3535 | # define FMT_FUNC inline |
3536 | # include "format-inl.h" |
3537 | #else |
3538 | # define FMT_FUNC |
3539 | #endif |
3540 | |
3541 | #endif // FMT_FORMAT_H_ |
3542 | |