Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
printf.h
Go to the documentation of this file.
1/*
2 Formatting library for C++
3
4 Copyright (c) 2012 - 2016, Victor Zverovich
5 All rights reserved.
6
7 For the license information refer to format.h.
8 */
9
10#ifndef FMT_PRINTF_H_
11#define FMT_PRINTF_H_
12
13#include <algorithm> // std::fill_n
14#include <limits> // std::numeric_limits
15
16#include "ostream.h"
17
18namespace fmt {
19namespace internal {
20
21// Checks if a value fits in int - used to avoid warnings about comparing
22// signed and unsigned integers.
23template <bool IsSigned>
24struct IntChecker {
25 template <typename T>
26 static bool fits_in_int(T value) {
27 unsigned max = std::numeric_limits<int>::max();
28 return value <= max;
29 }
30 static bool fits_in_int(bool) { return true; }
31};
32
33template <>
34struct IntChecker<true> {
35 template <typename T>
36 static bool fits_in_int(T value) {
37 return value >= std::numeric_limits<int>::min() &&
38 value <= std::numeric_limits<int>::max();
39 }
40 static bool fits_in_int(int) { return true; }
41};
42
43class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
44 public:
46 FMT_THROW(FormatError("precision is not integer"));
47 }
48
49 template <typename T>
50 int visit_any_int(T value) {
51 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
52 FMT_THROW(FormatError("number is too big"));
53 return static_cast<int>(value);
54 }
55};
56
57// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
58class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
59 public:
60 template <typename T>
61 bool visit_any_int(T value) { return value == 0; }
62};
63
64// returns the default type for format specific "%s"
65class DefaultType : public ArgVisitor<DefaultType, char> {
66 public:
67 char visit_char(int) { return 'c'; }
68
69 char visit_bool(bool) { return 's'; }
70
71 char visit_pointer(const void *) { return 'p'; }
72
73 template <typename T>
74 char visit_any_int(T) { return 'd'; }
75
76 template <typename T>
77 char visit_any_double(T) { return 'g'; }
78
79 char visit_unhandled_arg() { return 's'; }
80};
81
82template <typename T, typename U>
83struct is_same {
84 enum { value = 0 };
85};
86
87template <typename T>
88struct is_same<T, T> {
89 enum { value = 1 };
90};
91
92// An argument visitor that converts an integer argument to T for printf,
93// if T is an integral type. If T is void, the argument is converted to
94// corresponding signed or unsigned type depending on the type specifier:
95// 'd' and 'i' - signed, other - unsigned)
96template <typename T = void>
97class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
98 private:
100 wchar_t type_;
101
103
104 public:
105 ArgConverter(internal::Arg &arg, wchar_t type)
106 : arg_(arg), type_(type) {}
107
108 void visit_bool(bool value) {
109 if (type_ != 's')
110 visit_any_int(value);
111 }
112
113 void visit_char(int value) {
114 if (type_ != 's')
115 visit_any_int(value);
116 }
117
118 template <typename U>
119 void visit_any_int(U value) {
120 bool is_signed = type_ == 'd' || type_ == 'i';
121 if (type_ == 's') {
122 is_signed = std::numeric_limits<U>::is_signed;
123 }
124
125 using internal::Arg;
126 typedef typename internal::Conditional<
127 is_same<T, void>::value, U, T>::type TargetType;
128 if (const_check(sizeof(TargetType) <= sizeof(int))) {
129 // Extra casts are used to silence warnings.
130 if (is_signed) {
131 arg_.type = Arg::INT;
132 arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
133 } else {
134 arg_.type = Arg::UINT;
135 typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
136 arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
137 }
138 } else {
139 if (is_signed) {
140 arg_.type = Arg::LONG_LONG;
141 // glibc's printf doesn't sign extend arguments of smaller types:
142 // std::printf("%lld", -42); // prints "4294967254"
143 // but we don't have to do the same because it's a UB.
144 arg_.long_long_value = static_cast<LongLong>(value);
145 } else {
146 arg_.type = Arg::ULONG_LONG;
147 arg_.ulong_long_value =
148 static_cast<typename internal::MakeUnsigned<U>::Type>(value);
149 }
150 }
151 }
152};
153
154// Converts an integer argument to char for printf.
155class CharConverter : public ArgVisitor<CharConverter, void> {
156 private:
158
160
161 public:
162 explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
163
164 template <typename T>
165 void visit_any_int(T value) {
166 arg_.type = internal::Arg::CHAR;
167 arg_.int_value = static_cast<char>(value);
168 }
169};
170
171// Checks if an argument is a valid printf width specifier and sets
172// left alignment if it is negative.
173class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
174 private:
176
178
179 public:
180 explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
181
183 FMT_THROW(FormatError("width is not integer"));
184 }
185
186 template <typename T>
187 unsigned visit_any_int(T value) {
188 typedef typename internal::IntTraits<T>::MainType UnsignedType;
189 UnsignedType width = static_cast<UnsignedType>(value);
190 if (internal::is_negative(value)) {
192 width = 0 - width;
193 }
194 unsigned int_max = std::numeric_limits<int>::max();
195 if (width > int_max)
196 FMT_THROW(FormatError("number is too big"));
197 return static_cast<unsigned>(width);
198 }
199};
200} // namespace internal
201
202/**
203 \rst
204 A ``printf`` argument formatter based on the `curiously recurring template
205 pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
206
207 To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some
208 or all of the visit methods with the same signatures as the methods in
209 `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.
210 Pass the subclass as the *Impl* template parameter. When a formatting
211 function processes an argument, it will dispatch to a visit method
212 specific to the argument type. For example, if the argument type is
213 ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
214 will be called. If the subclass doesn't contain a method with this signature,
215 then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its
216 superclass will be called.
217 \endrst
218 */
219template <typename Impl, typename Char, typename Spec>
220class BasicPrintfArgFormatter :
221 public internal::ArgFormatterBase<Impl, Char, Spec> {
222 private:
224 this->spec().type_ = 0;
225 this->write("(nil)");
226 }
227
228 typedef internal::ArgFormatterBase<Impl, Char, Spec> Base;
229
230 public:
231 /**
232 \rst
233 Constructs an argument formatter object.
234 *writer* is a reference to the output writer and *spec* contains format
235 specifier information for standard argument types.
236 \endrst
237 */
238 BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s)
239 : internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {}
240
241 /** Formats an argument of type ``bool``. */
242 void visit_bool(bool value) {
243 Spec &fmt_spec = this->spec();
244 if (fmt_spec.type_ != 's')
245 return this->visit_any_int(value);
246 fmt_spec.type_ = 0;
247 this->write(value);
248 }
249
250 /** Formats a character. */
251 void visit_char(int value) {
252 const Spec &fmt_spec = this->spec();
253 BasicWriter<Char> &w = this->writer();
254 if (fmt_spec.type_ && fmt_spec.type_ != 'c')
255 w.write_int(value, fmt_spec);
256 typedef typename BasicWriter<Char>::CharPtr CharPtr;
257 CharPtr out = CharPtr();
258 if (fmt_spec.width_ > 1) {
259 Char fill = ' ';
260 out = w.grow_buffer(fmt_spec.width_);
261 if (fmt_spec.align_ != ALIGN_LEFT) {
262 std::fill_n(out, fmt_spec.width_ - 1, fill);
263 out += fmt_spec.width_ - 1;
264 } else {
265 std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
266 }
267 } else {
268 out = w.grow_buffer(1);
269 }
270 *out = static_cast<Char>(value);
271 }
272
273 /** Formats a null-terminated C string. */
274 void visit_cstring(const char *value) {
275 if (value)
276 Base::visit_cstring(value);
277 else if (this->spec().type_ == 'p')
279 else
280 this->write("(null)");
281 }
282
283 /** Formats a pointer. */
284 void visit_pointer(const void *value) {
285 if (value)
286 return Base::visit_pointer(value);
287 this->spec().type_ = 0;
289 }
290
291 /** Formats an argument of a custom (user-defined) type. */
292 void visit_custom(internal::Arg::CustomValue c) {
293 BasicFormatter<Char> formatter(ArgList(), this->writer());
294 const Char format_str[] = {'}', 0};
295 const Char *format = format_str;
296 c.format(&formatter, c.value, &format);
297 }
298};
299
300/** The default printf argument formatter. */
301template <typename Char>
303 public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec> {
304 public:
305 /** Constructs an argument formatter object. */
306 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
307 : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s) {}
308};
309
310/** This template formats data and writes the output to a writer. */
311template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
313 private:
314 BasicWriter<Char> &writer_;
315
316 void parse_flags(FormatSpec &spec, const Char *&s);
317
318 // Returns the argument with specified index or, if arg_index is equal
319 // to the maximum unsigned value, the next argument.
320 internal::Arg get_arg(
321 const Char *s,
322 unsigned arg_index = (std::numeric_limits<unsigned>::max)());
323
324 // Parses argument index, flags and width and returns the argument index.
325 unsigned parse_header(const Char *&s, FormatSpec &spec);
326
327 public:
328 /**
329 \rst
330 Constructs a ``PrintfFormatter`` object. References to the arguments and
331 the writer are stored in the formatter object so make sure they have
332 appropriate lifetimes.
333 \endrst
334 */
335 explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
336 : FormatterBase(al), writer_(w) {}
337
338 /** Formats stored arguments and writes the output to the writer. */
339 void format(BasicCStringRef<Char> format_str);
340};
341
342template <typename Char, typename AF>
343void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) {
344 for (;;) {
345 switch (*s++) {
346 case '-':
347 spec.align_ = ALIGN_LEFT;
348 break;
349 case '+':
350 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
351 break;
352 case '0':
353 spec.fill_ = '0';
354 break;
355 case ' ':
356 spec.flags_ |= SIGN_FLAG;
357 break;
358 case '#':
359 spec.flags_ |= HASH_FLAG;
360 break;
361 default:
362 --s;
363 return;
364 }
365 }
366}
367
368template <typename Char, typename AF>
369internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
370 unsigned arg_index) {
371 (void)s;
372 const char *error = FMT_NULL;
373 internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
374 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
375 if (error)
376 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
377 return arg;
378}
379
380template <typename Char, typename AF>
381unsigned PrintfFormatter<Char, AF>::parse_header(
382 const Char *&s, FormatSpec &spec) {
383 unsigned arg_index = std::numeric_limits<unsigned>::max();
384 Char c = *s;
385 if (c >= '0' && c <= '9') {
386 // Parse an argument index (if followed by '$') or a width possibly
387 // preceded with '0' flag(s).
388 unsigned value = internal::parse_nonnegative_int(s);
389 if (*s == '$') { // value is an argument index
390 ++s;
391 arg_index = value;
392 } else {
393 if (c == '0')
394 spec.fill_ = '0';
395 if (value != 0) {
396 // Nonzero value means that we parsed width and don't need to
397 // parse it or flags again, so return now.
398 spec.width_ = value;
399 return arg_index;
400 }
401 }
402 }
403 parse_flags(spec, s);
404 // Parse width.
405 if (*s >= '0' && *s <= '9') {
406 spec.width_ = internal::parse_nonnegative_int(s);
407 } else if (*s == '*') {
408 ++s;
409 spec.width_ = internal::WidthHandler(spec).visit(get_arg(s));
410 }
411 return arg_index;
412}
413
414template <typename Char, typename AF>
415void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
416 const Char *start = format_str.c_str();
417 const Char *s = start;
418 while (*s) {
419 Char c = *s++;
420 if (c != '%') continue;
421 if (*s == c) {
422 write(writer_, start, s);
423 start = ++s;
424 continue;
425 }
426 write(writer_, start, s - 1);
427
428 FormatSpec spec;
429 spec.align_ = ALIGN_RIGHT;
430
431 // Parse argument index, flags and width.
432 unsigned arg_index = parse_header(s, spec);
433
434 // Parse precision.
435 if (*s == '.') {
436 ++s;
437 if ('0' <= *s && *s <= '9') {
438 spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s));
439 } else if (*s == '*') {
440 ++s;
442 } else {
443 spec.precision_ = 0;
444 }
445 }
446
447 using internal::Arg;
448 Arg arg = get_arg(s, arg_index);
449 if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg))
450 spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
451 if (spec.fill_ == '0') {
452 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
454 else
455 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
456 }
457
458 // Parse length and convert the argument to the required type.
459 using internal::ArgConverter;
460 switch (*s++) {
461 case 'h':
462 if (*s == 'h')
463 ArgConverter<signed char>(arg, *++s).visit(arg);
464 else
465 ArgConverter<short>(arg, *s).visit(arg);
466 break;
467 case 'l':
468 if (*s == 'l')
469 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
470 else
471 ArgConverter<long>(arg, *s).visit(arg);
472 break;
473 case 'j':
474 ArgConverter<intmax_t>(arg, *s).visit(arg);
475 break;
476 case 'z':
477 ArgConverter<std::size_t>(arg, *s).visit(arg);
478 break;
479 case 't':
480 ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
481 break;
482 case 'L':
483 // printf produces garbage when 'L' is omitted for long double, no
484 // need to do the same.
485 break;
486 default:
487 --s;
488 ArgConverter<void>(arg, *s).visit(arg);
489 }
490
491 // Parse type.
492 if (!*s)
493 FMT_THROW(FormatError("invalid format string"));
494 spec.type_ = static_cast<char>(*s++);
495
496 if (spec.type_ == 's') {
497 // set the format type to the default if 's' is specified
498 spec.type_ = internal::DefaultType().visit(arg);
499 }
500
501 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
502 // Normalize type.
503 switch (spec.type_) {
504 case 'i': case 'u':
505 spec.type_ = 'd';
506 break;
507 case 'c':
508 // TODO: handle wchar_t
509 internal::CharConverter(arg).visit(arg);
510 break;
511 }
512 }
513
514 start = s;
515
516 // Format argument.
517 AF(writer_, spec).visit(arg);
518 }
519 write(writer_, start, s);
520}
521
522inline void printf(Writer &w, CStringRef format, ArgList args) {
523 PrintfFormatter<char>(args, w).format(format);
524}
526
527inline void printf(WWriter &w, WCStringRef format, ArgList args) {
528 PrintfFormatter<wchar_t>(args, w).format(format);
529}
531
532/**
533 \rst
534 Formats arguments and returns the result as a string.
535
536 **Example**::
537
538 std::string message = fmt::sprintf("The answer is %d", 42);
539 \endrst
540*/
541inline std::string sprintf(CStringRef format, ArgList args) {
542 MemoryWriter w;
543 printf(w, format, args);
544 return w.str();
545}
547
548inline std::wstring sprintf(WCStringRef format, ArgList args) {
549 WMemoryWriter w;
550 printf(w, format, args);
551 return w.str();
552}
554
555/**
556 \rst
557 Prints formatted data to the file *f*.
558
559 **Example**::
560
561 fmt::fprintf(stderr, "Don't %s!", "panic");
562 \endrst
563 */
564FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
566
567/**
568 \rst
569 Prints formatted data to ``stdout``.
570
571 **Example**::
572
573 fmt::printf("Elapsed time: %.2f seconds", 1.23);
574 \endrst
575 */
576inline int printf(CStringRef format, ArgList args) {
577 return fprintf(stdout, format, args);
578}
580
581/**
582 \rst
583 Prints formatted data to the stream *os*.
584
585 **Example**::
586
587 fprintf(cerr, "Don't %s!", "panic");
588 \endrst
589 */
590inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) {
591 MemoryWriter w;
592 printf(w, format_str, args);
594 return static_cast<int>(w.size());
595}
597} // namespace fmt
598
599#ifdef FMT_HEADER_ONLY
600# include "printf.cc"
601#endif
602
603#endif // FMT_PRINTF_H_
void visit_cstring(const char *value)
Definition printf.h:274
void visit_pointer(const void *value)
Definition printf.h:284
void visit_bool(bool value)
Definition printf.h:242
void visit_custom(internal::Arg::CustomValue c)
Definition printf.h:292
void visit_char(int value)
Definition printf.h:251
BasicPrintfArgFormatter(BasicWriter< Char > &w, Spec &s)
Definition printf.h:238
internal::ArgFormatterBase< Impl, Char, Spec > Base
Definition printf.h:228
PrintfArgFormatter(BasicWriter< Char > &w, FormatSpec &s)
Definition printf.h:306
void format(BasicCStringRef< Char > format_str)
Definition printf.h:415
internal::Arg get_arg(const Char *s, unsigned arg_index=(std::numeric_limits< unsigned >::max)())
Definition printf.h:369
unsigned parse_header(const Char *&s, FormatSpec &spec)
Definition printf.h:381
PrintfFormatter(const ArgList &al, BasicWriter< Char > &w)
Definition printf.h:335
void parse_flags(FormatSpec &spec, const Char *&s)
Definition printf.h:343
BasicWriter< Char > & writer_
Definition printf.h:314
void visit_any_int(U value)
Definition printf.h:119
ArgConverter(internal::Arg &arg, wchar_t type)
Definition printf.h:105
void visit_bool(bool value)
Definition printf.h:108
internal::Arg & arg_
Definition printf.h:99
void visit_char(int value)
Definition printf.h:113
CharConverter(internal::Arg &arg)
Definition printf.h:162
internal::Arg & arg_
Definition printf.h:157
void visit_any_int(T value)
Definition printf.h:165
char visit_pointer(const void *)
Definition printf.h:71
Arg next_arg(const char *&error)
Definition format.h:2210
Arg get_arg(unsigned arg_index, const char *&error)
Definition format.h:2219
bool visit_any_int(T value)
Definition printf.h:61
unsigned visit_any_int(T value)
Definition printf.h:187
WidthHandler(FormatSpec &spec)
Definition printf.h:180
#define FMT_FUNC
Definition format.h:4170
#define FMT_VARIADIC(ReturnType, func,...)
Definition format.h:3708
#define FMT_API
Definition format.h:94
#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition format.h:291
#define FMT_THROW(x)
Definition format.h:222
#define FMT_VARIADIC_W(ReturnType, func,...)
Definition format.h:3714
#define FMT_NULL
Definition format.h:273
FMT_FUNC void write(std::ostream &os, Writer &w)
Definition ostream.cc:15
Definition format.h:408
FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args)
Definition printf.cc:18
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
void printf(WWriter &w, WCStringRef format, ArgList args)
Definition printf.h:527
std::wstring sprintf(WCStringRef format, ArgList args)
Definition printf.h:548
std::string sprintf(CStringRef format, ArgList args)
Definition printf.h:541
void printf(Writer &w, CStringRef format, ArgList args)
Definition printf.h:522
int printf(CStringRef format, ArgList args)
Definition printf.h:576
@ ALIGN_LEFT
Definition format.h:1794
@ ALIGN_NUMERIC
Definition format.h:1794
@ ALIGN_RIGHT
Definition format.h:1794
@ HASH_FLAG
Definition format.h:1799
@ PLUS_FLAG
Definition format.h:1799
@ SIGN_FLAG
Definition format.h:1799
int fprintf(std::ostream &os, CStringRef format_str, ArgList args)
Definition printf.h:590
Definition json.hpp:4518
Alignment align_
Definition format.h:1833
unsigned flags_
Definition format.h:1855
bool flag(unsigned f) const
Definition format.h:1863
unsigned width_
Definition format.h:1820
wchar_t fill_
Definition format.h:1823
static bool fits_in_int(int)
Definition printf.h:40
static bool fits_in_int(T value)
Definition printf.h:36
static bool fits_in_int(T value)
Definition printf.h:26
static bool fits_in_int(bool)
Definition printf.h:30