58 unsigned num_parts = 0;
61 if (begin != end) ++num_parts;
73 unsigned brace_counter = 0;
74 for (; begin != end; ++begin) {
77 }
else if (*begin ==
'}') {
78 if (brace_counter == 0u)
break;
89 template <
typename Char>
92 parse_format_string<true>(format_str, counter);
96 template <
typename Char,
typename PartHandler>
110 format_str_(format_str),
111 parse_context_(format_str) {}
115 handler_(part::make_text({begin,
to_unsigned(end - begin)}));
119 part_ = part::make_arg_index(parse_context_.
next_arg_id());
124 part_ = part::make_arg_index(
id);
128 part_ = part::make_arg_name(
id);
140 repl.specs, parse_context_);
142 if (*it !=
'}') on_error(
"missing '}' in format string");
143 repl.arg_id = part_.
part_kind == part::kind::arg_index
146 auto part = part::make_replacement(repl);
154 template <
bool IS_CONSTEXPR,
typename Char,
typename PartHandler>
156 PartHandler handler) {
157 parse_format_string<IS_CONSTEXPR>(
162 template <
typename Range,
typename Context,
typename Id>
165 Context& ctx, Id arg_id) {
172 template <
typename Context,
typename Range,
typename CompiledFormat>
174 ->
typename Context::iterator {
178 Context ctx(out.begin(), args);
180 const auto& parts = cf.parts();
181 for (
auto part_it = std::begin(parts); part_it != std::end(parts);
183 const auto& part = *part_it;
184 const auto&
value = part.val;
187 switch (part.part_kind) {
188 case format_part_t::kind::text: {
190 auto output = ctx.out();
192 it = std::copy_n(
text.begin(),
text.size(), it);
193 ctx.advance_to(output);
197 case format_part_t::kind::arg_index:
199 internal::format_arg<Range>(parse_ctx, ctx,
value.arg_index);
202 case format_part_t::kind::arg_name:
204 internal::format_arg<Range>(parse_ctx, ctx,
value.str);
207 case format_part_t::kind::replacement: {
208 const auto& arg_id_value =
value.repl.arg_id.val;
210 ? ctx.arg(arg_id_value.index)
211 : ctx.arg(arg_id_value.name);
213 auto specs =
value.repl.specs;
215 handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
216 handle_dynamic_spec<precision_checker>(specs.precision,
217 specs.precision_ref, ctx);
222 if (specs.sign !=
sign::none) checker.check_sign();
223 if (specs.alt) checker.require_numeric_argument();
224 if (specs.precision >= 0) checker.check_precision();
239 template <
typename S,
typename =
void>
247 compile_format_string<false>(format_str,
249 compiled_parts.push_back(part);
261 template <
typename Char,
unsigned N>
265 unsigned counter = 0;
271 parts[(*counter)++] = part;
273 } collector{parts.
data, &counter};
274 compile_format_string<true>(format_str, collector);
276 parts.
data[counter] =
282 template <
typename T> constexpr
const T&
constexpr_max(
const T& a,
const T& b) {
283 return (a < b) ? b : a;
286 template <
typename S>
295 #if FMT_USE_CONSTEXPR 299 static const unsigned num_format_parts = 1;
306 compile_to_parts<char_type, num_format_parts>(
308 return compiled_parts.data;
312 template <
typename S,
typename... Args>
320 template <
typename Context,
typename Range,
typename CompiledFormat>
323 typename Context::iterator;
331 #ifdef __cpp_if_constexpr 332 template <
typename... Args>
struct type_list {};
335 template <
int N,
typename T,
typename... Args>
336 constexpr
const auto&
get(
const T& first,
const Args&... rest) {
337 static_assert(N < 1 +
sizeof...(Args),
"index is out of bounds");
338 if constexpr (N == 0)
341 return get<N - 1>(rest...);
344 template <
int N,
typename>
struct get_type_impl;
346 template <
int N,
typename... Args>
struct get_type_impl<N, type_list<Args...>> {
350 template <
int N,
typename T>
353 template <
typename Char>
struct text {
357 template <
typename OutputIt,
typename... Args>
358 OutputIt
format(OutputIt out,
const Args&...)
const {
360 return copy_str<Char>(data.
begin(), data.
end(), out);
364 template <
typename Char>
367 return {{&s[pos], size}};
370 template <
typename Char,
typename OutputIt,
typename T,
371 std::enable_if_t<std::is_integral_v<T>,
int> = 0>
372 OutputIt format_default(OutputIt out, T
value) {
378 template <
typename Char,
typename OutputIt>
379 OutputIt format_default(OutputIt out,
double value) {
385 template <
typename Char,
typename OutputIt>
386 OutputIt format_default(OutputIt out, Char value) {
391 template <
typename Char,
typename OutputIt>
392 OutputIt format_default(OutputIt out,
const Char* value) {
393 auto length = std::char_traits<Char>::length(value);
394 return copy_str<Char>(value, value + length, out);
398 template <
typename Char,
typename T,
int N>
struct field {
401 template <
typename OutputIt,
typename... Args>
402 OutputIt
format(OutputIt out,
const Args&... args)
const {
404 const T&
arg = get<N>(args...);
405 return format_default<Char>(out,
arg);
409 template <
typename L,
typename R>
struct concat {
414 template <
typename OutputIt,
typename... Args>
415 OutputIt
format(OutputIt out,
const Args&... args)
const {
416 out = lhs.format(out, args...);
417 return rhs.format(out, args...);
421 template <
typename L,
typename R>
422 constexpr concat<L, R> make_concat(L lhs, R rhs) {
426 struct unknown_format {};
428 template <
typename Char>
430 for (
size_t size = str.
size(); pos != size; ++pos) {
431 if (str[pos] ==
'{' || str[pos] ==
'}')
break;
436 template <
typename Args,
size_t POS,
int ID,
typename S>
439 template <
typename Args,
size_t POS,
int ID,
typename T,
typename S>
440 constexpr
auto parse_tail(T head, S format_str) {
442 constexpr
auto tail = compile_format_string<Args, POS, ID>(format_str);
447 return make_concat(head, tail);
455 template <
typename Args,
size_t POS,
int ID,
typename S>
459 if constexpr (str[POS] ==
'{') {
460 if (POS + 1 == str.size())
462 if constexpr (str[POS + 1] ==
'{') {
463 return parse_tail<Args, POS + 2, ID>(
make_text(str, POS, 1), format_str);
464 }
else if constexpr (str[POS + 1] ==
'}') {
465 using type = get_type<ID, Args>;
466 if constexpr (std::is_same<type, int>::value) {
467 return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
470 return unknown_format();
473 return unknown_format();
475 }
else if constexpr (str[POS] ==
'}') {
476 if (POS + 1 == str.size())
478 return parse_tail<Args, POS + 2, ID>(
make_text(str, POS, 1), format_str);
480 constexpr
auto end = parse_text(str, POS + 1);
481 return parse_tail<Args, end, ID>(
make_text(str, POS, end - POS),
485 #endif // __cpp_if_constexpr 488 #if FMT_USE_CONSTEXPR 489 # ifdef __cpp_if_constexpr 490 template <
typename... Args,
typename S,
492 constexpr
auto compile(S format_str) {
494 if constexpr (str.size() == 0) {
495 return internal::make_text(str, 0, 0);
501 internal::unknown_format>()) {
509 template <
typename CompiledFormat,
typename... Args,
512 CompiledFormat>::
value)>
513 std::basic_string<Char>
format(
const CompiledFormat& cf,
const Args&... args) {
515 cf.format(std::back_inserter(buffer), args...);
519 template <
typename OutputIt,
typename CompiledFormat,
typename... Args,
521 CompiledFormat>::
value)>
522 OutputIt
format_to(OutputIt out,
const CompiledFormat& cf,
523 const Args&... args) {
524 return cf.format(out, args...);
527 template <
typename... Args,
typename S,
532 # endif // __cpp_if_constexpr 533 #endif // FMT_USE_CONSTEXPR 536 template <
typename... Args,
typename Char,
size_t N>
543 template <
typename CompiledFormat,
typename... Args,
546 CompiledFormat>::value)>
547 std::basic_string<Char>
format(
const CompiledFormat& cf,
const Args&... args) {
551 internal::cf::vformat_to<context>(range(buffer), cf,
552 {make_format_args<context>(args...)});
556 template <
typename OutputIt,
typename CompiledFormat,
typename... Args,
558 CompiledFormat>::value)>
559 OutputIt
format_to(OutputIt out,
const CompiledFormat& cf,
560 const Args&... args) {
564 return internal::cf::vformat_to<context>(
565 range(out), cf, {make_format_args<context>(args...)});
568 template <
typename OutputIt,
typename CompiledFormat,
typename... Args,
571 const CompiledFormat& cf,
572 const Args&... args) {
575 return {it.base(), it.count()};
578 template <
typename CompiledFormat,
typename... Args>
585 #endif // FMT_COMPILE_H_ #define FMT_BEGIN_NAMESPACE
FMT_CONSTEXPR iterator end() const
FMT_CONSTEXPR const Char * parse_format_specs(const Char *begin, const Char *end, SpecHandler &&handler)
void format_arg(basic_format_parse_context< typename Range::value_type > &parse_ctx, Context &ctx, Id arg_id)
FMT_CONSTEXPR const Char * on_format_specs(const Char *begin, const Char *end)
FMT_CONSTEXPR void on_arg_id()
FMT_CONSTEXPR void check_arg_id(int)
constexpr const T & constexpr_max(const T &a, const T &b)
#define FMT_CONSTEXPR_DECL
auto vformat_to(Range out, CompiledFormat &cf, basic_format_args< Context > args) -> typename Context::iterator
void vformat_to(basic_memory_buffer< Char > &buf, const text_style &ts, basic_string_view< Char > format_str, basic_format_args< buffer_context< Char >> args)
FMT_CONSTEXPR int next_arg_id()
typename internal::char_t_impl< S >::type char_t
OutputIt format_to(OutputIt out, const CompiledFormat &cf, const Args &... args)
#define FMT_END_NAMESPACE
FMT_CONSTEXPR size_t size() const
FMT_CONSTEXPR void compile_format_string(basic_string_view< Char > format_str, PartHandler handler)
checked_ptr< typename Container::value_type > reserve(std::back_insert_iterator< Container > &it, std::size_t n)
typename std::enable_if< B, T >::type enable_if_t
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
OutputIterator copy(const RangeT &range, OutputIterator out)
std::basic_string< Char > format(const CompiledFormat &cf, const Args &... args)
FMT_CONSTEXPR void on_error(const char *)
#define FMT_ENABLE_IF(...)
std::size_t formatted_size(const CompiledFormat &cf, const Args &... args)
typename std::remove_cv< remove_reference_t< T > >::type remove_cvref_t
FMT_CONSTEXPR format_part_array< Char, N > compile_to_parts(basic_string_view< Char > format_str)
FMT_CONSTEXPR auto visit_format_arg(Visitor &&vis, const basic_format_arg< Context > &arg) -> decltype(vis(0))
format_to_n_result< OutputIt > format_to_n(OutputIt out, size_t n, const CompiledFormat &cf, const Args &... args)
FMT_CONSTEXPR void on_arg_id(basic_string_view< Char >)
FMT_CONSTEXPR void on_arg_id(int)
FMT_CONSTEXPR void require_numeric_argument()
FMT_CONSTEXPR iterator begin() const
auto compile(const Char(&format_str)[N]) -> internal::compiled_format< const Char *, Args... >
FMT_CONSTEXPR unsigned count_parts(basic_string_view< Char > format_str)
FMT_CONSTEXPR void on_replacement_field(const Char *)
internal::named_arg< T, Char > arg(const S &name, const T &arg)
FMT_CONSTEXPR std::make_unsigned< Int >::type to_unsigned(Int value)