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