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