Scippy

SoPlex

Sequential object-oriented simPlex

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 
15 namespace internal {
16 
17 // Part of a compiled format string. It can be either literal text or a
18 // replacement field.
19 template <typename Char> struct format_part {
20  enum class kind { arg_index, arg_name, text, replacement };
21 
22  struct replacement {
25  };
26 
28  union value {
29  int arg_index;
31  replacement repl;
32 
33  FMT_CONSTEXPR value(int index = 0) : arg_index(index) {}
35  FMT_CONSTEXPR value(replacement r) : repl(r) {}
36  } val;
37  // Position past the end of the argument id.
38  const Char* arg_id_end = nullptr;
39 
41  : part_kind(k), val(v) {}
42 
44  return format_part(kind::arg_index, index);
45  }
47  return format_part(kind::arg_name, name);
48  }
50  return format_part(kind::text, text);
51  }
52  static FMT_CONSTEXPR format_part make_replacement(replacement repl) {
53  return format_part(kind::replacement, repl);
54  }
55 };
56 
57 template <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 
64  FMT_CONSTEXPR void on_arg_id() { ++num_parts; }
65  FMT_CONSTEXPR void on_arg_id(int) { ++num_parts; }
67 
68  FMT_CONSTEXPR void on_replacement_field(const Char*) {}
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.
89 template <typename Char>
91  part_counter<Char> counter;
92  parse_format_string<true>(format_str, counter);
93  return counter.num_parts;
94 }
95 
96 template <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 
119  part_ = part::make_arg_index(parse_context_.next_arg_id());
120  }
121 
122  FMT_CONSTEXPR void on_arg_id(int id) {
123  parse_context_.check_arg_id(id);
124  part_ = part::make_arg_index(id);
125  }
126 
128  part_ = part::make_arg_name(id);
129  }
130 
132  part_.arg_id_end = ptr;
133  handler_(part_);
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
144  ? arg_ref<Char>(part_.val.arg_index)
145  : arg_ref<Char>(part_.val.str);
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.
154 template <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 
162 template <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.
171 namespace cf {
172 template <typename Context, typename Range, typename CompiledFormat>
173 auto 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 
219  error_handler h;
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 
239 template <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 
256 template <typename Char, unsigned N> struct format_part_array {
258  FMT_CONSTEXPR format_part_array() = default;
259 };
260 
261 template <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 
282 template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) {
283  return (a < b) ? b : a;
284 }
285 
286 template <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>(
308  return compiled_parts.data;
309  }
310 };
311 
312 template <typename S, typename... Args>
314  public:
315  using typename compiled_format_base<S>::char_type;
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
332 template <typename... Args> struct type_list {};
333 
334 // Returns a reference to the argument at index N from [first, rest...].
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)
339  return first;
340  else
341  return get<N - 1>(rest...);
342 }
343 
344 template <int N, typename> struct get_type_impl;
345 
346 template <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 
350 template <int N, typename T>
351 using get_type = typename get_type_impl<N, T>::type;
352 
353 template <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 
364 template <typename Char>
365 constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
366  size_t size) {
367  return {{&s[pos], size}};
368 }
369 
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) {
373  // TODO: reserve
374  format_int fi(value);
375  return std::copy(fi.data(), fi.data() + fi.size(), out);
376 }
377 
378 template <typename Char, typename OutputIt>
379 OutputIt format_default(OutputIt out, double value) {
380  writer w(out);
381  w.write(value);
382  return w.out();
383 }
384 
385 template <typename Char, typename OutputIt>
386 OutputIt format_default(OutputIt out, Char value) {
387  *out++ = value;
388  return out;
389 }
390 
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);
395 }
396 
397 // A replacement field that refers to argument N.
398 template <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 
409 template <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 
421 template <typename L, typename R>
422 constexpr concat<L, R> make_concat(L lhs, R rhs) {
423  return {lhs, rhs};
424 }
425 
426 struct unknown_format {};
427 
428 template <typename Char>
429 constexpr 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 
436 template <typename Args, size_t POS, int ID, typename S>
437 constexpr auto compile_format_string(S format_str);
438 
439 template <typename Args, size_t POS, int ID, typename T, typename S>
440 constexpr 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.
455 template <typename Args, size_t POS, int ID, typename S>
456 constexpr 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
490 template <typename... Args, typename S,
492 constexpr 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 
509 template <typename CompiledFormat, typename... Args,
510  typename Char = typename CompiledFormat::char_type,
512  CompiledFormat>::value)>
513 std::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 
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...);
525 }
526 # else
527 template <typename... Args, typename S,
529 constexpr 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.
536 template <typename... Args, typename Char, size_t N>
537 auto 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 
543 template <typename CompiledFormat, typename... Args,
544  typename Char = typename CompiledFormat::char_type,
546  CompiledFormat>::value)>
547 std::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 
556 template <typename OutputIt, typename CompiledFormat, typename... Args,
558  CompiledFormat>::value)>
559 OutputIt 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 
568 template <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 
578 template <typename CompiledFormat, typename... Args>
579 std::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_
#define FMT_BEGIN_NAMESPACE
Definition: core.h:163
unsigned num_parts
Definition: compile.h:58
static FMT_CONSTEXPR format_part make_text(basic_string_view< Char > text)
Definition: compile.h:49
FMT_CONSTEXPR iterator end() const
Definition: core.h:326
FMT_CONSTEXPR const Char * parse_format_specs(const Char *begin, const Char *end, SpecHandler &&handler)
Definition: format.h:2421
static FMT_CONSTEXPR format_part make_replacement(replacement repl)
Definition: compile.h:52
std::vector< internal::format_part< char_type > > parts_container
Definition: compile.h:242
void format_arg(basic_format_parse_context< typename Range::value_type > &parse_ctx, Context &ctx, Id arg_id)
Definition: compile.h:163
FMT_CONSTEXPR value(replacement r)
Definition: compile.h:35
static FMT_CONSTEXPR format_part make_arg_name(basic_string_view< Char > name)
Definition: compile.h:46
FMT_CONSTEXPR const Char * on_format_specs(const Char *begin, const Char *end)
Definition: compile.h:70
FMT_CONSTEXPR void on_arg_id(int id)
Definition: compile.h:122
FMT_CONSTEXPR void on_arg_id()
Definition: compile.h:64
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
Definition: compile.h:113
FMT_CONSTEXPR void check_arg_id(int)
Definition: core.h:522
constexpr const T & constexpr_max(const T &a, const T &b)
Definition: compile.h:282
union internal::format_part::value val
#define FMT_CONSTEXPR_DECL
Definition: core.h:76
constexpr compiled_format(basic_string_view< char_type > format_str)
Definition: compile.h:327
auto vformat_to(Range out, CompiledFormat &cf, basic_format_args< Context > args) -> typename Context::iterator
Definition: compile.h:173
FMT_CONSTEXPR format_string_compiler(basic_string_view< Char > format_str, PartHandler handler)
Definition: compile.h:107
parts_container compiled_parts
Definition: compile.h:244
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)
Definition: color.h:473
FMT_CONSTEXPR int next_arg_id()
Definition: core.h:512
typename internal::char_t_impl< S >::type char_t
Definition: core.h:458
std::size_t size() const
Definition: format.h:2865
OutputIt format_to(OutputIt out, const CompiledFormat &cf, const Args &... args)
Definition: compile.h:559
static FMT_CONSTEXPR format_part make_arg_index(int index)
Definition: compile.h:43
#define FMT_END_NAMESPACE
Definition: core.h:158
FMT_CONSTEXPR size_t size() const
Definition: core.h:323
dynamic_format_specs< Char > specs
Definition: compile.h:24
FMT_CONSTEXPR void compile_format_string(basic_string_view< Char > format_str, PartHandler handler)
Definition: compile.h:155
FMT_CONSTEXPR const Char * on_format_specs(const Char *begin, const Char *end)
Definition: compile.h:136
checked_ptr< typename Container::value_type > reserve(std::back_insert_iterator< Container > &it, std::size_t n)
Definition: format.h:323
FMT_CONSTEXPR void on_arg_id(basic_string_view< Char > id)
Definition: compile.h:127
FMT_CONSTEXPR void on_arg_id()
Definition: compile.h:118
typename std::enable_if< B, T >::type enable_if_t
Definition: core.h:204
FMT_CONSTEXPR void on_replacement_field(const Char *ptr)
Definition: compile.h:131
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
Definition: compile.h:60
std::string to_string(const T &value)
Definition: format.h:3245
OutputIterator copy(const RangeT &range, OutputIterator out)
Definition: ranges.h:58
std::basic_string< Char > format(const CompiledFormat &cf, const Args &... args)
Definition: compile.h:547
FMT_CONSTEXPR void on_error(const char *)
Definition: compile.h:85
#define FMT_ENABLE_IF(...)
Definition: core.h:220
std::size_t formatted_size(const CompiledFormat &cf, const Args &... args)
Definition: compile.h:579
void to_string_view(...)
typename std::remove_cv< remove_reference_t< T > >::type remove_cvref_t
Definition: core.h:213
FMT_CONSTEXPR format_part_array< Char, N > compile_to_parts(basic_string_view< Char > format_str)
Definition: compile.h:262
const char * data() const
Definition: format.h:2873
FMT_CONSTEXPR auto visit_format_arg(Visitor &&vis, const basic_format_arg< Context > &arg) -> decltype(vis(0))
Definition: core.h:1004
FMT_CONSTEXPR format_part(kind k=kind::arg_index, value v={})
Definition: compile.h:40
format_to_n_result< OutputIt > format_to_n(OutputIt out, size_t n, const CompiledFormat &cf, const Args &... args)
Definition: compile.h:570
type
Definition: core.h:687
format_part< Char > data[N]
Definition: compile.h:257
FMT_CONSTEXPR void on_arg_id(basic_string_view< Char >)
Definition: compile.h:66
FMT_CONSTEXPR void on_arg_id(int)
Definition: compile.h:65
FMT_CONSTEXPR void advance_to(basic_format_parse_context< Char, ErrorHandler > &ctx, const Char *p)
Definition: format.h:3085
compiled_format_base(basic_string_view< char_type > format_str)
Definition: compile.h:246
FMT_CONSTEXPR void require_numeric_argument()
Definition: format.h:2056
void write(int value)
Definition: format.h:1654
FMT_CONSTEXPR iterator begin() const
Definition: core.h:325
auto compile(const Char(&format_str)[N]) -> internal::compiled_format< const Char *, Args... >
Definition: compile.h:537
FMT_CONSTEXPR unsigned count_parts(basic_string_view< Char > format_str)
Definition: compile.h:90
FMT_CONSTEXPR void on_replacement_field(const Char *)
Definition: compile.h:68
basic_string_view< Char > str
Definition: compile.h:30
FMT_CONSTEXPR value(basic_string_view< Char > s)
Definition: compile.h:34
basic_string_view< char_type > format_str_
Definition: compile.h:318
FMT_CONSTEXPR value(int index=0)
Definition: compile.h:33
const Char * arg_id_end
Definition: compile.h:38
iterator out() const
Definition: format.h:1626
const parts_container & parts() const
Definition: compile.h:253
#define FMT_CONSTEXPR
Definition: core.h:75
internal::named_arg< T, Char > arg(const S &name, const T &arg)
Definition: core.h:1422
basic_string_view< Char > format_str_
Definition: compile.h:103
FMT_CONSTEXPR std::make_unsigned< Int >::type to_unsigned(Int value)
Definition: core.h:265
FMT_CONSTEXPR compiled_format_base(basic_string_view< char_type >)
Definition: compile.h:291
const void * ptr(const T *p)
Definition: format.h:3159
basic_format_parse_context< Char > parse_context_
Definition: compile.h:104