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
49 ReplacementItem() = default;
53 char Pad, StringRef Options)
56
59 size_t Index = 0;
60 size_t Align = 0;
62 char Pad = 0;
64};
65
67protected:
70
71 static bool consumeFieldLayout(StringRef &Spec, AlignStyle &Where,
72 size_t &Align, char &Pad);
73
74 static std::pair<ReplacementItem, StringRef>
76
79 : Fmt(Fmt), Adapters(Adapters) {}
80
83
84public:
85 void format(raw_ostream &S) const {
86 for (auto &R : parseFormatString(Fmt)) {
87 if (R.Type == ReplacementType::Empty)
88 continue;
89 if (R.Type == ReplacementType::Literal) {
90 S << R.Spec;
91 continue;
92 }
93 if (R.Index >= Adapters.size()) {
94 S << R.Spec;
95 continue;
96 }
97
98 auto *W = Adapters[R.Index];
99
100 FmtAlign Align(*W, R.Where, R.Align, R.Pad);
101 Align.format(S, R.Options);
102 }
103 }
105
106 static std::optional<ReplacementItem> parseReplacementItem(StringRef Spec);
107
108 std::string str() const {
109 std::string Result;
110 raw_string_ostream Stream(Result);
111 Stream << *this;
112 Stream.flush();
113 return Result;
114 }
115
116 template <unsigned N> SmallString<N> sstr() const {
117 SmallString<N> Result;
118 raw_svector_ostream Stream(Result);
119 Stream << *this;
120 return Result;
121 }
122
123 template <unsigned N> operator SmallString<N>() const { return sstr<N>(); }
124
125 operator std::string() const { return str(); }
126};
127
128template <typename Tuple> class formatv_object : public formatv_object_base {
129 // Storage for the parameter adapters. Since the base class erases the type
130 // of the parameters, we have to own the storage for the parameters here, and
131 // have the base class store type-erased pointers into this tuple.
132 Tuple Parameters;
133 std::array<support::detail::format_adapter *, std::tuple_size<Tuple>::value>
134 ParameterPointers;
135
136 // The parameters are stored in a std::tuple, which does not provide runtime
137 // indexing capabilities. In order to enable runtime indexing, we use this
138 // structure to put the parameters into a std::array. Since the parameters
139 // are not all the same type, we use some type-erasure by wrapping the
140 // parameters in a template class that derives from a non-template superclass.
141 // Essentially, we are converting a std::tuple<Derived<Ts...>> to a
142 // std::array<Base*>.
143 struct create_adapters {
144 template <typename... Ts>
145 std::array<support::detail::format_adapter *, std::tuple_size<Tuple>::value>
146 operator()(Ts &...Items) {
147 return {{&Items...}};
148 }
149 };
150
151public:
152 formatv_object(StringRef Fmt, Tuple &&Params)
153 : formatv_object_base(Fmt, ParameterPointers),
154 Parameters(std::move(Params)) {
155 ParameterPointers = std::apply(create_adapters(), Parameters);
156 }
157
158 formatv_object(formatv_object const &rhs) = delete;
159
162 Parameters(std::move(rhs.Parameters)) {
163 ParameterPointers = std::apply(create_adapters(), Parameters);
164 Adapters = ParameterPointers;
165 }
166};
167
168// Format text given a format string and replacement parameters.
169//
170// ===General Description===
171//
172// Formats textual output. `Fmt` is a string consisting of one or more
173// replacement sequences with the following grammar:
174//
175// rep_field ::= "{" index ["," layout] [":" format] "}"
176// index ::= <non-negative integer>
177// layout ::= [[[char]loc]width]
178// format ::= <any string not containing "{" or "}">
179// char ::= <any character except "{" or "}">
180// loc ::= "-" | "=" | "+"
181// width ::= <positive integer>
182//
183// index - A non-negative integer specifying the index of the item in the
184// parameter pack to print. Any other value is invalid.
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//
250template <typename... Ts>
251inline auto formatv(const char *Fmt, Ts &&...Vals)
252 -> formatv_object<decltype(std::make_tuple(
253 support::detail::build_format_adapter(std::forward<Ts>(Vals))...))> {
254 using ParamTuple = decltype(std::make_tuple(
255 support::detail::build_format_adapter(std::forward<Ts>(Vals))...));
257 Fmt, std::make_tuple(support::detail::build_format_adapter(
258 std::forward<Ts>(Vals))...));
259}
260
261} // end namespace llvm
262
263#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:1210
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
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)
static bool consumeFieldLayout(StringRef &Spec, AlignStyle &Where, size_t &Align, char &Pad)
static std::optional< ReplacementItem > parseReplacementItem(StringRef Spec)
ArrayRef< support::detail::format_adapter * > Adapters
formatv_object_base(formatv_object_base const &rhs)=delete
std::string str() const
SmallString< N > sstr() const
static std::pair< ReplacementItem, StringRef > splitLiteralAndReplacement(StringRef Fmt)
formatv_object_base(StringRef Fmt, ArrayRef< support::detail::format_adapter * > Adapters)
formatv_object(formatv_object &&rhs)
formatv_object(StringRef Fmt, Tuple &&Params)
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(const char *Fmt, Ts &&...Vals) -> formatv_object< decltype(std::make_tuple(support::detail::build_format_adapter(std::forward< 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:1849
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
ReplacementItem(StringRef Literal)
ReplacementItem(StringRef Spec, size_t Index, size_t Align, AlignStyle Where, char Pad, StringRef Options)