File indexing completed on 2026-05-10 08:44:30
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_SUPPORT_FORMATPROVIDERS_H
0015 #define LLVM_SUPPORT_FORMATPROVIDERS_H
0016
0017 #include "llvm/ADT/STLExtras.h"
0018 #include "llvm/ADT/StringSwitch.h"
0019 #include "llvm/ADT/Twine.h"
0020 #include "llvm/Support/FormatVariadicDetails.h"
0021 #include "llvm/Support/NativeFormatting.h"
0022
0023 #include <array>
0024 #include <optional>
0025 #include <type_traits>
0026
0027 namespace llvm {
0028 namespace support {
0029 namespace detail {
0030 template <typename T>
0031 struct use_integral_formatter
0032 : public std::integral_constant<
0033 bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
0034 int64_t, uint64_t, int, unsigned, long, unsigned long,
0035 long long, unsigned long long>::value> {};
0036
0037 template <typename T>
0038 struct use_char_formatter
0039 : public std::integral_constant<bool, std::is_same_v<T, char>> {};
0040
0041 template <typename T>
0042 struct is_cstring
0043 : public std::integral_constant<bool,
0044 is_one_of<T, char *, const char *>::value> {
0045 };
0046
0047 template <typename T>
0048 struct use_string_formatter
0049 : public std::integral_constant<bool,
0050 std::is_convertible_v<T, llvm::StringRef>> {
0051 };
0052
0053 template <typename T>
0054 struct use_pointer_formatter
0055 : public std::integral_constant<bool, std::is_pointer_v<T> &&
0056 !is_cstring<T>::value> {};
0057
0058 template <typename T>
0059 struct use_double_formatter
0060 : public std::integral_constant<bool, std::is_floating_point_v<T>> {};
0061
0062 class HelperFunctions {
0063 protected:
0064 static std::optional<size_t> parseNumericPrecision(StringRef Str) {
0065 size_t Prec;
0066 std::optional<size_t> Result;
0067 if (Str.empty())
0068 Result = std::nullopt;
0069 else if (Str.getAsInteger(10, Prec)) {
0070 assert(false && "Invalid precision specifier");
0071 Result = std::nullopt;
0072 } else {
0073 assert(Prec < 100 && "Precision out of range");
0074 Result = std::min<size_t>(99u, Prec);
0075 }
0076 return Result;
0077 }
0078
0079 static std::optional<HexPrintStyle> consumeHexStyle(StringRef &Str) {
0080 if (!Str.starts_with_insensitive("x"))
0081 return std::nullopt;
0082
0083 if (Str.consume_front("x-"))
0084 return HexPrintStyle::Lower;
0085 if (Str.consume_front("X-"))
0086 return HexPrintStyle::Upper;
0087 if (Str.consume_front("x+") || Str.consume_front("x"))
0088 return HexPrintStyle::PrefixLower;
0089 if (!Str.consume_front("X+"))
0090 Str.consume_front("X");
0091 return HexPrintStyle::PrefixUpper;
0092 }
0093
0094 static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style,
0095 size_t Default) {
0096 Str.consumeInteger(10, Default);
0097 if (isPrefixedHexStyle(Style))
0098 Default += 2;
0099 return Default;
0100 }
0101 };
0102 }
0103 }
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128 template <typename T>
0129 struct format_provider<
0130 T, std::enable_if_t<support::detail::use_integral_formatter<T>::value>>
0131 : public support::detail::HelperFunctions {
0132 private:
0133 public:
0134 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
0135 size_t Digits = 0;
0136 if (std::optional<HexPrintStyle> HS = consumeHexStyle(Style)) {
0137 Digits = consumeNumHexDigits(Style, *HS, 0);
0138 write_hex(Stream, V, *HS, Digits);
0139 return;
0140 }
0141
0142 IntegerStyle IS = IntegerStyle::Integer;
0143 if (Style.consume_front("N") || Style.consume_front("n"))
0144 IS = IntegerStyle::Number;
0145 else if (Style.consume_front("D") || Style.consume_front("d"))
0146 IS = IntegerStyle::Integer;
0147
0148 Style.consumeInteger(10, Digits);
0149 assert(Style.empty() && "Invalid integral format style!");
0150 write_integer(Stream, V, Digits, IS);
0151 }
0152 };
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176 template <typename T>
0177 struct format_provider<
0178 T, std::enable_if_t<support::detail::use_pointer_formatter<T>::value>>
0179 : public support::detail::HelperFunctions {
0180 private:
0181 public:
0182 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
0183 HexPrintStyle HS = HexPrintStyle::PrefixUpper;
0184 if (std::optional<HexPrintStyle> consumed = consumeHexStyle(Style))
0185 HS = *consumed;
0186 size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2);
0187 write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, Digits);
0188 }
0189 };
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 template <typename T>
0203 struct format_provider<
0204 T, std::enable_if_t<support::detail::use_string_formatter<T>::value>> {
0205 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
0206 size_t N = StringRef::npos;
0207 if (!Style.empty() && Style.getAsInteger(10, N)) {
0208 assert(false && "Style is not a valid integer");
0209 }
0210 llvm::StringRef S = V;
0211 Stream << S.substr(0, N);
0212 }
0213 };
0214
0215
0216
0217
0218
0219 template <> struct format_provider<Twine> {
0220 static void format(const Twine &V, llvm::raw_ostream &Stream,
0221 StringRef Style) {
0222 format_provider<std::string>::format(V.str(), Stream, Style);
0223 }
0224 };
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235 template <typename T>
0236 struct format_provider<
0237 T, std::enable_if_t<support::detail::use_char_formatter<T>::value>> {
0238 static void format(const char &V, llvm::raw_ostream &Stream,
0239 StringRef Style) {
0240 if (Style.empty())
0241 Stream << V;
0242 else {
0243 int X = static_cast<int>(V);
0244 format_provider<int>::format(X, Stream, Style);
0245 }
0246 }
0247 };
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 template <> struct format_provider<bool> {
0266 static void format(const bool &B, llvm::raw_ostream &Stream,
0267 StringRef Style) {
0268 Stream << StringSwitch<const char *>(Style)
0269 .Case("Y", B ? "YES" : "NO")
0270 .Case("y", B ? "yes" : "no")
0271 .CaseLower("D", B ? "1" : "0")
0272 .Case("T", B ? "TRUE" : "FALSE")
0273 .Cases("t", "", B ? "true" : "false")
0274 .Default(B ? "1" : "0");
0275 }
0276 };
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301 template <typename T>
0302 struct format_provider<
0303 T, std::enable_if_t<support::detail::use_double_formatter<T>::value>>
0304 : public support::detail::HelperFunctions {
0305 static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
0306 FloatStyle S;
0307 if (Style.consume_front("P") || Style.consume_front("p"))
0308 S = FloatStyle::Percent;
0309 else if (Style.consume_front("F") || Style.consume_front("f"))
0310 S = FloatStyle::Fixed;
0311 else if (Style.consume_front("E"))
0312 S = FloatStyle::ExponentUpper;
0313 else if (Style.consume_front("e"))
0314 S = FloatStyle::Exponent;
0315 else
0316 S = FloatStyle::Fixed;
0317
0318 std::optional<size_t> Precision = parseNumericPrecision(Style);
0319 if (!Precision)
0320 Precision = getDefaultPrecision(S);
0321
0322 write_double(Stream, static_cast<double>(V), S, Precision);
0323 }
0324 };
0325
0326 namespace support {
0327 namespace detail {
0328 template <typename IterT>
0329 using IterValue = typename std::iterator_traits<IterT>::value_type;
0330
0331 template <typename IterT>
0332 struct range_item_has_provider
0333 : public std::integral_constant<
0334 bool,
0335 !support::detail::uses_missing_provider<IterValue<IterT>>::value> {};
0336 }
0337 }
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362 template <typename IterT> class format_provider<llvm::iterator_range<IterT>> {
0363 using value = typename std::iterator_traits<IterT>::value_type;
0364
0365 static StringRef consumeOneOption(StringRef &Style, char Indicator,
0366 StringRef Default) {
0367 if (Style.empty())
0368 return Default;
0369 if (Style.front() != Indicator)
0370 return Default;
0371 Style = Style.drop_front();
0372 if (Style.empty()) {
0373 assert(false && "Invalid range style");
0374 return Default;
0375 }
0376
0377 for (const char *D : std::array<const char *, 3>{"[]", "<>", "()"}) {
0378 if (Style.front() != D[0])
0379 continue;
0380 size_t End = Style.find_first_of(D[1]);
0381 if (End == StringRef::npos) {
0382 assert(false && "Missing range option end delimeter!");
0383 return Default;
0384 }
0385 StringRef Result = Style.slice(1, End);
0386 Style = Style.drop_front(End + 1);
0387 return Result;
0388 }
0389 assert(false && "Invalid range style!");
0390 return Default;
0391 }
0392
0393 static std::pair<StringRef, StringRef> parseOptions(StringRef Style) {
0394 StringRef Sep = consumeOneOption(Style, '$', ", ");
0395 StringRef Args = consumeOneOption(Style, '@', "");
0396 assert(Style.empty() && "Unexpected text in range option string!");
0397 return std::make_pair(Sep, Args);
0398 }
0399
0400 public:
0401 static_assert(support::detail::range_item_has_provider<IterT>::value,
0402 "Range value_type does not have a format provider!");
0403 static void format(const llvm::iterator_range<IterT> &V,
0404 llvm::raw_ostream &Stream, StringRef Style) {
0405 StringRef Sep;
0406 StringRef ArgStyle;
0407 std::tie(Sep, ArgStyle) = parseOptions(Style);
0408 auto Begin = V.begin();
0409 auto End = V.end();
0410 if (Begin != End) {
0411 auto Adapter = support::detail::build_format_adapter(*Begin);
0412 Adapter.format(Stream, ArgStyle);
0413 ++Begin;
0414 }
0415 while (Begin != End) {
0416 Stream << Sep;
0417 auto Adapter = support::detail::build_format_adapter(*Begin);
0418 Adapter.format(Stream, ArgStyle);
0419 ++Begin;
0420 }
0421 }
0422 };
0423 }
0424
0425 #endif