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