SoPlex Documentation
Loading...
Searching...
No Matches
compile.h
Go to the documentation of this file.
1// Formatting library for C++ - experimental format string compilation
2//
3// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
4// All rights reserved.
5//
6// For the license information refer to format.h.
7
8#ifndef FMT_COMPILE_H_
9#define FMT_COMPILE_H_
10
11#include <vector>
12#include "format.h"
13
15namespace internal {
16
17// Part of a compiled format string. It can be either literal text or a
18// replacement field.
56
57template <typename Char> struct part_counter {
58 unsigned num_parts = 0;
59
60 FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
61 if (begin != end) ++num_parts;
62 }
63
67
69
70 FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
71 const Char* end) {
72 // Find the matching brace.
73 unsigned brace_counter = 0;
74 for (; begin != end; ++begin) {
75 if (*begin == '{') {
76 ++brace_counter;
77 } else if (*begin == '}') {
78 if (brace_counter == 0u) break;
79 --brace_counter;
80 }
81 }
82 return begin;
83 }
84
85 FMT_CONSTEXPR void on_error(const char*) {}
86};
87
88// Counts the number of parts in a format string.
89template <typename Char>
91 part_counter<Char> counter;
92 parse_format_string<true>(format_str, counter);
93 return counter.num_parts;
94}
95
96template <typename Char, typename PartHandler>
98 private:
100
101 PartHandler handler_;
105
106 public:
108 PartHandler handler)
109 : handler_(handler),
110 format_str_(format_str),
111 parse_context_(format_str) {}
112
113 FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
114 if (begin != end)
115 handler_(part::make_text({begin, to_unsigned(end - begin)}));
116 }
117
121
123 parse_context_.check_arg_id(id);
125 }
126
130
134 }
135
136 FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
137 const Char* end) {
138 auto repl = typename part::replacement();
140 repl.specs, parse_context_);
141 auto it = parse_format_specs(begin, end, handler);
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);
147 part.arg_id_end = begin;
148 handler_(part);
149 return it;
150 }
151};
152
153// Compiles a format string and invokes handler(part) for each parsed part.
154template <bool IS_CONSTEXPR, typename Char, typename PartHandler>
156 PartHandler handler) {
157 parse_format_string<IS_CONSTEXPR>(
158 format_str,
159 format_string_compiler<Char, PartHandler>(format_str, handler));
160}
161
162template <typename Range, typename Context, typename Id>
165 Context& ctx, Id arg_id) {
166 ctx.advance_to(
167 visit_format_arg(arg_formatter<Range>(ctx, &parse_ctx), ctx.arg(arg_id)));
168}
169
170// vformat_to is defined in a subnamespace to prevent ADL.
171namespace cf {
172template <typename Context, typename Range, typename CompiledFormat>
173auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
174 -> typename Context::iterator {
175 using char_type = typename Context::char_type;
177 to_string_view(cf.format_str_));
178 Context ctx(out.begin(), args);
179
180 const auto& parts = cf.parts();
181 for (auto part_it = std::begin(parts); part_it != std::end(parts);
182 ++part_it) {
183 const auto& part = *part_it;
184 const auto& value = part.val;
185
186 using format_part_t = format_part<char_type>;
187 switch (part.part_kind) {
188 case format_part_t::kind::text: {
189 const auto text = value.str;
190 auto output = ctx.out();
191 auto&& it = reserve(output, text.size());
192 it = std::copy_n(text.begin(), text.size(), it);
193 ctx.advance_to(output);
194 break;
195 }
196
197 case format_part_t::kind::arg_index:
198 advance_to(parse_ctx, part.arg_id_end);
199 internal::format_arg<Range>(parse_ctx, ctx, value.arg_index);
200 break;
201
202 case format_part_t::kind::arg_name:
203 advance_to(parse_ctx, part.arg_id_end);
204 internal::format_arg<Range>(parse_ctx, ctx, value.str);
205 break;
206
207 case format_part_t::kind::replacement: {
208 const auto& arg_id_value = value.repl.arg_id.val;
209 const auto arg = value.repl.arg_id.kind == arg_id_kind::index
210 ? ctx.arg(arg_id_value.index)
211 : ctx.arg(arg_id_value.name);
212
213 auto specs = value.repl.specs;
214
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);
218
220 numeric_specs_checker<error_handler> checker(h, arg.type());
221 if (specs.align == align::numeric) checker.require_numeric_argument();
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();
225
226 advance_to(parse_ctx, part.arg_id_end);
227 ctx.advance_to(
228 visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
229 break;
230 }
231 }
232 }
233 return ctx.out();
234}
235} // namespace cf
236
238
239template <typename S, typename = void>
242 using parts_container = std::vector<internal::format_part<char_type>>;
243
245
247 compile_format_string<false>(format_str,
248 [this](const format_part<char_type>& part) {
249 compiled_parts.push_back(part);
250 });
251 }
252
253 const parts_container& parts() const { return compiled_parts; }
254};
255
256template <typename Char, unsigned N> struct format_part_array {
259};
260
261template <typename Char, unsigned N>
263 basic_string_view<Char> format_str) {
265 unsigned counter = 0;
266 // This is not a lambda for compatibility with older compilers.
267 struct {
268 format_part<Char>* parts;
269 unsigned* counter;
270 FMT_CONSTEXPR void operator()(const format_part<Char>& part) {
271 parts[(*counter)++] = part;
272 }
273 } collector{parts.data, &counter};
274 compile_format_string<true>(format_str, collector);
275 if (counter < N) {
276 parts.data[counter] =
278 }
279 return parts;
280}
281
282template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) {
283 return (a < b) ? b : a;
284}
285
286template <typename S>
290
292
293// Workaround for old compilers. Format string compilation will not be
294// performed there anyway.
295#if FMT_USE_CONSTEXPR
296 static FMT_CONSTEXPR_DECL const unsigned num_format_parts =
298#else
299 static const unsigned num_format_parts = 1;
300#endif
301
302 using parts_container = format_part<char_type>[num_format_parts];
303
304 const parts_container& parts() const {
305 static FMT_CONSTEXPR_DECL const auto compiled_parts =
306 compile_to_parts<char_type, num_format_parts>(
307 internal::to_string_view(S()));
308 return compiled_parts.data;
309 }
310};
311
312template <typename S, typename... Args>
314 public:
316
317 private:
319
320 template <typename Context, typename Range, typename CompiledFormat>
321 friend auto cf::vformat_to(Range out, CompiledFormat& cf,
323 typename Context::iterator;
324
325 public:
326 compiled_format() = delete;
327 explicit constexpr compiled_format(basic_string_view<char_type> format_str)
328 : compiled_format_base<S>(format_str), format_str_(format_str) {}
329};
330
331#ifdef __cpp_if_constexpr
332template <typename... Args> struct type_list {};
333
334// Returns a reference to the argument at index N from [first, rest...].
335template <int N, typename T, typename... Args>
336constexpr 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)
339 return first;
340 else
341 return get<N - 1>(rest...);
342}
343
344template <int N, typename> struct get_type_impl;
345
346template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
347 using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
348};
349
350template <int N, typename T>
351using get_type = typename get_type_impl<N, T>::type;
352
353template <typename Char> struct text {
355 using char_type = Char;
356
357 template <typename OutputIt, typename... Args>
358 OutputIt format(OutputIt out, const Args&...) const {
359 // TODO: reserve
360 return copy_str<Char>(data.begin(), data.end(), out);
361 }
362};
363
364template <typename Char>
365constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
366 size_t size) {
367 return {{&s[pos], size}};
368}
369
370template <typename Char, typename OutputIt, typename T,
371 std::enable_if_t<std::is_integral_v<T>, int> = 0>
372OutputIt format_default(OutputIt out, T value) {
373 // TODO: reserve
374 format_int fi(value);
375 return std::copy(fi.data(), fi.data() + fi.size(), out);
376}
377
378template <typename Char, typename OutputIt>
379OutputIt format_default(OutputIt out, double value) {
380 writer w(out);
381 w.write(value);
382 return w.out();
383}
384
385template <typename Char, typename OutputIt>
386OutputIt format_default(OutputIt out, Char value) {
387 *out++ = value;
388 return out;
389}
390
391template <typename Char, typename OutputIt>
392OutputIt 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);
395}
396
397// A replacement field that refers to argument N.
398template <typename Char, typename T, int N> struct field {
399 using char_type = Char;
400
401 template <typename OutputIt, typename... Args>
402 OutputIt format(OutputIt out, const Args&... args) const {
403 // This ensures that the argument type is convertile to `const T&`.
404 const T& arg = get<N>(args...);
405 return format_default<Char>(out, arg);
406 }
407};
408
409template <typename L, typename R> struct concat {
410 L lhs;
411 R rhs;
412 using char_type = typename L::char_type;
413
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...);
418 }
419};
420
421template <typename L, typename R>
422constexpr concat<L, R> make_concat(L lhs, R rhs) {
423 return {lhs, rhs};
424}
425
426struct unknown_format {};
427
428template <typename Char>
429constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
430 for (size_t size = str.size(); pos != size; ++pos) {
431 if (str[pos] == '{' || str[pos] == '}') break;
432 }
433 return pos;
434}
435
436template <typename Args, size_t POS, int ID, typename S>
437constexpr auto compile_format_string(S format_str);
438
439template <typename Args, size_t POS, int ID, typename T, typename S>
440constexpr auto parse_tail(T head, S format_str) {
441 if constexpr (POS != to_string_view(format_str).size()) {
442 constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
443 if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
444 unknown_format>())
445 return tail;
446 else
447 return make_concat(head, tail);
448 } else {
449 return head;
450 }
451}
452
453// Compiles a non-empty format string and returns the compiled representation
454// or unknown_format() on unrecognized input.
455template <typename Args, size_t POS, int ID, typename S>
456constexpr auto compile_format_string(S format_str) {
457 using char_type = typename S::char_type;
458 constexpr basic_string_view<char_type> str = format_str;
459 if constexpr (str[POS] == '{') {
460 if (POS + 1 == str.size())
461 throw format_error("unmatched '{' in format string");
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>(),
468 format_str);
469 } else {
470 return unknown_format();
471 }
472 } else {
473 return unknown_format();
474 }
475 } else if constexpr (str[POS] == '}') {
476 if (POS + 1 == str.size())
477 throw format_error("unmatched '}' in format string");
478 return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
479 } else {
480 constexpr auto end = parse_text(str, POS + 1);
481 return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
482 format_str);
483 }
484}
485#endif // __cpp_if_constexpr
486} // namespace internal
487
488#if FMT_USE_CONSTEXPR
489# ifdef __cpp_if_constexpr
490template <typename... Args, typename S,
492constexpr auto compile(S format_str) {
493 constexpr basic_string_view<typename S::char_type> str = format_str;
494 if constexpr (str.size() == 0) {
495 return internal::make_text(str, 0, 0);
496 } else {
497 constexpr auto result =
498 internal::compile_format_string<internal::type_list<Args...>, 0, 0>(
499 format_str);
500 if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
501 internal::unknown_format>()) {
502 return internal::compiled_format<S, Args...>(to_string_view(format_str));
503 } else {
504 return result;
505 }
506 }
507}
508
509template <typename CompiledFormat, typename... Args,
510 typename Char = typename CompiledFormat::char_type,
512 CompiledFormat>::value)>
513std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
515 cf.format(std::back_inserter(buffer), args...);
516 return to_string(buffer);
517}
518
519template <typename OutputIt, typename CompiledFormat, typename... Args,
521 CompiledFormat>::value)>
522OutputIt format_to(OutputIt out, const CompiledFormat& cf,
523 const Args&... args) {
524 return cf.format(out, args...);
525}
526# else
527template <typename... Args, typename S,
529constexpr auto compile(S format_str) -> internal::compiled_format<S, Args...> {
530 return internal::compiled_format<S, Args...>(to_string_view(format_str));
531}
532# endif // __cpp_if_constexpr
533#endif // FMT_USE_CONSTEXPR
534
535// Compiles the format string which must be a string literal.
536template <typename... Args, typename Char, size_t N>
537auto compile(const Char (&format_str)[N])
538 -> internal::compiled_format<const Char*, Args...> {
539 return internal::compiled_format<const Char*, Args...>(
540 basic_string_view<Char>(format_str, N - 1));
541}
542
543template <typename CompiledFormat, typename... Args,
544 typename Char = typename CompiledFormat::char_type,
546 CompiledFormat>::value)>
547std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
549 using range = buffer_range<Char>;
550 using context = buffer_context<Char>;
551 internal::cf::vformat_to<context>(range(buffer), cf,
552 {make_format_args<context>(args...)});
553 return to_string(buffer);
554}
555
556template <typename OutputIt, typename CompiledFormat, typename... Args,
558 CompiledFormat>::value)>
559OutputIt format_to(OutputIt out, const CompiledFormat& cf,
560 const Args&... args) {
561 using char_type = typename CompiledFormat::char_type;
564 return internal::cf::vformat_to<context>(
565 range(out), cf, {make_format_args<context>(args...)});
566}
567
568template <typename OutputIt, typename CompiledFormat, typename... Args,
571 const CompiledFormat& cf,
572 const Args&... args) {
573 auto it =
575 return {it.base(), it.count()};
576}
577
578template <typename CompiledFormat, typename... Args>
579std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
580 return format_to(internal::counting_iterator(), cf, args...).count();
581}
582
584
585#endif // FMT_COMPILE_H_
FMT_CONSTEXPR size_t size() const
Definition core.h:323
FMT_CONSTEXPR iterator end() const
Definition core.h:326
FMT_CONSTEXPR iterator begin() const
Definition core.h:325
constexpr compiled_format(basic_string_view< char_type > format_str)
Definition compile.h:327
basic_string_view< char_type > format_str_
Definition compile.h:318
FMT_CONSTEXPR void on_arg_id()
Definition compile.h:118
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
Definition compile.h:113
FMT_CONSTEXPR void on_arg_id(int id)
Definition compile.h:122
FMT_CONSTEXPR format_string_compiler(basic_string_view< Char > format_str, PartHandler handler)
Definition compile.h:107
basic_string_view< Char > format_str_
Definition compile.h:103
FMT_CONSTEXPR void on_replacement_field(const Char *ptr)
Definition compile.h:131
FMT_CONSTEXPR void on_arg_id(basic_string_view< Char > id)
Definition compile.h:127
FMT_CONSTEXPR const Char * on_format_specs(const Char *begin, const Char *end)
Definition compile.h:136
basic_format_parse_context< Char > parse_context_
Definition compile.h:104
FMT_CONSTEXPR void require_numeric_argument()
Definition format.h:2056
FMT_CONSTEXPR void check_sign()
Definition format.h:2061
FMT_CONSTEXPR void check_precision()
Definition format.h:2069
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
Definition color.h:562
auto compile(const Char(&format_str)[N]) -> internal::compiled_format< const Char *, Args... >
Definition compile.h:537
std::size_t formatted_size(const CompiledFormat &cf, const Args &... args)
Definition compile.h:579
format_to_n_result< OutputIt > format_to_n(OutputIt out, size_t n, const CompiledFormat &cf, const Args &... args)
Definition compile.h:570
std::basic_string< Char > format(const CompiledFormat &cf, const Args &... args)
Definition compile.h:547
OutputIt format_to(OutputIt out, const CompiledFormat &cf, const Args &... args)
Definition compile.h:559
typename std::enable_if< B, T >::type enable_if_t
Definition core.h:204
internal::named_arg< T, Char > arg(const S &name, const T &arg)
Definition core.h:1422
typename std::remove_cv< remove_reference_t< T > >::type remove_cvref_t
Definition core.h:213
#define FMT_CONSTEXPR
Definition core.h:75
#define FMT_BEGIN_NAMESPACE
Definition core.h:163
FMT_CONSTEXPR auto visit_format_arg(Visitor &&vis, const basic_format_arg< Context > &arg) -> decltype(vis(0))
Definition core.h:1004
basic_string_view< Char > to_string_view(const Char *s)
Definition core.h:397
#define FMT_ENABLE_IF(...)
Definition core.h:220
typename internal::char_t_impl< S >::type char_t
Definition core.h:458
#define FMT_END_NAMESPACE
Definition core.h:158
#define FMT_CONSTEXPR_DECL
Definition core.h:76
const void * ptr(const T *p)
Definition format.h:3159
FMT_CONSTEXPR void advance_to(basic_format_parse_context< Char, ErrorHandler > &ctx, const Char *p)
Definition format.h:3085
std::string to_string(const T &value)
Definition format.h:3245
@ numeric
Definition format.h:1005
auto vformat_to(Range out, CompiledFormat &cf, basic_format_args< Context > args) -> typename Context::iterator
Definition compile.h:173
checked_ptr< typename Container::value_type > reserve(std::back_insert_iterator< Container > &it, std::size_t n)
Definition format.h:323
void format_arg(basic_format_parse_context< typename Range::value_type > &parse_ctx, Context &ctx, Id arg_id)
Definition compile.h:163
FMT_CONSTEXPR format_part_array< Char, N > compile_to_parts(basic_string_view< Char > format_str)
Definition compile.h:262
void to_string_view(...)
FMT_CONSTEXPR const Char * parse_format_specs(const Char *begin, const Char *end, SpecHandler &&handler)
Definition format.h:2421
FMT_CONSTEXPR std::make_unsigned< Int >::type to_unsigned(Int value)
Definition core.h:265
FMT_CONSTEXPR void compile_format_string(basic_string_view< Char > format_str, PartHandler handler)
Definition compile.h:155
@ char_type
Definition core.h:698
constexpr const T & constexpr_max(const T &a, const T &b)
Definition compile.h:282
FMT_CONSTEXPR unsigned count_parts(basic_string_view< Char > format_str)
Definition compile.h:90
@ none
Definition format.h:1010
parts_container compiled_parts
Definition compile.h:244
compiled_format_base(basic_string_view< char_type > format_str)
Definition compile.h:246
std::vector< internal::format_part< char_type > > parts_container
Definition compile.h:242
const parts_container & parts() const
Definition compile.h:253
FMT_NORETURN FMT_API void on_error(const char *message)
dynamic_format_specs< Char > specs
Definition compile.h:24
format_part< Char > data[N]
Definition compile.h:257
FMT_CONSTEXPR format_part_array()=default
static FMT_CONSTEXPR format_part make_arg_index(int index)
Definition compile.h:43
static FMT_CONSTEXPR format_part make_text(basic_string_view< Char > text)
Definition compile.h:49
FMT_CONSTEXPR format_part(kind k=kind::arg_index, value v={})
Definition compile.h:40
union internal::format_part::value val
static FMT_CONSTEXPR format_part make_arg_name(basic_string_view< Char > name)
Definition compile.h:46
const Char * arg_id_end
Definition compile.h:38
static FMT_CONSTEXPR format_part make_replacement(replacement repl)
Definition compile.h:52
FMT_CONSTEXPR void on_arg_id()
Definition compile.h:64
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
Definition compile.h:60
FMT_CONSTEXPR void on_replacement_field(const Char *)
Definition compile.h:68
FMT_CONSTEXPR void on_arg_id(basic_string_view< Char >)
Definition compile.h:66
FMT_CONSTEXPR void on_error(const char *)
Definition compile.h:85
FMT_CONSTEXPR void on_arg_id(int)
Definition compile.h:65
FMT_CONSTEXPR const Char * on_format_specs(const Char *begin, const Char *end)
Definition compile.h:70
FMT_CONSTEXPR value(basic_string_view< Char > s)
Definition compile.h:34
FMT_CONSTEXPR value(int index=0)
Definition compile.h:33
FMT_CONSTEXPR value(replacement r)
Definition compile.h:35
basic_string_view< Char > str
Definition compile.h:30