blob: f00833ec309f0fd9b5a0187d9436134e5b5119ae [file] [log] [blame]
Victor Zverovichb076df42012-12-07 08:31:09 -08001/*
Victor Zverovichfaccb4c2012-12-12 07:44:41 -08002 String formatting library for C++
3
4 Copyright (c) 2012, Victor Zverovich
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Victor Zverovichb076df42012-12-07 08:31:09 -080026 */
27
Victor Zverovichd53f2092012-12-16 15:06:31 -080028// Disable useless MSVC warnings.
Victor Zverovichf8c91062012-12-17 15:41:00 -080029#undef _CRT_SECURE_NO_WARNINGS
Victor Zverovichd53f2092012-12-16 15:06:31 -080030#define _CRT_SECURE_NO_WARNINGS
Victor Zverovichc240a122012-12-21 15:02:25 -080031#undef _SCL_SECURE_NO_WARNINGS
32#define _SCL_SECURE_NO_WARNINGS
Victor Zverovichd53f2092012-12-16 15:06:31 -080033
Victor Zverovichfbfedcf2013-01-14 15:16:20 -080034#include "format.h"
35
Victor Zverovich72f896d2012-12-12 09:17:28 -080036#include <cctype>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070037#include <cmath>
38
39namespace {
40
41#ifndef _MSC_VER
42
43inline int SignBit(double value) {
44 // When compiled in C++11 mode signbit is no longer a macro but a function
45 // defined in namespace std and the macro is undefined.
46 using namespace std;
47 return signbit(value);
48}
49
50inline int IsInf(double x) {
51#ifdef isinf
52 return isinf(x);
53#else
54 return std::isinf(x);
55#endif
56}
57
58#define FMT_SNPRINTF snprintf
59
60#else
61
62inline int SignBit(double value) {
63 if (value < 0) return 1;
64 if (value == value) return 0;
65 int dec = 0, sign = 0;
66 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
67 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
68 return sign;
69}
70
71inline int IsInf(double x) { return !_finite(x); }
72
73#define FMT_SNPRINTF sprintf_s
74
75#endif // _MSC_VER
76
77template <typename Char>
78struct CharTraits;
79
80template <>
81struct CharTraits<char> {
82 template <typename T>
83 static int FormatFloat(char *buffer, std::size_t size,
84 const char *format, unsigned width, int precision, T value) {
85 if (width == 0) {
86 return precision < 0 ?
87 FMT_SNPRINTF(buffer, size, format, value) :
88 FMT_SNPRINTF(buffer, size, format, precision, value);
89 }
90 return precision < 0 ?
91 FMT_SNPRINTF(buffer, size, format, width, value) :
92 FMT_SNPRINTF(buffer, size, format, width, precision, value);
93 }
94};
95
96template <>
97struct CharTraits<wchar_t> {
98 template <typename T>
99 static int FormatFloat(wchar_t *buffer, std::size_t size,
100 const wchar_t *format, unsigned width, int precision, T value) {
101 if (width == 0) {
102 return precision < 0 ?
103 swprintf(buffer, size, format, value) :
104 swprintf(buffer, size, format, precision, value);
105 }
106 return precision < 0 ?
107 swprintf(buffer, size, format, width, value) :
108 swprintf(buffer, size, format, width, precision, value);
109 }
110};
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800111
Victor Zverovich93e41252013-09-08 13:07:04 -0700112const char DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800113 "0001020304050607080910111213141516171819"
114 "2021222324252627282930313233343536373839"
115 "4041424344454647484950515253545556575859"
116 "6061626364656667686970717273747576777879"
117 "8081828384858687888990919293949596979899";
Victor Zverovich93e41252013-09-08 13:07:04 -0700118}
Victor Zverovich877abaf2013-01-08 09:56:05 -0800119
Victor Zverovich687301c2013-01-26 16:07:28 -0800120void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800121 if (std::isprint(static_cast<unsigned char>(code))) {
122 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800123 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800124 }
125 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800126 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800127 << static_cast<unsigned>(code) << type));
128}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700129
130
131// Fills the padding around the content and returns the pointer to the
132// content area.
133template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700134typename fmt::BasicWriter<Char>::CharPtr
135 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
136 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700137 std::size_t padding = total_size - content_size;
138 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700139 Char fill_char = static_cast<Char>(fill);
140 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700141 buffer += left_padding;
142 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700143 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700144 return content;
145}
146
147template <typename Char>
148void fmt::BasicWriter<Char>::FormatDecimal(
149 CharPtr buffer, uint64_t value, unsigned num_digits) {
150 --num_digits;
151 while (value >= 100) {
152 // Integer division is slow so do it for a group of two digits instead
153 // of for every digit. The idea comes from the talk by Alexandrescu
154 // "Three Optimization Tips for C++". See speed-test for a comparison.
155 unsigned index = (value % 100) * 2;
156 value /= 100;
Victor Zverovich93e41252013-09-08 13:07:04 -0700157 buffer[num_digits] = DIGITS[index + 1];
158 buffer[num_digits - 1] = DIGITS[index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700159 num_digits -= 2;
160 }
161 if (value < 10) {
162 *buffer = static_cast<char>('0' + value);
163 return;
164 }
165 unsigned index = static_cast<unsigned>(value * 2);
Victor Zverovich93e41252013-09-08 13:07:04 -0700166 buffer[1] = DIGITS[index + 1];
167 buffer[0] = DIGITS[index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700168}
169
170template <typename Char>
171typename fmt::BasicWriter<Char>::CharPtr
172 fmt::BasicWriter<Char>::PrepareFilledBuffer(
173 unsigned size, const AlignSpec &spec, char sign) {
174 unsigned width = spec.width();
175 if (width <= size) {
176 CharPtr p = GrowBuffer(size);
177 *p = sign;
178 return p + size - 1;
179 }
180 CharPtr p = GrowBuffer(width);
181 CharPtr end = p + width;
182 Alignment align = spec.align();
Victor Zverovich563a5752013-09-08 13:47:06 -0700183 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700184 if (align == ALIGN_LEFT) {
185 *p = sign;
186 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700187 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700188 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700189 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700190 *p = sign;
191 p += size;
192 } else {
193 if (align == ALIGN_NUMERIC) {
194 if (sign) {
195 *p++ = sign;
196 --size;
197 }
198 } else {
199 *(end - size) = sign;
200 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700201 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700202 p = end;
203 }
204 return p - 1;
205}
206
207template <typename Char>
208template <typename T>
209void fmt::BasicWriter<Char>::FormatDouble(
210 T value, const FormatSpec &spec, int precision) {
211 // Check type.
212 char type = spec.type();
213 bool upper = false;
214 switch (type) {
215 case 0:
216 type = 'g';
217 break;
218 case 'e': case 'f': case 'g':
219 break;
220 case 'F':
221#ifdef _MSC_VER
222 // MSVC's printf doesn't support 'F'.
223 type = 'f';
224#endif
225 // Fall through.
226 case 'E': case 'G':
227 upper = true;
228 break;
229 default:
230 internal::ReportUnknownType(type, "double");
231 break;
232 }
233
234 char sign = 0;
235 // Use SignBit instead of value < 0 because the latter is always
236 // false for NaN.
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700237 if (SignBit(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700238 sign = '-';
239 value = -value;
240 } else if (spec.sign_flag()) {
241 sign = spec.plus_flag() ? '+' : ' ';
242 }
243
244 if (value != value) {
245 // Format NaN ourselves because sprintf's output is not consistent
246 // across platforms.
247 std::size_t size = 4;
248 const char *nan = upper ? " NAN" : " nan";
249 if (!sign) {
250 --size;
251 ++nan;
252 }
253 CharPtr out = FormatString(nan, size, spec);
254 if (sign)
255 *out = sign;
256 return;
257 }
258
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700259 if (IsInf(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700260 // Format infinity ourselves because sprintf's output is not consistent
261 // across platforms.
262 std::size_t size = 4;
263 const char *inf = upper ? " INF" : " inf";
264 if (!sign) {
265 --size;
266 ++inf;
267 }
268 CharPtr out = FormatString(inf, size, spec);
269 if (sign)
270 *out = sign;
271 return;
272 }
273
274 std::size_t offset = buffer_.size();
275 unsigned width = spec.width();
276 if (sign) {
277 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
278 if (width > 0)
279 --width;
280 ++offset;
281 }
282
283 // Build format string.
284 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
285 Char format[MAX_FORMAT_SIZE];
286 Char *format_ptr = format;
287 *format_ptr++ = '%';
288 unsigned width_for_sprintf = width;
289 if (spec.hash_flag())
290 *format_ptr++ = '#';
291 if (spec.align() == ALIGN_CENTER) {
292 width_for_sprintf = 0;
293 } else {
294 if (spec.align() == ALIGN_LEFT)
295 *format_ptr++ = '-';
296 if (width != 0)
297 *format_ptr++ = '*';
298 }
299 if (precision >= 0) {
300 *format_ptr++ = '.';
301 *format_ptr++ = '*';
302 }
303 if (internal::IsLongDouble<T>::VALUE)
304 *format_ptr++ = 'L';
305 *format_ptr++ = type;
306 *format_ptr = '\0';
307
308 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700309 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700310 for (;;) {
311 std::size_t size = buffer_.capacity() - offset;
312 Char *start = &buffer_[offset];
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700313 int n = CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700314 start, size, format, width_for_sprintf, precision, value);
315 if (n >= 0 && offset + n < buffer_.capacity()) {
316 if (sign) {
317 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
318 *start != ' ') {
319 *(start - 1) = sign;
320 sign = 0;
321 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700322 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700323 }
324 ++n;
325 }
326 if (spec.align() == ALIGN_CENTER &&
327 spec.width() > static_cast<unsigned>(n)) {
328 unsigned width = spec.width();
329 CharPtr p = GrowBuffer(width);
330 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700331 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700332 return;
333 }
334 if (spec.fill() != ' ' || sign) {
335 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700336 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700337 if (sign)
338 *(start - 1) = sign;
339 }
340 GrowBuffer(n);
341 return;
342 }
343 buffer_.reserve(n >= 0 ? offset + n + 1 : 2 * buffer_.capacity());
344 }
345}
346
347// Throws Exception(message) if format contains '}', otherwise throws
348// FormatError reporting unmatched '{'. The idea is that unmatched '{'
349// should override other errors.
350template <typename Char>
351void fmt::BasicFormatter<Char>::ReportError(
352 const Char *s, StringRef message) const {
353 for (int num_open_braces = num_open_braces_; *s; ++s) {
354 if (*s == '{') {
355 ++num_open_braces;
356 } else if (*s == '}') {
357 if (--num_open_braces == 0)
358 throw fmt::FormatError(message);
359 }
360 }
361 throw fmt::FormatError("unmatched '{' in format");
362}
363
364// Parses an unsigned integer advancing s to the end of the parsed input.
365// This function assumes that the first character of s is a digit.
366template <typename Char>
367unsigned fmt::BasicFormatter<Char>::ParseUInt(const Char *&s) const {
368 assert('0' <= *s && *s <= '9');
369 unsigned value = 0;
370 do {
371 unsigned new_value = value * 10 + (*s++ - '0');
372 if (new_value < value) // Check if value wrapped around.
373 ReportError(s, "number is too big in format");
374 value = new_value;
375 } while ('0' <= *s && *s <= '9');
376 return value;
377}
378
379template <typename Char>
380inline const typename fmt::BasicFormatter<Char>::Arg
381 &fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) {
382 unsigned arg_index = 0;
383 if (*s < '0' || *s > '9') {
384 if (*s != '}' && *s != ':')
385 ReportError(s, "invalid argument index in format string");
386 if (next_arg_index_ < 0) {
387 ReportError(s,
388 "cannot switch from manual to automatic argument indexing");
389 }
390 arg_index = next_arg_index_++;
391 } else {
392 if (next_arg_index_ > 0) {
393 ReportError(s,
394 "cannot switch from automatic to manual argument indexing");
395 }
396 next_arg_index_ = -1;
397 arg_index = ParseUInt(s);
398 }
399 if (arg_index >= args_.size())
400 ReportError(s, "argument index is out of range in format");
401 return *args_[arg_index];
402}
403
404template <typename Char>
405void fmt::BasicFormatter<Char>::CheckSign(const Char *&s, const Arg &arg) {
406 if (arg.type > LAST_NUMERIC_TYPE) {
407 ReportError(s,
408 Format("format specifier '{0}' requires numeric argument") << *s);
409 }
410 if (arg.type == UINT || arg.type == ULONG) {
411 ReportError(s,
412 Format("format specifier '{0}' requires signed argument") << *s);
413 }
414 ++s;
415}
416
417template <typename Char>
418void fmt::BasicFormatter<Char>::DoFormat() {
419 const Char *start = format_;
420 format_ = 0;
421 next_arg_index_ = 0;
422 const Char *s = start;
423 typedef internal::Array<Char, BasicWriter<Char>::INLINE_BUFFER_SIZE> Buffer;
424 BasicWriter<Char> &writer = *writer_;
425 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700426 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700427 if (c != '{' && c != '}') continue;
428 if (*s == c) {
429 writer.buffer_.append(start, s);
430 start = ++s;
431 continue;
432 }
433 if (c == '}')
434 throw FormatError("unmatched '}' in format");
435 num_open_braces_= 1;
436 writer.buffer_.append(start, s - 1);
437
438 const Arg &arg = ParseArgIndex(s);
439
440 FormatSpec spec;
441 int precision = -1;
442 if (*s == ':') {
443 ++s;
444
445 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700446 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700447 const Char *p = s + 1;
448 spec.align_ = ALIGN_DEFAULT;
449 do {
450 switch (*p) {
451 case '<':
452 spec.align_ = ALIGN_LEFT;
453 break;
454 case '>':
455 spec.align_ = ALIGN_RIGHT;
456 break;
457 case '=':
458 spec.align_ = ALIGN_NUMERIC;
459 break;
460 case '^':
461 spec.align_ = ALIGN_CENTER;
462 break;
463 }
464 if (spec.align_ != ALIGN_DEFAULT) {
465 if (p != s) {
466 if (c == '}') break;
467 if (c == '{')
468 ReportError(s, "invalid fill character '{'");
469 s += 2;
470 spec.fill_ = c;
471 } else ++s;
472 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
473 ReportError(s, "format specifier '=' requires numeric argument");
474 break;
475 }
476 } while (--p >= s);
477 }
478
479 // Parse sign.
480 switch (*s) {
481 case '+':
482 CheckSign(s, arg);
483 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
484 break;
485 case '-':
486 CheckSign(s, arg);
487 break;
488 case ' ':
489 CheckSign(s, arg);
490 spec.flags_ |= SIGN_FLAG;
491 break;
492 }
493
494 if (*s == '#') {
495 if (arg.type > LAST_NUMERIC_TYPE)
496 ReportError(s, "format specifier '#' requires numeric argument");
497 spec.flags_ |= HASH_FLAG;
498 ++s;
499 }
500
501 // Parse width and zero flag.
502 if ('0' <= *s && *s <= '9') {
503 if (*s == '0') {
504 if (arg.type > LAST_NUMERIC_TYPE)
505 ReportError(s, "format specifier '0' requires numeric argument");
506 spec.align_ = ALIGN_NUMERIC;
507 spec.fill_ = '0';
508 }
509 // Zero may be parsed again as a part of the width, but it is simpler
510 // and more efficient than checking if the next char is a digit.
511 unsigned value = ParseUInt(s);
512 if (value > INT_MAX)
513 ReportError(s, "number is too big in format");
514 spec.width_ = value;
515 }
516
517 // Parse precision.
518 if (*s == '.') {
519 ++s;
520 precision = 0;
521 if ('0' <= *s && *s <= '9') {
522 unsigned value = ParseUInt(s);
523 if (value > INT_MAX)
524 ReportError(s, "number is too big in format");
525 precision = value;
526 } else if (*s == '{') {
527 ++s;
528 ++num_open_braces_;
529 const Arg &precision_arg = ParseArgIndex(s);
530 unsigned long value = 0;
531 switch (precision_arg.type) {
532 case INT:
533 if (precision_arg.int_value < 0)
534 ReportError(s, "negative precision in format");
535 value = precision_arg.int_value;
536 break;
537 case UINT:
538 value = precision_arg.uint_value;
539 break;
540 case LONG:
541 if (precision_arg.long_value < 0)
542 ReportError(s, "negative precision in format");
543 value = precision_arg.long_value;
544 break;
545 case ULONG:
546 value = precision_arg.ulong_value;
547 break;
548 default:
549 ReportError(s, "precision is not integer");
550 }
551 if (value > INT_MAX)
552 ReportError(s, "number is too big in format");
553 precision = value;
554 if (*s++ != '}')
555 throw FormatError("unmatched '{' in format");
556 --num_open_braces_;
557 } else {
558 ReportError(s, "missing precision in format");
559 }
560 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
561 ReportError(s,
562 "precision specifier requires floating-point argument");
563 }
564 }
565
566 // Parse type.
567 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700568 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700569 }
570
571 if (*s++ != '}')
572 throw FormatError("unmatched '{' in format");
573 start = s;
574
575 // Format argument.
576 switch (arg.type) {
577 case INT:
578 writer.FormatInt(arg.int_value, spec);
579 break;
580 case UINT:
581 writer.FormatInt(arg.uint_value, spec);
582 break;
583 case LONG:
584 writer.FormatInt(arg.long_value, spec);
585 break;
586 case ULONG:
587 writer.FormatInt(arg.ulong_value, spec);
588 break;
589 case DOUBLE:
590 writer.FormatDouble(arg.double_value, spec, precision);
591 break;
592 case LONG_DOUBLE:
593 writer.FormatDouble(arg.long_double_value, spec, precision);
594 break;
595 case CHAR: {
596 if (spec.type_ && spec.type_ != 'c')
597 internal::ReportUnknownType(spec.type_, "char");
598 typedef typename BasicWriter<Char>::CharPtr CharPtr;
599 CharPtr out = CharPtr();
600 if (spec.width_ > 1) {
601 out = writer.GrowBuffer(spec.width_);
602 if (spec.align_ == ALIGN_RIGHT) {
603 std::fill_n(out, spec.width_ - 1, spec.fill_);
604 out += spec.width_ - 1;
605 } else if (spec.align_ == ALIGN_CENTER) {
606 out = writer.FillPadding(out, spec.width_, 1, spec.fill_);
607 } else {
608 std::fill_n(out + 1, spec.width_ - 1, spec.fill_);
609 }
610 } else {
611 out = writer.GrowBuffer(1);
612 }
613 *out = arg.int_value;
614 break;
615 }
616 case STRING: {
617 if (spec.type_ && spec.type_ != 's')
618 internal::ReportUnknownType(spec.type_, "string");
619 const Char *str = arg.string.value;
620 std::size_t size = arg.string.size;
621 if (size == 0) {
622 if (!str)
623 throw FormatError("string pointer is null");
624 if (*str)
625 size = std::char_traits<Char>::length(str);
626 }
627 writer.FormatString(str, size, spec);
628 break;
629 }
630 case POINTER:
631 if (spec.type_ && spec.type_ != 'p')
632 internal::ReportUnknownType(spec.type_, "pointer");
633 spec.flags_= HASH_FLAG;
634 spec.type_ = 'x';
635 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
636 break;
637 case CUSTOM:
638 if (spec.type_)
639 internal::ReportUnknownType(spec.type_, "object");
640 arg.custom.format(writer, arg.custom.value, spec);
641 break;
642 default:
643 assert(false);
644 break;
645 }
646 }
647 writer.buffer_.append(start, s);
648}
649
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700650// Explicit instantiations for char.
651
Victor Zverovich7cae7632013-09-06 20:23:42 -0700652template void fmt::BasicWriter<char>::FormatDouble<double>(
653 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700654
Victor Zverovich7cae7632013-09-06 20:23:42 -0700655template void fmt::BasicWriter<char>::FormatDouble<long double>(
656 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700657
Victor Zverovich93e41252013-09-08 13:07:04 -0700658template fmt::BasicWriter<char>::CharPtr
659 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
660 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700661
Victor Zverovich7cae7632013-09-06 20:23:42 -0700662template void fmt::BasicWriter<char>::FormatDecimal(
663 CharPtr buffer, uint64_t value, unsigned num_digits);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700664
Victor Zverovich7cae7632013-09-06 20:23:42 -0700665template fmt::BasicWriter<char>::CharPtr
666 fmt::BasicWriter<char>::PrepareFilledBuffer(
667 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700668
Victor Zverovich7cae7632013-09-06 20:23:42 -0700669template void fmt::BasicFormatter<char>::ReportError(
670 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700671
Victor Zverovich7cae7632013-09-06 20:23:42 -0700672template unsigned fmt::BasicFormatter<char>::ParseUInt(const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700673
Victor Zverovich7cae7632013-09-06 20:23:42 -0700674template const fmt::BasicFormatter<char>::Arg
675 &fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700676
Victor Zverovich7cae7632013-09-06 20:23:42 -0700677template void fmt::BasicFormatter<char>::CheckSign(
678 const char *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700679
Victor Zverovich7cae7632013-09-06 20:23:42 -0700680template void fmt::BasicFormatter<char>::DoFormat();
681
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700682// Explicit instantiations for wchar_t.
683
Victor Zverovich7cae7632013-09-06 20:23:42 -0700684template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
685 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700686
Victor Zverovich7cae7632013-09-06 20:23:42 -0700687template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
688 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700689
Victor Zverovich7cae7632013-09-06 20:23:42 -0700690template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700691 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
692 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700693
Victor Zverovich7cae7632013-09-06 20:23:42 -0700694template void fmt::BasicWriter<wchar_t>::FormatDecimal(
695 CharPtr buffer, uint64_t value, unsigned num_digits);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700696
Victor Zverovich7cae7632013-09-06 20:23:42 -0700697template fmt::BasicWriter<wchar_t>::CharPtr
698 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
699 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700700
Victor Zverovich7cae7632013-09-06 20:23:42 -0700701template void fmt::BasicFormatter<wchar_t>::ReportError(
702 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700703
Victor Zverovich7cae7632013-09-06 20:23:42 -0700704template unsigned fmt::BasicFormatter<wchar_t>::ParseUInt(
705 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700706
Victor Zverovich7cae7632013-09-06 20:23:42 -0700707template const fmt::BasicFormatter<wchar_t>::Arg
708 &fmt::BasicFormatter<wchar_t>::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700709
Victor Zverovich7cae7632013-09-06 20:23:42 -0700710template void fmt::BasicFormatter<wchar_t>::CheckSign(
711 const wchar_t *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700712
Victor Zverovich7cae7632013-09-06 20:23:42 -0700713template void fmt::BasicFormatter<wchar_t>::DoFormat();