LLVM 20.0.0git
FormatVariadic.h
Go to the documentation of this file.
1//===- FormatVariadic.h - Efficient type-safe string formatting --*- 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 the formatv() function which can be used with other LLVM
10// subsystems to provide printf-like formatting, but with improved safety and
11// flexibility. The result of `formatv` is an object which can be streamed to
12// a raw_ostream or converted to a std::string or llvm::SmallString.
13//
14// // Convert to std::string.
15// std::string S = formatv("{0} {1}", 1234.412, "test").str();
16//
17// // Convert to llvm::SmallString
18// SmallString<8> S = formatv("{0} {1}", 1234.412, "test").sstr<8>();
19//
20// // Stream to an existing raw_ostream.
21// OS << formatv("{0} {1}", 1234.412, "test");
22//
23//===----------------------------------------------------------------------===//
24
25#ifndef LLVM_SUPPORT_FORMATVARIADIC_H
26#define LLVM_SUPPORT_FORMATVARIADIC_H
27
28#include "llvm/ADT/ArrayRef.h"
29#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/StringRef.h"
37#include <array>
38#include <cstddef>
39#include <optional>
40#include <string>
41#include <tuple>
42#include <utility>
43
44namespace llvm {
45
47
55
58 unsigned Index = 0;
59 unsigned Width = 0;
61 char Pad = 0;
63};
64
66protected:
70
73 bool Validate)
75
78
79public:
80 void format(raw_ostream &S) const {
81 const auto Replacements = parseFormatString(Fmt, Adapters.size(), Validate);
82 for (const auto &R : Replacements) {
83 if (R.Type == ReplacementType::Literal) {
84 S << R.Spec;
85 continue;
86 }
87 if (R.Index >= Adapters.size()) {
88 S << R.Spec;
89 continue;
90 }
91
92 auto *W = Adapters[R.Index];
93
94 FmtAlign Align(*W, R.Where, R.Width, R.Pad);
95 Align.format(S, R.Options);
96 }
97 }
98
99 // Parse and optionally validate format string (in debug builds).
101 parseFormatString(StringRef Fmt, size_t NumArgs, bool Validate);
102
103 std::string str() const {
104 std::string Result;
105 raw_string_ostream Stream(Result);
106 Stream << *this;
107 Stream.flush();
108 return Result;
109 }
110
111 template <unsigned N> SmallString<N> sstr() const {
112 SmallString<N> Result;
113 raw_svector_ostream Stream(Result);
114 Stream << *this;
115 return Result;
116 }
117
118 template <unsigned N> operator SmallString<N>() const { return sstr<N>(); }
119
120 operator std::string() const { return str(); }
121};
122
123template <typename Tuple> class formatv_object : public formatv_object_base {
124 // Storage for the parameter adapters. Since the base class erases the type
125 // of the parameters, we have to own the storage for the parameters here, and
126 // have the base class store type-erased pointers into this tuple.
127 Tuple Parameters;
128 std::array<support::detail::format_adapter *, std::tuple_size<Tuple>::value>
129 ParameterPointers;
130
131 // The parameters are stored in a std::tuple, which does not provide runtime
132 // indexing capabilities. In order to enable runtime indexing, we use this
133 // structure to put the parameters into a std::array. Since the parameters
134 // are not all the same type, we use some type-erasure by wrapping the
135 // parameters in a template class that derives from a non-template superclass.
136 // Essentially, we are converting a std::tuple<Derived<Ts...>> to a
137 // std::array<Base*>.
138 struct create_adapters {
139 template <typename... Ts>
140 std::array<support::detail::format_adapter *, std::tuple_size<Tuple>::value>
141 operator()(Ts &...Items) {
142 return {{&Items...}};
143 }
144 };
145
146public:
147 formatv_object(StringRef Fmt, Tuple &&Params, bool Validate)
148 : formatv_object_base(Fmt, ParameterPointers, Validate),
149 Parameters(std::move(Params)) {
150 ParameterPointers = std::apply(create_adapters(), Parameters);
151 }
152
153 formatv_object(formatv_object const &rhs) = delete;
154
157 Parameters(std::move(rhs.Parameters)) {
158 ParameterPointers = std::apply(create_adapters(), Parameters);
159 Adapters = ParameterPointers;
160 }
161};
162
163// Format text given a format string and replacement parameters.
164//
165// ===General Description===
166//
167// Formats textual output. `Fmt` is a string consisting of one or more
168// replacement sequences with the following grammar:
169//
170// rep_field ::= "{" [index] ["," layout] [":" format] "}"
171// index ::= <non-negative integer>
172// layout ::= [[[char]loc]width]
173// format ::= <any string not containing "{" or "}">
174// char ::= <any character except "{" or "}">
175// loc ::= "-" | "=" | "+"
176// width ::= <positive integer>
177//
178// index - An optional non-negative integer specifying the index of the item
179// in the parameter pack to print. Any other value is invalid. If its
180// not specified, it will be automatically assigned a value based on
181// the order of rep_field seen in the format string. Note that mixing
182// automatic and explicit index in the same call is an error and will
183// fail validation in assert-enabled builds.
184// layout - A string controlling how the field is laid out within the available
185// space.
186// format - A type-dependent string used to provide additional options to
187// the formatting operation. Refer to the documentation of the
188// various individual format providers for per-type options.
189// char - The padding character. Defaults to ' ' (space). Only valid if
190// `loc` is also specified.
191// loc - Where to print the formatted text within the field. Only valid if
192// `width` is also specified.
193// '-' : The field is left aligned within the available space.
194// '=' : The field is centered within the available space.
195// '+' : The field is right aligned within the available space (this
196// is the default).
197// width - The width of the field within which to print the formatted text.
198// If this is less than the required length then the `char` and `loc`
199// fields are ignored, and the field is printed with no leading or
200// trailing padding. If this is greater than the required length,
201// then the text is output according to the value of `loc`, and padded
202// as appropriate on the left and/or right by `char`.
203//
204// ===Special Characters===
205//
206// The characters '{' and '}' are reserved and cannot appear anywhere within a
207// replacement sequence. Outside of a replacement sequence, in order to print
208// a literal '{' it must be doubled as "{{".
209//
210// ===Parameter Indexing===
211//
212// `index` specifies the index of the parameter in the parameter pack to format
213// into the output. Note that it is possible to refer to the same parameter
214// index multiple times in a given format string. This makes it possible to
215// output the same value multiple times without passing it multiple times to the
216// function. For example:
217//
218// formatv("{0} {1} {0}", "a", "bb")
219//
220// would yield the string "abba". This can be convenient when it is expensive
221// to compute the value of the parameter, and you would otherwise have had to
222// save it to a temporary.
223//
224// ===Formatter Search===
225//
226// For a given parameter of type T, the following steps are executed in order
227// until a match is found:
228//
229// 1. If the parameter is of class type, and inherits from format_adapter,
230// Then format() is invoked on it to produce the formatted output. The
231// implementation should write the formatted text into `Stream`.
232// 2. If there is a suitable template specialization of format_provider<>
233// for type T containing a method whose signature is:
234// void format(const T &Obj, raw_ostream &Stream, StringRef Options)
235// Then this method is invoked as described in Step 1.
236// 3. If an appropriate operator<< for raw_ostream exists, it will be used.
237// For this to work, (raw_ostream& << const T&) must return raw_ostream&.
238//
239// If a match cannot be found through either of the above methods, a compiler
240// error is generated.
241//
242// ===Invalid Format String Handling===
243//
244// In the case of a format string which does not match the grammar described
245// above, the output is undefined. With asserts enabled, LLVM will trigger an
246// assertion. Otherwise, it will try to do something reasonable, but in general
247// the details of what that is are undefined.
248//
249
250// formatv() with validation enable/disable controlled by the first argument.
251template <typename... Ts>
252inline auto formatv(bool Validate, const char *Fmt, Ts &&...Vals) {
253 auto Params = std::make_tuple(
254 support::detail::build_format_adapter(std::forward<Ts>(Vals))...);
255 return formatv_object<decltype(Params)>(Fmt, std::move(Params), Validate);
256}
257
258// formatv() with validation enabled.
259template <typename... Ts> inline auto formatv(const char *Fmt, Ts &&...Vals) {
260 return formatv<Ts...>(true, Fmt, std::forward<Ts>(Vals)...);
261}
262
263} // end namespace llvm
264
265#endif // LLVM_SUPPORT_FORMATVARIADIC_H
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallString class.
This file defines the SmallVector class.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
void format(raw_ostream &S) const
formatv_object_base(formatv_object_base &&rhs)=default
static SmallVector< ReplacementItem, 2 > parseFormatString(StringRef Fmt, size_t NumArgs, bool Validate)
formatv_object_base(StringRef Fmt, ArrayRef< support::detail::format_adapter * > Adapters, bool Validate)
ArrayRef< support::detail::format_adapter * > Adapters
formatv_object_base(formatv_object_base const &rhs)=delete
std::string str() const
SmallString< N > sstr() const
formatv_object(formatv_object &&rhs)
formatv_object(StringRef Fmt, Tuple &&Params, bool Validate)
formatv_object(formatv_object const &rhs)=delete
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:691
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: AddressRanges.h:18
AlignStyle
Definition: FormatCommon.h:17
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
ReplacementType
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Helper class to format to a Width wide field, with alignment Where within that field.
Definition: FormatCommon.h:21
ReplacementItem(StringRef Literal)
ReplacementItem(StringRef Spec, unsigned Index, unsigned Width, AlignStyle Where, char Pad, StringRef Options)
ReplacementType Type