30 static_assert(std::is_same<Char, char>::value ||
31 std::is_same<Char, wchar_t>::value,
32 "Unsupported code unit type.");
35 using char_type = Char;
47 : out_(out), args_(args) {}
64 template <
typename T>
static auto fits_in_int(T
value) ->
bool {
65 unsigned max = to_unsigned(max_value<int>());
68 static auto fits_in_int(
bool) ->
bool {
return true; }
72 template <
typename T>
static auto fits_in_int(T
value) ->
bool {
73 return value >= (std::numeric_limits<int>::min)() &&
74 value <= max_value<int>();
76 static auto fits_in_int(
int) ->
bool {
return true; }
80 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
81 auto operator()(T
value) ->
int {
83 report_error(
"number is too big");
84 return (std::max)(
static_cast<int>(
value), 0);
87 template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
88 auto operator()(T) ->
int {
89 report_error(
"precision is not integer");
96 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
97 auto operator()(T
value) ->
bool {
101 template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
102 auto operator()(T) ->
bool {
115 using char_type =
typename Context::char_type;
122 : arg_(arg), type_(type) {}
124 void operator()(
bool value) {
125 if (type_ !=
's') operator()<
bool>(
value);
128 template <
typename U, FMT_ENABLE_IF(std::is_
integral<U>::value)>
129 void operator()(U
value) {
130 bool is_signed = type_ ==
'd' || type_ ==
'i';
131 using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
132 if (const_check(
sizeof(target_type) <=
sizeof(
int))) {
135 auto n =
static_cast<int>(
static_cast<target_type
>(
value));
136 arg_ = detail::make_arg<Context>(n);
139 auto n =
static_cast<unsigned>(
static_cast<unsigned_type
>(
value));
140 arg_ = detail::make_arg<Context>(n);
147 auto n =
static_cast<long long>(
value);
148 arg_ = detail::make_arg<Context>(n);
151 arg_ = detail::make_arg<Context>(n);
156 template <
typename U, FMT_ENABLE_IF(!std::is_
integral<U>::value)>
157 void operator()(U) {}
164template <
typename T,
typename Context,
typename Char>
177 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
178 void operator()(T
value) {
179 auto c =
static_cast<typename Context::char_type
>(
value);
180 arg_ = detail::make_arg<Context>(c);
183 template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
184 void operator()(T) {}
190 template <
typename T>
auto operator()(T) ->
const Char* {
return nullptr; }
191 auto operator()(
const Char* s) ->
const Char* {
return s; }
203 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
204 auto operator()(T
value) ->
unsigned {
205 auto width =
static_cast<uint32_or_64_or_128_t<T>
>(
value);
206 if (detail::is_negative(
value)) {
207 specs_.align = align::left;
210 unsigned int_max = to_unsigned(max_value<int>());
211 if (width > int_max) report_error(
"number is too big");
212 return static_cast<unsigned>(width);
215 template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
216 auto operator()(T) ->
unsigned {
217 report_error(
"width is not integer");
224template <
typename Char>
231template <
typename Char>
239 void write_null_pointer(
bool is_string =
false) {
240 auto s = this->specs;
241 s.type = presentation_type::none;
242 write_bytes<Char>(this->out, is_string ?
"(null)" :
"(nil)", s);
248 :
base(make_arg_formatter(iter, s)), context_(ctx) {}
252 template <
typename T, FMT_ENABLE_IF(detail::is_
integral<T>::value)>
253 void operator()(T
value) {
256 if (!std::is_same<T, Char>::value) {
257 base::operator()(
value);
261 if (s.type != presentation_type::none && s.type != presentation_type::chr) {
262 return (*
this)(
static_cast<int>(
value));
269 if (s.align == align::none || s.align == align::numeric)
270 s.align = align::right;
271 write<Char>(this->out,
static_cast<Char
>(
value), s);
274 template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
275 void operator()(T
value) {
276 base::operator()(
value);
282 base::operator()(
value);
284 write_null_pointer(this->specs.type != presentation_type::pointer);
290 base::operator()(
value);
292 write_null_pointer(this->specs.type != presentation_type::pointer);
300 base::operator()(
value);
302 write_null_pointer();
308 handle.format(parse_ctx, context_);
312template <
typename Char>
313void parse_flags(
format_specs& specs,
const Char*& it,
const Char* end) {
314 for (; it != end; ++it) {
317 specs.align = align::left;
320 specs.sign = sign::plus;
326 if (specs.sign != sign::plus) specs.sign = sign::space;
337template <
typename Char,
typename GetArg>
338auto parse_header(
const Char*& it,
const Char* end,
format_specs& specs,
339 GetArg get_arg) ->
int {
342 if (c >=
'0' && c <=
'9') {
345 int value = parse_nonnegative_int(it, end, -1);
346 if (it != end && *it ==
'$') {
348 arg_index = value != -1 ? value : max_value<int>();
350 if (c ==
'0') specs.fill =
'0';
354 if (value == -1) report_error(
"number is too big");
360 parse_flags(specs, it, end);
363 if (*it >=
'0' && *it <=
'9') {
364 specs.width = parse_nonnegative_int(it, end, -1);
365 if (specs.width == -1) report_error(
"number is too big");
366 }
else if (*it ==
'*') {
368 specs.width =
static_cast<int>(
375inline auto parse_printf_presentation_type(
char c, type t,
bool& upper)
376 -> presentation_type {
377 using pt = presentation_type;
378 constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
381 return in(t, integral_set) ? pt::dec : pt::none;
383 return in(t, integral_set) ? pt::oct : pt::none;
388 return in(t, integral_set) ? pt::hex : pt::none;
393 return in(t, float_set) ? pt::exp : pt::none;
398 return in(t, float_set) ? pt::fixed : pt::none;
403 return in(t, float_set) ? pt::general : pt::none;
408 return in(t, float_set) ? pt::hexfloat : pt::none;
410 return in(t, integral_set) ? pt::chr : pt::none;
412 return in(t, string_set | cstring_set) ? pt::string : pt::none;
414 return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
420template <
typename Char,
typename Context>
424 auto out = iterator(buf);
430 auto get_arg = [&](
int arg_index) {
432 arg_index = parse_ctx.next_arg_id();
434 parse_ctx.check_arg_id(--arg_index);
435 return detail::get_arg(
context, arg_index);
438 const Char* start = parse_ctx.begin();
439 const Char* end = parse_ctx.end();
442 if (!find<false, Char>(it, end,
'%', it)) {
447 if (it != end && *it == c) {
455 specs.align = align::right;
458 int arg_index = parse_header(it, end, specs, get_arg);
459 if (arg_index == 0) report_error(
"argument not found");
462 if (it != end && *it ==
'.') {
464 c = it != end ? *it : 0;
465 if (
'0' <= c && c <=
'9') {
466 specs.precision = parse_nonnegative_int(it, end, 0);
467 }
else if (c ==
'*') {
470 static_cast<int>(get_arg(-1).visit(printf_precision_handler()));
476 auto arg = get_arg(arg_index);
479 if (specs.precision >= 0 && arg.is_integral()) {
483 if (specs.precision >= 0 && arg.type() == type::cstring_type) {
484 auto str = arg.visit(get_cstring<Char>());
485 auto str_end = str + specs.precision;
486 auto nul = std::find(str, str_end, Char());
488 str, to_unsigned(nul != str_end ? nul - str : specs.precision));
489 arg = make_arg<basic_printf_context<Char>>(sv);
491 if (specs.alt && arg.visit(is_zero_int())) specs.alt =
false;
492 if (specs.fill.template get<Char>() ==
'0') {
493 if (arg.is_arithmetic() && specs.align != align::left)
494 specs.align = align::numeric;
501 c = it != end ? *it++ : 0;
502 Char t = it != end ? *it : 0;
507 t = it != end ? *it : 0;
508 convert_arg<signed char>(arg, t);
510 convert_arg<short>(arg, t);
516 t = it != end ? *it : 0;
517 convert_arg<long long>(arg, t);
519 convert_arg<long>(arg, t);
523 convert_arg<intmax_t>(arg, t);
526 convert_arg<size_t>(arg, t);
529 convert_arg<std::ptrdiff_t>(arg, t);
537 convert_arg<void>(arg, c);
541 if (it == end) report_error(
"invalid format string");
542 char type =
static_cast<char>(*it++);
543 if (arg.is_integral()) {
556 specs.type = parse_printf_presentation_type(type, arg.type(), upper);
557 if (specs.type == presentation_type::none)
558 report_error(
"invalid format specifier");
564 arg.visit(printf_arg_formatter<Char>(out, specs,
context));
582template <
typename Char = char,
typename... T>
583inline auto make_printf_args(T&... args)
584 ->
decltype(make_format_args<basic_printf_context<Char>>(args...)) {
585 return make_format_args<basic_printf_context<Char>>(args...);
592template <
typename Char>
595 -> std::basic_string<Char> {
597 detail::vprintf(buf, fmt, args);
598 return to_string(buf);
610template <
typename S,
typename... T,
typename Char = char_t<S>>
611inline auto sprintf(
const S& fmt,
const T&... args) -> std::basic_string<Char> {
612 return vsprintf(detail::to_string_view(fmt),
616template <
typename Char>
620 detail::vprintf(buf, fmt, args);
621 size_t size = buf.size();
622 return std::fwrite(buf.data(),
sizeof(Char), size, f) < size
624 :
static_cast<int>(size);
636template <
typename S,
typename... T,
typename Char = char_t<S>>
637inline auto fprintf(std::FILE* f,
const S& fmt,
const T&... args) ->
int {
638 return vfprintf(f, detail::to_string_view(fmt),
639 make_printf_args<Char>(args...));
642template <
typename Char>
646 return vfprintf(stdout, fmt, args);
658template <
typename... T>
659inline auto printf(
string_view fmt,
const T&... args) ->
int {
660 return vfprintf(stdout, fmt, make_printf_args(args...));
662template <
typename... T>
664 const T&... args) ->
int {
665 return vfprintf(stdout, fmt, make_printf_args<wchar_t>(args...));
basic_printf_context(basic_appender< Char > out, basic_format_args< basic_printf_context > args)
Definition printf.h:45