MLIR 23.0.0git
Format.h
Go to the documentation of this file.
1//===- Format.h - Utilities for String Format -------------------*- 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 declares utilities for formatting strings. They are specially
10// tailored to the needs of TableGen'ing op definitions and rewrite rules,
11// so they are not expected to be used as widely applicable utilities.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef MLIR_TABLEGEN_FORMAT_H_
16#define MLIR_TABLEGEN_FORMAT_H_
17
18#include "mlir/Support/LLVM.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/StringMap.h"
21#include "llvm/Support/FormatVariadic.h"
22
23namespace mlir {
24namespace tblgen {
25
26/// Format context containing substitutions for special placeholders.
27///
28/// This context divides special placeholders into two categories: builtin ones
29/// and custom ones.
30///
31/// Builtin placeholders are baked into `FmtContext` and each one of them has a
32/// dedicated setter. They can be used in all dialects. Their names follow the
33/// convention of `$_<name>`. The rationale of the leading underscore is to
34/// avoid confusion and name collision: op arguments/attributes/results are
35/// named as $<name>, and we can potentially support referencing those entities
36/// directly in the format template in the future.
37//
38/// Custom ones are registered by dialect-specific TableGen backends and use the
39/// same unified setter.
41public:
42 // Placeholder kinds
43 enum class PHKind : char {
45 Custom, // For custom placeholders
46 Builder, // For the $_builder placeholder
47 Self, // For the $_self placeholder
48 };
49
50 FmtContext() = default;
51
52 // Create a format context with a list of substitutions.
53 FmtContext(ArrayRef<std::pair<StringRef, StringRef>> subs);
54
55 // Setter for custom placeholders
56 FmtContext &addSubst(StringRef placeholder, const Twine &subst);
57
58 // Setters for builtin placeholders
59 FmtContext &withBuilder(Twine subst);
60 FmtContext &withSelf(Twine subst);
61
62 std::optional<StringRef> getSubstFor(PHKind placeholder) const;
63 std::optional<StringRef> getSubstFor(StringRef placeholder) const;
64
65 static PHKind getPlaceHolderKind(StringRef str);
66
67private:
68 struct PHKindInfo : DenseMapInfo<PHKind> {
69 using CharInfo = DenseMapInfo<char>;
70
71 static unsigned getHashValue(const PHKind &val) {
72 return CharInfo::getHashValue(static_cast<char>(val));
73 }
74
75 static bool isEqual(const PHKind &lhs, const PHKind &rhs) {
76 return lhs == rhs;
77 }
78 };
79
80 llvm::SmallDenseMap<PHKind, std::string, 4, PHKindInfo> builtinSubstMap;
81 llvm::StringMap<std::string> customSubstMap;
82};
83
84/// Struct representing a replacement segment for the formatted string. It can
85/// be a segment of the formatting template (for `Literal`) or a replacement
86/// parameter (for `PositionalPH`, `PositionalRangePH` and `SpecialPH`).
95
96 FmtReplacement() = default;
97 explicit FmtReplacement(StringRef literal)
98 : type(Type::Literal), spec(literal) {}
99 FmtReplacement(StringRef spec, size_t index)
101 FmtReplacement(StringRef spec, size_t index, size_t end)
105
107 StringRef spec;
108 size_t index = 0;
109 size_t end = kUnset;
111
112 static constexpr size_t kUnset = -1;
113};
114
116private:
117 static std::pair<FmtReplacement, StringRef> splitFmtSegment(StringRef fmt);
118 static std::vector<FmtReplacement> parseFormatString(StringRef fmt);
119
120protected:
121 // The parameters are stored in a std::tuple, which does not provide runtime
122 // indexing capabilities. In order to enable runtime indexing, we use this
123 // structure to put the parameters into a std::vector. Since the parameters
124 // are not all the same type, we use some type-erasure by wrapping the
125 // parameters in a template class that derives from a non-template superclass.
126 // Essentially, we are converting a std::tuple<Derived<Ts...>> to a
127 // std::vector<Base*>.
129 template <typename... Ts>
130 std::vector<llvm::support::detail::FormatFunctorRef>
131 operator()(Ts &...items) {
132 return std::vector<llvm::support::detail::FormatFunctorRef>{items...};
133 }
134 };
135
136 StringRef fmt;
138 std::vector<llvm::support::detail::FormatFunctorRef> adapters;
139 std::vector<FmtReplacement> replacements;
140
141public:
142 FmtObjectBase(StringRef fmt, const FmtContext *ctx, size_t numParams)
143 : fmt(fmt), context(ctx), replacements(parseFormatString(fmt)) {}
144
145 FmtObjectBase(const FmtObjectBase &that) = delete;
146
148 : fmt(that.fmt), context(that.context),
149 adapters(), // adapters are initialized by FmtObject
150 replacements(std::move(that.replacements)) {}
151
152 void format(llvm::raw_ostream &s) const;
153
154 std::string str() const {
155 std::string result;
156 llvm::raw_string_ostream s(result);
157 format(s);
158 return s.str();
159 }
160
161 template <unsigned N>
164 llvm::raw_svector_ostream s(result);
165 format(s);
166 return result;
167 }
168
169 template <unsigned N>
170 operator SmallString<N>() const {
171 return sstr<N>();
172 }
173
174 operator std::string() const { return str(); }
175};
176
177template <typename Tuple>
178class FmtObject : public FmtObjectBase {
179 // Storage for the parameter adapters. Since the base class erases the type
180 // of the parameters, we have to own the storage for the parameters here, and
181 // have the base class store type-erased pointers into this tuple.
182 Tuple parameters;
183
184public:
185 FmtObject(StringRef fmt, const FmtContext *ctx, Tuple &&params)
186 : FmtObjectBase(fmt, ctx, std::tuple_size<Tuple>::value),
187 parameters(std::move(params)) {
188 adapters.reserve(std::tuple_size<Tuple>::value);
189 adapters = std::apply(CreateAdapters(), parameters);
190 }
191
192 FmtObject(FmtObject const &that) = delete;
193
195 : FmtObjectBase(std::move(that)), parameters(std::move(that.parameters)) {
196 adapters.reserve(that.adapters.size());
197 adapters = std::apply(CreateAdapters(), parameters);
198 }
199};
200
202public:
203 using StrFormatAdapter = llvm::support::detail::FormatFunctor<std::string>;
204
205 FmtStrVecObject(StringRef fmt, const FmtContext *ctx,
206 ArrayRef<std::string> params);
207 FmtStrVecObject(FmtStrVecObject const &that) = delete;
209
210private:
212};
213
214/// Formats text by substituting placeholders in format string with replacement
215/// parameters.
216///
217/// There are two categories of placeholders accepted, both led by a '$' sign:
218///
219/// 1.a Positional placeholder: $[0-9]+
220/// 1.b Positional range placeholder: $[0-9]+...
221/// 2. Special placeholder: $[a-zA-Z_][a-zA-Z0-9_]*
222///
223/// Replacement parameters for positional placeholders are supplied as the
224/// `vals` parameter pack with 1:1 mapping. That is, $0 will be replaced by the
225/// first parameter in `vals`, $1 by the second one, and so on. Note that you
226/// can use the positional placeholders in any order and repeat any times, for
227/// example, "$2 $1 $1 $0" is accepted.
228///
229/// Replace parameters for positional range placeholders are supplied as if
230/// positional placeholders were specified with commas separating them.
231///
232/// Replacement parameters for special placeholders are supplied using the `ctx`
233/// format context.
234///
235/// The `fmt` is recorded as a `StringRef` inside the returned `FmtObject`.
236/// The caller needs to make sure the underlying data is available when the
237/// `FmtObject` is used.
238///
239/// `ctx` accepts a nullptr if there is no special placeholder is used.
240///
241/// If no substitution is provided for a placeholder or any error happens during
242/// format string parsing or replacement, the placeholder will be outputted
243/// as-is with an additional marker '<no-subst-found>', to aid debugging.
244///
245/// To print a '$' literally, escape it with '$$'.
246///
247/// This utility function is inspired by LLVM formatv(), with modifications
248/// specially tailored for TableGen C++ generation usage:
249///
250/// 1. This utility use '$' instead of '{' and '}' for denoting the placeholder
251/// because '{' and '}' are frequently used in C++ code.
252/// 2. This utility does not support format layout because it is rarely needed
253/// in C++ code generation.
254template <typename... Ts>
255inline auto tgfmt(StringRef fmt, const FmtContext *ctx, Ts &&...vals)
256 -> FmtObject<decltype(std::make_tuple(
257 llvm::support::detail::FormatFunctor(std::forward<Ts>(vals))...))> {
258 using ParamTuple = decltype(std::make_tuple(
259 llvm::support::detail::FormatFunctor(std::forward<Ts>(vals))...));
261 fmt, ctx,
262 std::make_tuple(
263 llvm::support::detail::FormatFunctor(std::forward<Ts>(vals))...));
264}
265
266/// Like tgfmt, but take replacement parameters as an array of strings instead.
267inline FmtStrVecObject tgfmtv(StringRef fmt, const FmtContext *ctx,
268 ArrayRef<std::string> params) {
269 return FmtStrVecObject(fmt, ctx, params);
270}
271
272} // namespace tblgen
273} // namespace mlir
274
275#endif // MLIR_TABLEGEN_FORMAT_H_
lhs
Format context containing substitutions for special placeholders.
Definition Format.h:40
FmtContext & withBuilder(Twine subst)
Definition Format.cpp:36
static PHKind getPlaceHolderKind(StringRef str)
Definition Format.cpp:64
std::optional< StringRef > getSubstFor(PHKind placeholder) const
Definition Format.cpp:47
FmtContext & withSelf(Twine subst)
Definition Format.cpp:41
FmtContext & addSubst(StringRef placeholder, const Twine &subst)
Definition Format.cpp:31
std::string str() const
Definition Format.h:154
FmtObjectBase(StringRef fmt, const FmtContext *ctx, size_t numParams)
Definition Format.h:142
void format(llvm::raw_ostream &s) const
Definition Format.cpp:145
const FmtContext * context
Definition Format.h:137
FmtObjectBase(FmtObjectBase &&that)
Definition Format.h:147
std::vector< llvm::support::detail::FormatFunctorRef > adapters
Definition Format.h:138
std::vector< FmtReplacement > replacements
Definition Format.h:139
FmtObjectBase(const FmtObjectBase &that)=delete
SmallString< N > sstr() const
Definition Format.h:162
FmtObject(FmtObject const &that)=delete
FmtObject(StringRef fmt, const FmtContext *ctx, Tuple &&params)
Definition Format.h:185
FmtObject(FmtObject &&that)
Definition Format.h:194
FmtStrVecObject(StringRef fmt, const FmtContext *ctx, ArrayRef< std::string > params)
Definition Format.cpp:200
llvm::support::detail::FormatFunctor< std::string > StrFormatAdapter
Definition Format.h:203
FmtStrVecObject(FmtStrVecObject const &that)=delete
auto tgfmt(StringRef fmt, const FmtContext *ctx, Ts &&...vals) -> FmtObject< decltype(std::make_tuple(llvm::support::detail::FormatFunctor(std::forward< Ts >(vals))...))>
Formats text by substituting placeholders in format string with replacement parameters.
Definition Format.h:255
FmtStrVecObject tgfmtv(StringRef fmt, const FmtContext *ctx, ArrayRef< std::string > params)
Like tgfmt, but take replacement parameters as an array of strings instead.
Definition Format.h:267
Include the generated interface declarations.
llvm::DenseMapInfo< T, Enable > DenseMapInfo
Definition LLVM.h:116
std::vector< llvm::support::detail::FormatFunctorRef > operator()(Ts &...items)
Definition Format.h:131
FmtReplacement(StringRef literal)
Definition Format.h:97
FmtReplacement(StringRef spec, size_t index)
Definition Format.h:99
static constexpr size_t kUnset
Definition Format.h:112
FmtContext::PHKind placeholder
Definition Format.h:110
FmtReplacement(StringRef spec, FmtContext::PHKind placeholder)
Definition Format.h:103
FmtReplacement(StringRef spec, size_t index, size_t end)
Definition Format.h:101