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