LLVM 22.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/// | (empty) | Same as D / d | | | |
116/// ==========================================================================
117///
118
119template <typename T>
121 T, std::enable_if_t<support::detail::use_integral_formatter<T>::value>>
123private:
124public:
125 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
126 size_t Digits = 0;
127 if (std::optional<HexPrintStyle> HS = consumeHexStyle(Style)) {
128 Digits = consumeNumHexDigits(Style, *HS, 0);
129 write_hex(Stream, V, *HS, Digits);
130 return;
131 }
132
134 if (Style.consume_front("N") || Style.consume_front("n"))
136 else if (Style.consume_front("D") || Style.consume_front("d"))
138
139 Style.consumeInteger(10, Digits);
140 assert(Style.empty() && "Invalid integral format style!");
141 write_integer(Stream, V, Digits, IS);
142 }
143};
144
145/// Implementation of format_provider<T> for integral pointer types.
146///
147/// The options string of a pointer type has the grammar:
148///
149/// pointer_options :: [style][precision]
150/// style :: <see table below>
151/// digits :: <non-negative integer> 0-sizeof(void*)
152///
153/// ==========================================================================
154/// | S | Meaning | Example |
155/// --------------------------------------------------------------------------
156/// | | | Input | Output |
157/// ==========================================================================
158/// | x- | Hex no prefix, lower | 0xDEADBEEF | deadbeef |
159/// | X- | Hex no prefix, upper | 0xDEADBEEF | DEADBEEF |
160/// | x+ / x | Hex + prefix, lower | 0xDEADBEEF | 0xdeadbeef |
161/// | X+ / X | Hex + prefix, upper | 0xDEADBEEF | 0xDEADBEEF |
162/// | (empty) | Same as X+ / X | | |
163/// ==========================================================================
164///
165/// The default precision is the number of nibbles in a machine word, and in all
166/// cases indicates the minimum number of nibbles to print.
167template <typename T>
169 T, std::enable_if_t<support::detail::use_pointer_formatter<T>::value>>
171private:
172public:
173 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
175 if (std::optional<HexPrintStyle> consumed = consumeHexStyle(Style))
176 HS = *consumed;
177 size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2);
178 write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, Digits);
179 }
180};
181
182/// Implementation of format_provider<T> for c-style strings and string
183/// objects such as std::string and llvm::StringRef.
184///
185/// The options string of a string type has the grammar:
186///
187/// string_options :: [length]
188///
189/// where `length` is an optional integer specifying the maximum number of
190/// characters in the string to print. If `length` is omitted, the string is
191/// printed up to the null terminator.
192
193template <typename T>
195 T, std::enable_if_t<support::detail::use_string_formatter<T>::value>> {
196 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
197 size_t N = StringRef::npos;
198 if (!Style.empty() && Style.getAsInteger(10, N)) {
199 assert(false && "Style is not a valid integer");
200 }
201 llvm::StringRef S = V;
202 Stream << S.substr(0, N);
203 }
204};
205
206/// Implementation of format_provider<T> for llvm::Twine.
207///
208/// This follows the same rules as the string formatter.
209
210template <> struct format_provider<Twine> {
211 static void format(const Twine &V, llvm::raw_ostream &Stream,
212 StringRef Style) {
213 format_provider<std::string>::format(V.str(), Stream, Style);
214 }
215};
216
217/// Implementation of format_provider<T> for characters.
218///
219/// The options string of a character type has the grammar:
220///
221/// char_options :: (empty) | [integer_options]
222///
223/// If `char_options` is empty, the character is displayed as an ASCII
224/// character. Otherwise, it is treated as an integer options string.
225///
226template <typename T>
228 T, std::enable_if_t<support::detail::use_char_formatter<T>::value>> {
229 static void format(const char &V, llvm::raw_ostream &Stream,
230 StringRef Style) {
231 if (Style.empty())
232 Stream << V;
233 else {
234 int X = static_cast<int>(V);
235 format_provider<int>::format(X, Stream, Style);
236 }
237 }
238};
239
240/// Implementation of format_provider<T> for type `bool`
241///
242/// The options string of a boolean type has the grammar:
243///
244/// bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t"
245///
246/// ==================================
247/// | C | Meaning |
248/// ==================================
249/// | Y | YES / NO |
250/// | y | yes / no |
251/// | D / d | Integer 0 or 1 |
252/// | T | TRUE / FALSE |
253/// | t | true / false |
254/// | (empty) | Equivalent to 't' |
255/// ==================================
256template <> struct format_provider<bool> {
257 static void format(const bool &B, llvm::raw_ostream &Stream,
258 StringRef Style) {
259 Stream << StringSwitch<const char *>(Style)
260 .Case("Y", B ? "YES" : "NO")
261 .Case("y", B ? "yes" : "no")
262 .CaseLower("D", B ? "1" : "0")
263 .Case("T", B ? "TRUE" : "FALSE")
264 .Cases("t", "", B ? "true" : "false")
265 .Default(B ? "1" : "0");
266 }
267};
268
269/// Implementation of format_provider<T> for floating point types.
270///
271/// The options string of a floating point type has the format:
272///
273/// float_options :: [style][precision]
274/// style :: <see table below>
275/// precision :: <non-negative integer> 0-99
276///
277/// =====================================================
278/// | style | Meaning | Example |
279/// -----------------------------------------------------
280/// | | | Input | Output |
281/// =====================================================
282/// | P / p | Percentage | 0.05 | 5.00% |
283/// | F / f | Fixed point | 1.0 | 1.00 |
284/// | E | Exponential with E | 100000 | 1.0E+05 |
285/// | e | Exponential with e | 100000 | 1.0e+05 |
286/// | (empty) | Same as F / f | | |
287/// =====================================================
288///
289/// The default precision is 6 for exponential (E / e) and 2 for everything
290/// else.
291
292template <typename T>
294 T, std::enable_if_t<support::detail::use_double_formatter<T>::value>>
296 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
297 FloatStyle S;
298 if (Style.consume_front("P") || Style.consume_front("p"))
300 else if (Style.consume_front("F") || Style.consume_front("f"))
302 else if (Style.consume_front("E"))
304 else if (Style.consume_front("e"))
306 else
308
309 std::optional<size_t> Precision = parseNumericPrecision(Style);
310 if (!Precision)
311 Precision = getDefaultPrecision(S);
312
313 write_double(Stream, static_cast<double>(V), S, Precision);
314 }
315};
316
317namespace support {
318namespace detail {
319template <typename IterT>
320using IterValue = typename std::iterator_traits<IterT>::value_type;
321
322template <typename IterT>
324 : public std::bool_constant<
325 !support::detail::uses_missing_provider<IterValue<IterT>>::value> {};
326} // namespace detail
327} // namespace support
328
329/// Implementation of format_provider<T> for ranges.
330///
331/// This will print an arbitrary range as a delimited sequence of items.
332///
333/// The options string of a range type has the grammar:
334///
335/// range_style ::= [separator] [element_style]
336/// separator ::= "$" delimeted_expr
337/// element_style ::= "@" delimeted_expr
338/// delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">"
339/// expr ::= <any string not containing delimeter>
340///
341/// where the separator expression is the string to insert between consecutive
342/// items in the range and the argument expression is the Style specification to
343/// be used when formatting the underlying type. The default separator if
344/// unspecified is ' ' (space). The syntax of the argument expression follows
345/// whatever grammar is dictated by the format provider or format adapter used
346/// to format the value type.
347///
348/// Note that attempting to format an `iterator_range<T>` where no format
349/// provider can be found for T will result in a compile error.
350///
351
352template <typename IterT> class format_provider<llvm::iterator_range<IterT>> {
353 using value = typename std::iterator_traits<IterT>::value_type;
354
355 static StringRef consumeOneOption(StringRef &Style, char Indicator,
357 if (Style.empty())
358 return Default;
359 if (Style.front() != Indicator)
360 return Default;
361 Style = Style.drop_front();
362 if (Style.empty()) {
363 assert(false && "Invalid range style");
364 return Default;
365 }
366
367 for (const char *D : std::array<const char *, 3>{"[]", "<>", "()"}) {
368 if (Style.front() != D[0])
369 continue;
370 size_t End = Style.find_first_of(D[1]);
371 if (End == StringRef::npos) {
372 assert(false && "Missing range option end delimeter!");
373 return Default;
374 }
375 StringRef Result = Style.slice(1, End);
376 Style = Style.drop_front(End + 1);
377 return Result;
378 }
379 assert(false && "Invalid range style!");
380 return Default;
381 }
382
383 static std::pair<StringRef, StringRef> parseOptions(StringRef Style) {
384 StringRef Sep = consumeOneOption(Style, '$', ", ");
385 StringRef Args = consumeOneOption(Style, '@', "");
386 assert(Style.empty() && "Unexpected text in range option string!");
387 return {Sep, Args};
388 }
389
390public:
392 "Range value_type does not have a format provider!");
394 llvm::raw_ostream &Stream, StringRef Style) {
395 StringRef Sep;
396 StringRef ArgStyle;
397 std::tie(Sep, ArgStyle) = parseOptions(Style);
398 auto Begin = V.begin();
399 auto End = V.end();
400 if (Begin != End) {
401 auto Adapter = support::detail::build_format_adapter(*Begin);
402 Adapter.format(Stream, ArgStyle);
403 ++Begin;
404 }
405 while (Begin != End) {
406 Stream << Sep;
407 auto Adapter = support::detail::build_format_adapter(*Begin);
408 Adapter.format(Stream, ArgStyle);
409 ++Begin;
410 }
411 }
412};
413} // namespace llvm
414
415#endif
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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...
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition StringRef.h:573
static constexpr size_t npos
Definition StringRef.h:57
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.
LLVM_ABI void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits, IntegerStyle Style)
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)