LLVM 20.0.0git
FormatProviders.h
Go to the documentation of this file.
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"
19#include "llvm/ADT/Twine.h"
22
23#include <array>
24#include <optional>
25#include <type_traits>
26
27namespace llvm {
28namespace support {
29namespace detail {
30template <typename T>
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>
39 : public std::integral_constant<bool, std::is_same_v<T, char>> {};
40
41template <typename T>
43 : public std::integral_constant<bool,
44 is_one_of<T, char *, const char *>::value> {
45};
46
47template <typename T>
49 : public std::integral_constant<bool,
50 std::is_convertible_v<T, llvm::StringRef>> {
51};
52
53template <typename T>
55 : public std::integral_constant<bool, std::is_pointer_v<T> &&
56 !is_cstring<T>::value> {};
57
58template <typename T>
60 : public std::integral_constant<bool, std::is_floating_point_v<T>> {};
61
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(10, 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>(99u, Prec);
75 }
76 return Result;
77 }
78
79 static std::optional<HexPrintStyle> consumeHexStyle(StringRef &Str) {
80 if (!Str.starts_with_insensitive("x"))
81 return std::nullopt;
82
83 if (Str.consume_front("x-"))
85 if (Str.consume_front("X-"))
87 if (Str.consume_front("x+") || Str.consume_front("x"))
89 if (!Str.consume_front("X+"))
90 Str.consume_front("X");
92 }
93
94 static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style,
95 size_t Default) {
96 Str.consumeInteger(10, Default);
97 if (isPrefixedHexStyle(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>
130 T, std::enable_if_t<support::detail::use_integral_formatter<T>::value>>
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(Style)) {
137 Digits = consumeNumHexDigits(Style, *HS, 0);
138 write_hex(Stream, V, *HS, Digits);
139 return;
140 }
141
143 if (Style.consume_front("N") || Style.consume_front("n"))
145 else if (Style.consume_front("D") || Style.consume_front("d"))
147
148 Style.consumeInteger(10, 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>
178 T, std::enable_if_t<support::detail::use_pointer_formatter<T>::value>>
180private:
181public:
182 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
184 if (std::optional<HexPrintStyle> consumed = consumeHexStyle(Style))
185 HS = *consumed;
186 size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2);
187 write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, 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>
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(10, N)) {
208 assert(false && "Style is not a valid integer");
209 }
210 llvm::StringRef S = V;
211 Stream << S.substr(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.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>
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(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("Y", B ? "YES" : "NO")
270 .Case("y", B ? "yes" : "no")
271 .CaseLower("D", B ? "1" : "0")
272 .Case("T", B ? "TRUE" : "FALSE")
273 .Cases("t", "", B ? "true" : "false")
274 .Default(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>
303 T, std::enable_if_t<support::detail::use_double_formatter<T>::value>>
305 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
306 FloatStyle S;
307 if (Style.consume_front("P") || Style.consume_front("p"))
309 else if (Style.consume_front("F") || Style.consume_front("f"))
311 else if (Style.consume_front("E"))
313 else if (Style.consume_front("e"))
315 else
317
318 std::optional<size_t> Precision = parseNumericPrecision(Style);
319 if (!Precision)
320 Precision = getDefaultPrecision(S);
321
322 write_double(Stream, static_cast<double>(V), 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>
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,
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(D[1]);
381 if (End == StringRef::npos) {
382 assert(false && "Missing range option end delimeter!");
383 return Default;
384 }
385 StringRef Result = Style.slice(1, End);
386 Style = Style.drop_front(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, '$', ", ");
395 StringRef Args = consumeOneOption(Style, '@', "");
396 assert(Style.empty() && "Unexpected text in range option string!");
397 return std::make_pair(Sep, Args);
398 }
399
400public:
402 "Range value_type does not have a format provider!");
404 llvm::raw_ostream &Stream, StringRef Style) {
405 StringRef Sep;
406 StringRef ArgStyle;
407 std::tie(Sep, 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
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
bool End
Definition: ELF_riscv.cpp:480
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:556
static constexpr size_t npos
Definition: StringRef.h:52
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
static void format(const llvm::iterator_range< IterT > &V, llvm::raw_ostream &Stream, StringRef Style)
A range adaptor for a pair of iterators.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style, size_t Default)
static std::optional< size_t > parseNumericPrecision(StringRef Str)
static std::optional< HexPrintStyle > consumeHexStyle(StringRef &Str)
std::enable_if_t< uses_format_member< T >::value, T > build_format_adapter(T &&Item)
typename std::iterator_traits< IterT >::value_type IterValue
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits, IntegerStyle Style)
size_t getDefaultPrecision(FloatStyle Style)
void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style, std::optional< size_t > Width=std::nullopt)
void write_double(raw_ostream &S, double D, FloatStyle Style, std::optional< size_t > Precision=std::nullopt)
@ Default
The result values are uniform if and only if all operands are uniform.
bool isPrefixedHexStyle(HexPrintStyle S)
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
#define N
static void format(const char &V, llvm::raw_ostream &Stream, StringRef Style)
static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style)
static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style)
static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style)
static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style)
static void format(const Twine &V, llvm::raw_ostream &Stream, StringRef Style)
static void format(const bool &B, llvm::raw_ostream &Stream, StringRef Style)