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