1//===- FormatProviders.h - Formatters for common LLVM types -----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements format providers for many common LLVM types, for example
10// allowing precision and width specifiers for scalar and string types.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_SUPPORT_FORMATPROVIDERS_H
15#define LLVM_SUPPORT_FORMATPROVIDERS_H
16
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/StringSwitch.h"
19#include "llvm/ADT/Twine.h"
20#include "llvm/Support/FormatVariadicDetails.h"
21#include "llvm/Support/NativeFormatting.h"
22
23#include <array>
24#include <optional>
25#include <type_traits>
26
27namespace llvm {
28namespace detail {
29template <typename T>
30struct use_integral_formatter
31 : public std::integral_constant<
32 bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
33 int64_t, uint64_t, int, unsigned, long, unsigned long,
34 long long, unsigned long long>::value> {};
35
36template <typename T>
37struct use_char_formatter
38 : public std::integral_constant<bool, std::is_same_v<T, char>> {};
39
40template <typename T>
41struct is_cstring
42 : public std::integral_constant<bool,
43 is_one_of<T, char *, const char *>::value> {
44};
45
46template <typename T>
47struct use_string_formatter
48 : public std::integral_constant<bool,
49 std::is_convertible_v<T, llvm::StringRef>> {
50};
51
52template <typename T>
53struct use_pointer_formatter
54 : public std::integral_constant<bool, std::is_pointer_v<T> &&
55 !is_cstring<T>::value> {};
56
57template <typename T>
58struct use_double_formatter
59 : public std::integral_constant<bool, std::is_floating_point_v<T>> {};
60
61class HelperFunctions {
62protected:
63 static std::optional<size_t> parseNumericPrecision(StringRef Str) {
64 size_t Prec;
65 std::optional<size_t> Result;
66 if (Str.empty())
67 Result = std::nullopt;
68 else if (Str.getAsInteger(Radix: 10, Result&: Prec)) {
69 assert(false && "Invalid precision specifier");
70 Result = std::nullopt;
71 } else {
72 assert(Prec < 100 && "Precision out of range");
73 Result = std::min<size_t>(a: 99u, b: Prec);
74 }
75 return Result;
76 }
77
78 static bool consumeHexStyle(StringRef &Str, HexPrintStyle &Style) {
79 if (!Str.starts_with_insensitive(Prefix: "x"))
80 return false;
81
82 if (Str.consume_front(Prefix: "x-"))
83 Style = HexPrintStyle::Lower;
84 else if (Str.consume_front(Prefix: "X-"))
85 Style = HexPrintStyle::Upper;
86 else if (Str.consume_front(Prefix: "x+") || Str.consume_front(Prefix: "x"))
87 Style = HexPrintStyle::PrefixLower;
88 else if (Str.consume_front(Prefix: "X+") || Str.consume_front(Prefix: "X"))
89 Style = HexPrintStyle::PrefixUpper;
90 return true;
91 }
92
93 static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style,
94 size_t Default) {
95 Str.consumeInteger(Radix: 10, Result&: Default);
96 if (isPrefixedHexStyle(S: Style))
97 Default += 2;
98 return Default;
99 }
100};
101}
102
103/// Implementation of format_provider<T> for integral arithmetic types.
104///
105/// The options string of an integral type has the grammar:
106///
107/// integer_options :: [style][digits]
108/// style :: <see table below>
109/// digits :: <non-negative integer> 0-99
110///
111/// ==========================================================================
112/// | style | Meaning | Example | Digits Meaning |
113/// --------------------------------------------------------------------------
114/// | | | Input | Output | |
115/// ==========================================================================
116/// | x- | Hex no prefix, lower | 42 | 2a | Minimum # digits |
117/// | X- | Hex no prefix, upper | 42 | 2A | Minimum # digits |
118/// | x+ / x | Hex + prefix, lower | 42 | 0x2a | Minimum # digits |
119/// | X+ / X | Hex + prefix, upper | 42 | 0x2A | Minimum # digits |
120/// | N / n | Digit grouped number | 123456 | 123,456 | Ignored |
121/// | D / d | Integer | 100000 | 100000 | Ignored |
122/// | (empty) | Same as D / d | | | |
123/// ==========================================================================
124///
125
126template <typename T>
127struct format_provider<
128 T, std::enable_if_t<detail::use_integral_formatter<T>::value>>
129 : public detail::HelperFunctions {
130private:
131public:
132 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
133 HexPrintStyle HS;
134 size_t Digits = 0;
135 if (consumeHexStyle(Str&: Style, Style&: HS)) {
136 Digits = consumeNumHexDigits(Str&: Style, Style: HS, Default: 0);
137 write_hex(Stream, V, HS, Digits);
138 return;
139 }
140
141 IntegerStyle IS = IntegerStyle::Integer;
142 if (Style.consume_front(Prefix: "N") || Style.consume_front(Prefix: "n"))
143 IS = IntegerStyle::Number;
144 else if (Style.consume_front(Prefix: "D") || Style.consume_front(Prefix: "d"))
145 IS = IntegerStyle::Integer;
146
147 Style.consumeInteger(Radix: 10, Result&: Digits);
148 assert(Style.empty() && "Invalid integral format style!");
149 write_integer(Stream, V, Digits, IS);
150 }
151};
152
153/// Implementation of format_provider<T> for integral pointer types.
154///
155/// The options string of a pointer type has the grammar:
156///
157/// pointer_options :: [style][precision]
158/// style :: <see table below>
159/// digits :: <non-negative integer> 0-sizeof(void*)
160///
161/// ==========================================================================
162/// | S | Meaning | Example |
163/// --------------------------------------------------------------------------
164/// | | | Input | Output |
165/// ==========================================================================
166/// | x- | Hex no prefix, lower | 0xDEADBEEF | deadbeef |
167/// | X- | Hex no prefix, upper | 0xDEADBEEF | DEADBEEF |
168/// | x+ / x | Hex + prefix, lower | 0xDEADBEEF | 0xdeadbeef |
169/// | X+ / X | Hex + prefix, upper | 0xDEADBEEF | 0xDEADBEEF |
170/// | (empty) | Same as X+ / X | | |
171/// ==========================================================================
172///
173/// The default precision is the number of nibbles in a machine word, and in all
174/// cases indicates the minimum number of nibbles to print.
175template <typename T>
176struct format_provider<
177 T, std::enable_if_t<detail::use_pointer_formatter<T>::value>>
178 : public detail::HelperFunctions {
179private:
180public:
181 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
182 HexPrintStyle HS = HexPrintStyle::PrefixUpper;
183 consumeHexStyle(Str&: Style, Style&: HS);
184 size_t Digits = consumeNumHexDigits(Str&: Style, Style: HS, Default: sizeof(void *) * 2);
185 write_hex(S&: Stream, N: reinterpret_cast<std::uintptr_t>(V), Style: HS, Width: Digits);
186 }
187};
188
189/// Implementation of format_provider<T> for c-style strings and string
190/// objects such as std::string and llvm::StringRef.
191///
192/// The options string of a string type has the grammar:
193///
194/// string_options :: [length]
195///
196/// where `length` is an optional integer specifying the maximum number of
197/// characters in the string to print. If `length` is omitted, the string is
198/// printed up to the null terminator.
199
200template <typename T>
201struct format_provider<
202 T, std::enable_if_t<detail::use_string_formatter<T>::value>> {
203 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
204 size_t N = StringRef::npos;
205 if (!Style.empty() && Style.getAsInteger(Radix: 10, Result&: N)) {
206 assert(false && "Style is not a valid integer");
207 }
208 llvm::StringRef S = V;
209 Stream << S.substr(Start: 0, N);
210 }
211};
212
213/// Implementation of format_provider<T> for llvm::Twine.
214///
215/// This follows the same rules as the string formatter.
216
217template <> struct format_provider<Twine> {
218 static void format(const Twine &V, llvm::raw_ostream &Stream,
219 StringRef Style) {
220 format_provider<std::string>::format(V: V.str(), Stream, Style);
221 }
222};
223
224/// Implementation of format_provider<T> for characters.
225///
226/// The options string of a character type has the grammar:
227///
228/// char_options :: (empty) | [integer_options]
229///
230/// If `char_options` is empty, the character is displayed as an ASCII
231/// character. Otherwise, it is treated as an integer options string.
232///
233template <typename T>
234struct format_provider<T,
235 std::enable_if_t<detail::use_char_formatter<T>::value>> {
236 static void format(const char &V, llvm::raw_ostream &Stream,
237 StringRef Style) {
238 if (Style.empty())
239 Stream << V;
240 else {
241 int X = static_cast<int>(V);
242 format_provider<int>::format(V: X, Stream, Style);
243 }
244 }
245};
246
247/// Implementation of format_provider<T> for type `bool`
248///
249/// The options string of a boolean type has the grammar:
250///
251/// bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t"
252///
253/// ==================================
254/// | C | Meaning |
255/// ==================================
256/// | Y | YES / NO |
257/// | y | yes / no |
258/// | D / d | Integer 0 or 1 |
259/// | T | TRUE / FALSE |
260/// | t | true / false |
261/// | (empty) | Equivalent to 't' |
262/// ==================================
263template <> struct format_provider<bool> {
264 static void format(const bool &B, llvm::raw_ostream &Stream,
265 StringRef Style) {
266 Stream << StringSwitch<const char *>(Style)
267 .Case(S: "Y", Value: B ? "YES" : "NO")
268 .Case(S: "y", Value: B ? "yes" : "no")
269 .CaseLower(S: "D", Value: B ? "1" : "0")
270 .Case(S: "T", Value: B ? "TRUE" : "FALSE")
271 .Cases(S0: "t", S1: "", Value: B ? "true" : "false")
272 .Default(Value: B ? "1" : "0");
273 }
274};
275
276/// Implementation of format_provider<T> for floating point types.
277///
278/// The options string of a floating point type has the format:
279///
280/// float_options :: [style][precision]
281/// style :: <see table below>
282/// precision :: <non-negative integer> 0-99
283///
284/// =====================================================
285/// | style | Meaning | Example |
286/// -----------------------------------------------------
287/// | | | Input | Output |
288/// =====================================================
289/// | P / p | Percentage | 0.05 | 5.00% |
290/// | F / f | Fixed point | 1.0 | 1.00 |
291/// | E | Exponential with E | 100000 | 1.0E+05 |
292/// | e | Exponential with e | 100000 | 1.0e+05 |
293/// | (empty) | Same as F / f | | |
294/// =====================================================
295///
296/// The default precision is 6 for exponential (E / e) and 2 for everything
297/// else.
298
299template <typename T>
300struct format_provider<T,
301 std::enable_if_t<detail::use_double_formatter<T>::value>>
302 : public detail::HelperFunctions {
303 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
304 FloatStyle S;
305 if (Style.consume_front(Prefix: "P") || Style.consume_front(Prefix: "p"))
306 S = FloatStyle::Percent;
307 else if (Style.consume_front(Prefix: "F") || Style.consume_front(Prefix: "f"))
308 S = FloatStyle::Fixed;
309 else if (Style.consume_front(Prefix: "E"))
310 S = FloatStyle::ExponentUpper;
311 else if (Style.consume_front(Prefix: "e"))
312 S = FloatStyle::Exponent;
313 else
314 S = FloatStyle::Fixed;
315
316 std::optional<size_t> Precision = parseNumericPrecision(Str: Style);
317 if (!Precision)
318 Precision = getDefaultPrecision(Style: S);
319
320 write_double(S&: Stream, D: static_cast<double>(V), Style: S, Precision);
321 }
322};
323
324namespace detail {
325template <typename IterT>
326using IterValue = typename std::iterator_traits<IterT>::value_type;
327
328template <typename IterT>
329struct range_item_has_provider
330 : public std::integral_constant<
331 bool, !uses_missing_provider<IterValue<IterT>>::value> {};
332}
333
334/// Implementation of format_provider<T> for ranges.
335///
336/// This will print an arbitrary range as a delimited sequence of items.
337///
338/// The options string of a range type has the grammar:
339///
340/// range_style ::= [separator] [element_style]
341/// separator ::= "$" delimeted_expr
342/// element_style ::= "@" delimeted_expr
343/// delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">"
344/// expr ::= <any string not containing delimeter>
345///
346/// where the separator expression is the string to insert between consecutive
347/// items in the range and the argument expression is the Style specification to
348/// be used when formatting the underlying type. The default separator if
349/// unspecified is ' ' (space). The syntax of the argument expression follows
350/// whatever grammar is dictated by the format provider or format adapter used
351/// to format the value type.
352///
353/// Note that attempting to format an `iterator_range<T>` where no format
354/// provider can be found for T will result in a compile error.
355///
356
357template <typename IterT> class format_provider<llvm::iterator_range<IterT>> {
358 using value = typename std::iterator_traits<IterT>::value_type;
359
360 static StringRef consumeOneOption(StringRef &Style, char Indicator,
361 StringRef Default) {
362 if (Style.empty())
363 return Default;
364 if (Style.front() != Indicator)
365 return Default;
366 Style = Style.drop_front();
367 if (Style.empty()) {
368 assert(false && "Invalid range style");
369 return Default;
370 }
371
372 for (const char *D : std::array<const char *, 3>{"[]", "<>", "()"}) {
373 if (Style.front() != D[0])
374 continue;
375 size_t End = Style.find_first_of(C: D[1]);
376 if (End == StringRef::npos) {
377 assert(false && "Missing range option end delimeter!");
378 return Default;
379 }
380 StringRef Result = Style.slice(Start: 1, End);
381 Style = Style.drop_front(N: End + 1);
382 return Result;
383 }
384 assert(false && "Invalid range style!");
385 return Default;
386 }
387
388 static std::pair<StringRef, StringRef> parseOptions(StringRef Style) {
389 StringRef Sep = consumeOneOption(Style, Indicator: '$', Default: ", ");
390 StringRef Args = consumeOneOption(Style, Indicator: '@', Default: "");
391 assert(Style.empty() && "Unexpected text in range option string!");
392 return std::make_pair(x&: Sep, y&: Args);
393 }
394
395public:
396 static_assert(detail::range_item_has_provider<IterT>::value,
397 "Range value_type does not have a format provider!");
398 static void format(const llvm::iterator_range<IterT> &V,
399 llvm::raw_ostream &Stream, StringRef Style) {
400 StringRef Sep;
401 StringRef ArgStyle;
402 std::tie(args&: Sep, args&: ArgStyle) = parseOptions(Style);
403 auto Begin = V.begin();
404 auto End = V.end();
405 if (Begin != End) {
406 auto Adapter = detail::build_format_adapter(*Begin);
407 Adapter.format(Stream, ArgStyle);
408 ++Begin;
409 }
410 while (Begin != End) {
411 Stream << Sep;
412 auto Adapter = detail::build_format_adapter(*Begin);
413 Adapter.format(Stream, ArgStyle);
414 ++Begin;
415 }
416 }
417};
418}
419
420#endif
421

source code of include/llvm-17/llvm/Support/FormatProviders.h