llvm.org GIT mirror llvm / e93da60
[Support] Add type-safe alternative to llvm::format() llvm::format() is somewhat unsafe. The compiler does not check that integer parameter size matches the %x or %d size and it does not complain when a StringRef is passed for a %s. And correctly using a StringRef with format() is ugly because you have to convert it to a std::string then call c_str(). The cases where llvm::format() is useful is controlling how numbers and strings are printed, especially when you want fixed width output. This patch adds some new formatting functions to raw_streams to format numbers and StringRefs in a type safe manner. Some examples: OS << format_hex(255, 6) => "0x00ff" OS << format_hex(255, 4) => "0xff" OS << format_decimal(0, 5) => " 0" OS << format_decimal(255, 5) => " 255" OS << right_justify(Str, 5) => " foo" OS << left_justify(Str, 5) => "foo " git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218463 91177308-0d34-0410-b5e6-96231b3b80d8 Nick Kledzik 5 years ago
4 changed file(s) with 164 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
2121
2222 #ifndef LLVM_SUPPORT_FORMAT_H
2323 #define LLVM_SUPPORT_FORMAT_H
24
25 #include "llvm/ADT/StringRef.h"
2426
2527 #include
2628 #include
224226 Val5, Val6);
225227 }
226228
229 /// This is a helper class used for left_justify() and right_justify().
230 class FormattedString {
231 StringRef Str;
232 unsigned Width;
233 bool RightJustify;
234 friend class raw_ostream;
235 public:
236 FormattedString(StringRef S, unsigned W, bool R)
237 : Str(S), Width(W), RightJustify(R) { }
238 };
239
240 /// left_justify - append spaces after string so total output is
241 /// \p Width characters. If \p Str is larger that \p Width, full string
242 /// is written with no padding.
243 inline FormattedString left_justify(StringRef Str, unsigned Width) {
244 return FormattedString(Str, Width, false);
245 }
246
247 /// right_justify - add spaces before string so total output is
248 /// \p Width characters. If \p Str is larger that \p Width, full string
249 /// is written with no padding.
250 inline FormattedString right_justify(StringRef Str, unsigned Width) {
251 return FormattedString(Str, Width, true);
252 }
253
254 /// This is a helper class used for format_hex() and format_decimal().
255 class FormattedNumber {
256 uint64_t HexValue;
257 int64_t DecValue;
258 unsigned Width;
259 bool Hex;
260 bool Upper;
261 friend class raw_ostream;
262 public:
263 FormattedNumber(uint64_t HV, int64_t DV, unsigned W, bool H, bool U)
264 : HexValue(HV), DecValue(DV), Width(W), Hex(H), Upper(U) { }
265 };
266
267 /// format_hex - Output \p N as a fixed width hexadecimal. If number will not
268 /// fit in width, full number is still printed. Examples:
269 /// OS << format_hex(255, 4) => 0xff
270 /// OS << format_hex(255, 4, true) => 0xFF
271 /// OS << format_hex(255, 6) => 0x00ff
272 /// OS << format_hex(255, 2) => 0xff
273 inline FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false) {
274 assert(Width <= 18 && "hex width must be <= 18");
275 return FormattedNumber(N, 0, Width, true, Upper);
276 }
277
278 /// format_decimal - Output \p N as a right justified, fixed-width decimal. If
279 /// number will not fit in width, full number is still printed. Examples:
280 /// OS << format_decimal(0, 5) => " 0"
281 /// OS << format_decimal(255, 5) => " 255"
282 /// OS << format_decimal(-1, 3) => " -1"
283 /// OS << format_decimal(12345, 3) => "12345"
284 inline FormattedNumber format_decimal(int64_t N, unsigned Width) {
285 return FormattedNumber(0, N, Width, false, false);
286 }
287
288
227289 } // end namespace llvm
228290
229291 #endif
2020
2121 namespace llvm {
2222 class format_object_base;
23 class FormattedString;
24 class FormattedNumber;
2325 template
2426 class SmallVectorImpl;
2527
210212 // Formatted output, see the format() function in Support/Format.h.
211213 raw_ostream &operator<<(const format_object_base &Fmt);
212214
215 // Formatted output, see the leftJustify() function in Support/Format.h.
216 raw_ostream &operator<<(const FormattedString &);
217
218 // Formatted output, see the formatHex() function in Support/Format.h.
219 raw_ostream &operator<<(const FormattedNumber &);
220
213221 /// indent - Insert 'NumSpaces' spaces.
214222 raw_ostream &indent(unsigned NumSpaces);
215223
1919 #include "llvm/Support/ErrorHandling.h"
2020 #include "llvm/Support/FileSystem.h"
2121 #include "llvm/Support/Format.h"
22 #include "llvm/Support/MathExtras.h"
2223 #include "llvm/Support/Process.h"
2324 #include "llvm/Support/Program.h"
2425 #include
393394 }
394395 }
395396
397 raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
398 unsigned Len = FS.Str.size();
399 int PadAmount = FS.Width - Len;
400 if (FS.RightJustify && (PadAmount > 0))
401 this->indent(PadAmount);
402 this->operator<<(FS.Str);
403 if (!FS.RightJustify && (PadAmount > 0))
404 this->indent(PadAmount);
405 return *this;
406 }
407
408 raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
409 if (FN.Hex) {
410 unsigned Nibbles = (64 - countLeadingZeros(FN.HexValue)+3)/4;
411 unsigned Width = (FN.Width > Nibbles+2) ? FN.Width : Nibbles+2;
412
413 char NumberBuffer[20] = "0x0000000000000000";
414 char *EndPtr = NumberBuffer+Width;
415 char *CurPtr = EndPtr;
416 const char A = FN.Upper ? 'A' : 'a';
417 unsigned long long N = FN.HexValue;
418 while (N) {
419 uintptr_t x = N % 16;
420 *--CurPtr = (x < 10 ? '0' + x : A + x - 10);
421 N /= 16;
422 }
423
424 return write(NumberBuffer, Width);
425 } else {
426 // Zero is a special case.
427 if (FN.DecValue == 0) {
428 this->indent(FN.Width-1);
429 return *this << '0';
430 }
431 char NumberBuffer[32];
432 char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
433 char *CurPtr = EndPtr;
434 bool Neg = (FN.DecValue < 0);
435 uint64_t N = Neg ? -FN.DecValue : FN.DecValue;
436 while (N) {
437 *--CurPtr = '0' + char(N % 10);
438 N /= 10;
439 }
440 int Len = EndPtr - CurPtr;
441 int Pad = FN.Width - Len;
442 if (Neg)
443 --Pad;
444 if (Pad > 0)
445 this->indent(Pad);
446 if (Neg)
447 *this << '-';
448 return write(CurPtr, Len);
449 }
450 }
451
452
396453 /// indent - Insert 'NumSpaces' spaces.
397454 raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
398455 static const char Spaces[] = " "
142142 EXPECT_EQ("\\001\\010\\200", Str);
143143 }
144144
145 TEST(raw_ostreamTest, Justify) {
146 EXPECT_EQ("xyz ", printToString(left_justify("xyz", 6), 6));
147 EXPECT_EQ("abc", printToString(left_justify("abc", 3), 3));
148 EXPECT_EQ("big", printToString(left_justify("big", 1), 3));
149 EXPECT_EQ(" xyz", printToString(right_justify("xyz", 6), 6));
150 EXPECT_EQ("abc", printToString(right_justify("abc", 3), 3));
151 EXPECT_EQ("big", printToString(right_justify("big", 1), 3));
145152 }
153
154 TEST(raw_ostreamTest, FormatHex) {
155 EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 6), 6));
156 EXPECT_EQ("0x001234", printToString(format_hex(0x1234, 8), 8));
157 EXPECT_EQ("0x00001234", printToString(format_hex(0x1234, 10), 10));
158 EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 4), 6));
159 EXPECT_EQ("0xff", printToString(format_hex(255, 4), 4));
160 EXPECT_EQ("0xFF", printToString(format_hex(255, 4, true), 4));
161 EXPECT_EQ("0x1", printToString(format_hex(1, 3), 3));
162 EXPECT_EQ("0x12", printToString(format_hex(0x12, 3), 4));
163 EXPECT_EQ("0x123", printToString(format_hex(0x123, 3), 5));
164 EXPECT_EQ("0xffffffffffffffff",
165 printToString(format_hex(UINT64_MAX, 18), 18));
166 EXPECT_EQ("0x8000000000000000",
167 printToString(format_hex((INT64_MIN), 18), 18));
168 }
169
170 TEST(raw_ostreamTest, FormatDecimal) {
171 EXPECT_EQ(" 0", printToString(format_decimal(0, 4), 4));
172 EXPECT_EQ(" -1", printToString(format_decimal(-1, 4), 4));
173 EXPECT_EQ(" -1", printToString(format_decimal(-1, 6), 6));
174 EXPECT_EQ("1234567890", printToString(format_decimal(1234567890, 10), 10));
175 EXPECT_EQ(" 9223372036854775807",
176 printToString(format_decimal(INT64_MAX, 21), 21));
177 EXPECT_EQ(" -9223372036854775808",
178 printToString(format_decimal(INT64_MIN, 21), 21));
179 }
180
181
182 }