37 #define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string) 39 template <
typename T,
typename... Tail>
65 const Char* arg_id_end =
nullptr;
68 : part_kind(k), val(v) {}
85 unsigned num_parts = 0;
88 if (begin != end) ++num_parts;
94 return ++num_parts, 0;
102 unsigned brace_counter = 0;
103 for (; begin != end; ++begin) {
106 }
else if (*begin ==
'}') {
107 if (brace_counter == 0u)
break;
118 template <
typename Char>
121 parse_format_string<true>(format_str, counter);
125 template <
typename Char,
typename PartHandler>
139 format_str_(format_str),
140 parse_context_(format_str) {}
144 handler_(part::make_text({begin,
to_unsigned(end - begin)}));
148 part_ = part::make_arg_index(parse_context_.
next_arg_id());
154 part_ = part::make_arg_index(
id);
159 part_ = part::make_arg_name(
id);
172 repl.specs, parse_context_);
174 if (*it !=
'}') on_error(
"missing '}' in format string");
175 repl.arg_id = part_.
part_kind == part::kind::arg_index
178 auto part = part::make_replacement(repl);
186 template <
bool IS_CONSTEXPR,
typename Char,
typename PartHandler>
188 PartHandler handler) {
189 parse_format_string<IS_CONSTEXPR>(
194 template <
typename OutputIt,
typename Context,
typename Id>
197 Context& ctx, Id arg_id) {
205 template <
typename Context,
typename OutputIt,
typename CompiledFormat>
211 Context ctx(out, args);
213 const auto& parts = cf.parts();
214 for (
auto part_it = std::begin(parts); part_it != std::end(parts);
216 const auto& part = *part_it;
217 const auto&
value = part.val;
220 switch (part.part_kind) {
221 case format_part_t::kind::text: {
222 const auto text =
value.str;
223 auto output = ctx.out();
224 auto&& it =
reserve(output, text.size());
225 it = std::copy_n(text.begin(), text.size(), it);
226 ctx.advance_to(output);
230 case format_part_t::kind::arg_index:
232 detail::format_arg<OutputIt>(parse_ctx, ctx,
value.arg_index);
235 case format_part_t::kind::arg_name:
237 detail::format_arg<OutputIt>(parse_ctx, ctx,
value.str);
240 case format_part_t::kind::replacement: {
241 const auto& arg_id_value =
value.repl.arg_id.val;
243 ? ctx.arg(arg_id_value.index)
244 : ctx.arg(arg_id_value.name);
246 auto specs =
value.repl.specs;
248 handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
249 handle_dynamic_spec<precision_checker>(specs.precision,
250 specs.precision_ref, ctx);
255 if (specs.sign !=
sign::none) checker.check_sign();
256 if (specs.alt) checker.require_numeric_argument();
257 if (specs.precision >= 0) checker.check_precision();
262 ctx,
nullptr, &specs),
274 template <
typename S,
typename =
void>
282 compile_format_string<false>(format_str,
284 compiled_parts.push_back(part);
296 template <
typename Char,
unsigned N>
300 unsigned counter = 0;
306 parts[(*counter)++] = part;
308 } collector{parts.
data, &counter};
309 compile_format_string<true>(format_str, collector);
311 parts.
data[counter] =
317 template <
typename T> constexpr
const T&
constexpr_max(
const T& a,
const T& b) {
318 return (a < b) ? b : a;
321 template <
typename S>
330 #if FMT_USE_CONSTEXPR 334 static const unsigned num_format_parts = 1;
341 compile_to_parts<char_type, num_format_parts>(
343 return compiled_parts.data;
347 template <
typename S,
typename... Args>
355 template <
typename Context,
typename OutputIt,
typename CompiledFormat>
358 typename Context::iterator;
366 #ifdef __cpp_if_constexpr 367 template <
typename... Args>
struct type_list {};
370 template <
int N,
typename T,
typename... Args>
371 constexpr
const auto&
get([[maybe_unused]]
const T&
first,
372 [[maybe_unused]]
const Args&... rest) {
373 static_assert(N < 1 +
sizeof...(Args),
"index is out of bounds");
374 if constexpr (N == 0)
377 return get<N - 1>(rest...);
380 template <
int N,
typename>
struct get_type_impl;
382 template <
int N,
typename... Args>
struct get_type_impl<N, type_list<Args...>> {
386 template <
int N,
typename T>
389 template <
typename T>
struct is_compiled_format : std::false_type {};
391 template <
typename Char>
struct text {
395 template <
typename OutputIt,
typename... Args>
396 OutputIt
format(OutputIt out,
const Args&...)
const {
397 return write<Char>(out, data);
401 template <
typename Char>
402 struct is_compiled_format<text<Char>> : std::true_type {};
404 template <
typename Char>
407 return {{&s[pos], size}};
410 template <
typename Char>
struct code_unit {
414 template <
typename OutputIt,
typename... Args>
415 OutputIt
format(OutputIt out,
const Args&...)
const {
416 return write<Char>(out, value);
420 template <
typename Char>
421 struct is_compiled_format<code_unit<Char>> : std::true_type {};
424 template <
typename Char,
typename T,
int N>
struct field {
427 template <
typename OutputIt,
typename... Args>
428 OutputIt
format(OutputIt out,
const Args&... args)
const {
430 const T&
arg = get<N>(args...);
431 return write<Char>(out,
arg);
435 template <
typename Char,
typename T,
int N>
436 struct is_compiled_format<field<Char, T, N>> : std::true_type {};
439 template <
typename Char,
typename T,
int N>
struct spec_field {
443 template <
typename OutputIt,
typename... Args>
444 OutputIt
format(OutputIt out,
const Args&... args)
const {
446 const T&
arg = get<N>(args...);
448 make_format_args<basic_format_context<OutputIt, Char>>(args...);
450 return fmt.format(arg, ctx);
454 template <
typename Char,
typename T,
int N>
455 struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
457 template <
typename L,
typename R>
struct concat {
462 template <
typename OutputIt,
typename... Args>
463 OutputIt
format(OutputIt out,
const Args&... args)
const {
464 out = lhs.format(out, args...);
465 return rhs.format(out, args...);
469 template <
typename L,
typename R>
470 struct is_compiled_format<concat<L, R>> : std::true_type {};
472 template <
typename L,
typename R>
473 constexpr concat<L, R> make_concat(L lhs, R rhs) {
477 struct unknown_format {};
479 template <
typename Char>
481 for (
size_t size = str.
size(); pos != size; ++pos) {
482 if (str[pos] ==
'{' || str[pos] ==
'}')
break;
487 template <
typename Args,
size_t POS,
int ID,
typename S>
490 template <
typename Args,
size_t POS,
int ID,
typename T,
typename S>
491 constexpr
auto parse_tail(T head, S format_str) {
494 constexpr
auto tail = compile_format_string<Args, POS, ID>(format_str);
499 return make_concat(head, tail);
505 template <
typename T,
typename Char>
struct parse_specs_result {
511 template <
typename T,
typename Char>
513 size_t pos,
int arg_id) {
517 auto end = f.parse(ctx);
518 return {f, pos + (end - str.data()) + 1, ctx.
next_arg_id()};
523 template <
typename Args,
size_t POS,
int ID,
typename S>
527 if constexpr (str[POS] ==
'{') {
528 if (POS + 1 == str.size())
530 if constexpr (str[POS + 1] ==
'{') {
531 return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
532 }
else if constexpr (str[POS + 1] ==
'}') {
533 using type = get_type<ID, Args>;
534 return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
536 }
else if constexpr (str[POS + 1] ==
':') {
537 using type = get_type<ID, Args>;
538 constexpr
auto result = parse_specs<type>(str, POS + 2, ID);
539 return parse_tail<Args, result.end, result.next_arg_id>(
540 spec_field<char_type, type, ID>{result.fmt}, format_str);
542 return unknown_format();
544 }
else if constexpr (str[POS] ==
'}') {
545 if (POS + 1 == str.size())
547 return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
549 constexpr
auto end = parse_text(str, POS + 1);
550 if constexpr (end - POS > 1) {
551 return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
554 return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
560 template <
typename... Args,
typename S,
563 constexpr
auto compile(S format_str) {
565 if constexpr (str.size() == 0) {
566 return detail::make_text(str, 0, 0);
572 detail::unknown_format>()) {
580 template <
typename... Args,
typename S,
585 #endif // __cpp_if_constexpr 588 template <
typename... Args,
typename Char,
size_t N>
597 template <
typename... Args>
603 #if FMT_USE_CONSTEXPR 604 # ifdef __cpp_if_constexpr 606 template <
typename CompiledFormat,
typename... Args,
608 FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
610 const Args&... args) {
616 template <
typename OutputIt,
typename CompiledFormat,
typename... Args,
617 FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
618 OutputIt
format_to(OutputIt out,
const CompiledFormat& cf,
619 const Args&... args) {
620 return cf.format(out, args...);
622 # endif // __cpp_if_constexpr 623 #endif // FMT_USE_CONSTEXPR 625 template <
typename CompiledFormat,
typename... Args,
628 CompiledFormat>::value)>
629 std::basic_string<Char>
format(
const CompiledFormat& cf,
const Args&... args) {
633 make_format_args<context>(args...));
637 template <
typename S,
typename... Args,
641 #ifdef __cpp_if_constexpr 642 if constexpr (std::is_same<typename S::char_type, char>::value) {
644 if (str.size() == 2 && str[0] ==
'{' && str[1] ==
'}')
649 return format(compiled, std::forward<Args>(args)...);
652 template <
typename OutputIt,
typename CompiledFormat,
typename... Args,
654 CompiledFormat>::value)>
655 OutputIt
format_to(OutputIt out,
const CompiledFormat& cf,
656 const Args&... args) {
659 return detail::cf::vformat_to<context>(out, cf,
660 make_format_args<context>(args...));
663 template <
typename OutputIt,
typename S,
typename... Args,
665 OutputIt
format_to(OutputIt out,
const S&,
const Args&... args) {
667 return format_to(out, compiled, args...);
670 template <
typename OutputIt,
typename CompiledFormat,
typename... Args>
671 auto format_to_n(OutputIt out,
size_t n,
const CompiledFormat& cf,
672 const Args&... args) ->
673 typename std::enable_if<
677 CompiledFormat>::value,
681 return {it.base(), it.count()};
684 template <
typename OutputIt,
typename S,
typename... Args,
687 const Args&... args) {
691 return {it.base(), it.count()};
694 template <
typename CompiledFormat,
typename... Args>
701 #endif // FMT_COMPILE_H_ constexpr auto compile(S format_str) -> detail::compiled_format< S, Args... >
#define FMT_BEGIN_NAMESPACE
constexpr size_t size() const
FMT_CONSTEXPR void require_numeric_argument()
FMT_CONSTEXPR void remove_prefix(size_t n)
void format_arg(basic_format_parse_context< typename Context::char_type > &parse_ctx, Context &ctx, Id arg_id)
FMT_CONSTEXPR unsigned count_parts(basic_string_view< Char > format_str)
FMT_CONSTEXPR void on_replacement_field(int, const Char *)
FMT_CONSTEXPR void compile_format_string(basic_string_view< Char > format_str, PartHandler handler)
void vformat_to(buffer< Char > &buf, const text_style &ts, basic_string_view< Char > format_str, basic_format_args< buffer_context< type_identity_t< Char >>> args)
FMT_CONSTEXPR void check_arg_id(int)
#define FMT_CONSTEXPR_DECL
FMT_CONSTEXPR std::make_unsigned< Int >::type to_unsigned(Int value)
FMT_CONSTEXPR int next_arg_id()
OutputIt format_to(OutputIt out, const CompiledFormat &cf, const Args &... args)
#define FMT_END_NAMESPACE
typename std::enable_if< B, T >::type enable_if_t
auto format_to_n(OutputIt out, size_t n, const CompiledFormat &cf, const Args &... args) -> typename std::enable_if< detail::is_output_iterator< OutputIt, typename CompiledFormat::char_type >::value &&std::is_base_of< detail::basic_compiled_format, CompiledFormat >::value, format_to_n_result< OutputIt >>::type
std::basic_string< Char > format(const CompiledFormat &cf, const Args &... args)
#define FMT_ENABLE_IF(...)
typename detail::char_t_impl< S >::type char_t
typename std::remove_cv< remove_reference_t< T > >::type remove_cvref_t
FMT_CONSTEXPR int on_arg_id(basic_string_view< Char >)
size_t formatted_size(const CompiledFormat &cf, const Args &... args)
constexpr const T & constexpr_max(const T &a, const T &b)
FMT_CONSTEXPR format_part_array< Char, N > compile_to_parts(basic_string_view< Char > format_str)
FMT_CONSTEXPR void on_error(const char *)
FMT_CONSTEXPR int on_arg_id(int)
FMT_CONSTEXPR const Char * parse_format_specs(const Char *begin, const Char *end, SpecHandler &&handler)
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
const T & first(const T &value, const Tail &...)
checked_ptr< typename Container::value_type > reserve(std::back_insert_iterator< Container > it, size_t n)
FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(Visitor &&vis, const basic_format_arg< Context > &arg) -> decltype(vis(0))
FMT_CONSTEXPR int on_arg_id()
detail::named_arg< Char, T > arg(const Char *name, const T &arg)
FMT_CONSTEXPR const Char * on_format_specs(int, const Char *begin, const Char *end)
auto vformat_to(OutputIt out, CompiledFormat &cf, basic_format_args< Context > args) -> typename Context::iterator