LLVM 23.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"
38#include <array>
39#include <cstddef>
40#include <string>
41#include <tuple>
42#include <utility>
43
44namespace llvm {
45
47
64
66protected:
70
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(Result) << *this;
106 return Result;
107 }
108
109 template <unsigned N> SmallString<N> sstr() const {
110 SmallString<N> Result;
111 raw_svector_ostream(Result) << *this;
112 return Result;
113 }
114
115 template <unsigned N> operator SmallString<N>() const { return sstr<N>(); }
116
117 operator std::string() const { return str(); }
118};
119
120template <typename Tuple> class formatv_object : public formatv_object_base {
121 // Storage for the parameter adapters. Since the base class erases the type
122 // of the parameters, we have to own the storage for the parameters here, and
123 // have the base class store type-erased pointers into this tuple.
124 Tuple Parameters;
125 std::array<support::detail::format_adapter *, std::tuple_size<Tuple>::value>
126 ParameterPointers;
127
128 // The parameters are stored in a std::tuple, which does not provide runtime
129 // indexing capabilities. In order to enable runtime indexing, we use this
130 // structure to put the parameters into a std::array. Since the parameters
131 // are not all the same type, we use some type-erasure by wrapping the
132 // parameters in a template class that derives from a non-template superclass.
133 // Essentially, we are converting a std::tuple<Derived<Ts...>> to a
134 // std::array<Base*>.
135 struct create_adapters {
136 template <typename... Ts>
137 std::array<support::detail::format_adapter *, std::tuple_size<Tuple>::value>
138 operator()(Ts &...Items) {
139 return {{&Items...}};
140 }
141 };
142
143public:
144 formatv_object(StringRef Fmt, Tuple &&Params, bool Validate)
145 : formatv_object_base(Fmt, ParameterPointers, Validate),
146 Parameters(std::move(Params)) {
147 ParameterPointers = std::apply(create_adapters(), Parameters);
148 }
149
150 formatv_object(formatv_object const &rhs) = delete;
151
154 Parameters(std::move(rhs.Parameters)) {
155 ParameterPointers = std::apply(create_adapters(), Parameters);
156 Adapters = ParameterPointers;
157 }
158};
159
160// Format text given a format string and replacement parameters.
161//
162// ===General Description===
163//
164// Formats textual output. `Fmt` is a string consisting of one or more
165// replacement sequences with the following grammar:
166//
167// rep_field ::= "{" [index] ["," layout] [":" format] "}"
168// index ::= <non-negative integer>
169// layout ::= [[[char]loc]width]
170// format ::= <any string not containing "{" or "}">
171// char ::= <any character except "{" or "}">
172// loc ::= "-" | "=" | "+"
173// width ::= <positive integer>
174//
175// index - An optional non-negative integer specifying the index of the item
176// in the parameter pack to print. Any other value is invalid. If its
177// not specified, it will be automatically assigned a value based on
178// the order of rep_field seen in the format string. Note that mixing
179// automatic and explicit index in the same call is an error and will
180// fail validation in assert-enabled builds.
181// layout - A string controlling how the field is laid out within the available
182// space.
183// format - A type-dependent string used to provide additional options to
184// the formatting operation. Refer to the documentation of the
185// various individual format providers for per-type options.
186// char - The padding character. Defaults to ' ' (space). Only valid if
187// `loc` is also specified.
188// loc - Where to print the formatted text within the field. Only valid if
189// `width` is also specified.
190// '-' : The field is left aligned within the available space.
191// '=' : The field is centered within the available space.
192// '+' : The field is right aligned within the available space (this
193// is the default).
194// width - The width of the field within which to print the formatted text.
195// If this is less than the required length then the `char` and `loc`
196// fields are ignored, and the field is printed with no leading or
197// trailing padding. If this is greater than the required length,
198// then the text is output according to the value of `loc`, and padded
199// as appropriate on the left and/or right by `char`.
200//
201// ===Special Characters===
202//
203// The characters '{' and '}' are reserved and cannot appear anywhere within a
204// replacement sequence. Outside of a replacement sequence, in order to print
205// a literal '{' it must be doubled as "{{".
206//
207// ===Parameter Indexing===
208//
209// `index` specifies the index of the parameter in the parameter pack to format
210// into the output. Note that it is possible to refer to the same parameter
211// index multiple times in a given format string. This makes it possible to
212// output the same value multiple times without passing it multiple times to the
213// function. For example:
214//
215// formatv("{0} {1} {0}", "a", "bb")
216//
217// would yield the string "abba". This can be convenient when it is expensive
218// to compute the value of the parameter, and you would otherwise have had to
219// save it to a temporary.
220//
221// ===Formatter Search===
222//
223// For a given parameter of type T, the following steps are executed in order
224// until a match is found:
225//
226// 1. If the parameter is of class type, and inherits from format_adapter,
227// Then format() is invoked on it to produce the formatted output. The
228// implementation should write the formatted text into `Stream`.
229// 2. If there is a suitable template specialization of format_provider<>
230// for type T containing a method whose signature is:
231// void format(const T &Obj, raw_ostream &Stream, StringRef Options)
232// Then this method is invoked as described in Step 1.
233// 3. If an appropriate operator<< for raw_ostream exists, it will be used.
234// For this to work, (raw_ostream& << const T&) must return raw_ostream&.
235//
236// If a match cannot be found through either of the above methods, a compiler
237// error is generated.
238//
239// ===Invalid Format String Handling===
240//
241// In the case of a format string which does not match the grammar described
242// above, the output is undefined. With asserts enabled, LLVM will trigger an
243// assertion. Otherwise, it will try to do something reasonable, but in general
244// the details of what that is are undefined.
245//
246
247// formatv() with validation enable/disable controlled by the first argument.
248template <typename... Ts>
249inline auto formatv(bool Validate, const char *Fmt, Ts &&...Vals) {
250 auto Params = std::make_tuple(
251 support::detail::build_format_adapter(std::forward<Ts>(Vals))...);
252 return formatv_object<decltype(Params)>(Fmt, std::move(Params), Validate);
253}
254
255// formatv() with validation enabled.
256template <typename... Ts> inline auto formatv(const char *Fmt, Ts &&...Vals) {
257 return formatv<Ts...>(true, Fmt, std::forward<Ts>(Vals)...);
258}
259
260} // end namespace llvm
261
262#endif // LLVM_SUPPORT_FORMATVARIADIC_H
#define LLVM_ABI
Definition Compiler.h:213
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:40
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.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
void format(raw_ostream &S) const
formatv_object_base(formatv_object_base &&rhs)=default
static LLVM_ABI 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:53
A raw_ostream that writes to an std::string.
A raw_ostream that writes to an SmallVector or SmallString.
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
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
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:1915
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870
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.
ReplacementItem(StringRef Literal)
ReplacementItem(StringRef Spec, unsigned Index, unsigned Width, AlignStyle Where, char Pad, StringRef Options)
ReplacementType Type