35 size_t count()
const {
return count_; }
48 it.
count_ +=
static_cast<size_t>(
n);
55 template <
typename Char,
typename InputIt>
70 : out_(out), limit_(limit) {}
81 OutputIt
base()
const {
return out_; }
82 size_t count()
const {
return count_; }
87 template <
typename OutputIt,
88 typename Enable =
typename std::is_void<
92 template <
typename OutputIt>
106 if (this->count_++ < this->limit_) ++this->out_;
117 return this->count_ < this->limit_ ? *this->out_ : blackhole_;
121 template <
typename OutputIt>
131 if (this->count_++ < this->limit_) *this->out_++ = val;
143 template <
typename S>
159 #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
160 # define FMT_COMPILE(s) \
161 FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
163 # define FMT_COMPILE(s) FMT_STRING(s)
166 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
167 template <
typename Char,
size_t N,
168 fmt::detail_exported::fixed_string<Char, N> Str>
169 struct udl_compiled_string : compiled_string {
170 using char_type = Char;
171 constexpr
operator basic_string_view<char_type>()
const {
172 return {Str.data, N - 1};
177 template <
typename T,
typename... Tail>
182 #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
183 template <
typename... Args>
struct type_list {};
186 template <
int N,
typename T,
typename... Args>
187 constexpr
const auto&
get([[maybe_unused]]
const T&
first,
188 [[maybe_unused]]
const Args&... rest) {
189 static_assert(N < 1 +
sizeof...(Args),
"index is out of bounds");
190 if constexpr (N == 0)
196 template <typename Char, typename... Args>
198 type_list<Args...>) {
202 template <
int N,
typename>
struct get_type_impl;
204 template <
int N,
typename... Args>
struct get_type_impl<N, type_list<Args...>> {
206 remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
209 template <
int N,
typename T>
212 template <
typename T>
struct is_compiled_format : std::false_type {};
214 template <
typename Char>
struct text {
215 basic_string_view<Char>
data;
218 template <
typename OutputIt,
typename... Args>
219 constexpr OutputIt
format(OutputIt out,
const Args&...)
const {
220 return write<Char>(out,
data);
224 template <
typename Char>
225 struct is_compiled_format<
text<Char>> : std::true_type {};
227 template <
typename Char>
228 constexpr text<Char> make_text(basic_string_view<Char>
s,
size_t pos,
230 return {{&
s[pos],
size}};
233 template <
typename Char>
struct code_unit {
237 template <
typename OutputIt,
typename... Args>
238 constexpr OutputIt
format(OutputIt out,
const Args&...)
const {
239 return write<Char>(out, value);
244 template <
typename T,
int N,
typename... Args>
245 constexpr
const T& get_arg_checked(
const Args&... args) {
246 const auto&
arg = detail::get<N>(args...);
254 template <
typename Char>
255 struct is_compiled_format<code_unit<Char>> : std::true_type {};
258 template <
typename Char,
typename T,
int N>
struct field {
261 template <
typename OutputIt,
typename... Args>
262 constexpr OutputIt
format(OutputIt out,
const Args&... args)
const {
263 return write<Char>(out, get_arg_checked<T, N>(args...));
267 template <
typename Char,
typename T,
int N>
268 struct is_compiled_format<field<Char,
T, N>> : std::true_type {};
271 template <
typename Char>
struct runtime_named_field {
273 basic_string_view<Char>
name;
275 template <
typename OutputIt,
typename T>
276 constexpr
static bool try_format_argument(
279 [[maybe_unused]] basic_string_view<Char> arg_name,
const T&
arg) {
281 if (arg_name ==
arg.name) {
282 out = write<Char>(out,
arg.value);
289 template <
typename OutputIt,
typename... Args>
290 constexpr OutputIt
format(OutputIt out,
const Args&... args)
const {
291 bool found = (try_format_argument(out, name, args) || ...);
293 FMT_THROW(format_error(
"argument with specified name is not found"));
299 template <
typename Char>
300 struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
303 template <
typename Char,
typename T,
int N>
struct spec_field {
305 formatter<T, Char>
fmt;
307 template <
typename OutputIt,
typename... Args>
309 const Args&... args)
const {
311 fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
312 basic_format_context<OutputIt, Char> ctx(out, vargs);
313 return fmt.format(get_arg_checked<T, N>(args...), ctx);
317 template <
typename Char,
typename T,
int N>
318 struct is_compiled_format<spec_field<Char,
T, N>> : std::true_type {};
320 template <
typename L,
typename R>
struct concat {
325 template <
typename OutputIt,
typename... Args>
326 constexpr OutputIt
format(OutputIt out,
const Args&... args)
const {
327 out = lhs.format(out, args...);
328 return rhs.format(out, args...);
332 template <
typename L,
typename R>
333 struct is_compiled_format<
concat<L, R>> : std::true_type {};
335 template <
typename L,
typename R>
336 constexpr concat<L, R> make_concat(L lhs, R rhs) {
340 struct unknown_format {};
342 template <
typename Char>
343 constexpr
size_t parse_text(basic_string_view<Char> str,
size_t pos) {
344 for (
size_t size = str.size(); pos !=
size; ++pos) {
345 if (str[pos] ==
'{' || str[pos] ==
'}')
break;
350 template <
typename Args,
size_t POS,
int ID,
typename S>
351 constexpr
auto compile_format_string(S format_str);
353 template <
typename Args,
size_t POS,
int ID,
typename T,
typename S>
354 constexpr
auto parse_tail(
T head, S format_str) {
356 basic_string_view<typename S::char_type>(format_str).
size()) {
357 constexpr
auto tail = compile_format_string<Args, POS, ID>(format_str);
362 return make_concat(head, tail);
368 template <
typename T,
typename Char>
struct parse_specs_result {
369 formatter<T, Char>
fmt;
374 constexpr
int manual_indexing_id = -1;
376 template <
typename T,
typename Char>
377 constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
378 size_t pos,
int next_arg_id) {
379 str.remove_prefix(pos);
380 auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id);
381 auto f = formatter<T, Char>();
382 auto end = f.parse(ctx);
384 next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
387 template <
typename Char>
struct arg_id_handler {
388 arg_ref<Char> arg_id;
390 constexpr
int operator()() {
391 FMT_ASSERT(
false,
"handler cannot be used with automatic indexing");
394 constexpr
int operator()(
int id) {
395 arg_id = arg_ref<Char>(
id);
398 constexpr
int operator()(basic_string_view<Char>
id) {
399 arg_id = arg_ref<Char>(
id);
403 constexpr
void on_error(
const char* message) {
408 template <
typename Char>
struct parse_arg_id_result {
409 arg_ref<Char> arg_id;
410 const Char* arg_id_end;
413 template <
int ID,
typename Char>
415 auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
417 return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
420 template <
typename T,
typename Enable =
void>
struct field_type {
421 using type = remove_cvref_t<T>;
424 template <
typename T>
429 template <
typename T,
typename Args,
size_t END_POS,
int ARG_INDEX,
int NEXT_ID,
431 constexpr
auto parse_replacement_field_then_tail(S format_str) {
433 constexpr
auto str = basic_string_view<char_type>(format_str);
435 if constexpr (c ==
'}') {
436 return parse_tail<Args, END_POS + 1, NEXT_ID>(
439 }
else if constexpr (c ==
':') {
441 str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
442 return parse_tail<Args,
result.end,
result.next_arg_id>(
451 template <
typename Args,
size_t POS,
int ID,
typename S>
452 constexpr
auto compile_format_string(S format_str) {
454 constexpr
auto str = basic_string_view<char_type>(format_str);
455 if constexpr (str[POS] ==
'{') {
456 if constexpr (POS + 1 == str.size())
457 FMT_THROW(format_error("unmatched '{
' in format string"));
458 if constexpr (str[POS + 1] == '{
') {
459 return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
460 } else if constexpr (str[POS + 1] == '}
' || str[POS + 1] == ':
') {
461 static_assert(ID != manual_indexing_id,
462 "cannot switch from manual to automatic argument indexing");
463 constexpr auto next_id =
464 ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
465 return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
466 POS + 1, ID, next_id>(
469 constexpr auto arg_id_result =
470 parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
471 constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
472 constexpr char_type c =
473 arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
474 static_assert(c == '}
' || c == ':
', "missing '}
' in format string");
475 if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
477 ID == manual_indexing_id || ID == 0,
478 "cannot switch from automatic to manual argument indexing");
479 constexpr auto arg_index = arg_id_result.arg_id.val.index;
480 return parse_replacement_field_then_tail<get_type<arg_index, Args>,
481 Args, arg_id_end_pos,
482 arg_index, manual_indexing_id>(
484 } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
485 constexpr auto arg_index =
486 get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
487 if constexpr (arg_index != invalid_arg_index) {
488 constexpr auto next_id =
489 ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
490 return parse_replacement_field_then_tail<
491 decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
492 arg_index, next_id>(format_str);
494 if constexpr (c == '}
') {
495 return parse_tail<Args, arg_id_end_pos + 1, ID>(
496 runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
498 } else if constexpr (c == ':
') {
499 return unknown_format(); // no type info for specs parsing
504 } else if constexpr (str[POS] == '}
') {
505 if constexpr (POS + 1 == str.size())
506 FMT_THROW(format_error("unmatched '}
' in format string"));
507 return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
509 constexpr auto end = parse_text(str, POS + 1);
510 if constexpr (end - POS > 1) {
511 return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
514 return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
520 template <typename... Args, typename S,
521 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
522 constexpr auto compile(S format_str) {
523 constexpr auto str = basic_string_view<typename S::char_type>(format_str);
524 if constexpr (str.size() == 0) {
525 return detail::make_text(str, 0, 0);
527 constexpr auto result =
528 detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
533 #endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
534 } // namespace detail
536 FMT_MODULE_EXPORT_BEGIN
538 #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
540 template <typename CompiledFormat, typename... Args,
541 typename Char = typename CompiledFormat::char_type,
542 FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
543 FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
544 const Args&... args) {
545 auto s = std::basic_string<Char>();
546 cf.format(std::back_inserter(s), args...);
550 template <typename OutputIt, typename CompiledFormat, typename... Args,
551 FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
552 constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
553 const Args&... args) {
554 return cf.format(out, args...);
557 template <typename S, typename... Args,
558 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
559 FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
561 if constexpr (std::is_same<typename S::char_type, char>::value) {
562 constexpr auto str = basic_string_view<typename S::char_type>(S());
563 if constexpr (str.size() == 2 && str[0] == '{
' && str[1] == '}
') {
564 const auto& first = detail::first(args...);
565 if constexpr (detail::is_named_arg<
566 remove_cvref_t<decltype(first)>>::value) {
567 return fmt::to_string(first.value);
569 return fmt::to_string(first);
573 constexpr auto compiled = detail::compile<Args...>(S());
574 if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
575 detail::unknown_format>()) {
576 return format(static_cast<basic_string_view<typename S::char_type>>(S()),
577 std::forward<Args>(args)...);
579 return format(compiled, std::forward<Args>(args)...);
583 template <typename OutputIt, typename S, typename... Args,
584 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
585 FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
586 constexpr auto compiled = detail::compile<Args...>(S());
587 if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
588 detail::unknown_format>()) {
589 return format_to(out,
590 static_cast<basic_string_view<typename S::char_type>>(S()),
591 std::forward<Args>(args)...);
593 return format_to(out, compiled, std::forward<Args>(args)...);
598 template <typename OutputIt, typename S, typename... Args,
599 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
600 format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
601 const S& format_str, Args&&... args) {
602 auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
603 std::forward<Args>(args)...);
604 return {it.base(), it.count()};
607 template <typename S, typename... Args,
608 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
609 size_t formatted_size(const S& format_str, const Args&... args) {
610 return format_to(detail::counting_iterator(), format_str, args...).count();
613 template <typename S, typename... Args,
614 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
615 void print(std::FILE* f, const S& format_str, const Args&... args) {
616 memory_buffer buffer;
617 format_to(std::back_inserter(buffer), format_str, args...);
618 detail::print(f, {buffer.data(), buffer.size()});
621 template <typename S, typename... Args,
622 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
623 void print(const S& format_str, const Args&... args) {
624 print(stdout, format_str, args...);
627 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
628 inline namespace literals {
629 template <detail_exported::fixed_string Str>
630 constexpr detail::udl_compiled_string<
631 remove_cvref_t<decltype(Str.data[0])>,
632 sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
636 } // namespace literals
639 FMT_MODULE_EXPORT_END
642 #endif // FMT_COMPILE_H_