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 <cerrno>
37 #include <cmath>
38 #include <cstddef> // std::byte
39 #include <cstdint>
40 #include <cwchar>
41 #include <limits>
42 #include <memory>
43 #include <stdexcept>
44 #include <utility> // std::swap
45
46 #include "core.h"
47
48 #ifdef __INTEL_COMPILER
49 # define FMT_ICC_VERSION __INTEL_COMPILER
50 #elif defined(__ICL)
51 # define FMT_ICC_VERSION __ICL
52 #else
53 # define FMT_ICC_VERSION 0
54 #endif
55
56 #ifdef __NVCC__
57 # define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__)
58 #else
59 # define FMT_CUDA_VERSION 0
60 #endif
61
62 #ifdef __has_builtin
63 # define FMT_HAS_BUILTIN(x) __has_builtin(x)
64 #else
65 # define FMT_HAS_BUILTIN(x) 0
66 #endif
67
68 #if FMT_GCC_VERSION || FMT_CLANG_VERSION
69 # define FMT_NOINLINE __attribute__((noinline))
70 #else
71 # define FMT_NOINLINE
72 #endif
73
74 #if FMT_GCC_VERSION
75 # define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden")))
76 #else
77 # define FMT_GCC_VISIBILITY_HIDDEN
78 #endif
79
80 #if __cplusplus == 201103L || __cplusplus == 201402L
81 # if defined(__INTEL_COMPILER) || defined(__PGI)
82 # define FMT_FALLTHROUGH
83 # elif defined(__clang__)
84 # define FMT_FALLTHROUGH [[clang::fallthrough]]
85 # elif FMT_GCC_VERSION >= 700 && \
86 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
87 # define FMT_FALLTHROUGH [[gnu::fallthrough]]
88 # else
89 # define FMT_FALLTHROUGH
90 # endif
91 #elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \
92 (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
93 # define FMT_FALLTHROUGH [[fallthrough]]
94 #else
95 # define FMT_FALLTHROUGH
96 #endif
97
98 #ifndef FMT_MAYBE_UNUSED
99 # if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
100 # define FMT_MAYBE_UNUSED [[maybe_unused]]
101 # else
102 # define FMT_MAYBE_UNUSED
103 # endif
104 #endif
105
106 #ifndef FMT_THROW
107 # if FMT_EXCEPTIONS
108 # if FMT_MSC_VER || FMT_NVCC
109 FMT_BEGIN_NAMESPACE
110 namespace detail {
do_throw(const Exception & x)111 template <typename Exception> inline void do_throw(const Exception& x) {
112 // Silence unreachable code warnings in MSVC and NVCC because these
113 // are nearly impossible to fix in a generic code.
114 volatile bool b = true;
115 if (b) throw x;
116 }
117 } // namespace detail
118 FMT_END_NAMESPACE
119 # define FMT_THROW(x) detail::do_throw(x)
120 # else
121 # define FMT_THROW(x) throw x
122 # endif
123 # else
124 # define FMT_THROW(x) \
125 do { \
126 FMT_ASSERT(false, (x).what()); \
127 } while (false)
128 # endif
129 #endif
130
131 #if FMT_EXCEPTIONS
132 # define FMT_TRY try
133 # define FMT_CATCH(x) catch (x)
134 #else
135 # define FMT_TRY if (true)
136 # define FMT_CATCH(x) if (false)
137 #endif
138
139 #ifndef FMT_USE_USER_DEFINED_LITERALS
140 // EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs.
141 # if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
142 FMT_MSC_VER >= 1900) && \
143 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480)
144 # define FMT_USE_USER_DEFINED_LITERALS 1
145 # else
146 # define FMT_USE_USER_DEFINED_LITERALS 0
147 # endif
148 #endif
149
150 #ifndef FMT_USE_FLOAT
151 # define FMT_USE_FLOAT 1
152 #endif
153
154 #ifndef FMT_USE_DOUBLE
155 # define FMT_USE_DOUBLE 1
156 #endif
157
158 #ifndef FMT_USE_LONG_DOUBLE
159 # define FMT_USE_LONG_DOUBLE 1
160 #endif
161
162 // Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of
163 // integer formatter template instantiations to just one by only using the
164 // largest integer type. This results in a reduction in binary size but will
165 // cause a decrease in integer formatting performance.
166 #if !defined(FMT_REDUCE_INT_INSTANTIATIONS)
167 # define FMT_REDUCE_INT_INSTANTIATIONS 0
168 #endif
169
170 // __builtin_clz is broken in clang with Microsoft CodeGen:
171 // https://github.com/fmtlib/fmt/issues/519
172 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER
173 # define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
174 #endif
175 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER
176 # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
177 #endif
178 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_ctz))
179 # define FMT_BUILTIN_CTZ(n) __builtin_ctz(n)
180 #endif
181 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_ctzll))
182 # define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n)
183 #endif
184
185 #if FMT_MSC_VER
186 # include <intrin.h> // _BitScanReverse[64], _BitScanForward[64], _umul128
187 #endif
188
189 // Some compilers masquerade as both MSVC and GCC-likes or otherwise support
190 // __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the
191 // MSVC intrinsics if the clz and clzll builtins are not available.
192 #if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(FMT_BUILTIN_CTZLL)
193 FMT_BEGIN_NAMESPACE
194 namespace detail {
195 // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning.
196 # if !defined(__clang__)
197 # pragma managed(push, off)
198 # pragma intrinsic(_BitScanForward)
199 # pragma intrinsic(_BitScanReverse)
200 # if defined(_WIN64)
201 # pragma intrinsic(_BitScanForward64)
202 # pragma intrinsic(_BitScanReverse64)
203 # endif
204 # endif
205
clz(uint32_t x)206 inline int clz(uint32_t x) {
207 unsigned long r = 0;
208 _BitScanReverse(&r, x);
209 FMT_ASSERT(x != 0, "");
210 // Static analysis complains about using uninitialized data
211 // "r", but the only way that can happen is if "x" is 0,
212 // which the callers guarantee to not happen.
213 FMT_MSC_WARNING(suppress : 6102)
214 return 31 ^ static_cast<int>(r);
215 }
216 # define FMT_BUILTIN_CLZ(n) detail::clz(n)
217
clzll(uint64_t x)218 inline int clzll(uint64_t x) {
219 unsigned long r = 0;
220 # ifdef _WIN64
221 _BitScanReverse64(&r, x);
222 # else
223 // Scan the high 32 bits.
224 if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) return 63 ^ (r + 32);
225 // Scan the low 32 bits.
226 _BitScanReverse(&r, static_cast<uint32_t>(x));
227 # endif
228 FMT_ASSERT(x != 0, "");
229 FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning.
230 return 63 ^ static_cast<int>(r);
231 }
232 # define FMT_BUILTIN_CLZLL(n) detail::clzll(n)
233
ctz(uint32_t x)234 inline int ctz(uint32_t x) {
235 unsigned long r = 0;
236 _BitScanForward(&r, x);
237 FMT_ASSERT(x != 0, "");
238 FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning.
239 return static_cast<int>(r);
240 }
241 # define FMT_BUILTIN_CTZ(n) detail::ctz(n)
242
ctzll(uint64_t x)243 inline int ctzll(uint64_t x) {
244 unsigned long r = 0;
245 FMT_ASSERT(x != 0, "");
246 FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning.
247 # ifdef _WIN64
248 _BitScanForward64(&r, x);
249 # else
250 // Scan the low 32 bits.
251 if (_BitScanForward(&r, static_cast<uint32_t>(x))) return static_cast<int>(r);
252 // Scan the high 32 bits.
253 _BitScanForward(&r, static_cast<uint32_t>(x >> 32));
254 r += 32;
255 # endif
256 return static_cast<int>(r);
257 }
258 # define FMT_BUILTIN_CTZLL(n) detail::ctzll(n)
259 # if !defined(__clang__)
260 # pragma managed(pop)
261 # endif
262 } // namespace detail
263 FMT_END_NAMESPACE
264 #endif
265
266 // Enable the deprecated numeric alignment.
267 #ifndef FMT_DEPRECATED_NUMERIC_ALIGN
268 # define FMT_DEPRECATED_NUMERIC_ALIGN 0
269 #endif
270
271 FMT_BEGIN_NAMESPACE
272 namespace detail {
273
274 #if __cplusplus >= 202002L || \
275 (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002)
276 # define FMT_CONSTEXPR20 constexpr
277 #else
278 # define FMT_CONSTEXPR20
279 #endif
280
281 // An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have
282 // undefined behavior (e.g. due to type aliasing).
283 // Example: uint64_t d = bit_cast<uint64_t>(2.718);
284 template <typename Dest, typename Source>
bit_cast(const Source & source)285 inline Dest bit_cast(const Source& source) {
286 static_assert(sizeof(Dest) == sizeof(Source), "size mismatch");
287 Dest dest;
288 std::memcpy(&dest, &source, sizeof(dest));
289 return dest;
290 }
291
is_big_endian()292 inline bool is_big_endian() {
293 const auto u = 1u;
294 struct bytes {
295 char data[sizeof(u)];
296 };
297 return bit_cast<bytes>(u).data[0] == 0;
298 }
299
300 // A fallback implementation of uintptr_t for systems that lack it.
301 struct fallback_uintptr {
302 unsigned char value[sizeof(void*)];
303
304 fallback_uintptr() = default;
fallback_uintptrfallback_uintptr305 explicit fallback_uintptr(const void* p) {
306 *this = bit_cast<fallback_uintptr>(p);
307 if (is_big_endian()) {
308 for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j)
309 std::swap(value[i], value[j]);
310 }
311 }
312 };
313 #ifdef UINTPTR_MAX
314 using uintptr_t = ::uintptr_t;
to_uintptr(const void * p)315 inline uintptr_t to_uintptr(const void* p) { return bit_cast<uintptr_t>(p); }
316 #else
317 using uintptr_t = fallback_uintptr;
to_uintptr(const void * p)318 inline fallback_uintptr to_uintptr(const void* p) {
319 return fallback_uintptr(p);
320 }
321 #endif
322
323 // Returns the largest possible value for type T. Same as
324 // std::numeric_limits<T>::max() but shorter and not affected by the max macro.
max_value()325 template <typename T> constexpr T max_value() {
326 return (std::numeric_limits<T>::max)();
327 }
num_bits()328 template <typename T> constexpr int num_bits() {
329 return std::numeric_limits<T>::digits;
330 }
331 // std::numeric_limits<T>::digits may return 0 for 128-bit ints.
332 template <> constexpr int num_bits<int128_t>() { return 128; }
333 template <> constexpr int num_bits<uint128_t>() { return 128; }
334 template <> constexpr int num_bits<fallback_uintptr>() {
335 return static_cast<int>(sizeof(void*) *
336 std::numeric_limits<unsigned char>::digits);
337 }
338
assume(bool condition)339 FMT_INLINE void assume(bool condition) {
340 (void)condition;
341 #if FMT_HAS_BUILTIN(__builtin_assume)
342 __builtin_assume(condition);
343 #endif
344 }
345
346 // An approximation of iterator_t for pre-C++20 systems.
347 template <typename T>
348 using iterator_t = decltype(std::begin(std::declval<T&>()));
349 template <typename T> using sentinel_t = decltype(std::end(std::declval<T&>()));
350
351 // A workaround for std::string not having mutable data() until C++17.
get_data(std::basic_string<Char> & s)352 template <typename Char> inline Char* get_data(std::basic_string<Char>& s) {
353 return &s[0];
354 }
355 template <typename Container>
get_data(Container & c)356 inline typename Container::value_type* get_data(Container& c) {
357 return c.data();
358 }
359
360 #if defined(_SECURE_SCL) && _SECURE_SCL
361 // Make a checked iterator to avoid MSVC warnings.
362 template <typename T> using checked_ptr = stdext::checked_array_iterator<T*>;
make_checked(T * p,size_t size)363 template <typename T> checked_ptr<T> make_checked(T* p, size_t size) {
364 return {p, size};
365 }
366 #else
367 template <typename T> using checked_ptr = T*;
make_checked(T * p,size_t)368 template <typename T> inline T* make_checked(T* p, size_t) { return p; }
369 #endif
370
371 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
372 #if FMT_CLANG_VERSION >= 307
373 __attribute__((no_sanitize("undefined")))
374 #endif
375 inline checked_ptr<typename Container::value_type>
reserve(std::back_insert_iterator<Container> it,size_t n)376 reserve(std::back_insert_iterator<Container> it, size_t n) {
377 Container& c = get_container(it);
378 size_t size = c.size();
379 c.resize(size + n);
380 return make_checked(get_data(c) + size, n);
381 }
382
383 template <typename T>
reserve(buffer_appender<T> it,size_t n)384 inline buffer_appender<T> reserve(buffer_appender<T> it, size_t n) {
385 buffer<T>& buf = get_container(it);
386 buf.try_reserve(buf.size() + n);
387 return it;
388 }
389
reserve(Iterator & it,size_t)390 template <typename Iterator> constexpr Iterator& reserve(Iterator& it, size_t) {
391 return it;
392 }
393
394 template <typename OutputIt>
395 using reserve_iterator =
396 remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
397
398 template <typename T, typename OutputIt>
to_pointer(OutputIt,size_t)399 constexpr T* to_pointer(OutputIt, size_t) {
400 return nullptr;
401 }
to_pointer(buffer_appender<T> it,size_t n)402 template <typename T> T* to_pointer(buffer_appender<T> it, size_t n) {
403 buffer<T>& buf = get_container(it);
404 auto size = buf.size();
405 if (buf.capacity() < size + n) return nullptr;
406 buf.try_resize(size + n);
407 return buf.data() + size;
408 }
409
410 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
base_iterator(std::back_insert_iterator<Container> & it,checked_ptr<typename Container::value_type>)411 inline std::back_insert_iterator<Container> base_iterator(
412 std::back_insert_iterator<Container>& it,
413 checked_ptr<typename Container::value_type>) {
414 return it;
415 }
416
417 template <typename Iterator>
base_iterator(Iterator,Iterator it)418 constexpr Iterator base_iterator(Iterator, Iterator it) {
419 return it;
420 }
421
422 // An output iterator that counts the number of objects written to it and
423 // discards them.
424 class counting_iterator {
425 private:
426 size_t count_;
427
428 public:
429 using iterator_category = std::output_iterator_tag;
430 using difference_type = std::ptrdiff_t;
431 using pointer = void;
432 using reference = void;
433 using _Unchecked_type = counting_iterator; // Mark iterator as checked.
434
435 struct value_type {
436 template <typename T> void operator=(const T&) {}
437 };
438
counting_iterator()439 counting_iterator() : count_(0) {}
440
count()441 size_t count() const { return count_; }
442
443 counting_iterator& operator++() {
444 ++count_;
445 return *this;
446 }
447 counting_iterator operator++(int) {
448 auto it = *this;
449 ++*this;
450 return it;
451 }
452
453 friend counting_iterator operator+(counting_iterator it, difference_type n) {
454 it.count_ += static_cast<size_t>(n);
455 return it;
456 }
457
458 value_type operator*() const { return {}; }
459 };
460
461 // <algorithm> is spectacularly slow to compile in C++20 so use a simple fill_n
462 // instead (#1998).
463 template <typename OutputIt, typename Size, typename T>
fill_n(OutputIt out,Size count,const T & value)464 FMT_CONSTEXPR OutputIt fill_n(OutputIt out, Size count, const T& value) {
465 for (Size i = 0; i < count; ++i) *out++ = value;
466 return out;
467 }
468 template <typename T, typename Size>
fill_n(T * out,Size count,char value)469 FMT_CONSTEXPR20 T* fill_n(T* out, Size count, char value) {
470 if (is_constant_evaluated()) {
471 return fill_n<T*, Size, T>(out, count, value);
472 }
473 std::memset(out, value, to_unsigned(count));
474 return out + count;
475 }
476
477 template <typename InputIt, typename OutChar>
478 using needs_conversion = bool_constant<
479 std::is_same<typename std::iterator_traits<InputIt>::value_type,
480 char>::value &&
481 std::is_same<OutChar, char8_type>::value>;
482
483 template <typename OutChar, typename InputIt, typename OutputIt,
484 FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
copy_str(InputIt begin,InputIt end,OutputIt it)485 FMT_CONSTEXPR OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
486 while (begin != end) *it++ = *begin++;
487 return it;
488 }
489
490 template <typename OutChar, typename InputIt,
491 FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
copy_str(InputIt begin,InputIt end,OutChar * out)492 FMT_CONSTEXPR20 OutChar* copy_str(InputIt begin, InputIt end, OutChar* out) {
493 if (is_constant_evaluated()) {
494 return copy_str<OutChar, InputIt, OutChar*>(begin, end, out);
495 }
496 return std::uninitialized_copy(begin, end, out);
497 }
498
499 template <typename OutChar, typename InputIt, typename OutputIt,
500 FMT_ENABLE_IF(needs_conversion<InputIt, OutChar>::value)>
copy_str(InputIt begin,InputIt end,OutputIt it)501 OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
502 while (begin != end) *it++ = static_cast<char8_type>(*begin++);
503 return it;
504 }
505
506 template <typename OutChar, typename InputIt,
507 FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
copy_str(InputIt begin,InputIt end,buffer_appender<OutChar> out)508 buffer_appender<OutChar> copy_str(InputIt begin, InputIt end,
509 buffer_appender<OutChar> out) {
510 get_container(out).append(begin, end);
511 return out;
512 }
513
514 template <typename Char, typename InputIt>
copy_str(InputIt begin,InputIt end,counting_iterator it)515 inline counting_iterator copy_str(InputIt begin, InputIt end,
516 counting_iterator it) {
517 return it + (end - begin);
518 }
519
520 template <typename Char>
code_point_length(const Char * begin)521 FMT_CONSTEXPR int code_point_length(const Char* begin) {
522 if (const_check(sizeof(Char) != 1)) return 1;
523 constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
524 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0};
525 int len = lengths[static_cast<unsigned char>(*begin) >> 3];
526
527 // Compute the pointer to the next character early so that the next
528 // iteration can start working on the next character. Neither Clang
529 // nor GCC figure out this reordering on their own.
530 return len + !len;
531 }
532
533 // A public domain branchless UTF-8 decoder by Christopher Wellons:
534 // https://github.com/skeeto/branchless-utf8
535 /* Decode the next character, c, from s, reporting errors in e.
536 *
537 * Since this is a branchless decoder, four bytes will be read from the
538 * buffer regardless of the actual length of the next character. This
539 * means the buffer _must_ have at least three bytes of zero padding
540 * following the end of the data stream.
541 *
542 * Errors are reported in e, which will be non-zero if the parsed
543 * character was somehow invalid: invalid byte sequence, non-canonical
544 * encoding, or a surrogate half.
545 *
546 * The function returns a pointer to the next character. When an error
547 * occurs, this pointer will be a guess that depends on the particular
548 * error, but it will always advance at least one byte.
549 */
utf8_decode(const char * s,uint32_t * c,int * e)550 FMT_CONSTEXPR inline const char* utf8_decode(const char* s, uint32_t* c,
551 int* e) {
552 constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
553 constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
554 constexpr const int shiftc[] = {0, 18, 12, 6, 0};
555 constexpr const int shifte[] = {0, 6, 4, 2, 0};
556
557 int len = code_point_length(s);
558 const char* next = s + len;
559
560 // Assume a four-byte character and load four bytes. Unused bits are
561 // shifted out.
562 *c = uint32_t(s[0] & masks[len]) << 18;
563 *c |= uint32_t(s[1] & 0x3f) << 12;
564 *c |= uint32_t(s[2] & 0x3f) << 6;
565 *c |= uint32_t(s[3] & 0x3f) << 0;
566 *c >>= shiftc[len];
567
568 // Accumulate the various error conditions.
569 using uchar = unsigned char;
570 *e = (*c < mins[len]) << 6; // non-canonical encoding
571 *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half?
572 *e |= (*c > 0x10FFFF) << 8; // out of range?
573 *e |= (uchar(s[1]) & 0xc0) >> 2;
574 *e |= (uchar(s[2]) & 0xc0) >> 4;
575 *e |= uchar(s[3]) >> 6;
576 *e ^= 0x2a; // top two bits of each tail byte correct?
577 *e >>= shifte[len];
578
579 return next;
580 }
581
582 template <typename F>
for_each_codepoint(string_view s,F f)583 FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) {
584 auto decode = [f](const char* p) {
585 auto cp = uint32_t();
586 auto error = 0;
587 p = utf8_decode(p, &cp, &error);
588 f(cp, error);
589 return p;
590 };
591 auto p = s.data();
592 const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars.
593 if (s.size() >= block_size) {
594 for (auto end = p + s.size() - block_size + 1; p < end;) p = decode(p);
595 }
596 if (auto num_chars_left = s.data() + s.size() - p) {
597 char buf[2 * block_size - 1] = {};
598 copy_str<char>(p, p + num_chars_left, buf);
599 p = buf;
600 do {
601 p = decode(p);
602 } while (p - buf < num_chars_left);
603 }
604 }
605
606 template <typename Char>
compute_width(basic_string_view<Char> s)607 inline size_t compute_width(basic_string_view<Char> s) {
608 return s.size();
609 }
610
611 // Computes approximate display width of a UTF-8 string.
compute_width(string_view s)612 FMT_CONSTEXPR inline size_t compute_width(string_view s) {
613 size_t num_code_points = 0;
614 // It is not a lambda for compatibility with C++14.
615 struct count_code_points {
616 size_t* count;
617 FMT_CONSTEXPR void operator()(uint32_t cp, int error) const {
618 *count +=
619 1 +
620 (error == 0 && cp >= 0x1100 &&
621 (cp <= 0x115f || // Hangul Jamo init. consonants
622 cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET〈
623 cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET 〉
624 // CJK ... Yi except Unicode Character “〿”:
625 (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
626 (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables
627 (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs
628 (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms
629 (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms
630 (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms
631 (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms
632 (cp >= 0x20000 && cp <= 0x2fffd) || // CJK
633 (cp >= 0x30000 && cp <= 0x3fffd) ||
634 // Miscellaneous Symbols and Pictographs + Emoticons:
635 (cp >= 0x1f300 && cp <= 0x1f64f) ||
636 // Supplemental Symbols and Pictographs:
637 (cp >= 0x1f900 && cp <= 0x1f9ff)));
638 }
639 };
640 for_each_codepoint(s, count_code_points{&num_code_points});
641 return num_code_points;
642 }
643
compute_width(basic_string_view<char8_type> s)644 inline size_t compute_width(basic_string_view<char8_type> s) {
645 return compute_width(basic_string_view<char>(
646 reinterpret_cast<const char*>(s.data()), s.size()));
647 }
648
649 template <typename Char>
code_point_index(basic_string_view<Char> s,size_t n)650 inline size_t code_point_index(basic_string_view<Char> s, size_t n) {
651 size_t size = s.size();
652 return n < size ? n : size;
653 }
654
655 // Calculates the index of the nth code point in a UTF-8 string.
code_point_index(basic_string_view<char8_type> s,size_t n)656 inline size_t code_point_index(basic_string_view<char8_type> s, size_t n) {
657 const char8_type* data = s.data();
658 size_t num_code_points = 0;
659 for (size_t i = 0, size = s.size(); i != size; ++i) {
660 if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) return i;
661 }
662 return s.size();
663 }
664
665 template <typename T>
666 using is_fast_float = bool_constant<std::numeric_limits<T>::is_iec559 &&
667 sizeof(T) <= sizeof(double)>;
668
669 #ifndef FMT_USE_FULL_CACHE_DRAGONBOX
670 # define FMT_USE_FULL_CACHE_DRAGONBOX 0
671 #endif
672
673 template <typename T>
674 template <typename U>
append(const U * begin,const U * end)675 void buffer<T>::append(const U* begin, const U* end) {
676 while (begin != end) {
677 auto count = to_unsigned(end - begin);
678 try_reserve(size_ + count);
679 auto free_cap = capacity_ - size_;
680 if (free_cap < count) count = free_cap;
681 std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count));
682 size_ += count;
683 begin += count;
684 }
685 }
686
687 template <typename OutputIt, typename T, typename Traits>
flush()688 void iterator_buffer<OutputIt, T, Traits>::flush() {
689 auto size = this->size();
690 this->clear();
691 out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
692 }
693 } // namespace detail
694
695 // The number of characters to store in the basic_memory_buffer object itself
696 // to avoid dynamic memory allocation.
697 enum { inline_buffer_size = 500 };
698
699 /**
700 \rst
701 A dynamically growing memory buffer for trivially copyable/constructible types
702 with the first ``SIZE`` elements stored in the object itself.
703
704 You can use one of the following type aliases for common character types:
705
706 +----------------+------------------------------+
707 | Type | Definition |
708 +================+==============================+
709 | memory_buffer | basic_memory_buffer<char> |
710 +----------------+------------------------------+
711 | wmemory_buffer | basic_memory_buffer<wchar_t> |
712 +----------------+------------------------------+
713
714 **Example**::
715
716 axom::fmt::memory_buffer out;
717 format_to(out, "The answer is {}.", 42);
718
719 This will append the following output to the ``out`` object:
720
721 .. code-block:: none
722
723 The answer is 42.
724
725 The output can be converted to an ``std::string`` with ``to_string(out)``.
726 \endrst
727 */
728 template <typename T, size_t SIZE = inline_buffer_size,
729 typename Allocator = std::allocator<T>>
730 class basic_memory_buffer final : public detail::buffer<T> {
731 private:
732 T store_[SIZE];
733
734 // Don't inherit from Allocator avoid generating type_info for it.
735 Allocator alloc_;
736
737 // Deallocate memory allocated by the buffer.
deallocate()738 void deallocate() {
739 T* data = this->data();
740 if (data != store_) alloc_.deallocate(data, this->capacity());
741 }
742
743 protected:
744 void grow(size_t size) final FMT_OVERRIDE;
745
746 public:
747 using value_type = T;
748 using const_reference = const T&;
749
750 explicit basic_memory_buffer(const Allocator& alloc = Allocator())
alloc_(alloc)751 : alloc_(alloc) {
752 this->set(store_, SIZE);
753 }
~basic_memory_buffer()754 ~basic_memory_buffer() { deallocate(); }
755
756 private:
757 // Move data from other to this buffer.
move(basic_memory_buffer & other)758 void move(basic_memory_buffer& other) {
759 alloc_ = std::move(other.alloc_);
760 T* data = other.data();
761 size_t size = other.size(), capacity = other.capacity();
762 if (data == other.store_) {
763 this->set(store_, capacity);
764 std::uninitialized_copy(other.store_, other.store_ + size,
765 detail::make_checked(store_, capacity));
766 } else {
767 this->set(data, capacity);
768 // Set pointer to the inline array so that delete is not called
769 // when deallocating.
770 other.set(other.store_, 0);
771 }
772 this->resize(size);
773 }
774
775 public:
776 /**
777 \rst
778 Constructs a :class:`axom::fmt::basic_memory_buffer` object moving the content
779 of the other object to it.
780 \endrst
781 */
basic_memory_buffer(basic_memory_buffer && other)782 basic_memory_buffer(basic_memory_buffer&& other) FMT_NOEXCEPT { move(other); }
783
784 /**
785 \rst
786 Moves the content of the other ``basic_memory_buffer`` object to this one.
787 \endrst
788 */
789 basic_memory_buffer& operator=(basic_memory_buffer&& other) FMT_NOEXCEPT {
790 FMT_ASSERT(this != &other, "");
791 deallocate();
792 move(other);
793 return *this;
794 }
795
796 // Returns a copy of the allocator associated with this buffer.
get_allocator()797 Allocator get_allocator() const { return alloc_; }
798
799 /**
800 Resizes the buffer to contain *count* elements. If T is a POD type new
801 elements may not be initialized.
802 */
resize(size_t count)803 void resize(size_t count) { this->try_resize(count); }
804
805 /** Increases the buffer capacity to *new_capacity*. */
reserve(size_t new_capacity)806 void reserve(size_t new_capacity) { this->try_reserve(new_capacity); }
807
808 // Directly append data into the buffer
809 using detail::buffer<T>::append;
810 template <typename ContiguousRange>
append(const ContiguousRange & range)811 void append(const ContiguousRange& range) {
812 append(range.data(), range.data() + range.size());
813 }
814 };
815
816 template <typename T, size_t SIZE, typename Allocator>
grow(size_t size)817 void basic_memory_buffer<T, SIZE, Allocator>::grow(size_t size) {
818 #ifdef FMT_FUZZ
819 if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much");
820 #endif
821 const size_t max_size = std::allocator_traits<Allocator>::max_size(alloc_);
822 size_t old_capacity = this->capacity();
823 size_t new_capacity = old_capacity + old_capacity / 2;
824 if (size > new_capacity)
825 new_capacity = size;
826 else if (new_capacity > max_size)
827 new_capacity = size > max_size ? size : max_size;
828 T* old_data = this->data();
829 T* new_data =
830 std::allocator_traits<Allocator>::allocate(alloc_, new_capacity);
831 // The following code doesn't throw, so the raw pointer above doesn't leak.
832 std::uninitialized_copy(old_data, old_data + this->size(),
833 detail::make_checked(new_data, new_capacity));
834 this->set(new_data, new_capacity);
835 // deallocate must not throw according to the standard, but even if it does,
836 // the buffer already uses the new storage and will deallocate it in
837 // destructor.
838 if (old_data != store_) alloc_.deallocate(old_data, old_capacity);
839 }
840
841 using memory_buffer = basic_memory_buffer<char>;
842 using wmemory_buffer = basic_memory_buffer<wchar_t>;
843
844 template <typename T, size_t SIZE, typename Allocator>
845 struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type {
846 };
847
848 /** A formatting error such as invalid format string. */
849 FMT_CLASS_API
850 class FMT_API format_error : public std::runtime_error {
851 public:
852 explicit format_error(const char* message) : std::runtime_error(message) {}
853 explicit format_error(const std::string& message)
854 : std::runtime_error(message) {}
855 format_error(const format_error&) = default;
856 format_error& operator=(const format_error&) = default;
857 format_error(format_error&&) = default;
858 format_error& operator=(format_error&&) = default;
859 ~format_error() FMT_NOEXCEPT FMT_OVERRIDE;
860 };
861
862 namespace detail {
863
864 template <typename T>
865 using is_signed =
866 std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
867 std::is_same<T, int128_t>::value>;
868
869 // Returns true if value is negative, false otherwise.
870 // Same as `value < 0` but doesn't produce warnings if T is an unsigned type.
871 template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
872 FMT_CONSTEXPR bool is_negative(T value) {
873 return value < 0;
874 }
875 template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
876 FMT_CONSTEXPR bool is_negative(T) {
877 return false;
878 }
879
880 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
881 FMT_CONSTEXPR bool is_supported_floating_point(T) {
882 return (std::is_same<T, float>::value && FMT_USE_FLOAT) ||
883 (std::is_same<T, double>::value && FMT_USE_DOUBLE) ||
884 (std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
885 }
886
887 // Smallest of uint32_t, uint64_t, uint128_t that is large enough to
888 // represent all values of an integral type T.
889 template <typename T>
890 using uint32_or_64_or_128_t =
891 conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
892 uint32_t,
893 conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
894 template <typename T>
895 using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
896
897 // 128-bit integer type used internally
898 struct FMT_EXTERN_TEMPLATE_API uint128_wrapper {
899 uint128_wrapper() = default;
900
901 #if FMT_USE_INT128
902 uint128_t internal_;
903
904 uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT
905 : internal_{static_cast<uint128_t>(low) |
906 (static_cast<uint128_t>(high) << 64)} {}
907
908 uint128_wrapper(uint128_t u) : internal_{u} {}
909
910 uint64_t high() const FMT_NOEXCEPT { return uint64_t(internal_ >> 64); }
911 uint64_t low() const FMT_NOEXCEPT { return uint64_t(internal_); }
912
913 uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT {
914 internal_ += n;
915 return *this;
916 }
917 #else
918 uint64_t high_;
919 uint64_t low_;
920
921 uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT : high_{high},
922 low_{low} {}
923
924 uint64_t high() const FMT_NOEXCEPT { return high_; }
925 uint64_t low() const FMT_NOEXCEPT { return low_; }
926
927 uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT {
928 # if defined(_MSC_VER) && defined(_M_X64)
929 unsigned char carry = _addcarry_u64(0, low_, n, &low_);
930 _addcarry_u64(carry, high_, 0, &high_);
931 return *this;
932 # else
933 uint64_t sum = low_ + n;
934 high_ += (sum < low_ ? 1 : 0);
935 low_ = sum;
936 return *this;
937 # endif
938 }
939 #endif
940 };
941
942 // Table entry type for divisibility test used internally
943 template <typename T> struct FMT_EXTERN_TEMPLATE_API divtest_table_entry {
944 T mod_inv;
945 T max_quotient;
946 };
947
948 // Static data is placed in this class template for the header-only config.
949 template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
950 static const uint64_t powers_of_10_64[];
951 static const uint32_t zero_or_powers_of_10_32_new[];
952 static const uint64_t zero_or_powers_of_10_64_new[];
953 static const uint64_t grisu_pow10_significands[];
954 static const int16_t grisu_pow10_exponents[];
955 static const divtest_table_entry<uint32_t> divtest_table_for_pow5_32[];
956 static const divtest_table_entry<uint64_t> divtest_table_for_pow5_64[];
957 static const uint64_t dragonbox_pow10_significands_64[];
958 static const uint128_wrapper dragonbox_pow10_significands_128[];
959 // log10(2) = 0x0.4d104d427de7fbcc...
960 static const uint64_t log10_2_significand = 0x4d104d427de7fbcc;
961 #if !FMT_USE_FULL_CACHE_DRAGONBOX
962 static const uint64_t powers_of_5_64[];
963 static const uint32_t dragonbox_pow10_recovery_errors[];
964 #endif
965 // GCC generates slightly better code for pairs than chars.
966 using digit_pair = char[2];
967 static const digit_pair digits[];
968 static constexpr const char hex_digits[] = "0123456789abcdef";
969 static const char foreground_color[];
970 static const char background_color[];
971 static const char reset_color[5];
972 static const wchar_t wreset_color[5];
973 static const char signs[];
974 static constexpr const unsigned prefixes[] = {0, 0, 0x1000000u | '+',
975 0x1000000u | ' '};
976 static constexpr const char left_padding_shifts[] = {31, 31, 0, 1, 0};
977 static constexpr const char right_padding_shifts[] = {0, 31, 0, 1, 0};
978
979 // DEPRECATED! These are for ABI compatibility.
980 static const uint32_t zero_or_powers_of_10_32[];
981 static const uint64_t zero_or_powers_of_10_64[];
982 };
983
984 // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
985 // This is a function instead of an array to workaround a bug in GCC10 (#1810).
986 FMT_INLINE uint16_t bsr2log10(int bsr) {
987 static constexpr uint16_t data[] = {
988 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
989 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
990 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
991 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
992 return data[bsr];
993 }
994
995 #ifndef FMT_EXPORTED
996 FMT_EXTERN template struct basic_data<void>;
997 #endif
998
999 // This is a struct rather than an alias to avoid shadowing warnings in gcc.
1000 struct data : basic_data<> {};
1001
1002 template <typename T> FMT_CONSTEXPR int count_digits_fallback(T n) {
1003 int count = 1;
1004 for (;;) {
1005 // Integer division is slow so do it for a group of four digits instead
1006 // of for every digit. The idea comes from the talk by Alexandrescu
1007 // "Three Optimization Tips for C++". See speed-test for a comparison.
1008 if (n < 10) return count;
1009 if (n < 100) return count + 1;
1010 if (n < 1000) return count + 2;
1011 if (n < 10000) return count + 3;
1012 n /= 10000u;
1013 count += 4;
1014 }
1015 }
1016 #if FMT_USE_INT128
1017 FMT_CONSTEXPR inline int count_digits(uint128_t n) {
1018 return count_digits_fallback(n);
1019 }
1020 #endif
1021
1022 // Returns the number of decimal digits in n. Leading zeros are not counted
1023 // except for n == 0 in which case count_digits returns 1.
1024 FMT_CONSTEXPR20 inline int count_digits(uint64_t n) {
1025 if (is_constant_evaluated()) {
1026 return count_digits_fallback(n);
1027 }
1028 #ifdef FMT_BUILTIN_CLZLL
1029 // https://github.com/fmtlib/format-benchmark/blob/master/digits10
1030 auto t = bsr2log10(FMT_BUILTIN_CLZLL(n | 1) ^ 63);
1031 return t - (n < data::zero_or_powers_of_10_64_new[t]);
1032 #else
1033 return count_digits_fallback(n);
1034 #endif
1035 }
1036
1037 // Counts the number of digits in n. BITS = log2(radix).
1038 template <int BITS, typename UInt> FMT_CONSTEXPR int count_digits(UInt n) {
1039 #ifdef FMT_BUILTIN_CLZ
1040 if (num_bits<UInt>() == 32)
1041 return (FMT_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
1042 #endif
1043 int num_digits = 0;
1044 do {
1045 ++num_digits;
1046 } while ((n >>= BITS) != 0);
1047 return num_digits;
1048 }
1049
1050 template <> int count_digits<4>(detail::fallback_uintptr n);
1051
1052 #if FMT_GCC_VERSION || FMT_CLANG_VERSION
1053 # define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
1054 #elif FMT_MSC_VER
1055 # define FMT_ALWAYS_INLINE __forceinline
1056 #else
1057 # define FMT_ALWAYS_INLINE inline
1058 #endif
1059
1060 #ifdef FMT_BUILTIN_CLZ
1061 // Optional version of count_digits for better performance on 32-bit platforms.
1062 FMT_CONSTEXPR20 inline int count_digits(uint32_t n) {
1063 if (is_constant_evaluated()) {
1064 return count_digits_fallback(n);
1065 }
1066 auto t = bsr2log10(FMT_BUILTIN_CLZ(n | 1) ^ 31);
1067 return t - (n < data::zero_or_powers_of_10_32_new[t]);
1068 }
1069 #endif
1070
1071 template <typename Int> constexpr int digits10() FMT_NOEXCEPT {
1072 return std::numeric_limits<Int>::digits10;
1073 }
1074 template <> constexpr int digits10<int128_t>() FMT_NOEXCEPT { return 38; }
1075 template <> constexpr int digits10<uint128_t>() FMT_NOEXCEPT { return 38; }
1076
1077 // DEPRECATED! grouping will be merged into thousands_sep.
1078 template <typename Char> FMT_API std::string grouping_impl(locale_ref loc);
1079 template <typename Char> inline std::string grouping(locale_ref loc) {
1080 return grouping_impl<char>(loc);
1081 }
1082 template <> inline std::string grouping<wchar_t>(locale_ref loc) {
1083 return grouping_impl<wchar_t>(loc);
1084 }
1085
1086 template <typename Char> FMT_API Char thousands_sep_impl(locale_ref loc);
1087 template <typename Char> inline Char thousands_sep(locale_ref loc) {
1088 return Char(thousands_sep_impl<char>(loc));
1089 }
1090 template <> inline wchar_t thousands_sep(locale_ref loc) {
1091 return thousands_sep_impl<wchar_t>(loc);
1092 }
1093
1094 template <typename Char> FMT_API Char decimal_point_impl(locale_ref loc);
1095 template <typename Char> inline Char decimal_point(locale_ref loc) {
1096 return Char(decimal_point_impl<char>(loc));
1097 }
1098 template <> inline wchar_t decimal_point(locale_ref loc) {
1099 return decimal_point_impl<wchar_t>(loc);
1100 }
1101
1102 // Compares two characters for equality.
1103 template <typename Char> bool equal2(const Char* lhs, const char* rhs) {
1104 return lhs[0] == rhs[0] && lhs[1] == rhs[1];
1105 }
1106 inline bool equal2(const char* lhs, const char* rhs) {
1107 return memcmp(lhs, rhs, 2) == 0;
1108 }
1109
1110 // Copies two characters from src to dst.
1111 template <typename Char> void copy2(Char* dst, const char* src) {
1112 *dst++ = static_cast<Char>(*src++);
1113 *dst = static_cast<Char>(*src);
1114 }
1115 FMT_INLINE void copy2(char* dst, const char* src) { memcpy(dst, src, 2); }
1116
1117 template <typename Iterator> struct format_decimal_result {
1118 Iterator begin;
1119 Iterator end;
1120 };
1121
1122 // Formats a decimal unsigned integer value writing into out pointing to a
1123 // buffer of specified size. The caller must ensure that the buffer is large
1124 // enough.
1125 template <typename Char, typename UInt>
1126 FMT_CONSTEXPR20 format_decimal_result<Char*> format_decimal(Char* out,
1127 UInt value,
1128 int size) {
1129 FMT_ASSERT(size >= count_digits(value), "invalid digit count");
1130 out += size;
1131 Char* end = out;
1132 if (is_constant_evaluated()) {
1133 while (value >= 10) {
1134 *--out = static_cast<Char>('0' + value % 10);
1135 value /= 10;
1136 }
1137 *--out = static_cast<Char>('0' + value);
1138 return {out, end};
1139 }
1140 while (value >= 100) {
1141 // Integer division is slow so do it for a group of two digits instead
1142 // of for every digit. The idea comes from the talk by Alexandrescu
1143 // "Three Optimization Tips for C++". See speed-test for a comparison.
1144 out -= 2;
1145 copy2(out, data::digits[value % 100]);
1146 value /= 100;
1147 }
1148 if (value < 10) {
1149 *--out = static_cast<Char>('0' + value);
1150 return {out, end};
1151 }
1152 out -= 2;
1153 copy2(out, data::digits[value]);
1154 return {out, end};
1155 }
1156
1157 template <typename Char, typename UInt, typename Iterator,
1158 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
1159 inline format_decimal_result<Iterator> format_decimal(Iterator out, UInt value,
1160 int size) {
1161 // Buffer is large enough to hold all digits (digits10 + 1).
1162 Char buffer[digits10<UInt>() + 1];
1163 auto end = format_decimal(buffer, value, size).end;
1164 return {out, detail::copy_str<Char>(buffer, end, out)};
1165 }
1166
1167 template <unsigned BASE_BITS, typename Char, typename UInt>
1168 FMT_CONSTEXPR Char* format_uint(Char* buffer, UInt value, int num_digits,
1169 bool upper = false) {
1170 buffer += num_digits;
1171 Char* end = buffer;
1172 do {
1173 const char* digits = upper ? "0123456789ABCDEF" : data::hex_digits;
1174 unsigned digit = (value & ((1 << BASE_BITS) - 1));
1175 *--buffer = static_cast<Char>(BASE_BITS < 4 ? static_cast<char>('0' + digit)
1176 : digits[digit]);
1177 } while ((value >>= BASE_BITS) != 0);
1178 return end;
1179 }
1180
1181 template <unsigned BASE_BITS, typename Char>
1182 Char* format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits,
1183 bool = false) {
1184 auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
1185 int start = (num_digits + char_digits - 1) / char_digits - 1;
1186 if (int start_digits = num_digits % char_digits) {
1187 unsigned value = n.value[start--];
1188 buffer = format_uint<BASE_BITS>(buffer, value, start_digits);
1189 }
1190 for (; start >= 0; --start) {
1191 unsigned value = n.value[start];
1192 buffer += char_digits;
1193 auto p = buffer;
1194 for (int i = 0; i < char_digits; ++i) {
1195 unsigned digit = (value & ((1 << BASE_BITS) - 1));
1196 *--p = static_cast<Char>(data::hex_digits[digit]);
1197 value >>= BASE_BITS;
1198 }
1199 }
1200 return buffer;
1201 }
1202
1203 template <unsigned BASE_BITS, typename Char, typename It, typename UInt>
1204 inline It format_uint(It out, UInt value, int num_digits, bool upper = false) {
1205 if (auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1206 format_uint<BASE_BITS>(ptr, value, num_digits, upper);
1207 return out;
1208 }
1209 // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1).
1210 char buffer[num_bits<UInt>() / BASE_BITS + 1];
1211 format_uint<BASE_BITS>(buffer, value, num_digits, upper);
1212 return detail::copy_str<Char>(buffer, buffer + num_digits, out);
1213 }
1214
1215 // A converter from UTF-8 to UTF-16.
1216 class utf8_to_utf16 {
1217 private:
1218 wmemory_buffer buffer_;
1219
1220 public:
1221 FMT_API explicit utf8_to_utf16(string_view s);
1222 operator wstring_view() const { return {&buffer_[0], size()}; }
1223 size_t size() const { return buffer_.size() - 1; }
1224 const wchar_t* c_str() const { return &buffer_[0]; }
1225 std::wstring str() const { return {&buffer_[0], size()}; }
1226 };
1227
1228 template <typename T = void> struct null {};
1229
1230 // Workaround an array initialization issue in gcc 4.8.
1231 template <typename Char> struct fill_t {
1232 private:
1233 enum { max_size = 4 };
1234 Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)};
1235 unsigned char size_ = 1;
1236
1237 public:
1238 FMT_CONSTEXPR void operator=(basic_string_view<Char> s) {
1239 auto size = s.size();
1240 if (size > max_size) {
1241 FMT_THROW(format_error("invalid fill"));
1242 return;
1243 }
1244 for (size_t i = 0; i < size; ++i) data_[i] = s[i];
1245 size_ = static_cast<unsigned char>(size);
1246 }
1247
1248 constexpr size_t size() const { return size_; }
1249 constexpr const Char* data() const { return data_; }
1250
1251 FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; }
1252 FMT_CONSTEXPR const Char& operator[](size_t index) const {
1253 return data_[index];
1254 }
1255 };
1256 } // namespace detail
1257
1258 // We cannot use enum classes as bit fields because of a gcc bug
1259 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414.
1260 namespace align {
1261 enum type { none, left, right, center, numeric };
1262 }
1263 using align_t = align::type;
1264
1265 namespace sign {
1266 enum type { none, minus, plus, space };
1267 }
1268 using sign_t = sign::type;
1269
1270 // Format specifiers for built-in and string types.
1271 template <typename Char> struct basic_format_specs {
1272 int width;
1273 int precision;
1274 char type;
1275 align_t align : 4;
1276 sign_t sign : 3;
1277 bool alt : 1; // Alternate form ('#').
1278 bool localized : 1;
1279 detail::fill_t<Char> fill;
1280
1281 constexpr basic_format_specs()
1282 : width(0),
1283 precision(-1),
1284 type(0),
1285 align(align::none),
1286 sign(sign::none),
1287 alt(false),
1288 localized(false) {}
1289 };
1290
1291 using format_specs = basic_format_specs<char>;
1292
1293 namespace detail {
1294 namespace dragonbox {
1295
1296 // Type-specific information that Dragonbox uses.
1297 template <class T> struct float_info;
1298
1299 template <> struct float_info<float> {
1300 using carrier_uint = uint32_t;
1301 static const int significand_bits = 23;
1302 static const int exponent_bits = 8;
1303 static const int min_exponent = -126;
1304 static const int max_exponent = 127;
1305 static const int exponent_bias = -127;
1306 static const int decimal_digits = 9;
1307 static const int kappa = 1;
1308 static const int big_divisor = 100;
1309 static const int small_divisor = 10;
1310 static const int min_k = -31;
1311 static const int max_k = 46;
1312 static const int cache_bits = 64;
1313 static const int divisibility_check_by_5_threshold = 39;
1314 static const int case_fc_pm_half_lower_threshold = -1;
1315 static const int case_fc_pm_half_upper_threshold = 6;
1316 static const int case_fc_lower_threshold = -2;
1317 static const int case_fc_upper_threshold = 6;
1318 static const int case_shorter_interval_left_endpoint_lower_threshold = 2;
1319 static const int case_shorter_interval_left_endpoint_upper_threshold = 3;
1320 static const int shorter_interval_tie_lower_threshold = -35;
1321 static const int shorter_interval_tie_upper_threshold = -35;
1322 static const int max_trailing_zeros = 7;
1323 };
1324
1325 template <> struct float_info<double> {
1326 using carrier_uint = uint64_t;
1327 static const int significand_bits = 52;
1328 static const int exponent_bits = 11;
1329 static const int min_exponent = -1022;
1330 static const int max_exponent = 1023;
1331 static const int exponent_bias = -1023;
1332 static const int decimal_digits = 17;
1333 static const int kappa = 2;
1334 static const int big_divisor = 1000;
1335 static const int small_divisor = 100;
1336 static const int min_k = -292;
1337 static const int max_k = 326;
1338 static const int cache_bits = 128;
1339 static const int divisibility_check_by_5_threshold = 86;
1340 static const int case_fc_pm_half_lower_threshold = -2;
1341 static const int case_fc_pm_half_upper_threshold = 9;
1342 static const int case_fc_lower_threshold = -4;
1343 static const int case_fc_upper_threshold = 9;
1344 static const int case_shorter_interval_left_endpoint_lower_threshold = 2;
1345 static const int case_shorter_interval_left_endpoint_upper_threshold = 3;
1346 static const int shorter_interval_tie_lower_threshold = -77;
1347 static const int shorter_interval_tie_upper_threshold = -77;
1348 static const int max_trailing_zeros = 16;
1349 };
1350
1351 template <typename T> struct decimal_fp {
1352 using significand_type = typename float_info<T>::carrier_uint;
1353 significand_type significand;
1354 int exponent;
1355 };
1356
1357 template <typename T> FMT_API decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT;
1358 } // namespace dragonbox
1359
1360 template <typename T>
1361 constexpr typename dragonbox::float_info<T>::carrier_uint exponent_mask() {
1362 using uint = typename dragonbox::float_info<T>::carrier_uint;
1363 return ((uint(1) << dragonbox::float_info<T>::exponent_bits) - 1)
1364 << dragonbox::float_info<T>::significand_bits;
1365 }
1366
1367 // A floating-point presentation format.
1368 enum class float_format : unsigned char {
1369 general, // General: exponent notation or fixed point based on magnitude.
1370 exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
1371 fixed, // Fixed point with the default precision of 6, e.g. 0.0012.
1372 hex
1373 };
1374
1375 struct float_specs {
1376 int precision;
1377 float_format format : 8;
1378 sign_t sign : 8;
1379 bool upper : 1;
1380 bool locale : 1;
1381 bool binary32 : 1;
1382 bool use_grisu : 1;
1383 bool showpoint : 1;
1384 };
1385
1386 // Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
1387 template <typename Char, typename It> It write_exponent(int exp, It it) {
1388 FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range");
1389 if (exp < 0) {
1390 *it++ = static_cast<Char>('-');
1391 exp = -exp;
1392 } else {
1393 *it++ = static_cast<Char>('+');
1394 }
1395 if (exp >= 100) {
1396 const char* top = data::digits[exp / 100];
1397 if (exp >= 1000) *it++ = static_cast<Char>(top[0]);
1398 *it++ = static_cast<Char>(top[1]);
1399 exp %= 100;
1400 }
1401 const char* d = data::digits[exp];
1402 *it++ = static_cast<Char>(d[0]);
1403 *it++ = static_cast<Char>(d[1]);
1404 return it;
1405 }
1406
1407 template <typename T>
1408 int format_float(T value, int precision, float_specs specs, buffer<char>& buf);
1409
1410 // Formats a floating-point number with snprintf.
1411 template <typename T>
1412 int snprintf_float(T value, int precision, float_specs specs,
1413 buffer<char>& buf);
1414
1415 template <typename T> T promote_float(T value) { return value; }
1416 inline double promote_float(float value) { return static_cast<double>(value); }
1417
1418 template <typename ErrorHandler = error_handler, typename Char>
1419 FMT_CONSTEXPR float_specs parse_float_type_spec(
1420 const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) {
1421 auto result = float_specs();
1422 result.showpoint = specs.alt;
1423 result.locale = specs.localized;
1424 switch (specs.type) {
1425 case 0:
1426 result.format = float_format::general;
1427 break;
1428 case 'G':
1429 result.upper = true;
1430 FMT_FALLTHROUGH;
1431 case 'g':
1432 result.format = float_format::general;
1433 break;
1434 case 'E':
1435 result.upper = true;
1436 FMT_FALLTHROUGH;
1437 case 'e':
1438 result.format = float_format::exp;
1439 result.showpoint |= specs.precision != 0;
1440 break;
1441 case 'F':
1442 result.upper = true;
1443 FMT_FALLTHROUGH;
1444 case 'f':
1445 result.format = float_format::fixed;
1446 result.showpoint |= specs.precision != 0;
1447 break;
1448 case 'A':
1449 result.upper = true;
1450 FMT_FALLTHROUGH;
1451 case 'a':
1452 result.format = float_format::hex;
1453 break;
1454 #ifdef FMT_DEPRECATED_N_SPECIFIER
1455 case 'n':
1456 result.locale = true;
1457 break;
1458 #endif
1459 default:
1460 eh.on_error("invalid type specifier");
1461 break;
1462 }
1463 return result;
1464 }
1465
1466 template <typename ErrorHandler>
1467 FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) {
1468 switch (spec) {
1469 case 0:
1470 case 'd':
1471 case 'x':
1472 case 'X':
1473 case 'b':
1474 case 'B':
1475 case 'o':
1476 #ifdef FMT_DEPRECATED_N_SPECIFIER
1477 case 'n':
1478 #endif
1479 case 'c':
1480 break;
1481 default:
1482 eh.on_error("invalid type specifier");
1483 break;
1484 }
1485 }
1486
1487 template <typename Char, typename Handler>
1488 FMT_CONSTEXPR void handle_char_specs(const basic_format_specs<Char>& specs,
1489 Handler&& handler) {
1490 if (specs.type && specs.type != 'c') return handler.on_int();
1491 if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
1492 handler.on_error("invalid format specifier for char");
1493 handler.on_char();
1494 }
1495
1496 template <typename Char, typename Handler>
1497 FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler&& handler) {
1498 if (spec == 0 || spec == 's')
1499 handler.on_string();
1500 else if (spec == 'p')
1501 handler.on_pointer();
1502 else
1503 handler.on_error("invalid type specifier");
1504 }
1505
1506 template <typename Char, typename ErrorHandler>
1507 FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) {
1508 if (spec != 0 && spec != 's') eh.on_error("invalid type specifier");
1509 }
1510
1511 template <typename Char, typename ErrorHandler>
1512 FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
1513 if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier");
1514 }
1515
1516 template <typename ErrorHandler>
1517 class char_specs_checker : public ErrorHandler {
1518 private:
1519 char type_;
1520
1521 public:
1522 FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh)
1523 : ErrorHandler(eh), type_(type) {}
1524
1525 FMT_CONSTEXPR void on_int() { check_int_type_spec(type_, *this); }
1526 FMT_CONSTEXPR void on_char() {}
1527 };
1528
1529 template <typename ErrorHandler>
1530 class cstring_type_checker : public ErrorHandler {
1531 public:
1532 FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh)
1533 : ErrorHandler(eh) {}
1534
1535 FMT_CONSTEXPR void on_string() {}
1536 FMT_CONSTEXPR void on_pointer() {}
1537 };
1538
1539 template <typename OutputIt, typename Char>
1540 FMT_NOINLINE FMT_CONSTEXPR OutputIt fill(OutputIt it, size_t n,
1541 const fill_t<Char>& fill) {
1542 auto fill_size = fill.size();
1543 if (fill_size == 1) return detail::fill_n(it, n, fill[0]);
1544 auto data = fill.data();
1545 for (size_t i = 0; i < n; ++i)
1546 it = copy_str<Char>(data, data + fill_size, it);
1547 return it;
1548 }
1549
1550 // Writes the output of f, padded according to format specifications in specs.
1551 // size: output size in code units.
1552 // width: output display width in (terminal) column positions.
1553 template <align::type align = align::left, typename OutputIt, typename Char,
1554 typename F>
1555 FMT_CONSTEXPR OutputIt write_padded(OutputIt out,
1556 const basic_format_specs<Char>& specs,
1557 size_t size, size_t width, F&& f) {
1558 static_assert(align == align::left || align == align::right, "");
1559 unsigned spec_width = to_unsigned(specs.width);
1560 size_t padding = spec_width > width ? spec_width - width : 0;
1561 auto* shifts = align == align::left ? data::left_padding_shifts
1562 : data::right_padding_shifts;
1563 size_t left_padding = padding >> shifts[specs.align];
1564 size_t right_padding = padding - left_padding;
1565 auto it = reserve(out, size + padding * specs.fill.size());
1566 if (left_padding != 0) it = fill(it, left_padding, specs.fill);
1567 it = f(it);
1568 if (right_padding != 0) it = fill(it, right_padding, specs.fill);
1569 return base_iterator(out, it);
1570 }
1571
1572 template <align::type align = align::left, typename OutputIt, typename Char,
1573 typename F>
1574 constexpr OutputIt write_padded(OutputIt out,
1575 const basic_format_specs<Char>& specs,
1576 size_t size, F&& f) {
1577 return write_padded<align>(out, specs, size, size, f);
1578 }
1579
1580 template <typename Char, typename OutputIt>
1581 OutputIt write_bytes(OutputIt out, string_view bytes,
1582 const basic_format_specs<Char>& specs) {
1583 return write_padded(out, specs, bytes.size(),
1584 [bytes](reserve_iterator<OutputIt> it) {
1585 const char* data = bytes.data();
1586 return copy_str<Char>(data, data + bytes.size(), it);
1587 });
1588 }
1589
1590 template <typename Char, typename OutputIt>
1591 constexpr OutputIt write_char(OutputIt out, Char value,
1592 const basic_format_specs<Char>& specs) {
1593 return write_padded(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
1594 *it++ = value;
1595 return it;
1596 });
1597 }
1598
1599 // Data for write_int that doesn't depend on output iterator type. It is used to
1600 // avoid template code bloat.
1601 template <typename Char> struct write_int_data {
1602 size_t size;
1603 size_t padding;
1604
1605 FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix,
1606 const basic_format_specs<Char>& specs)
1607 : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
1608 if (specs.align == align::numeric) {
1609 auto width = to_unsigned(specs.width);
1610 if (width > size) {
1611 padding = width - size;
1612 size = width;
1613 }
1614 } else if (specs.precision > num_digits) {
1615 size = (prefix >> 24) + to_unsigned(specs.precision);
1616 padding = to_unsigned(specs.precision - num_digits);
1617 }
1618 }
1619 };
1620
1621 // Writes an integer in the format
1622 // <left-padding><prefix><numeric-padding><digits><right-padding>
1623 // where <digits> are written by write_digits(it).
1624 // prefix contains chars in three lower bytes and the size in the fourth byte.
1625 template <typename OutputIt, typename Char, typename W>
1626 FMT_CONSTEXPR FMT_INLINE OutputIt
1627 write_int(OutputIt out, int num_digits, unsigned prefix,
1628 const basic_format_specs<Char>& specs, W write_digits) {
1629 // Slightly faster check for specs.width == 0 && specs.precision == -1.
1630 if ((specs.width | (specs.precision + 1)) == 0) {
1631 auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
1632 if (prefix != 0) {
1633 for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1634 *it++ = static_cast<Char>(p & 0xff);
1635 }
1636 return base_iterator(out, write_digits(it));
1637 }
1638 auto data = write_int_data<Char>(num_digits, prefix, specs);
1639 return write_padded<align::right>(
1640 out, specs, data.size, [=](reserve_iterator<OutputIt> it) {
1641 for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1642 *it++ = static_cast<Char>(p & 0xff);
1643 it = detail::fill_n(it, data.padding, static_cast<Char>('0'));
1644 return write_digits(it);
1645 });
1646 }
1647
1648 template <typename OutputIt, typename UInt, typename Char>
1649 bool write_int_localized(OutputIt& out, UInt value, unsigned prefix,
1650 const basic_format_specs<Char>& specs,
1651 locale_ref loc) {
1652 static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, "");
1653 const auto sep_size = 1;
1654 std::string groups = grouping<Char>(loc);
1655 if (groups.empty()) return false;
1656 auto sep = thousands_sep<Char>(loc);
1657 if (!sep) return false;
1658 int num_digits = count_digits(value);
1659 int size = num_digits, n = num_digits;
1660 std::string::const_iterator group = groups.cbegin();
1661 while (group != groups.cend() && n > *group && *group > 0 &&
1662 *group != max_value<char>()) {
1663 size += sep_size;
1664 n -= *group;
1665 ++group;
1666 }
1667 if (group == groups.cend()) size += sep_size * ((n - 1) / groups.back());
1668 char digits[40];
1669 format_decimal(digits, value, num_digits);
1670 basic_memory_buffer<Char> buffer;
1671 if (prefix != 0) ++size;
1672 const auto usize = to_unsigned(size);
1673 buffer.resize(usize);
1674 basic_string_view<Char> s(&sep, sep_size);
1675 // Index of a decimal digit with the least significant digit having index 0.
1676 int digit_index = 0;
1677 group = groups.cbegin();
1678 auto p = buffer.data() + size - 1;
1679 for (int i = num_digits - 1; i > 0; --i) {
1680 *p-- = static_cast<Char>(digits[i]);
1681 if (*group <= 0 || ++digit_index % *group != 0 ||
1682 *group == max_value<char>())
1683 continue;
1684 if (group + 1 != groups.cend()) {
1685 digit_index = 0;
1686 ++group;
1687 }
1688 std::uninitialized_copy(s.data(), s.data() + s.size(),
1689 make_checked(p, s.size()));
1690 p -= s.size();
1691 }
1692 *p-- = static_cast<Char>(*digits);
1693 if (prefix != 0) *p = static_cast<Char>(prefix);
1694 auto data = buffer.data();
1695 out = write_padded<align::right>(
1696 out, specs, usize, usize, [=](reserve_iterator<OutputIt> it) {
1697 return copy_str<Char>(data, data + size, it);
1698 });
1699 return true;
1700 }
1701
1702 FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) {
1703 prefix |= prefix != 0 ? value << 8 : value;
1704 prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
1705 }
1706
1707 template <typename OutputIt, typename T, typename Char>
1708 FMT_CONSTEXPR OutputIt write_int(OutputIt out, T value,
1709 const basic_format_specs<Char>& specs,
1710 locale_ref loc) {
1711 auto prefix = 0u;
1712 auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
1713 if (is_negative(value)) {
1714 prefix = 0x01000000 | '-';
1715 abs_value = 0 - abs_value;
1716 } else {
1717 prefix = data::prefixes[specs.sign];
1718 }
1719 auto utype = static_cast<unsigned>(specs.type);
1720 switch (specs.type) {
1721 case 0:
1722 case 'd': {
1723 if (specs.localized &&
1724 write_int_localized(out, static_cast<uint64_or_128_t<T>>(abs_value),
1725 prefix, specs, loc)) {
1726 return out;
1727 }
1728 auto num_digits = count_digits(abs_value);
1729 return write_int(
1730 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
1731 return format_decimal<Char>(it, abs_value, num_digits).end;
1732 });
1733 }
1734 case 'x':
1735 case 'X': {
1736 if (specs.alt) prefix_append(prefix, (utype << 8) | '0');
1737 bool upper = specs.type != 'x';
1738 int num_digits = count_digits<4>(abs_value);
1739 return write_int(
1740 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
1741 return format_uint<4, Char>(it, abs_value, num_digits, upper);
1742 });
1743 }
1744 case 'b':
1745 case 'B': {
1746 if (specs.alt) prefix_append(prefix, (utype << 8) | '0');
1747 int num_digits = count_digits<1>(abs_value);
1748 return write_int(out, num_digits, prefix, specs,
1749 [=](reserve_iterator<OutputIt> it) {
1750 return format_uint<1, Char>(it, abs_value, num_digits);
1751 });
1752 }
1753 case 'o': {
1754 int num_digits = count_digits<3>(abs_value);
1755 if (specs.alt && specs.precision <= num_digits && abs_value != 0) {
1756 // Octal prefix '0' is counted as a digit, so only add it if precision
1757 // is not greater than the number of digits.
1758 prefix_append(prefix, '0');
1759 }
1760 return write_int(out, num_digits, prefix, specs,
1761 [=](reserve_iterator<OutputIt> it) {
1762 return format_uint<3, Char>(it, abs_value, num_digits);
1763 });
1764 }
1765 #ifdef FMT_DEPRECATED_N_SPECIFIER
1766 case 'n':
1767 return write_int_localized(out, abs_value, prefix, specs, loc);
1768 #endif
1769 case 'c':
1770 return write_char(out, static_cast<Char>(abs_value), specs);
1771 default:
1772 FMT_THROW(format_error("invalid type specifier"));
1773 }
1774 return out;
1775 }
1776
1777 template <typename OutputIt, typename StrChar, typename Char>
1778 FMT_CONSTEXPR OutputIt write(OutputIt out, basic_string_view<StrChar> s,
1779 const basic_format_specs<Char>& specs) {
1780 auto data = s.data();
1781 auto size = s.size();
1782 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
1783 size = code_point_index(s, to_unsigned(specs.precision));
1784 auto width = specs.width != 0
1785 ? compute_width(basic_string_view<StrChar>(data, size))
1786 : 0;
1787 return write_padded(out, specs, size, width,
1788 [=](reserve_iterator<OutputIt> it) {
1789 return copy_str<Char>(data, data + size, it);
1790 });
1791 }
1792
1793 template <typename Char, typename OutputIt>
1794 OutputIt write_nonfinite(OutputIt out, bool isinf,
1795 const basic_format_specs<Char>& specs,
1796 const float_specs& fspecs) {
1797 auto str =
1798 isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan");
1799 constexpr size_t str_size = 3;
1800 auto sign = fspecs.sign;
1801 auto size = str_size + (sign ? 1 : 0);
1802 return write_padded(out, specs, size, [=](reserve_iterator<OutputIt> it) {
1803 if (sign) *it++ = static_cast<Char>(data::signs[sign]);
1804 return copy_str<Char>(str, str + str_size, it);
1805 });
1806 }
1807
1808 // A decimal floating-point number significand * pow(10, exp).
1809 struct big_decimal_fp {
1810 const char* significand;
1811 int significand_size;
1812 int exponent;
1813 };
1814
1815 inline int get_significand_size(const big_decimal_fp& fp) {
1816 return fp.significand_size;
1817 }
1818 template <typename T>
1819 inline int get_significand_size(const dragonbox::decimal_fp<T>& fp) {
1820 return count_digits(fp.significand);
1821 }
1822
1823 template <typename Char, typename OutputIt>
1824 inline OutputIt write_significand(OutputIt out, const char* significand,
1825 int& significand_size) {
1826 return copy_str<Char>(significand, significand + significand_size, out);
1827 }
1828 template <typename Char, typename OutputIt, typename UInt>
1829 inline OutputIt write_significand(OutputIt out, UInt significand,
1830 int significand_size) {
1831 return format_decimal<Char>(out, significand, significand_size).end;
1832 }
1833
1834 template <typename Char, typename UInt,
1835 FMT_ENABLE_IF(std::is_integral<UInt>::value)>
1836 inline Char* write_significand(Char* out, UInt significand,
1837 int significand_size, int integral_size,
1838 Char decimal_point) {
1839 if (!decimal_point)
1840 return format_decimal(out, significand, significand_size).end;
1841 auto end = format_decimal(out + 1, significand, significand_size).end;
1842 if (integral_size == 1)
1843 out[0] = out[1];
1844 else
1845 std::uninitialized_copy_n(out + 1, integral_size, out);
1846 out[integral_size] = decimal_point;
1847 return end;
1848 }
1849
1850 template <typename OutputIt, typename UInt, typename Char,
1851 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
1852 inline OutputIt write_significand(OutputIt out, UInt significand,
1853 int significand_size, int integral_size,
1854 Char decimal_point) {
1855 // Buffer is large enough to hold digits (digits10 + 1) and a decimal point.
1856 Char buffer[digits10<UInt>() + 2];
1857 auto end = write_significand(buffer, significand, significand_size,
1858 integral_size, decimal_point);
1859 return detail::copy_str<Char>(buffer, end, out);
1860 }
1861
1862 template <typename OutputIt, typename Char>
1863 inline OutputIt write_significand(OutputIt out, const char* significand,
1864 int significand_size, int integral_size,
1865 Char decimal_point) {
1866 out = detail::copy_str<Char>(significand, significand + integral_size, out);
1867 if (!decimal_point) return out;
1868 *out++ = decimal_point;
1869 return detail::copy_str<Char>(significand + integral_size,
1870 significand + significand_size, out);
1871 }
1872
1873 template <typename OutputIt, typename DecimalFP, typename Char>
1874 OutputIt write_float(OutputIt out, const DecimalFP& fp,
1875 const basic_format_specs<Char>& specs, float_specs fspecs,
1876 Char decimal_point) {
1877 auto significand = fp.significand;
1878 int significand_size = get_significand_size(fp);
1879 static const Char zero = static_cast<Char>('0');
1880 auto sign = fspecs.sign;
1881 size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
1882 using iterator = reserve_iterator<OutputIt>;
1883
1884 int output_exp = fp.exponent + significand_size - 1;
1885 auto use_exp_format = [=]() {
1886 if (fspecs.format == float_format::exp) return true;
1887 if (fspecs.format != float_format::general) return false;
1888 // Use the fixed notation if the exponent is in [exp_lower, exp_upper),
1889 // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation.
1890 const int exp_lower = -4, exp_upper = 16;
1891 return output_exp < exp_lower ||
1892 output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper);
1893 };
1894 if (use_exp_format()) {
1895 int num_zeros = 0;
1896 if (fspecs.showpoint) {
1897 num_zeros = fspecs.precision - significand_size;
1898 if (num_zeros < 0) num_zeros = 0;
1899 size += to_unsigned(num_zeros);
1900 } else if (significand_size == 1) {
1901 decimal_point = Char();
1902 }
1903 auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
1904 int exp_digits = 2;
1905 if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
1906
1907 size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
1908 char exp_char = fspecs.upper ? 'E' : 'e';
1909 auto write = [=](iterator it) {
1910 if (sign) *it++ = static_cast<Char>(data::signs[sign]);
1911 // Insert a decimal point after the first digit and add an exponent.
1912 it = write_significand(it, significand, significand_size, 1,
1913 decimal_point);
1914 if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero);
1915 *it++ = static_cast<Char>(exp_char);
1916 return write_exponent<Char>(output_exp, it);
1917 };
1918 return specs.width > 0 ? write_padded<align::right>(out, specs, size, write)
1919 : base_iterator(out, write(reserve(out, size)));
1920 }
1921
1922 int exp = fp.exponent + significand_size;
1923 if (fp.exponent >= 0) {
1924 // 1234e5 -> 123400000[.0+]
1925 size += to_unsigned(fp.exponent);
1926 int num_zeros = fspecs.precision - exp;
1927 #ifdef FMT_FUZZ
1928 if (num_zeros > 5000)
1929 throw std::runtime_error("fuzz mode - avoiding excessive cpu use");
1930 #endif
1931 if (fspecs.showpoint) {
1932 if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1;
1933 if (num_zeros > 0) size += to_unsigned(num_zeros) + 1;
1934 }
1935 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1936 if (sign) *it++ = static_cast<Char>(data::signs[sign]);
1937 it = write_significand<Char>(it, significand, significand_size);
1938 it = detail::fill_n(it, fp.exponent, zero);
1939 if (!fspecs.showpoint) return it;
1940 *it++ = decimal_point;
1941 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
1942 });
1943 } else if (exp > 0) {
1944 // 1234e-2 -> 12.34[0+]
1945 int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
1946 size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0);
1947 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1948 if (sign) *it++ = static_cast<Char>(data::signs[sign]);
1949 it = write_significand(it, significand, significand_size, exp,
1950 decimal_point);
1951 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
1952 });
1953 }
1954 // 1234e-6 -> 0.001234
1955 int num_zeros = -exp;
1956 if (significand_size == 0 && fspecs.precision >= 0 &&
1957 fspecs.precision < num_zeros) {
1958 num_zeros = fspecs.precision;
1959 }
1960 bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint;
1961 size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
1962 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1963 if (sign) *it++ = static_cast<Char>(data::signs[sign]);
1964 *it++ = zero;
1965 if (!pointy) return it;
1966 *it++ = decimal_point;
1967 it = detail::fill_n(it, num_zeros, zero);
1968 return write_significand<Char>(it, significand, significand_size);
1969 });
1970 }
1971
1972 template <typename Char, typename OutputIt, typename T,
1973 FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1974 OutputIt write(OutputIt out, T value, basic_format_specs<Char> specs,
1975 locale_ref loc = {}) {
1976 if (const_check(!is_supported_floating_point(value))) return out;
1977 float_specs fspecs = parse_float_type_spec(specs);
1978 fspecs.sign = specs.sign;
1979 if (std::signbit(value)) { // value < 0 is false for NaN so use signbit.
1980 fspecs.sign = sign::minus;
1981 value = -value;
1982 } else if (fspecs.sign == sign::minus) {
1983 fspecs.sign = sign::none;
1984 }
1985
1986 if (!std::isfinite(value))
1987 return write_nonfinite(out, std::isinf(value), specs, fspecs);
1988
1989 if (specs.align == align::numeric && fspecs.sign) {
1990 auto it = reserve(out, 1);
1991 *it++ = static_cast<Char>(data::signs[fspecs.sign]);
1992 out = base_iterator(out, it);
1993 fspecs.sign = sign::none;
1994 if (specs.width != 0) --specs.width;
1995 }
1996
1997 memory_buffer buffer;
1998 if (fspecs.format == float_format::hex) {
1999 if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]);
2000 snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
2001 return write_bytes(out, {buffer.data(), buffer.size()}, specs);
2002 }
2003 int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
2004 if (fspecs.format == float_format::exp) {
2005 if (precision == max_value<int>())
2006 FMT_THROW(format_error("number is too big"));
2007 else
2008 ++precision;
2009 }
2010 if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
2011 fspecs.use_grisu = is_fast_float<T>();
2012 int exp = format_float(promote_float(value), precision, fspecs, buffer);
2013 fspecs.precision = precision;
2014 Char point =
2015 fspecs.locale ? decimal_point<Char>(loc) : static_cast<Char>('.');
2016 auto fp = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
2017 return write_float(out, fp, specs, fspecs, point);
2018 }
2019
2020 template <typename Char, typename OutputIt, typename T,
2021 FMT_ENABLE_IF(is_fast_float<T>::value)>
2022 OutputIt write(OutputIt out, T value) {
2023 if (const_check(!is_supported_floating_point(value))) return out;
2024
2025 using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
2026 using uint = typename dragonbox::float_info<floaty>::carrier_uint;
2027 auto bits = bit_cast<uint>(value);
2028
2029 auto fspecs = float_specs();
2030 auto sign_bit = bits & (uint(1) << (num_bits<uint>() - 1));
2031 if (sign_bit != 0) {
2032 fspecs.sign = sign::minus;
2033 value = -value;
2034 }
2035
2036 static const auto specs = basic_format_specs<Char>();
2037 uint mask = exponent_mask<floaty>();
2038 if ((bits & mask) == mask)
2039 return write_nonfinite(out, std::isinf(value), specs, fspecs);
2040
2041 auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
2042 return write_float(out, dec, specs, fspecs, static_cast<Char>('.'));
2043 }
2044
2045 template <typename Char, typename OutputIt, typename T,
2046 FMT_ENABLE_IF(std::is_floating_point<T>::value &&
2047 !is_fast_float<T>::value)>
2048 inline OutputIt write(OutputIt out, T value) {
2049 return write(out, value, basic_format_specs<Char>());
2050 }
2051
2052 template <typename Char, typename OutputIt, typename UIntPtr>
2053 OutputIt write_ptr(OutputIt out, UIntPtr value,
2054 const basic_format_specs<Char>* specs) {
2055 int num_digits = count_digits<4>(value);
2056 auto size = to_unsigned(num_digits) + size_t(2);
2057 auto write = [=](reserve_iterator<OutputIt> it) {
2058 *it++ = static_cast<Char>('0');
2059 *it++ = static_cast<Char>('x');
2060 return format_uint<4, Char>(it, value, num_digits);
2061 };
2062 return specs ? write_padded<align::right>(out, *specs, size, write)
2063 : base_iterator(out, write(reserve(out, size)));
2064 }
2065
2066 template <typename T> struct is_integral : std::is_integral<T> {};
2067 template <> struct is_integral<int128_t> : std::true_type {};
2068 template <> struct is_integral<uint128_t> : std::true_type {};
2069
2070 template <typename Char, typename OutputIt>
2071 OutputIt write(OutputIt out, monostate) {
2072 FMT_ASSERT(false, "");
2073 return out;
2074 }
2075
2076 template <typename Char, typename OutputIt,
2077 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
2078 OutputIt write(OutputIt out, string_view value) {
2079 auto it = reserve(out, value.size());
2080 it = copy_str<Char>(value.begin(), value.end(), it);
2081 return base_iterator(out, it);
2082 }
2083
2084 template <typename Char, typename OutputIt>
2085 FMT_CONSTEXPR OutputIt write(OutputIt out, basic_string_view<Char> value) {
2086 auto it = reserve(out, value.size());
2087 it = copy_str<Char>(value.begin(), value.end(), it);
2088 return base_iterator(out, it);
2089 }
2090
2091 template <typename Char, typename OutputIt, typename T,
2092 FMT_ENABLE_IF(is_string<T>::value)>
2093 constexpr OutputIt write(OutputIt out, const T& value) {
2094 return write<Char>(out, to_string_view(value));
2095 }
2096
2097 template <typename Char, typename OutputIt, typename T,
2098 FMT_ENABLE_IF(is_integral<T>::value &&
2099 !std::is_same<T, bool>::value &&
2100 !std::is_same<T, Char>::value)>
2101 FMT_CONSTEXPR OutputIt write(OutputIt out, T value) {
2102 auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
2103 bool negative = is_negative(value);
2104 // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer.
2105 if (negative) abs_value = ~abs_value + 1;
2106 int num_digits = count_digits(abs_value);
2107 auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
2108 auto it = reserve(out, size);
2109 if (auto ptr = to_pointer<Char>(it, size)) {
2110 if (negative) *ptr++ = static_cast<Char>('-');
2111 format_decimal<Char>(ptr, abs_value, num_digits);
2112 return out;
2113 }
2114 if (negative) *it++ = static_cast<Char>('-');
2115 it = format_decimal<Char>(it, abs_value, num_digits).end;
2116 return base_iterator(out, it);
2117 }
2118
2119 // FMT_ENABLE_IF() condition separated to workaround MSVC bug
2120 template <
2121 typename Char, typename OutputIt, typename T,
2122 bool check =
2123 std::is_enum<T>::value && !std::is_same<T, Char>::value &&
2124 mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value !=
2125 type::custom_type,
2126 FMT_ENABLE_IF(check)>
2127 FMT_CONSTEXPR OutputIt write(OutputIt out, T value) {
2128 return write<Char>(
2129 out, static_cast<typename std::underlying_type<T>::type>(value));
2130 }
2131
2132 template <typename Char, typename OutputIt>
2133 constexpr OutputIt write(OutputIt out, bool value) {
2134 return write<Char>(out, string_view(value ? "true" : "false"));
2135 }
2136
2137 template <typename Char, typename OutputIt>
2138 FMT_CONSTEXPR OutputIt write(OutputIt out, Char value) {
2139 auto it = reserve(out, 1);
2140 *it++ = value;
2141 return base_iterator(out, it);
2142 }
2143
2144 template <typename Char, typename OutputIt>
2145 FMT_CONSTEXPR OutputIt write(OutputIt out, const Char* value) {
2146 if (!value) {
2147 FMT_THROW(format_error("string pointer is null"));
2148 } else {
2149 auto length = std::char_traits<Char>::length(value);
2150 out = write(out, basic_string_view<Char>(value, length));
2151 }
2152 return out;
2153 }
2154
2155 template <typename Char, typename OutputIt>
2156 OutputIt write(OutputIt out, const void* value) {
2157 return write_ptr<Char>(out, to_uintptr(value), nullptr);
2158 }
2159
2160 template <typename Char, typename OutputIt, typename T>
2161 auto write(OutputIt out, const T& value) -> typename std::enable_if<
2162 mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value ==
2163 type::custom_type,
2164 OutputIt>::type {
2165 using context_type = basic_format_context<OutputIt, Char>;
2166 using formatter_type =
2167 conditional_t<has_formatter<T, context_type>::value,
2168 typename context_type::template formatter_type<T>,
2169 fallback_formatter<T, Char>>;
2170 context_type ctx(out, {}, {});
2171 return formatter_type().format(value, ctx);
2172 }
2173
2174 // An argument visitor that formats the argument and writes it via the output
2175 // iterator. It's a class and not a generic lambda for compatibility with C++11.
2176 template <typename OutputIt, typename Char> struct default_arg_formatter {
2177 using context = basic_format_context<OutputIt, Char>;
2178
2179 OutputIt out;
2180 basic_format_args<context> args;
2181 locale_ref loc;
2182
2183 template <typename T> OutputIt operator()(T value) {
2184 return write<Char>(out, value);
2185 }
2186
2187 OutputIt operator()(typename basic_format_arg<context>::handle handle) {
2188 basic_format_parse_context<Char> parse_ctx({});
2189 basic_format_context<OutputIt, Char> format_ctx(out, args, loc);
2190 handle.format(parse_ctx, format_ctx);
2191 return format_ctx.out();
2192 }
2193 };
2194
2195 template <typename OutputIt, typename Char,
2196 typename ErrorHandler = error_handler>
2197 class arg_formatter_base {
2198 public:
2199 using iterator = OutputIt;
2200 using char_type = Char;
2201 using format_specs = basic_format_specs<Char>;
2202
2203 private:
2204 iterator out_;
2205 const format_specs& specs_;
2206 locale_ref locale_;
2207
2208 // Attempts to reserve space for n extra characters in the output range.
2209 // Returns a pointer to the reserved range or a reference to out_.
2210 auto reserve(size_t n) -> decltype(detail::reserve(out_, n)) {
2211 return detail::reserve(out_, n);
2212 }
2213
2214 void write(char value) {
2215 auto&& it = reserve(1);
2216 *it++ = value;
2217 }
2218
2219 template <typename Ch, FMT_ENABLE_IF(std::is_same<Ch, Char>::value)>
2220 void write(Ch value) {
2221 out_ = detail::write<Char>(out_, value);
2222 }
2223
2224 void write(string_view value) {
2225 auto&& it = reserve(value.size());
2226 it = copy_str<Char>(value.begin(), value.end(), it);
2227 }
2228 void write(wstring_view value) {
2229 static_assert(std::is_same<Char, wchar_t>::value, "");
2230 auto&& it = reserve(value.size());
2231 it = copy_str<Char>(value.begin(), value.end(), it);
2232 }
2233
2234 template <typename Ch>
2235 void write(const Ch* s, size_t size, const format_specs& specs) {
2236 auto width =
2237 specs.width != 0 ? compute_width(basic_string_view<Ch>(s, size)) : 0;
2238 out_ = write_padded(out_, specs, size, width,
2239 [=](reserve_iterator<OutputIt> it) {
2240 return copy_str<Char>(s, s + size, it);
2241 });
2242 }
2243
2244 template <typename Ch>
2245 FMT_CONSTEXPR void write(basic_string_view<Ch> s,
2246 const format_specs& specs = {}) {
2247 out_ = detail::write(out_, s, specs);
2248 }
2249
2250 void write_pointer(const void* p) {
2251 out_ = write_ptr<char_type>(out_, to_uintptr(p), &specs_);
2252 }
2253
2254 struct char_spec_handler : ErrorHandler {
2255 arg_formatter_base& formatter;
2256 Char value;
2257
2258 constexpr char_spec_handler(arg_formatter_base& f, Char val)
2259 : formatter(f), value(val) {}
2260
2261 FMT_CONSTEXPR void on_int() {
2262 // char is only formatted as int if there are specs.
2263 formatter.out_ =
2264 detail::write_int(formatter.out_, static_cast<int>(value),
2265 formatter.specs_, formatter.locale_);
2266 }
2267 FMT_CONSTEXPR void on_char() {
2268 formatter.out_ = write_char(formatter.out_, value, formatter.specs_);
2269 }
2270 };
2271
2272 struct cstring_spec_handler : error_handler {
2273 arg_formatter_base& formatter;
2274 const Char* value;
2275
2276 cstring_spec_handler(arg_formatter_base& f, const Char* val)
2277 : formatter(f), value(val) {}
2278
2279 void on_string() { formatter.write(value); }
2280 void on_pointer() { formatter.write_pointer(value); }
2281 };
2282
2283 protected:
2284 iterator out() { return out_; }
2285 const format_specs& specs() { return specs_; }
2286
2287 FMT_CONSTEXPR void write(bool value) {
2288 write(string_view(value ? "true" : "false"), specs_);
2289 }
2290
2291 void write(const Char* value) {
2292 if (value)
2293 write(basic_string_view<char_type>(value), specs_);
2294 else
2295 FMT_THROW(format_error("string pointer is null"));
2296 }
2297
2298 public:
2299 constexpr arg_formatter_base(OutputIt out, const format_specs& s, locale_ref loc)
2300 : out_(out), specs_(s), locale_(loc) {}
2301
2302 iterator operator()(monostate) {
2303 FMT_ASSERT(false, "invalid argument type");
2304 return out_;
2305 }
2306
2307 template <typename T, FMT_ENABLE_IF(is_integral<T>::value)>
2308 FMT_CONSTEXPR FMT_INLINE iterator operator()(T value) {
2309 return out_ = detail::write_int(out_, value, specs_, locale_);
2310 }
2311
2312 FMT_CONSTEXPR iterator operator()(Char value) {
2313 handle_char_specs(specs_,
2314 char_spec_handler(*this, static_cast<Char>(value)));
2315 return out_;
2316 }
2317
2318 FMT_CONSTEXPR iterator operator()(bool value) {
2319 if (specs_.type && specs_.type != 's') return (*this)(value ? 1 : 0);
2320 write(value != 0);
2321 return out_;
2322 }
2323
2324 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
2325 iterator operator()(T value) {
2326 if (const_check(is_supported_floating_point(value)))
2327 out_ = detail::write(out_, value, specs_, locale_);
2328 else
2329 FMT_ASSERT(false, "unsupported float argument type");
2330 return out_;
2331 }
2332
2333 iterator operator()(const Char* value) {
2334 handle_cstring_type_spec(specs_.type, cstring_spec_handler(*this, value));
2335 return out_;
2336 }
2337
2338 FMT_CONSTEXPR iterator operator()(basic_string_view<Char> value) {
2339 check_string_type_spec(specs_.type, error_handler());
2340 write(value, specs_);
2341 return out_;
2342 }
2343
2344 iterator operator()(const void* value) {
2345 check_pointer_type_spec(specs_.type, error_handler());
2346 write_pointer(value);
2347 return out_;
2348 }
2349 };
2350
2351 /** The default argument formatter. */
2352 template <typename OutputIt, typename Char>
2353 class arg_formatter : public arg_formatter_base<OutputIt, Char> {
2354 private:
2355 using char_type = Char;
2356 using base = arg_formatter_base<OutputIt, Char>;
2357 using context_type = basic_format_context<OutputIt, Char>;
2358
2359 context_type& ctx_;
2360
2361 public:
2362 using iterator = typename base::iterator;
2363 using format_specs = typename base::format_specs;
2364
2365 /**
2366 \rst
2367 Constructs an argument formatter object.
2368 *ctx* is a reference to the formatting context,
2369 *specs* contains format specifier information for standard argument types.
2370 \endrst
2371 */
2372 constexpr explicit arg_formatter(context_type& ctx, const format_specs& specs)
2373 : base(ctx.out(), specs, ctx.locale()), ctx_(ctx) {}
2374
2375 using base::operator();
2376
2377 iterator operator()(typename basic_format_arg<context_type>::handle) {
2378 // User-defined types are handled separately because they require access to
2379 // the parse context.
2380 return ctx_.out();
2381 }
2382 };
2383
2384 template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
2385 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
2386 }
2387
2388 // Parses the range [begin, end) as an unsigned integer. This function assumes
2389 // that the range is non-empty and the first character is a digit.
2390 template <typename Char, typename ErrorHandler>
2391 FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end,
2392 ErrorHandler&& eh) {
2393 FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
2394 unsigned value = 0;
2395 // Convert to unsigned to prevent a warning.
2396 constexpr unsigned max_int = max_value<int>();
2397 unsigned big = max_int / 10;
2398 do {
2399 // Check for overflow.
2400 if (value > big) {
2401 value = max_int + 1;
2402 break;
2403 }
2404 value = value * 10 + unsigned(*begin - '0');
2405 ++begin;
2406 } while (begin != end && '0' <= *begin && *begin <= '9');
2407 if (value > max_int) eh.on_error("number is too big");
2408 return static_cast<int>(value);
2409 }
2410
2411 template <typename Context> class custom_formatter {
2412 private:
2413 using char_type = typename Context::char_type;
2414
2415 basic_format_parse_context<char_type>& parse_ctx_;
2416 Context& ctx_;
2417
2418 public:
2419 explicit custom_formatter(basic_format_parse_context<char_type>& parse_ctx,
2420 Context& ctx)
2421 : parse_ctx_(parse_ctx), ctx_(ctx) {}
2422
2423 void operator()(typename basic_format_arg<Context>::handle h) const {
2424 h.format(parse_ctx_, ctx_);
2425 }
2426
2427 template <typename T> void operator()(T) const {}
2428 };
2429
2430 template <typename T>
2431 using is_integer =
2432 bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
2433 !std::is_same<T, char>::value &&
2434 !std::is_same<T, wchar_t>::value>;
2435
2436 template <typename ErrorHandler> class width_checker {
2437 public:
2438 explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {}
2439
2440 template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
2441 FMT_CONSTEXPR unsigned long long operator()(T value) {
2442 if (is_negative(value)) handler_.on_error("negative width");
2443 return static_cast<unsigned long long>(value);
2444 }
2445
2446 template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
2447 FMT_CONSTEXPR unsigned long long operator()(T) {
2448 handler_.on_error("width is not integer");
2449 return 0;
2450 }
2451
2452 private:
2453 ErrorHandler& handler_;
2454 };
2455
2456 template <typename ErrorHandler> class precision_checker {
2457 public:
2458 explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {}
2459
2460 template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
2461 FMT_CONSTEXPR unsigned long long operator()(T value) {
2462 if (is_negative(value)) handler_.on_error("negative precision");
2463 return static_cast<unsigned long long>(value);
2464 }
2465
2466 template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
2467 FMT_CONSTEXPR unsigned long long operator()(T) {
2468 handler_.on_error("precision is not integer");
2469 return 0;
2470 }
2471
2472 private:
2473 ErrorHandler& handler_;
2474 };
2475
2476 // A format specifier handler that sets fields in basic_format_specs.
2477 template <typename Char> class specs_setter {
2478 public:
2479 explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs)
2480 : specs_(specs) {}
2481
2482 FMT_CONSTEXPR specs_setter(const specs_setter& other)
2483 : specs_(other.specs_) {}
2484
2485 FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; }
2486 FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
2487 specs_.fill = fill;
2488 }
2489 FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; }
2490 FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; }
2491 FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; }
2492 FMT_CONSTEXPR void on_hash() { specs_.alt = true; }
2493 FMT_CONSTEXPR void on_localized() { specs_.localized = true; }
2494
2495 FMT_CONSTEXPR void on_zero() {
2496 specs_.align = align::numeric;
2497 specs_.fill[0] = Char('0');
2498 }
2499
2500 FMT_CONSTEXPR void on_width(int width) { specs_.width = width; }
2501 FMT_CONSTEXPR void on_precision(int precision) {
2502 specs_.precision = precision;
2503 }
2504 FMT_CONSTEXPR void end_precision() {}
2505
2506 FMT_CONSTEXPR void on_type(Char type) {
2507 specs_.type = static_cast<char>(type);
2508 }
2509
2510 protected:
2511 basic_format_specs<Char>& specs_;
2512 };
2513
2514 template <typename ErrorHandler> class numeric_specs_checker {
2515 public:
2516 FMT_CONSTEXPR numeric_specs_checker(ErrorHandler& eh, detail::type arg_type)
2517 : error_handler_(eh), arg_type_(arg_type) {}
2518
2519 FMT_CONSTEXPR void require_numeric_argument() {
2520 if (!is_arithmetic_type(arg_type_))
2521 error_handler_.on_error("format specifier requires numeric argument");
2522 }
2523
2524 FMT_CONSTEXPR void check_sign() {
2525 require_numeric_argument();
2526 if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
2527 arg_type_ != type::long_long_type && arg_type_ != type::char_type) {
2528 error_handler_.on_error("format specifier requires signed argument");
2529 }
2530 }
2531
2532 FMT_CONSTEXPR void check_precision() {
2533 if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
2534 error_handler_.on_error("precision not allowed for this argument type");
2535 }
2536
2537 private:
2538 ErrorHandler& error_handler_;
2539 detail::type arg_type_;
2540 };
2541
2542 // A format specifier handler that checks if specifiers are consistent with the
2543 // argument type.
2544 template <typename Handler> class specs_checker : public Handler {
2545 private:
2546 numeric_specs_checker<Handler> checker_;
2547
2548 // Suppress an MSVC warning about using this in initializer list.
2549 FMT_CONSTEXPR Handler& error_handler() { return *this; }
2550
2551 public:
2552 FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type)
2553 : Handler(handler), checker_(error_handler(), arg_type) {}
2554
2555 FMT_CONSTEXPR specs_checker(const specs_checker& other)
2556 : Handler(other), checker_(error_handler(), other.arg_type_) {}
2557
2558 FMT_CONSTEXPR void on_align(align_t align) {
2559 if (align == align::numeric) checker_.require_numeric_argument();
2560 Handler::on_align(align);
2561 }
2562
2563 FMT_CONSTEXPR void on_plus() {
2564 checker_.check_sign();
2565 Handler::on_plus();
2566 }
2567
2568 FMT_CONSTEXPR void on_minus() {
2569 checker_.check_sign();
2570 Handler::on_minus();
2571 }
2572
2573 FMT_CONSTEXPR void on_space() {
2574 checker_.check_sign();
2575 Handler::on_space();
2576 }
2577
2578 FMT_CONSTEXPR void on_hash() {
2579 checker_.require_numeric_argument();
2580 Handler::on_hash();
2581 }
2582
2583 FMT_CONSTEXPR void on_localized() {
2584 checker_.require_numeric_argument();
2585 Handler::on_localized();
2586 }
2587
2588 FMT_CONSTEXPR void on_zero() {
2589 checker_.require_numeric_argument();
2590 Handler::on_zero();
2591 }
2592
2593 FMT_CONSTEXPR void end_precision() { checker_.check_precision(); }
2594 };
2595
2596 template <template <typename> class Handler, typename FormatArg,
2597 typename ErrorHandler>
2598 FMT_CONSTEXPR int get_dynamic_spec(FormatArg arg, ErrorHandler eh) {
2599 unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg);
2600 if (value > to_unsigned(max_value<int>())) eh.on_error("number is too big");
2601 return static_cast<int>(value);
2602 }
2603
2604 struct auto_id {};
2605
2606 template <typename Context, typename ID>
2607 FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, ID id) {
2608 auto arg = ctx.arg(id);
2609 if (!arg) ctx.on_error("argument not found");
2610 return arg;
2611 }
2612
2613 // The standard format specifier handler with checking.
2614 template <typename ParseContext, typename Context>
2615 class specs_handler : public specs_setter<typename Context::char_type> {
2616 public:
2617 using char_type = typename Context::char_type;
2618
2619 FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs,
2620 ParseContext& parse_ctx, Context& ctx)
2621 : specs_setter<char_type>(specs),
2622 parse_context_(parse_ctx),
2623 context_(ctx) {}
2624
2625 template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
2626 this->specs_.width = get_dynamic_spec<width_checker>(
2627 get_arg(arg_id), context_.error_handler());
2628 }
2629
2630 template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
2631 this->specs_.precision = get_dynamic_spec<precision_checker>(
2632 get_arg(arg_id), context_.error_handler());
2633 }
2634
2635 void on_error(const char* message) { context_.on_error(message); }
2636
2637 private:
2638 // This is only needed for compatibility with gcc 4.4.
2639 using format_arg = typename Context::format_arg;
2640
2641 FMT_CONSTEXPR format_arg get_arg(auto_id) {
2642 return detail::get_arg(context_, parse_context_.next_arg_id());
2643 }
2644
2645 FMT_CONSTEXPR format_arg get_arg(int arg_id) {
2646 parse_context_.check_arg_id(arg_id);
2647 return detail::get_arg(context_, arg_id);
2648 }
2649
2650 FMT_CONSTEXPR format_arg get_arg(basic_string_view<char_type> arg_id) {
2651 parse_context_.check_arg_id(arg_id);
2652 return detail::get_arg(context_, arg_id);
2653 }
2654
2655 ParseContext& parse_context_;
2656 Context& context_;
2657 };
2658
2659 enum class arg_id_kind { none, index, name };
2660
2661 // An argument reference.
2662 template <typename Char> struct arg_ref {
2663 FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
2664
2665 FMT_CONSTEXPR explicit arg_ref(int index)
2666 : kind(arg_id_kind::index), val(index) {}
2667 FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name)
2668 : kind(arg_id_kind::name), val(name) {}
2669
2670 FMT_CONSTEXPR arg_ref& operator=(int idx) {
2671 kind = arg_id_kind::index;
2672 val.index = idx;
2673 return *this;
2674 }
2675
2676 arg_id_kind kind;
2677 union value {
2678 FMT_CONSTEXPR value(int id = 0) : index{id} {}
2679 FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {}
2680
2681 int index;
2682 basic_string_view<Char> name;
2683 } val;
2684 };
2685
2686 // Format specifiers with width and precision resolved at formatting rather
2687 // than parsing time to allow re-using the same parsed specifiers with
2688 // different sets of arguments (precompilation of format strings).
2689 template <typename Char>
2690 struct dynamic_format_specs : basic_format_specs<Char> {
2691 arg_ref<Char> width_ref;
2692 arg_ref<Char> precision_ref;
2693 };
2694
2695 // Format spec handler that saves references to arguments representing dynamic
2696 // width and precision to be resolved at formatting time.
2697 template <typename ParseContext>
2698 class dynamic_specs_handler
2699 : public specs_setter<typename ParseContext::char_type> {
2700 public:
2701 using char_type = typename ParseContext::char_type;
2702
2703 FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs,
2704 ParseContext& ctx)
2705 : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}
2706
2707 FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other)
2708 : specs_setter<char_type>(other),
2709 specs_(other.specs_),
2710 context_(other.context_) {}
2711
2712 template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
2713 specs_.width_ref = make_arg_ref(arg_id);
2714 }
2715
2716 template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
2717 specs_.precision_ref = make_arg_ref(arg_id);
2718 }
2719
2720 FMT_CONSTEXPR void on_error(const char* message) {
2721 context_.on_error(message);
2722 }
2723
2724 private:
2725 using arg_ref_type = arg_ref<char_type>;
2726
2727 FMT_CONSTEXPR arg_ref_type make_arg_ref(int arg_id) {
2728 context_.check_arg_id(arg_id);
2729 return arg_ref_type(arg_id);
2730 }
2731
2732 FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) {
2733 return arg_ref_type(context_.next_arg_id());
2734 }
2735
2736 FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<char_type> arg_id) {
2737 context_.check_arg_id(arg_id);
2738 basic_string_view<char_type> format_str(
2739 context_.begin(), to_unsigned(context_.end() - context_.begin()));
2740 return arg_ref_type(arg_id);
2741 }
2742
2743 dynamic_format_specs<char_type>& specs_;
2744 ParseContext& context_;
2745 };
2746
2747 template <typename Char, typename IDHandler>
2748 FMT_CONSTEXPR const Char* do_parse_arg_id(const Char* begin, const Char* end,
2749 IDHandler&& handler) {
2750 FMT_ASSERT(begin != end, "");
2751 Char c = *begin;
2752 if (c >= '0' && c <= '9') {
2753 int index = 0;
2754 if (c != '0')
2755 index = parse_nonnegative_int(begin, end, handler);
2756 else
2757 ++begin;
2758 if (begin == end || (*begin != '}' && *begin != ':'))
2759 handler.on_error("invalid format string");
2760 else
2761 handler(index);
2762 return begin;
2763 }
2764 if (!is_name_start(c)) {
2765 handler.on_error("invalid format string");
2766 return begin;
2767 }
2768 auto it = begin;
2769 do {
2770 ++it;
2771 } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9')));
2772 handler(basic_string_view<Char>(begin, to_unsigned(it - begin)));
2773 return it;
2774 }
2775
2776 template <typename Char, typename IDHandler>
2777 FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_arg_id(const Char* begin,
2778 const Char* end,
2779 IDHandler&& handler) {
2780 Char c = *begin;
2781 if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler);
2782 handler();
2783 return begin;
2784 }
2785
2786 // Adapts SpecHandler to IDHandler API for dynamic width.
2787 template <typename SpecHandler, typename Char> struct width_adapter {
2788 explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {}
2789
2790 FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
2791 FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); }
2792 FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
2793 handler.on_dynamic_width(id);
2794 }
2795
2796 FMT_CONSTEXPR void on_error(const char* message) {
2797 handler.on_error(message);
2798 }
2799
2800 SpecHandler& handler;
2801 };
2802
2803 // Adapts SpecHandler to IDHandler API for dynamic precision.
2804 template <typename SpecHandler, typename Char> struct precision_adapter {
2805 explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {}
2806
2807 FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
2808 FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); }
2809 FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
2810 handler.on_dynamic_precision(id);
2811 }
2812
2813 FMT_CONSTEXPR void on_error(const char* message) {
2814 handler.on_error(message);
2815 }
2816
2817 SpecHandler& handler;
2818 };
2819
2820 template <typename Char> constexpr bool is_ascii_letter(Char c) {
2821 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
2822 }
2823
2824 // Converts a character to ASCII. Returns a number > 127 on conversion failure.
2825 template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
2826 constexpr Char to_ascii(Char value) {
2827 return value;
2828 }
2829 template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
2830 constexpr typename std::underlying_type<Char>::type to_ascii(Char value) {
2831 return value;
2832 }
2833
2834 // Parses fill and alignment.
2835 template <typename Char, typename Handler>
2836 FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
2837 Handler&& handler) {
2838 FMT_ASSERT(begin != end, "");
2839 auto align = align::none;
2840 auto p = begin + code_point_length(begin);
2841 if (p >= end) p = begin;
2842 for (;;) {
2843 switch (to_ascii(*p)) {
2844 case '<':
2845 align = align::left;
2846 break;
2847 case '>':
2848 align = align::right;
2849 break;
2850 #if FMT_DEPRECATED_NUMERIC_ALIGN
2851 case '=':
2852 align = align::numeric;
2853 break;
2854 #endif
2855 case '^':
2856 align = align::center;
2857 break;
2858 default:
2859 break;
2860 }
2861 if (align != align::none) {
2862 if (p != begin) {
2863 auto c = *begin;
2864 if (c == '{')
2865 return handler.on_error("invalid fill character '{'"), begin;
2866 handler.on_fill(basic_string_view<Char>(begin, to_unsigned(p - begin)));
2867 begin = p + 1;
2868 } else
2869 ++begin;
2870 handler.on_align(align);
2871 break;
2872 } else if (p == begin) {
2873 break;
2874 }
2875 p = begin;
2876 }
2877 return begin;
2878 }
2879
2880 template <typename Char, typename Handler>
2881 FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end,
2882 Handler&& handler) {
2883 FMT_ASSERT(begin != end, "");
2884 if ('0' <= *begin && *begin <= '9') {
2885 handler.on_width(parse_nonnegative_int(begin, end, handler));
2886 } else if (*begin == '{') {
2887 ++begin;
2888 if (begin != end)
2889 begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler));
2890 if (begin == end || *begin != '}')
2891 return handler.on_error("invalid format string"), begin;
2892 ++begin;
2893 }
2894 return begin;
2895 }
2896
2897 template <typename Char, typename Handler>
2898 FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end,
2899 Handler&& handler) {
2900 ++begin;
2901 auto c = begin != end ? *begin : Char();
2902 if ('0' <= c && c <= '9') {
2903 handler.on_precision(parse_nonnegative_int(begin, end, handler));
2904 } else if (c == '{') {
2905 ++begin;
2906 if (begin != end) {
2907 begin =
2908 parse_arg_id(begin, end, precision_adapter<Handler, Char>(handler));
2909 }
2910 if (begin == end || *begin++ != '}')
2911 return handler.on_error("invalid format string"), begin;
2912 } else {
2913 return handler.on_error("missing precision specifier"), begin;
2914 }
2915 handler.end_precision();
2916 return begin;
2917 }
2918
2919 // Parses standard format specifiers and sends notifications about parsed
2920 // components to handler.
2921 template <typename Char, typename SpecHandler>
2922 FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_format_specs(
2923 const Char* begin, const Char* end, SpecHandler&& handler) {
2924 if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) &&
2925 *begin != 'L') {
2926 handler.on_type(*begin++);
2927 return begin;
2928 }
2929
2930 if (begin == end) return begin;
2931
2932 begin = parse_align(begin, end, handler);
2933 if (begin == end) return begin;
2934
2935 // Parse sign.
2936 switch (to_ascii(*begin)) {
2937 case '+':
2938 handler.on_plus();
2939 ++begin;
2940 break;
2941 case '-':
2942 handler.on_minus();
2943 ++begin;
2944 break;
2945 case ' ':
2946 handler.on_space();
2947 ++begin;
2948 break;
2949 default:
2950 break;
2951 }
2952 if (begin == end) return begin;
2953
2954 if (*begin == '#') {
2955 handler.on_hash();
2956 if (++begin == end) return begin;
2957 }
2958
2959 // Parse zero flag.
2960 if (*begin == '0') {
2961 handler.on_zero();
2962 if (++begin == end) return begin;
2963 }
2964
2965 begin = parse_width(begin, end, handler);
2966 if (begin == end) return begin;
2967
2968 // Parse precision.
2969 if (*begin == '.') {
2970 begin = parse_precision(begin, end, handler);
2971 if (begin == end) return begin;
2972 }
2973
2974 if (*begin == 'L') {
2975 handler.on_localized();
2976 ++begin;
2977 }
2978
2979 // Parse type.
2980 if (begin != end && *begin != '}') handler.on_type(*begin++);
2981 return begin;
2982 }
2983
2984 // Return the result via the out param to workaround gcc bug 77539.
2985 template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
2986 FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr& out) {
2987 for (out = first; out != last; ++out) {
2988 if (*out == value) return true;
2989 }
2990 return false;
2991 }
2992
2993 template <>
2994 inline bool find<false, char>(const char* first, const char* last, char value,
2995 const char*& out) {
2996 out = static_cast<const char*>(
2997 std::memchr(first, value, detail::to_unsigned(last - first)));
2998 return out != nullptr;
2999 }
3000
3001 template <typename Handler, typename Char> struct id_adapter {
3002 Handler& handler;
3003 int arg_id;
3004
3005 FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); }
3006 FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); }
3007 FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
3008 arg_id = handler.on_arg_id(id);
3009 }
3010 FMT_CONSTEXPR void on_error(const char* message) {
3011 handler.on_error(message);
3012 }
3013 };
3014
3015 template <typename Char, typename Handler>
3016 FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
3017 const Char* end,
3018 Handler&& handler) {
3019 ++begin;
3020 if (begin == end) return handler.on_error("invalid format string"), end;
3021 if (*begin == '}') {
3022 handler.on_replacement_field(handler.on_arg_id(), begin);
3023 } else if (*begin == '{') {
3024 handler.on_text(begin, begin + 1);
3025 } else {
3026 auto adapter = id_adapter<Handler, Char>{handler, 0};
3027 begin = parse_arg_id(begin, end, adapter);
3028 Char c = begin != end ? *begin : Char();
3029 if (c == '}') {
3030 handler.on_replacement_field(adapter.arg_id, begin);
3031 } else if (c == ':') {
3032 begin = handler.on_format_specs(adapter.arg_id, begin + 1, end);
3033 if (begin == end || *begin != '}')
3034 return handler.on_error("unknown format specifier"), end;
3035 } else {
3036 return handler.on_error("missing '}' in format string"), end;
3037 }
3038 }
3039 return begin + 1;
3040 }
3041
3042 template <bool IS_CONSTEXPR, typename Char, typename Handler>
3043 FMT_CONSTEXPR_DECL FMT_INLINE void parse_format_string(
3044 basic_string_view<Char> format_str, Handler&& handler) {
3045 auto begin = format_str.data();
3046 auto end = begin + format_str.size();
3047 if (end - begin < 32) {
3048 // Use a simple loop instead of memchr for small strings.
3049 const Char* p = begin;
3050 while (p != end) {
3051 auto c = *p++;
3052 if (c == '{') {
3053 handler.on_text(begin, p - 1);
3054 begin = p = parse_replacement_field(p - 1, end, handler);
3055 } else if (c == '}') {
3056 if (p == end || *p != '}')
3057 return handler.on_error("unmatched '}' in format string");
3058 handler.on_text(begin, p);
3059 begin = ++p;
3060 }
3061 }
3062 handler.on_text(begin, end);
3063 return;
3064 }
3065 struct writer {
3066 FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) {
3067 if (pbegin == pend) return;
3068 for (;;) {
3069 const Char* p = nullptr;
3070 if (!find<IS_CONSTEXPR>(pbegin, pend, '}', p))
3071 return handler_.on_text(pbegin, pend);
3072 ++p;
3073 if (p == pend || *p != '}')
3074 return handler_.on_error("unmatched '}' in format string");
3075 handler_.on_text(pbegin, p);
3076 pbegin = p + 1;
3077 }
3078 }
3079 Handler& handler_;
3080 } write{handler};
3081 while (begin != end) {
3082 // Doing two passes with memchr (one for '{' and another for '}') is up to
3083 // 2.5x faster than the naive one-pass implementation on big format strings.
3084 const Char* p = begin;
3085 if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p))
3086 return write(begin, end);
3087 write(begin, p);
3088 begin = parse_replacement_field(p, end, handler);
3089 }
3090 }
3091
3092 template <typename T, typename ParseContext>
3093 FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
3094 ParseContext& ctx) {
3095 using char_type = typename ParseContext::char_type;
3096 using context = buffer_context<char_type>;
3097 using mapped_type = conditional_t<
3098 detail::mapped_type_constant<T, context>::value != type::custom_type,
3099 decltype(arg_mapper<context>().map(std::declval<const T&>())), T>;
3100 auto f = conditional_t<has_formatter<mapped_type, context>::value,
3101 formatter<mapped_type, char_type>,
3102 detail::fallback_formatter<T, char_type>>();
3103 return f.parse(ctx);
3104 }
3105
3106 template <typename OutputIt, typename Char, typename Context>
3107 struct format_handler : detail::error_handler {
3108 basic_format_parse_context<Char> parse_context;
3109 Context context;
3110
3111 format_handler(OutputIt out, basic_string_view<Char> str,
3112 basic_format_args<Context> format_args, detail::locale_ref loc)
3113 : parse_context(str), context(out, format_args, loc) {}
3114
3115 void on_text(const Char* begin, const Char* end) {
3116 auto text = basic_string_view<Char>(begin, to_unsigned(end - begin));
3117 context.advance_to(write<Char>(context.out(), text));
3118 }
3119
3120 int on_arg_id() { return parse_context.next_arg_id(); }
3121 int on_arg_id(int id) { return parse_context.check_arg_id(id), id; }
3122 int on_arg_id(basic_string_view<Char> id) {
3123 int arg_id = context.arg_id(id);
3124 if (arg_id < 0) on_error("argument not found");
3125 return arg_id;
3126 }
3127
3128 FMT_INLINE void on_replacement_field(int id, const Char*) {
3129 auto arg = get_arg(context, id);
3130 context.advance_to(visit_format_arg(
3131 default_arg_formatter<OutputIt, Char>{context.out(), context.args(),
3132 context.locale()},
3133 arg));
3134 }
3135
3136 const Char* on_format_specs(int id, const Char* begin, const Char* end) {
3137 auto arg = get_arg(context, id);
3138 if (arg.type() == type::custom_type) {
3139 advance_to(parse_context, begin);
3140 visit_format_arg(custom_formatter<Context>(parse_context, context), arg);
3141 return parse_context.begin();
3142 }
3143 auto specs = basic_format_specs<Char>();
3144 using parse_context_t = basic_format_parse_context<Char>;
3145 specs_checker<specs_handler<parse_context_t, Context>> handler(
3146 specs_handler<parse_context_t, Context>(specs, parse_context, context),
3147 arg.type());
3148 begin = parse_format_specs(begin, end, handler);
3149 if (begin == end || *begin != '}') on_error("missing '}' in format string");
3150 context.advance_to(
3151 visit_format_arg(arg_formatter<OutputIt, Char>(context, specs), arg));
3152 return begin;
3153 }
3154 };
3155
3156 // A parse context with extra argument id checks. It is only used at compile
3157 // time because adding checks at runtime would introduce substantial overhead
3158 // and would be redundant since argument ids are checked when arguments are
3159 // retrieved anyway.
3160 template <typename Char, typename ErrorHandler = error_handler>
3161 class compile_parse_context
3162 : public basic_format_parse_context<Char, ErrorHandler> {
3163 private:
3164 int num_args_;
3165 using base = basic_format_parse_context<Char, ErrorHandler>;
3166
3167 public:
3168 explicit FMT_CONSTEXPR compile_parse_context(
3169 basic_string_view<Char> format_str, int num_args = max_value<int>(),
3170 ErrorHandler eh = {})
3171 : base(format_str, eh), num_args_(num_args) {}
3172
3173 FMT_CONSTEXPR int next_arg_id() {
3174 int id = base::next_arg_id();
3175 if (id >= num_args_) this->on_error("argument not found");
3176 return id;
3177 }
3178
3179 FMT_CONSTEXPR void check_arg_id(int id) {
3180 base::check_arg_id(id);
3181 if (id >= num_args_) this->on_error("argument not found");
3182 }
3183 using base::check_arg_id;
3184 };
3185
3186 template <typename Char, typename ErrorHandler, typename... Args>
3187 class format_string_checker {
3188 public:
3189 explicit FMT_CONSTEXPR format_string_checker(
3190 basic_string_view<Char> format_str, ErrorHandler eh)
3191 : context_(format_str, num_args, eh),
3192 parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
3193
3194 FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
3195
3196 FMT_CONSTEXPR int on_arg_id() { return context_.next_arg_id(); }
3197 FMT_CONSTEXPR int on_arg_id(int id) { return context_.check_arg_id(id), id; }
3198 FMT_CONSTEXPR int on_arg_id(basic_string_view<Char>) {
3199 on_error("compile-time checks don't support named arguments");
3200 return 0;
3201 }
3202
3203 FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
3204
3205 FMT_CONSTEXPR const Char* on_format_specs(int id, const Char* begin,
3206 const Char*) {
3207 advance_to(context_, begin);
3208 // id >= 0 check is a workaround for gcc 10 bug (#2065).
3209 return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
3210 }
3211
3212 FMT_CONSTEXPR void on_error(const char* message) {
3213 context_.on_error(message);
3214 }
3215
3216 private:
3217 using parse_context_type = compile_parse_context<Char, ErrorHandler>;
3218 enum { num_args = sizeof...(Args) };
3219
3220 // Format specifier parsing function.
3221 using parse_func = const Char* (*)(parse_context_type&);
3222
3223 parse_context_type context_;
3224 parse_func parse_funcs_[num_args > 0 ? num_args : 1];
3225 };
3226
3227 // Converts string literals to basic_string_view.
3228 template <typename Char, size_t N>
3229 FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view(
3230 const Char (&s)[N]) {
3231 // Remove trailing null character if needed. Won't be present if this is used
3232 // with raw character array (i.e. not defined as a string).
3233 return {s,
3234 N - ((std::char_traits<Char>::to_int_type(s[N - 1]) == 0) ? 1 : 0)};
3235 }
3236
3237 // Converts string_view to basic_string_view.
3238 template <typename Char>
3239 FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view(
3240 const std_string_view<Char>& s) {
3241 return {s.data(), s.size()};
3242 }
3243
3244 #define FMT_STRING_IMPL(s, base) \
3245 [] { \
3246 /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \
3247 /* Use a macro-like name to avoid shadowing warnings. */ \
3248 struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \
3249 using char_type = axom::fmt::remove_cvref_t<decltype(s[0])>; \
3250 FMT_MAYBE_UNUSED FMT_CONSTEXPR \
3251 operator axom::fmt::basic_string_view<char_type>() const { \
3252 return axom::fmt::detail::compile_string_to_view<char_type>(s); \
3253 } \
3254 }; \
3255 return FMT_COMPILE_STRING(); \
3256 }()
3257
3258 /**
3259 \rst
3260 Constructs a compile-time format string from a string literal *s*.
3261
3262 **Example**::
3263
3264 // A compile-time error because 'd' is an invalid specifier for strings.
3265 std::string s = axom::fmt::format(FMT_STRING("{:d}"), "foo");
3266 \endrst
3267 */
3268 #define FMT_STRING(s) FMT_STRING_IMPL(s, axom::fmt::compile_string)
3269
3270 template <typename... Args, typename S,
3271 enable_if_t<(is_compile_string<S>::value), int>>
3272 void check_format_string(S format_str) {
3273 FMT_CONSTEXPR_DECL auto s = to_string_view(format_str);
3274 using checker = format_string_checker<typename S::char_type, error_handler,
3275 remove_cvref_t<Args>...>;
3276 FMT_CONSTEXPR_DECL bool invalid_format =
3277 (parse_format_string<true>(s, checker(s, {})), true);
3278 (void)invalid_format;
3279 }
3280
3281 template <template <typename> class Handler, typename Context>
3282 FMT_CONSTEXPR void handle_dynamic_spec(int& value,
3283 arg_ref<typename Context::char_type> ref,
3284 Context& ctx) {
3285 switch (ref.kind) {
3286 case arg_id_kind::none:
3287 break;
3288 case arg_id_kind::index:
3289 value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.index),
3290 ctx.error_handler());
3291 break;
3292 case arg_id_kind::name:
3293 value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.name),
3294 ctx.error_handler());
3295 break;
3296 }
3297 }
3298
3299 using format_func = void (*)(detail::buffer<char>&, int, string_view);
3300
3301 FMT_API void format_error_code(buffer<char>& out, int error_code,
3302 string_view message) FMT_NOEXCEPT;
3303
3304 FMT_API void report_error(format_func func, int error_code,
3305 string_view message) FMT_NOEXCEPT;
3306 } // namespace detail
3307
3308 template <typename OutputIt, typename Char>
3309 using arg_formatter FMT_DEPRECATED_ALIAS =
3310 detail::arg_formatter<OutputIt, Char>;
3311
3312 /**
3313 An error returned by an operating system or a language runtime,
3314 for example a file opening error.
3315 */
3316 FMT_CLASS_API
3317 class FMT_API system_error : public std::runtime_error {
3318 private:
3319 void init(int err_code, string_view format_str, format_args args);
3320
3321 protected:
3322 int error_code_;
3323
3324 system_error() : std::runtime_error(""), error_code_(0) {}
3325
3326 public:
3327 /**
3328 \rst
3329 Constructs a :class:`axom::fmt::system_error` object with a description
3330 formatted with `axom::fmt::format_system_error`. *message* and additional
3331 arguments passed into the constructor are formatted similarly to
3332 `axom::fmt::format`.
3333
3334 **Example**::
3335
3336 // This throws a system_error with the description
3337 // cannot open file 'madeup': No such file or directory
3338 // or similar (system message may vary).
3339 const char *filename = "madeup";
3340 std::FILE *file = std::fopen(filename, "r");
3341 if (!file)
3342 throw axom::fmt::system_error(errno, "cannot open file '{}'", filename);
3343 \endrst
3344 */
3345 template <typename... Args>
3346 system_error(int error_code, string_view message, const Args&... args)
3347 : std::runtime_error("") {
3348 init(error_code, message, make_format_args(args...));
3349 }
3350 system_error(const system_error&) = default;
3351 system_error& operator=(const system_error&) = default;
3352 system_error(system_error&&) = default;
3353 system_error& operator=(system_error&&) = default;
3354 ~system_error() FMT_NOEXCEPT FMT_OVERRIDE;
3355
3356 int error_code() const { return error_code_; }
3357 };
3358
3359 /**
3360 \rst
3361 Formats an error returned by an operating system or a language runtime,
3362 for example a file opening error, and writes it to *out* in the following
3363 form:
3364
3365 .. parsed-literal::
3366 *<message>*: *<system-message>*
3367
3368 where *<message>* is the passed message and *<system-message>* is
3369 the system message corresponding to the error code.
3370 *error_code* is a system error code as given by ``errno``.
3371 If *error_code* is not a valid error code such as -1, the system message
3372 may look like "Unknown error -1" and is platform-dependent.
3373 \endrst
3374 */
3375 FMT_API void format_system_error(detail::buffer<char>& out, int error_code,
3376 string_view message) FMT_NOEXCEPT;
3377
3378 // Reports a system error without throwing an exception.
3379 // Can be used to report errors from destructors.
3380 FMT_API void report_system_error(int error_code,
3381 string_view message) FMT_NOEXCEPT;
3382
3383 /** Fast integer formatter. */
3384 class format_int {
3385 private:
3386 // Buffer should be large enough to hold all digits (digits10 + 1),
3387 // a sign and a null character.
3388 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
3389 mutable char buffer_[buffer_size];
3390 char* str_;
3391
3392 template <typename UInt> char* format_unsigned(UInt value) {
3393 auto n = static_cast<detail::uint32_or_64_or_128_t<UInt>>(value);
3394 return detail::format_decimal(buffer_, n, buffer_size - 1).begin;
3395 }
3396
3397 template <typename Int> char* format_signed(Int value) {
3398 auto abs_value = static_cast<detail::uint32_or_64_or_128_t<Int>>(value);
3399 bool negative = value < 0;
3400 if (negative) abs_value = 0 - abs_value;
3401 auto begin = format_unsigned(abs_value);
3402 if (negative) *--begin = '-';
3403 return begin;
3404 }
3405
3406 public:
3407 explicit format_int(int value) : str_(format_signed(value)) {}
3408 explicit format_int(long value) : str_(format_signed(value)) {}
3409 explicit format_int(long long value) : str_(format_signed(value)) {}
3410 explicit format_int(unsigned value) : str_(format_unsigned(value)) {}
3411 explicit format_int(unsigned long value) : str_(format_unsigned(value)) {}
3412 explicit format_int(unsigned long long value)
3413 : str_(format_unsigned(value)) {}
3414
3415 /** Returns the number of characters written to the output buffer. */
3416 size_t size() const {
3417 return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
3418 }
3419
3420 /**
3421 Returns a pointer to the output buffer content. No terminating null
3422 character is appended.
3423 */
3424 const char* data() const { return str_; }
3425
3426 /**
3427 Returns a pointer to the output buffer content with terminating null
3428 character appended.
3429 */
3430 const char* c_str() const {
3431 buffer_[buffer_size - 1] = '\0';
3432 return str_;
3433 }
3434
3435 /**
3436 \rst
3437 Returns the content of the output buffer as an ``std::string``.
3438 \endrst
3439 */
3440 std::string str() const { return std::string(str_, size()); }
3441 };
3442
3443 // A formatter specialization for the core types corresponding to detail::type
3444 // constants.
3445 template <typename T, typename Char>
3446 struct formatter<T, Char,
3447 enable_if_t<detail::type_constant<T, Char>::value !=
3448 detail::type::custom_type>> {
3449 FMT_CONSTEXPR formatter() = default;
3450
3451 // Parses format specifiers stopping either at the end of the range or at the
3452 // terminating '}'.
3453 template <typename ParseContext>
3454 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
3455 auto begin = ctx.begin(), end = ctx.end();
3456 if (begin == end) return begin;
3457 using handler_type = detail::dynamic_specs_handler<ParseContext>;
3458 auto type = detail::type_constant<T, Char>::value;
3459 detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
3460 type);
3461 auto it = parse_format_specs(begin, end, handler);
3462 auto eh = ctx.error_handler();
3463 switch (type) {
3464 case detail::type::none_type:
3465 FMT_ASSERT(false, "invalid argument type");
3466 break;
3467 case detail::type::bool_type:
3468 if (!specs_.type || specs_.type == 's') break;
3469 FMT_FALLTHROUGH;
3470 case detail::type::int_type:
3471 case detail::type::uint_type:
3472 case detail::type::long_long_type:
3473 case detail::type::ulong_long_type:
3474 case detail::type::int128_type:
3475 case detail::type::uint128_type:
3476 detail::check_int_type_spec(specs_.type, eh);
3477 break;
3478 case detail::type::char_type:
3479 handle_char_specs(
3480 specs_, detail::char_specs_checker<decltype(eh)>(specs_.type, eh));
3481 break;
3482 case detail::type::float_type:
3483 if (detail::const_check(FMT_USE_FLOAT))
3484 detail::parse_float_type_spec(specs_, eh);
3485 else
3486 FMT_ASSERT(false, "float support disabled");
3487 break;
3488 case detail::type::double_type:
3489 if (detail::const_check(FMT_USE_DOUBLE))
3490 detail::parse_float_type_spec(specs_, eh);
3491 else
3492 FMT_ASSERT(false, "double support disabled");
3493 break;
3494 case detail::type::long_double_type:
3495 if (detail::const_check(FMT_USE_LONG_DOUBLE))
3496 detail::parse_float_type_spec(specs_, eh);
3497 else
3498 FMT_ASSERT(false, "long double support disabled");
3499 break;
3500 case detail::type::cstring_type:
3501 detail::handle_cstring_type_spec(
3502 specs_.type, detail::cstring_type_checker<decltype(eh)>(eh));
3503 break;
3504 case detail::type::string_type:
3505 detail::check_string_type_spec(specs_.type, eh);
3506 break;
3507 case detail::type::pointer_type:
3508 detail::check_pointer_type_spec(specs_.type, eh);
3509 break;
3510 case detail::type::custom_type:
3511 // Custom format specifiers should be checked in parse functions of
3512 // formatter specializations.
3513 break;
3514 }
3515 return it;
3516 }
3517
3518 template <typename FormatContext>
3519 FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
3520 -> decltype(ctx.out()) {
3521 auto specs = specs_;
3522 detail::handle_dynamic_spec<detail::width_checker>(specs.width,
3523 specs.width_ref, ctx);
3524 detail::handle_dynamic_spec<detail::precision_checker>(
3525 specs.precision, specs.precision_ref, ctx);
3526 using af = detail::arg_formatter<typename FormatContext::iterator,
3527 typename FormatContext::char_type>;
3528 return visit_format_arg(af(ctx, specs),
3529 detail::make_arg<FormatContext>(val));
3530 }
3531
3532 private:
3533 detail::dynamic_format_specs<Char> specs_;
3534 };
3535
3536 #define FMT_FORMAT_AS(Type, Base) \
3537 template <typename Char> \
3538 struct formatter<Type, Char> : formatter<Base, Char> { \
3539 template <typename FormatContext> \
3540 auto format(Type const& val, FormatContext& ctx) const \
3541 -> decltype(ctx.out()) { \
3542 return formatter<Base, Char>::format(static_cast<Base>(val), ctx); \
3543 } \
3544 }
3545
3546 FMT_FORMAT_AS(signed char, int);
3547 FMT_FORMAT_AS(unsigned char, unsigned);
3548 FMT_FORMAT_AS(short, int);
3549 FMT_FORMAT_AS(unsigned short, unsigned);
3550 FMT_FORMAT_AS(long, long long);
3551 FMT_FORMAT_AS(unsigned long, unsigned long long);
3552 FMT_FORMAT_AS(Char*, const Char*);
3553 FMT_FORMAT_AS(std::basic_string<Char>, basic_string_view<Char>);
3554 FMT_FORMAT_AS(std::nullptr_t, const void*);
3555 FMT_FORMAT_AS(detail::std_string_view<Char>, basic_string_view<Char>);
3556 #ifdef __cpp_lib_byte
3557 FMT_FORMAT_AS(std::byte, unsigned);
3558 #endif
3559
3560 template <typename Char>
3561 struct formatter<void*, Char> : formatter<const void*, Char> {
3562 template <typename FormatContext>
3563 auto format(void* val, FormatContext& ctx) const -> decltype(ctx.out()) {
3564 return formatter<const void*, Char>::format(val, ctx);
3565 }
3566 };
3567
3568 template <typename Char, size_t N>
3569 struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {
3570 template <typename FormatContext>
3571 FMT_CONSTEXPR auto format(const Char* val, FormatContext& ctx) const
3572 -> decltype(ctx.out()) {
3573 return formatter<basic_string_view<Char>, Char>::format(val, ctx);
3574 }
3575 };
3576
3577 // A formatter for types known only at run time such as variant alternatives.
3578 //
3579 // Usage:
3580 // using variant = std::variant<int, std::string>;
3581 // template <>
3582 // struct formatter<variant>: dynamic_formatter<> {
3583 // auto format(const variant& v, format_context& ctx) {
3584 // return visit([&](const auto& val) {
3585 // return dynamic_formatter<>::format(val, ctx);
3586 // }, v);
3587 // }
3588 // };
3589 template <typename Char = char> class dynamic_formatter {
3590 private:
3591 struct null_handler : detail::error_handler {
3592 void on_align(align_t) {}
3593 void on_plus() {}
3594 void on_minus() {}
3595 void on_space() {}
3596 void on_hash() {}
3597 };
3598
3599 public:
3600 template <typename ParseContext>
3601 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
3602 format_str_ = ctx.begin();
3603 // Checks are deferred to formatting time when the argument type is known.
3604 detail::dynamic_specs_handler<ParseContext> handler(specs_, ctx);
3605 return parse_format_specs(ctx.begin(), ctx.end(), handler);
3606 }
3607
3608 template <typename T, typename FormatContext>
3609 auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
3610 handle_specs(ctx);
3611 detail::specs_checker<null_handler> checker(
3612 null_handler(), detail::mapped_type_constant<T, FormatContext>::value);
3613 checker.on_align(specs_.align);
3614 switch (specs_.sign) {
3615 case sign::none:
3616 break;
3617 case sign::plus:
3618 checker.on_plus();
3619 break;
3620 case sign::minus:
3621 checker.on_minus();
3622 break;
3623 case sign::space:
3624 checker.on_space();
3625 break;
3626 }
3627 if (specs_.alt) checker.on_hash();
3628 if (specs_.precision >= 0) checker.end_precision();
3629 using af = detail::arg_formatter<typename FormatContext::iterator,
3630 typename FormatContext::char_type>;
3631 visit_format_arg(af(ctx, specs_), detail::make_arg<FormatContext>(val));
3632 return ctx.out();
3633 }
3634
3635 private:
3636 template <typename Context> void handle_specs(Context& ctx) {
3637 detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
3638 specs_.width_ref, ctx);
3639 detail::handle_dynamic_spec<detail::precision_checker>(
3640 specs_.precision, specs_.precision_ref, ctx);
3641 }
3642
3643 detail::dynamic_format_specs<Char> specs_;
3644 const Char* format_str_;
3645 };
3646
3647 template <typename Char, typename ErrorHandler>
3648 FMT_CONSTEXPR void advance_to(
3649 basic_format_parse_context<Char, ErrorHandler>& ctx, const Char* p) {
3650 ctx.advance_to(ctx.begin() + (p - &*ctx.begin()));
3651 }
3652
3653 /**
3654 \rst
3655 Converts ``p`` to ``const void*`` for pointer formatting.
3656
3657 **Example**::
3658
3659 auto s = axom::fmt::format("{}", axom::fmt::ptr(p));
3660 \endrst
3661 */
3662 template <typename T> const void* ptr(T p) {
3663 static_assert(std::is_pointer<T>::value, "");
3664 return detail::bit_cast<const void*>(p);
3665 }
3666 template <typename T> const void* ptr(const std::unique_ptr<T>& p) {
3667 return p.get();
3668 }
3669 template <typename T> const void* ptr(const std::shared_ptr<T>& p) {
3670 return p.get();
3671 }
3672
3673 class bytes {
3674 private:
3675 string_view data_;
3676 friend struct formatter<bytes>;
3677
3678 public:
3679 explicit bytes(string_view data) : data_(data) {}
3680 };
3681
3682 template <> struct formatter<bytes> {
3683 private:
3684 detail::dynamic_format_specs<char> specs_;
3685
3686 public:
3687 template <typename ParseContext>
3688 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
3689 using handler_type = detail::dynamic_specs_handler<ParseContext>;
3690 detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
3691 detail::type::string_type);
3692 auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
3693 detail::check_string_type_spec(specs_.type, ctx.error_handler());
3694 return it;
3695 }
3696
3697 template <typename FormatContext>
3698 auto format(bytes b, FormatContext& ctx) -> decltype(ctx.out()) {
3699 detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
3700 specs_.width_ref, ctx);
3701 detail::handle_dynamic_spec<detail::precision_checker>(
3702 specs_.precision, specs_.precision_ref, ctx);
3703 return detail::write_bytes(ctx.out(), b.data_, specs_);
3704 }
3705 };
3706
3707 template <typename It, typename Sentinel, typename Char>
3708 struct arg_join : detail::view {
3709 It begin;
3710 Sentinel end;
3711 basic_string_view<Char> sep;
3712
3713 arg_join(It b, Sentinel e, basic_string_view<Char> s)
3714 : begin(b), end(e), sep(s) {}
3715 };
3716
3717 template <typename It, typename Sentinel, typename Char>
3718 struct formatter<arg_join<It, Sentinel, Char>, Char> {
3719 private:
3720 using value_type = typename std::iterator_traits<It>::value_type;
3721 using formatter_type =
3722 conditional_t<has_formatter<value_type, format_context>::value,
3723 formatter<value_type, Char>,
3724 detail::fallback_formatter<value_type, Char>>;
3725
3726 formatter_type value_formatter_;
3727
3728 public:
3729 template <typename ParseContext>
3730 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
3731 return value_formatter_.parse(ctx);
3732 }
3733
3734 template <typename FormatContext>
3735 auto format(const arg_join<It, Sentinel, Char>& value, FormatContext& ctx)
3736 -> decltype(ctx.out()) {
3737 auto it = value.begin;
3738 auto out = ctx.out();
3739 if (it != value.end) {
3740 out = value_formatter_.format(*it++, ctx);
3741 while (it != value.end) {
3742 out = detail::copy_str<Char>(value.sep.begin(), value.sep.end(), out);
3743 ctx.advance_to(out);
3744 out = value_formatter_.format(*it++, ctx);
3745 }
3746 }
3747 return out;
3748 }
3749 };
3750
3751 /**
3752 Returns an object that formats the iterator range `[begin, end)` with elements
3753 separated by `sep`.
3754 */
3755 template <typename It, typename Sentinel>
3756 arg_join<It, Sentinel, char> join(It begin, Sentinel end, string_view sep) {
3757 return {begin, end, sep};
3758 }
3759
3760 template <typename It, typename Sentinel>
3761 arg_join<It, Sentinel, wchar_t> join(It begin, Sentinel end, wstring_view sep) {
3762 return {begin, end, sep};
3763 }
3764
3765 /**
3766 \rst
3767 Returns an object that formats `range` with elements separated by `sep`.
3768
3769 **Example**::
3770
3771 std::vector<int> v = {1, 2, 3};
3772 axom::fmt::print("{}", axom::fmt::join(v, ", "));
3773 // Output: "1, 2, 3"
3774
3775 ``axom::fmt::join`` applies passed format specifiers to the range elements::
3776
3777 axom::fmt::print("{:02}", axom::fmt::join(v, ", "));
3778 // Output: "01, 02, 03"
3779 \endrst
3780 */
3781 template <typename Range>
3782 arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, char> join(
3783 Range&& range, string_view sep) {
3784 return join(std::begin(range), std::end(range), sep);
3785 }
3786
3787 template <typename Range>
3788 arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, wchar_t> join(
3789 Range&& range, wstring_view sep) {
3790 return join(std::begin(range), std::end(range), sep);
3791 }
3792
3793 /**
3794 \rst
3795 Converts *value* to ``std::string`` using the default format for type *T*.
3796
3797 **Example**::
3798
3799 #include <fmt/format.h>
3800
3801 std::string answer = axom::fmt::to_string(42);
3802 \endrst
3803 */
3804 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
3805 inline std::string to_string(const T& value) {
3806 std::string result;
3807 detail::write<char>(std::back_inserter(result), value);
3808 return result;
3809 }
3810
3811 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
3812 inline std::string to_string(T value) {
3813 // The buffer should be large enough to store the number including the sign or
3814 // "false" for bool.
3815 constexpr int max_size = detail::digits10<T>() + 2;
3816 char buffer[max_size > 5 ? static_cast<unsigned>(max_size) : 5];
3817 char* begin = buffer;
3818 return std::string(begin, detail::write<char>(begin, value));
3819 }
3820
3821 /**
3822 Converts *value* to ``std::wstring`` using the default format for type *T*.
3823 */
3824 template <typename T> inline std::wstring to_wstring(const T& value) {
3825 return format(FMT_STRING(L"{}"), value);
3826 }
3827
3828 template <typename Char, size_t SIZE>
3829 std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) {
3830 auto size = buf.size();
3831 detail::assume(size < std::basic_string<Char>().max_size());
3832 return std::basic_string<Char>(buf.data(), size);
3833 }
3834
3835 template <typename Char>
3836 void detail::vformat_to(
3837 detail::buffer<Char>& buf, basic_string_view<Char> format_str,
3838 basic_format_args<buffer_context<type_identity_t<Char>>> args,
3839 detail::locale_ref loc) {
3840 using iterator = typename buffer_context<Char>::iterator;
3841 auto out = buffer_appender<Char>(buf);
3842 if (format_str.size() == 2 && equal2(format_str.data(), "{}")) {
3843 auto arg = args.get(0);
3844 if (!arg) error_handler().on_error("argument not found");
3845 visit_format_arg(default_arg_formatter<iterator, Char>{out, args, loc},
3846 arg);
3847 return;
3848 }
3849 format_handler<iterator, Char, buffer_context<Char>> h(out, format_str, args,
3850 loc);
3851 parse_format_string<false>(format_str, h);
3852 }
3853
3854 #ifndef FMT_HEADER_ONLY
3855 extern template void detail::vformat_to(detail::buffer<char>&, string_view,
3856 basic_format_args<format_context>,
3857 detail::locale_ref);
3858 namespace detail {
3859
3860 extern template FMT_API std::string grouping_impl<char>(locale_ref loc);
3861 extern template FMT_API std::string grouping_impl<wchar_t>(locale_ref loc);
3862 extern template FMT_API char thousands_sep_impl<char>(locale_ref loc);
3863 extern template FMT_API wchar_t thousands_sep_impl<wchar_t>(locale_ref loc);
3864 extern template FMT_API char decimal_point_impl(locale_ref loc);
3865 extern template FMT_API wchar_t decimal_point_impl(locale_ref loc);
3866 extern template int format_float<double>(double value, int precision,
3867 float_specs specs, buffer<char>& buf);
3868 extern template int format_float<long double>(long double value, int precision,
3869 float_specs specs,
3870 buffer<char>& buf);
3871 int snprintf_float(float value, int precision, float_specs specs,
3872 buffer<char>& buf) = delete;
3873 extern template int snprintf_float<double>(double value, int precision,
3874 float_specs specs,
3875 buffer<char>& buf);
3876 extern template int snprintf_float<long double>(long double value,
3877 int precision,
3878 float_specs specs,
3879 buffer<char>& buf);
3880 } // namespace detail
3881 #endif
3882
3883 template <typename S, typename Char = char_t<S>,
3884 FMT_ENABLE_IF(detail::is_string<S>::value)>
3885 inline void vformat_to(
3886 detail::buffer<Char>& buf, const S& format_str,
3887 basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args) {
3888 return detail::vformat_to(buf, to_string_view(format_str), args);
3889 }
3890
3891 template <typename S, typename... Args, size_t SIZE = inline_buffer_size,
3892 typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
3893 inline typename buffer_context<Char>::iterator format_to(
3894 basic_memory_buffer<Char, SIZE>& buf, const S& format_str, Args&&... args) {
3895 const auto& vargs = axom::fmt::make_args_checked<Args...>(format_str, args...);
3896 detail::vformat_to(buf, to_string_view(format_str), vargs);
3897 return detail::buffer_appender<Char>(buf);
3898 }
3899
3900 template <typename OutputIt, typename Char = char>
3901 using format_context_t = basic_format_context<OutputIt, Char>;
3902
3903 template <typename OutputIt, typename Char = char>
3904 using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>;
3905
3906 template <typename OutputIt, typename Char = typename OutputIt::value_type>
3907 using format_to_n_context FMT_DEPRECATED_ALIAS = buffer_context<Char>;
3908
3909 template <typename OutputIt, typename Char = typename OutputIt::value_type>
3910 using format_to_n_args FMT_DEPRECATED_ALIAS =
3911 basic_format_args<buffer_context<Char>>;
3912
3913 template <typename OutputIt, typename Char, typename... Args>
3914 FMT_DEPRECATED format_arg_store<buffer_context<Char>, Args...>
3915 make_format_to_n_args(const Args&... args) {
3916 return format_arg_store<buffer_context<Char>, Args...>(args...);
3917 }
3918
3919 #if FMT_COMPILE_TIME_CHECKS
3920 template <typename... Args> struct format_string {
3921 string_view str;
3922
3923 template <size_t N> consteval format_string(const char (&s)[N]) : str(s) {
3924 if constexpr (detail::count_named_args<Args...>() == 0) {
3925 using checker = detail::format_string_checker<char, detail::error_handler,
3926 remove_cvref_t<Args>...>;
3927 detail::parse_format_string<true>(string_view(s, N), checker(s, {}));
3928 }
3929 }
3930
3931 template <typename T,
3932 FMT_ENABLE_IF(std::is_constructible_v<string_view, const T&>)>
3933 format_string(const T& s) : str(s) {}
3934 };
3935
3936 template <typename... Args>
3937 FMT_INLINE std::string format(
3938 format_string<std::type_identity_t<Args>...> format_str, Args&&... args) {
3939 return detail::vformat(format_str.str, make_format_args(args...));
3940 }
3941 #endif
3942
3943 template <typename Char, enable_if_t<(!std::is_same<Char, char>::value), int>>
3944 std::basic_string<Char> detail::vformat(
3945 basic_string_view<Char> format_str,
3946 basic_format_args<buffer_context<type_identity_t<Char>>> args) {
3947 basic_memory_buffer<Char> buffer;
3948 detail::vformat_to(buffer, format_str, args);
3949 return to_string(buffer);
3950 }
3951
3952 template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>
3953 void vprint(std::FILE* f, basic_string_view<Char> format_str,
3954 wformat_args args) {
3955 wmemory_buffer buffer;
3956 detail::vformat_to(buffer, format_str, args);
3957 buffer.push_back(L'\0');
3958 if (std::fputws(buffer.data(), f) == -1)
3959 FMT_THROW(system_error(errno, "cannot write to file"));
3960 }
3961
3962 template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>
3963 void vprint(basic_string_view<Char> format_str, wformat_args args) {
3964 vprint(stdout, format_str, args);
3965 }
3966
3967 #if FMT_USE_USER_DEFINED_LITERALS
3968 namespace detail {
3969 template <typename Char> struct udl_formatter {
3970 basic_string_view<Char> str;
3971
3972 template <typename... Args>
3973 std::basic_string<Char> operator()(Args&&... args) const {
3974 return format(str, std::forward<Args>(args)...);
3975 }
3976 };
3977
3978 template <typename Char> struct udl_arg {
3979 const Char* str;
3980
3981 template <typename T> named_arg<Char, T> operator=(T&& value) const {
3982 return {str, std::forward<T>(value)};
3983 }
3984 };
3985 } // namespace detail
3986
3987 inline namespace literals {
3988 /**
3989 \rst
3990 User-defined literal equivalent of :func:`axom::fmt::format`.
3991
3992 **Example**::
3993
3994 using namespace axom::fmt::literals;
3995 std::string message = "The answer is {}"_format(42);
3996 \endrst
3997 */
3998 constexpr detail::udl_formatter<char> operator"" _format(const char* s,
3999 size_t n) {
4000 return {{s, n}};
4001 }
4002 constexpr detail::udl_formatter<wchar_t> operator"" _format(const wchar_t* s,
4003 size_t n) {
4004 return {{s, n}};
4005 }
4006
4007 /**
4008 \rst
4009 User-defined literal equivalent of :func:`axom::fmt::arg`.
4010
4011 **Example**::
4012
4013 using namespace axom::fmt::literals;
4014 axom::fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
4015 \endrst
4016 */
4017 constexpr detail::udl_arg<char> operator"" _a(const char* s, size_t) {
4018 return {s};
4019 }
4020 constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
4021 return {s};
4022 }
4023 } // namespace literals
4024 #endif // FMT_USE_USER_DEFINED_LITERALS
4025 FMT_END_NAMESPACE
4026
4027 #ifdef FMT_HEADER_ONLY
4028 # define FMT_FUNC inline
4029 # include "format-inl.h"
4030 #else
4031 # define FMT_FUNC
4032 #endif
4033
4034 #endif // FMT_FORMAT_H_
4035