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