21template <
bool IsSigned>
struct int_checker {
22 template <
typename T>
static bool fits_in_int(T value) {
23 unsigned max = max_value<int>();
26 static bool fits_in_int(
bool) {
return true; }
29template <>
struct int_checker<true> {
30 template <
typename T>
static bool fits_in_int(T value) {
31 return value >= (std::numeric_limits<int>::min)() &&
32 value <= max_value<int>();
34 static bool fits_in_int(
int) {
return true; }
37class printf_precision_handler {
39 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
40 int operator()(T value) {
41 if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
43 return (std::max)(
static_cast<int>(value), 0);
46 template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
56 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
57 bool operator()(T value) {
61 template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
67template <
typename T>
struct make_unsigned_or_bool : std::make_unsigned<T> {};
69template <>
struct make_unsigned_or_bool<bool> {
using type = bool; };
71template <
typename T,
typename Context>
class arg_converter {
73 using char_type =
typename Context::char_type;
75 basic_format_arg<Context>& arg_;
79 arg_converter(basic_format_arg<Context>& arg, char_type type)
80 : arg_(arg), type_(type) {}
82 void operator()(
bool value) {
83 if (type_ !=
's') operator()<
bool>(value);
86 template <
typename U, FMT_ENABLE_IF(std::is_
integral<U>::value)>
87 void operator()(U value) {
88 bool is_signed = type_ ==
'd' || type_ ==
'i';
89 using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
90 if (const_check(
sizeof(target_type) <=
sizeof(
int))) {
93 arg_ = internal::make_arg<Context>(
94 static_cast<int>(
static_cast<target_type
>(value)));
96 using unsigned_type =
typename make_unsigned_or_bool<target_type>::type;
97 arg_ = internal::make_arg<Context>(
98 static_cast<unsigned>(
static_cast<unsigned_type
>(value)));
105 arg_ = internal::make_arg<Context>(
static_cast<long long>(value));
107 arg_ = internal::make_arg<Context>(
108 static_cast<typename make_unsigned_or_bool<U>::type
>(value));
113 template <
typename U, FMT_ENABLE_IF(!std::is_
integral<U>::value)>
114 void operator()(U) {}
121template <
typename T,
typename Context,
typename Char>
122void convert_arg(basic_format_arg<Context>& arg, Char type) {
123 visit_format_arg(arg_converter<T, Context>(arg, type), arg);
127template <
typename Context>
class char_converter {
129 basic_format_arg<Context>& arg_;
132 explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
134 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
135 void operator()(T value) {
136 arg_ = internal::make_arg<Context>(
137 static_cast<typename Context::char_type
>(value));
140 template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
141 void operator()(T) {}
146template <
typename Char>
class printf_width_handler {
148 using format_specs = basic_format_specs<Char>;
150 format_specs& specs_;
153 explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
155 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
156 unsigned operator()(T value) {
157 auto width =
static_cast<uint32_or_64_or_128_t<T>
>(value);
158 if (internal::is_negative(value)) {
159 specs_.align = align::left;
162 unsigned int_max = max_value<int>();
163 if (width > int_max) FMT_THROW(
format_error(
"number is too big"));
164 return static_cast<unsigned>(width);
167 template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
168 unsigned operator()(T) {
174template <
typename Char,
typename Context>
177 Context(std::back_inserter(buf), format, args).format();
180template <
typename OutputIt,
typename Char,
typename Context>
181internal::truncating_iterator<OutputIt> printf(
184 return Context(it, format, args).format();
188using internal::printf;
192template <
typename Char>
203template <
typename Range>
206 using iterator =
typename Range::iterator;
209 using char_type =
typename Range::value_type;
210 using base = internal::arg_formatter_base<Range>;
215 void write_null_pointer(
char) {
216 this->specs()->type = 0;
217 this->write(
"(nil)");
220 void write_null_pointer(
wchar_t) {
221 this->specs()->type = 0;
222 this->write(L
"(nil)");
226 using format_specs =
typename base::format_specs;
236 : base(Range(iter), &specs, internal::locale_ref()), context_(ctx) {}
238 template <
typename T, FMT_ENABLE_IF(fmt::
internal::is_
integral<T>::value)>
239 iterator operator()(T value) {
242 if (std::is_same<T, bool>::value) {
243 format_specs& fmt_specs = *this->specs();
244 if (fmt_specs.type !=
's')
return base::operator()(value ? 1 : 0);
246 this->write(value != 0);
247 }
else if (std::is_same<T, char_type>::value) {
248 format_specs& fmt_specs = *this->specs();
249 if (fmt_specs.type && fmt_specs.type !=
'c')
250 return (*
this)(
static_cast<int>(value));
251 fmt_specs.sign = sign::none;
252 fmt_specs.alt =
false;
253 fmt_specs.align = align::right;
254 return base::operator()(value);
256 return base::operator()(value);
261 template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
262 iterator operator()(T value) {
263 return base::operator()(value);
269 base::operator()(value);
270 else if (this->specs()->type ==
'p')
271 write_null_pointer(char_type());
273 this->write(
"(null)");
280 base::operator()(value);
281 else if (this->specs()->type ==
'p')
282 write_null_pointer(char_type());
284 this->write(L
"(null)");
289 return base::operator()(value);
292 iterator operator()(monostate value) {
return base::operator()(value); }
296 if (value)
return base::operator()(value);
297 this->specs()->type = 0;
298 write_null_pointer(char_type());
303 iterator
operator()(
typename basic_format_arg<context_type>::handle handle) {
304 handle.format(context_.parse_context(), context_);
309template <
typename T>
struct printf_formatter {
310 printf_formatter() =
delete;
312 template <
typename ParseContext>
313 auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
317 template <
typename FormatContext>
318 auto format(
const T& value, FormatContext& ctx) ->
decltype(ctx.out()) {
319 internal::format_value(internal::get_container(ctx.out()), value);
329 using iterator = OutputIt;
330 using format_arg = basic_format_arg<basic_printf_context>;
331 using parse_context_type = basic_printf_parse_context<Char>;
332 template <
typename T>
using formatter_type = printf_formatter<T>;
335 using format_specs = basic_format_specs<char_type>;
339 parse_context_type parse_ctx_;
341 static void parse_flags(format_specs& specs,
const Char*& it,
346 format_arg get_arg(
int arg_index = -1);
349 int parse_header(
const Char*& it,
const Char* end, format_specs& specs);
361 : out_(out), args_(args), parse_ctx_(format_str) {}
363 OutputIt out() {
return out_; }
364 void advance_to(OutputIt it) { out_ = it; }
366 internal::locale_ref locale() {
return {}; }
368 format_arg arg(
int id)
const {
return args_.
get(
id); }
370 parse_context_type& parse_context() {
return parse_ctx_; }
372 FMT_CONSTEXPR
void on_error(
const char* message) {
373 parse_ctx_.on_error(message);
377 template <
typename ArgFormatter = pr
intf_arg_formatter<buffer_range<Char>>>
381template <
typename OutputIt,
typename Char>
385 for (; it != end; ++it) {
388 specs.align = align::left;
391 specs.sign = sign::plus;
397 specs.sign = sign::space;
408template <
typename OutputIt,
typename Char>
409typename basic_printf_context<OutputIt, Char>::format_arg
412 arg_index = parse_ctx_.next_arg_id();
414 parse_ctx_.check_arg_id(--arg_index);
415 return internal::get_arg(*
this, arg_index);
418template <
typename OutputIt,
typename Char>
421 format_specs& specs) {
424 if (c >=
'0' && c <=
'9') {
427 internal::error_handler eh;
428 int value = parse_nonnegative_int(it, end, eh);
429 if (it != end && *it ==
'$') {
433 if (c ==
'0') specs.fill[0] =
'0';
442 parse_flags(specs, it, end);
445 if (*it >=
'0' && *it <=
'9') {
446 internal::error_handler eh;
447 specs.width = parse_nonnegative_int(it, end, eh);
448 }
else if (*it ==
'*') {
450 specs.width =
static_cast<int>(visit_format_arg(
451 internal::printf_width_handler<char_type>(specs), get_arg()));
457template <
typename OutputIt,
typename Char>
458template <
typename ArgFormatter>
460 auto out = this->out();
461 const Char* start = parse_ctx_.begin();
462 const Char* end = parse_ctx_.end();
466 if (c !=
'%')
continue;
467 if (it != end && *it == c) {
468 out = std::copy(start, it, out);
472 out = std::copy(start, it - 1, out);
475 specs.align = align::right;
478 int arg_index = parse_header(it, end, specs);
479 if (arg_index == 0) on_error(
"argument index out of range");
482 if (it != end && *it ==
'.') {
484 c = it != end ? *it : 0;
485 if (
'0' <= c && c <=
'9') {
486 internal::error_handler eh;
487 specs.precision = parse_nonnegative_int(it, end, eh);
488 }
else if (c ==
'*') {
490 specs.precision =
static_cast<int>(
491 visit_format_arg(internal::printf_precision_handler(), get_arg()));
497 format_arg arg = get_arg(arg_index);
498 if (specs.alt && visit_format_arg(internal::is_zero_int(), arg))
500 if (specs.fill[0] ==
'0') {
501 if (arg.is_arithmetic())
502 specs.align = align::numeric;
508 c = it != end ? *it++ : 0;
510 using internal::convert_arg;
515 t = it != end ? *it : 0;
516 convert_arg<signed char>(arg, t);
518 convert_arg<short>(arg, t);
524 t = it != end ? *it : 0;
525 convert_arg<long long>(arg, t);
527 convert_arg<long>(arg, t);
531 convert_arg<intmax_t>(arg, t);
534 convert_arg<std::size_t>(arg, t);
537 convert_arg<std::ptrdiff_t>(arg, t);
545 convert_arg<void>(arg, c);
549 if (it == end) FMT_THROW(
format_error(
"invalid format string"));
550 specs.type =
static_cast<char>(*it++);
551 if (arg.is_integral()) {
553 switch (specs.type) {
559 visit_format_arg(internal::char_converter<basic_printf_context>(arg),
568 visit_format_arg(ArgFormatter(out, specs, *
this), arg);
570 return std::copy(start, it, out);
573template <
typename Char>
590template <
typename... Args>
592 const Args&... args) {
602template <
typename... Args>
604 const Args&... args) {
608template <
typename S,
typename Char =
char_t<S>>
609inline std::basic_string<Char> vsprintf(
613 printf(buffer, to_string_view(format), args);
614 return to_string(buffer);
626template <
typename S,
typename... Args,
627 typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
628inline std::basic_string<Char> sprintf(
const S& format,
const Args&... args) {
630 return vsprintf(to_string_view(format), make_format_args<context>(args...));
633template <
typename S,
typename Char =
char_t<S>>
635 std::FILE* f,
const S& format,
638 printf(buffer, to_string_view(format), args);
639 std::size_t size = buffer.
size();
640 return std::fwrite(buffer.
data(),
sizeof(Char), size, f) < size
642 :
static_cast<int>(size);
654template <
typename S,
typename... Args,
655 typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
656inline int fprintf(std::FILE* f,
const S& format,
const Args&... args) {
658 return vfprintf(f, to_string_view(format),
659 make_format_args<context>(args...));
662template <
typename S,
typename Char =
char_t<S>>
666 return vfprintf(stdout, to_string_view(format), args);
678template <
typename S,
typename... Args,
679 FMT_ENABLE_IF(internal::is_string<S>::value)>
680inline int printf(
const S& format_str,
const Args&... args) {
682 return vprintf(to_string_view(format_str),
683 make_format_args<context>(args...));
686template <
typename S,
typename Char =
char_t<S>>
688 std::basic_ostream<Char>& os,
const S& format,
691 printf(buffer, to_string_view(format), args);
692 internal::write(os, buffer);
693 return static_cast<int>(buffer.
size());
697template <
typename ArgFormatter,
typename Char,
700typename ArgFormatter::iterator vprintf(
703 typename ArgFormatter::iterator iter(out);
704 Context(iter, format_str, args).template format<ArgFormatter>();
717template <
typename S,
typename... Args,
typename Char = char_t<S>>
718inline int fprintf(std::basic_ostream<Char>& os,
const S& format_str,
719 const Args&... args) {
721 return vfprintf(os, to_string_view(format_str),
722 make_format_args<context>(args...));
Char char_type
Definition: printf.h:328
basic_printf_context(OutputIt out, basic_string_view< char_type > format_str, basic_format_args< basic_printf_context > args)
Definition: printf.h:359
OutputIt format()
Definition: printf.h:459
std::size_t size() const FMT_NOEXCEPT
Definition: core.h:684
T * data() FMT_NOEXCEPT
Definition: core.h:690