Clean-up: consumer.hpp: coding style indentation fix
[lttng-tools.git] / src / vendor / fmt / compile.h
CommitLineData
05aa7e19
JG
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 "format.h"
12
13FMT_BEGIN_NAMESPACE
14namespace detail {
15
05aa7e19 16template <typename Char, typename InputIt>
8b75cd77
JG
17FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end,
18 counting_iterator it) {
05aa7e19
JG
19 return it + (end - begin);
20}
21
22template <typename OutputIt> class truncating_iterator_base {
23 protected:
24 OutputIt out_;
25 size_t limit_;
26 size_t count_ = 0;
27
28 truncating_iterator_base() : out_(), limit_(0) {}
29
30 truncating_iterator_base(OutputIt out, size_t limit)
31 : out_(out), limit_(limit) {}
32
33 public:
34 using iterator_category = std::output_iterator_tag;
35 using value_type = typename std::iterator_traits<OutputIt>::value_type;
36 using difference_type = std::ptrdiff_t;
37 using pointer = void;
38 using reference = void;
8b75cd77 39 FMT_UNCHECKED_ITERATOR(truncating_iterator_base);
05aa7e19
JG
40
41 OutputIt base() const { return out_; }
42 size_t count() const { return count_; }
43};
44
45// An output iterator that truncates the output and counts the number of objects
46// written to it.
47template <typename OutputIt,
48 typename Enable = typename std::is_void<
49 typename std::iterator_traits<OutputIt>::value_type>::type>
50class truncating_iterator;
51
52template <typename OutputIt>
53class truncating_iterator<OutputIt, std::false_type>
54 : public truncating_iterator_base<OutputIt> {
55 mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
56
57 public:
58 using value_type = typename truncating_iterator_base<OutputIt>::value_type;
59
60 truncating_iterator() = default;
61
62 truncating_iterator(OutputIt out, size_t limit)
63 : truncating_iterator_base<OutputIt>(out, limit) {}
64
65 truncating_iterator& operator++() {
66 if (this->count_++ < this->limit_) ++this->out_;
67 return *this;
68 }
69
70 truncating_iterator operator++(int) {
71 auto it = *this;
72 ++*this;
73 return it;
74 }
75
76 value_type& operator*() const {
77 return this->count_ < this->limit_ ? *this->out_ : blackhole_;
78 }
79};
80
81template <typename OutputIt>
82class truncating_iterator<OutputIt, std::true_type>
83 : public truncating_iterator_base<OutputIt> {
84 public:
85 truncating_iterator() = default;
86
87 truncating_iterator(OutputIt out, size_t limit)
88 : truncating_iterator_base<OutputIt>(out, limit) {}
89
90 template <typename T> truncating_iterator& operator=(T val) {
91 if (this->count_++ < this->limit_) *this->out_++ = val;
92 return *this;
93 }
94
95 truncating_iterator& operator++() { return *this; }
96 truncating_iterator& operator++(int) { return *this; }
97 truncating_iterator& operator*() { return *this; }
98};
99
100// A compile-time string which is compiled into fast formatting code.
101class compiled_string {};
102
103template <typename S>
104struct is_compiled_string : std::is_base_of<compiled_string, S> {};
105
106/**
107 \rst
108 Converts a string literal *s* into a format string that will be parsed at
109 compile time and converted into efficient formatting code. Requires C++17
110 ``constexpr if`` compiler support.
111
112 **Example**::
113
114 // Converts 42 into std::string using the most efficient method and no
115 // runtime format string processing.
116 std::string s = fmt::format(FMT_COMPILE("{}"), 42);
117 \endrst
118 */
119#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
120# define FMT_COMPILE(s) \
121 FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
122#else
123# define FMT_COMPILE(s) FMT_STRING(s)
124#endif
125
8b75cd77 126#if FMT_USE_NONTYPE_TEMPLATE_ARGS
05aa7e19
JG
127template <typename Char, size_t N,
128 fmt::detail_exported::fixed_string<Char, N> Str>
129struct udl_compiled_string : compiled_string {
130 using char_type = Char;
8b75cd77 131 explicit constexpr operator basic_string_view<char_type>() const {
05aa7e19
JG
132 return {Str.data, N - 1};
133 }
134};
135#endif
136
137template <typename T, typename... Tail>
138const T& first(const T& value, const Tail&...) {
139 return value;
140}
141
142#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
143template <typename... Args> struct type_list {};
144
145// Returns a reference to the argument at index N from [first, rest...].
146template <int N, typename T, typename... Args>
147constexpr const auto& get([[maybe_unused]] const T& first,
148 [[maybe_unused]] const Args&... rest) {
149 static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
150 if constexpr (N == 0)
151 return first;
152 else
153 return detail::get<N - 1>(rest...);
154}
155
156template <typename Char, typename... Args>
157constexpr int get_arg_index_by_name(basic_string_view<Char> name,
158 type_list<Args...>) {
159 return get_arg_index_by_name<Args...>(name);
160}
161
162template <int N, typename> struct get_type_impl;
163
164template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
165 using type =
166 remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
167};
168
169template <int N, typename T>
170using get_type = typename get_type_impl<N, T>::type;
171
172template <typename T> struct is_compiled_format : std::false_type {};
173
174template <typename Char> struct text {
175 basic_string_view<Char> data;
176 using char_type = Char;
177
178 template <typename OutputIt, typename... Args>
179 constexpr OutputIt format(OutputIt out, const Args&...) const {
180 return write<Char>(out, data);
181 }
182};
183
184template <typename Char>
185struct is_compiled_format<text<Char>> : std::true_type {};
186
187template <typename Char>
188constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
189 size_t size) {
190 return {{&s[pos], size}};
191}
192
193template <typename Char> struct code_unit {
194 Char value;
195 using char_type = Char;
196
197 template <typename OutputIt, typename... Args>
198 constexpr OutputIt format(OutputIt out, const Args&...) const {
199 return write<Char>(out, value);
200 }
201};
202
203// This ensures that the argument type is convertible to `const T&`.
204template <typename T, int N, typename... Args>
205constexpr const T& get_arg_checked(const Args&... args) {
206 const auto& arg = detail::get<N>(args...);
207 if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
208 return arg.value;
209 } else {
210 return arg;
211 }
212}
213
214template <typename Char>
215struct is_compiled_format<code_unit<Char>> : std::true_type {};
216
217// A replacement field that refers to argument N.
218template <typename Char, typename T, int N> struct field {
219 using char_type = Char;
220
221 template <typename OutputIt, typename... Args>
222 constexpr OutputIt format(OutputIt out, const Args&... args) const {
223 return write<Char>(out, get_arg_checked<T, N>(args...));
224 }
225};
226
227template <typename Char, typename T, int N>
228struct is_compiled_format<field<Char, T, N>> : std::true_type {};
229
230// A replacement field that refers to argument with name.
231template <typename Char> struct runtime_named_field {
232 using char_type = Char;
233 basic_string_view<Char> name;
234
235 template <typename OutputIt, typename T>
236 constexpr static bool try_format_argument(
237 OutputIt& out,
238 // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
239 [[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
240 if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
241 if (arg_name == arg.name) {
242 out = write<Char>(out, arg.value);
243 return true;
244 }
245 }
246 return false;
247 }
248
249 template <typename OutputIt, typename... Args>
250 constexpr OutputIt format(OutputIt out, const Args&... args) const {
251 bool found = (try_format_argument(out, name, args) || ...);
252 if (!found) {
253 FMT_THROW(format_error("argument with specified name is not found"));
254 }
255 return out;
256 }
257};
258
259template <typename Char>
260struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
261
262// A replacement field that refers to argument N and has format specifiers.
263template <typename Char, typename T, int N> struct spec_field {
264 using char_type = Char;
265 formatter<T, Char> fmt;
266
267 template <typename OutputIt, typename... Args>
268 constexpr FMT_INLINE OutputIt format(OutputIt out,
269 const Args&... args) const {
270 const auto& vargs =
271 fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
272 basic_format_context<OutputIt, Char> ctx(out, vargs);
273 return fmt.format(get_arg_checked<T, N>(args...), ctx);
274 }
275};
276
277template <typename Char, typename T, int N>
278struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
279
280template <typename L, typename R> struct concat {
281 L lhs;
282 R rhs;
283 using char_type = typename L::char_type;
284
285 template <typename OutputIt, typename... Args>
286 constexpr OutputIt format(OutputIt out, const Args&... args) const {
287 out = lhs.format(out, args...);
288 return rhs.format(out, args...);
289 }
290};
291
292template <typename L, typename R>
293struct is_compiled_format<concat<L, R>> : std::true_type {};
294
295template <typename L, typename R>
296constexpr concat<L, R> make_concat(L lhs, R rhs) {
297 return {lhs, rhs};
298}
299
300struct unknown_format {};
301
302template <typename Char>
303constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
304 for (size_t size = str.size(); pos != size; ++pos) {
305 if (str[pos] == '{' || str[pos] == '}') break;
306 }
307 return pos;
308}
309
310template <typename Args, size_t POS, int ID, typename S>
311constexpr auto compile_format_string(S format_str);
312
313template <typename Args, size_t POS, int ID, typename T, typename S>
314constexpr auto parse_tail(T head, S format_str) {
315 if constexpr (POS !=
316 basic_string_view<typename S::char_type>(format_str).size()) {
317 constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
318 if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
319 unknown_format>())
320 return tail;
321 else
322 return make_concat(head, tail);
323 } else {
324 return head;
325 }
326}
327
328template <typename T, typename Char> struct parse_specs_result {
329 formatter<T, Char> fmt;
330 size_t end;
331 int next_arg_id;
332};
333
334constexpr int manual_indexing_id = -1;
335
336template <typename T, typename Char>
337constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
338 size_t pos, int next_arg_id) {
339 str.remove_prefix(pos);
8b75cd77
JG
340 auto ctx = compile_parse_context<Char>(str, max_value<int>(), nullptr, {},
341 next_arg_id);
05aa7e19
JG
342 auto f = formatter<T, Char>();
343 auto end = f.parse(ctx);
8b75cd77 344 return {f, pos + fmt::detail::to_unsigned(end - str.data()),
05aa7e19
JG
345 next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
346}
347
348template <typename Char> struct arg_id_handler {
349 arg_ref<Char> arg_id;
350
351 constexpr int operator()() {
352 FMT_ASSERT(false, "handler cannot be used with automatic indexing");
353 return 0;
354 }
355 constexpr int operator()(int id) {
356 arg_id = arg_ref<Char>(id);
357 return 0;
358 }
359 constexpr int operator()(basic_string_view<Char> id) {
360 arg_id = arg_ref<Char>(id);
361 return 0;
362 }
363
364 constexpr void on_error(const char* message) {
365 FMT_THROW(format_error(message));
366 }
367};
368
369template <typename Char> struct parse_arg_id_result {
370 arg_ref<Char> arg_id;
371 const Char* arg_id_end;
372};
373
374template <int ID, typename Char>
375constexpr auto parse_arg_id(const Char* begin, const Char* end) {
376 auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
377 auto arg_id_end = parse_arg_id(begin, end, handler);
378 return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
379}
380
381template <typename T, typename Enable = void> struct field_type {
382 using type = remove_cvref_t<T>;
383};
384
385template <typename T>
386struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
387 using type = remove_cvref_t<decltype(T::value)>;
388};
389
390template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
391 typename S>
392constexpr auto parse_replacement_field_then_tail(S format_str) {
393 using char_type = typename S::char_type;
394 constexpr auto str = basic_string_view<char_type>(format_str);
395 constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
396 if constexpr (c == '}') {
397 return parse_tail<Args, END_POS + 1, NEXT_ID>(
398 field<char_type, typename field_type<T>::type, ARG_INDEX>(),
399 format_str);
8b75cd77
JG
400 } else if constexpr (c != ':') {
401 FMT_THROW(format_error("expected ':'"));
402 } else {
05aa7e19
JG
403 constexpr auto result = parse_specs<typename field_type<T>::type>(
404 str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
8b75cd77
JG
405 if constexpr (result.end >= str.size() || str[result.end] != '}') {
406 FMT_THROW(format_error("expected '}'"));
407 return 0;
408 } else {
409 return parse_tail<Args, result.end + 1, result.next_arg_id>(
410 spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
411 result.fmt},
412 format_str);
413 }
05aa7e19
JG
414 }
415}
416
417// Compiles a non-empty format string and returns the compiled representation
418// or unknown_format() on unrecognized input.
419template <typename Args, size_t POS, int ID, typename S>
420constexpr auto compile_format_string(S format_str) {
421 using char_type = typename S::char_type;
422 constexpr auto str = basic_string_view<char_type>(format_str);
423 if constexpr (str[POS] == '{') {
424 if constexpr (POS + 1 == str.size())
425 FMT_THROW(format_error("unmatched '{' in format string"));
426 if constexpr (str[POS + 1] == '{') {
427 return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
428 } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
429 static_assert(ID != manual_indexing_id,
430 "cannot switch from manual to automatic argument indexing");
431 constexpr auto next_id =
432 ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
433 return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
434 POS + 1, ID, next_id>(
435 format_str);
436 } else {
437 constexpr auto arg_id_result =
438 parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
439 constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
440 constexpr char_type c =
441 arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
442 static_assert(c == '}' || c == ':', "missing '}' in format string");
443 if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
444 static_assert(
445 ID == manual_indexing_id || ID == 0,
446 "cannot switch from automatic to manual argument indexing");
447 constexpr auto arg_index = arg_id_result.arg_id.val.index;
448 return parse_replacement_field_then_tail<get_type<arg_index, Args>,
449 Args, arg_id_end_pos,
450 arg_index, manual_indexing_id>(
451 format_str);
452 } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
453 constexpr auto arg_index =
454 get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
455 if constexpr (arg_index != invalid_arg_index) {
456 constexpr auto next_id =
457 ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
458 return parse_replacement_field_then_tail<
459 decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
460 arg_index, next_id>(format_str);
461 } else {
462 if constexpr (c == '}') {
463 return parse_tail<Args, arg_id_end_pos + 1, ID>(
464 runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
465 format_str);
466 } else if constexpr (c == ':') {
467 return unknown_format(); // no type info for specs parsing
468 }
469 }
470 }
471 }
472 } else if constexpr (str[POS] == '}') {
473 if constexpr (POS + 1 == str.size())
474 FMT_THROW(format_error("unmatched '}' in format string"));
475 return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
476 } else {
477 constexpr auto end = parse_text(str, POS + 1);
478 if constexpr (end - POS > 1) {
479 return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
480 format_str);
481 } else {
482 return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
483 format_str);
484 }
485 }
486}
487
488template <typename... Args, typename S,
489 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
490constexpr auto compile(S format_str) {
491 constexpr auto str = basic_string_view<typename S::char_type>(format_str);
492 if constexpr (str.size() == 0) {
493 return detail::make_text(str, 0, 0);
494 } else {
495 constexpr auto result =
496 detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
497 format_str);
498 return result;
499 }
500}
501#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
502} // namespace detail
503
504FMT_MODULE_EXPORT_BEGIN
505
506#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
507
508template <typename CompiledFormat, typename... Args,
509 typename Char = typename CompiledFormat::char_type,
510 FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
511FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
512 const Args&... args) {
513 auto s = std::basic_string<Char>();
514 cf.format(std::back_inserter(s), args...);
515 return s;
516}
517
518template <typename OutputIt, typename CompiledFormat, typename... Args,
519 FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
520constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
521 const Args&... args) {
522 return cf.format(out, args...);
523}
524
525template <typename S, typename... Args,
526 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
527FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
528 Args&&... args) {
529 if constexpr (std::is_same<typename S::char_type, char>::value) {
530 constexpr auto str = basic_string_view<typename S::char_type>(S());
531 if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
532 const auto& first = detail::first(args...);
533 if constexpr (detail::is_named_arg<
534 remove_cvref_t<decltype(first)>>::value) {
535 return fmt::to_string(first.value);
536 } else {
537 return fmt::to_string(first);
538 }
539 }
540 }
541 constexpr auto compiled = detail::compile<Args...>(S());
542 if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
543 detail::unknown_format>()) {
8b75cd77
JG
544 return fmt::format(
545 static_cast<basic_string_view<typename S::char_type>>(S()),
546 std::forward<Args>(args)...);
05aa7e19 547 } else {
8b75cd77 548 return fmt::format(compiled, std::forward<Args>(args)...);
05aa7e19
JG
549 }
550}
551
552template <typename OutputIt, typename S, typename... Args,
553 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
554FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
555 constexpr auto compiled = detail::compile<Args...>(S());
556 if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
557 detail::unknown_format>()) {
8b75cd77
JG
558 return fmt::format_to(
559 out, static_cast<basic_string_view<typename S::char_type>>(S()),
560 std::forward<Args>(args)...);
05aa7e19 561 } else {
8b75cd77 562 return fmt::format_to(out, compiled, std::forward<Args>(args)...);
05aa7e19
JG
563 }
564}
565#endif
566
567template <typename OutputIt, typename S, typename... Args,
568 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
569format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
570 const S& format_str, Args&&... args) {
8b75cd77
JG
571 auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
572 format_str, std::forward<Args>(args)...);
05aa7e19
JG
573 return {it.base(), it.count()};
574}
575
576template <typename S, typename... Args,
577 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
8b75cd77
JG
578FMT_CONSTEXPR20 size_t formatted_size(const S& format_str,
579 const Args&... args) {
580 return fmt::format_to(detail::counting_iterator(), format_str, args...)
581 .count();
05aa7e19
JG
582}
583
584template <typename S, typename... Args,
585 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
586void print(std::FILE* f, const S& format_str, const Args&... args) {
587 memory_buffer buffer;
8b75cd77 588 fmt::format_to(std::back_inserter(buffer), format_str, args...);
05aa7e19
JG
589 detail::print(f, {buffer.data(), buffer.size()});
590}
591
592template <typename S, typename... Args,
593 FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
594void print(const S& format_str, const Args&... args) {
595 print(stdout, format_str, args...);
596}
597
8b75cd77 598#if FMT_USE_NONTYPE_TEMPLATE_ARGS
05aa7e19 599inline namespace literals {
8b75cd77
JG
600template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
601 using char_t = remove_cvref_t<decltype(Str.data[0])>;
602 return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
603 Str>();
05aa7e19
JG
604}
605} // namespace literals
606#endif
607
608FMT_MODULE_EXPORT_END
609FMT_END_NAMESPACE
610
611#endif // FMT_COMPILE_H_
This page took 0.055742 seconds and 4 git commands to generate.