mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[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 " llvm-svn: 218463
This commit is contained in:
parent
ab00cb374c
commit
2ac9102fff
@ -23,6 +23,8 @@
|
||||
#ifndef LLVM_SUPPORT_FORMAT_H
|
||||
#define LLVM_SUPPORT_FORMAT_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#ifdef _MSC_VER
|
||||
@ -225,6 +227,66 @@ format(const char *Fmt, const T1 &Val1, const T2 &Val2, const T3 &Val3,
|
||||
Val5, Val6);
|
||||
}
|
||||
|
||||
/// This is a helper class used for left_justify() and right_justify().
|
||||
class FormattedString {
|
||||
StringRef Str;
|
||||
unsigned Width;
|
||||
bool RightJustify;
|
||||
friend class raw_ostream;
|
||||
public:
|
||||
FormattedString(StringRef S, unsigned W, bool R)
|
||||
: Str(S), Width(W), RightJustify(R) { }
|
||||
};
|
||||
|
||||
/// left_justify - append spaces after string so total output is
|
||||
/// \p Width characters. If \p Str is larger that \p Width, full string
|
||||
/// is written with no padding.
|
||||
inline FormattedString left_justify(StringRef Str, unsigned Width) {
|
||||
return FormattedString(Str, Width, false);
|
||||
}
|
||||
|
||||
/// right_justify - add spaces before string so total output is
|
||||
/// \p Width characters. If \p Str is larger that \p Width, full string
|
||||
/// is written with no padding.
|
||||
inline FormattedString right_justify(StringRef Str, unsigned Width) {
|
||||
return FormattedString(Str, Width, true);
|
||||
}
|
||||
|
||||
/// This is a helper class used for format_hex() and format_decimal().
|
||||
class FormattedNumber {
|
||||
uint64_t HexValue;
|
||||
int64_t DecValue;
|
||||
unsigned Width;
|
||||
bool Hex;
|
||||
bool Upper;
|
||||
friend class raw_ostream;
|
||||
public:
|
||||
FormattedNumber(uint64_t HV, int64_t DV, unsigned W, bool H, bool U)
|
||||
: HexValue(HV), DecValue(DV), Width(W), Hex(H), Upper(U) { }
|
||||
};
|
||||
|
||||
/// format_hex - Output \p N as a fixed width hexadecimal. If number will not
|
||||
/// fit in width, full number is still printed. Examples:
|
||||
/// OS << format_hex(255, 4) => 0xff
|
||||
/// OS << format_hex(255, 4, true) => 0xFF
|
||||
/// OS << format_hex(255, 6) => 0x00ff
|
||||
/// OS << format_hex(255, 2) => 0xff
|
||||
inline FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false) {
|
||||
assert(Width <= 18 && "hex width must be <= 18");
|
||||
return FormattedNumber(N, 0, Width, true, Upper);
|
||||
}
|
||||
|
||||
/// format_decimal - Output \p N as a right justified, fixed-width decimal. If
|
||||
/// number will not fit in width, full number is still printed. Examples:
|
||||
/// OS << format_decimal(0, 5) => " 0"
|
||||
/// OS << format_decimal(255, 5) => " 255"
|
||||
/// OS << format_decimal(-1, 3) => " -1"
|
||||
/// OS << format_decimal(12345, 3) => "12345"
|
||||
inline FormattedNumber format_decimal(int64_t N, unsigned Width) {
|
||||
return FormattedNumber(0, N, Width, false, false);
|
||||
}
|
||||
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
namespace llvm {
|
||||
class format_object_base;
|
||||
class FormattedString;
|
||||
class FormattedNumber;
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
|
||||
@ -211,6 +213,12 @@ public:
|
||||
// Formatted output, see the format() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const format_object_base &Fmt);
|
||||
|
||||
// Formatted output, see the leftJustify() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedString &);
|
||||
|
||||
// Formatted output, see the formatHex() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedNumber &);
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &indent(unsigned NumSpaces);
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include <cctype>
|
||||
@ -394,6 +395,62 @@ raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
|
||||
}
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
|
||||
unsigned Len = FS.Str.size();
|
||||
int PadAmount = FS.Width - Len;
|
||||
if (FS.RightJustify && (PadAmount > 0))
|
||||
this->indent(PadAmount);
|
||||
this->operator<<(FS.Str);
|
||||
if (!FS.RightJustify && (PadAmount > 0))
|
||||
this->indent(PadAmount);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
|
||||
if (FN.Hex) {
|
||||
unsigned Nibbles = (64 - countLeadingZeros(FN.HexValue)+3)/4;
|
||||
unsigned Width = (FN.Width > Nibbles+2) ? FN.Width : Nibbles+2;
|
||||
|
||||
char NumberBuffer[20] = "0x0000000000000000";
|
||||
char *EndPtr = NumberBuffer+Width;
|
||||
char *CurPtr = EndPtr;
|
||||
const char A = FN.Upper ? 'A' : 'a';
|
||||
unsigned long long N = FN.HexValue;
|
||||
while (N) {
|
||||
uintptr_t x = N % 16;
|
||||
*--CurPtr = (x < 10 ? '0' + x : A + x - 10);
|
||||
N /= 16;
|
||||
}
|
||||
|
||||
return write(NumberBuffer, Width);
|
||||
} else {
|
||||
// Zero is a special case.
|
||||
if (FN.DecValue == 0) {
|
||||
this->indent(FN.Width-1);
|
||||
return *this << '0';
|
||||
}
|
||||
char NumberBuffer[32];
|
||||
char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
|
||||
char *CurPtr = EndPtr;
|
||||
bool Neg = (FN.DecValue < 0);
|
||||
uint64_t N = Neg ? -FN.DecValue : FN.DecValue;
|
||||
while (N) {
|
||||
*--CurPtr = '0' + char(N % 10);
|
||||
N /= 10;
|
||||
}
|
||||
int Len = EndPtr - CurPtr;
|
||||
int Pad = FN.Width - Len;
|
||||
if (Neg)
|
||||
--Pad;
|
||||
if (Pad > 0)
|
||||
this->indent(Pad);
|
||||
if (Neg)
|
||||
*this << '-';
|
||||
return write(CurPtr, Len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
|
||||
static const char Spaces[] = " "
|
||||
|
@ -143,4 +143,41 @@ TEST(raw_ostreamTest, WriteEscaped) {
|
||||
EXPECT_EQ("\\001\\010\\200", Str);
|
||||
}
|
||||
|
||||
TEST(raw_ostreamTest, Justify) {
|
||||
EXPECT_EQ("xyz ", printToString(left_justify("xyz", 6), 6));
|
||||
EXPECT_EQ("abc", printToString(left_justify("abc", 3), 3));
|
||||
EXPECT_EQ("big", printToString(left_justify("big", 1), 3));
|
||||
EXPECT_EQ(" xyz", printToString(right_justify("xyz", 6), 6));
|
||||
EXPECT_EQ("abc", printToString(right_justify("abc", 3), 3));
|
||||
EXPECT_EQ("big", printToString(right_justify("big", 1), 3));
|
||||
}
|
||||
|
||||
TEST(raw_ostreamTest, FormatHex) {
|
||||
EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 6), 6));
|
||||
EXPECT_EQ("0x001234", printToString(format_hex(0x1234, 8), 8));
|
||||
EXPECT_EQ("0x00001234", printToString(format_hex(0x1234, 10), 10));
|
||||
EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 4), 6));
|
||||
EXPECT_EQ("0xff", printToString(format_hex(255, 4), 4));
|
||||
EXPECT_EQ("0xFF", printToString(format_hex(255, 4, true), 4));
|
||||
EXPECT_EQ("0x1", printToString(format_hex(1, 3), 3));
|
||||
EXPECT_EQ("0x12", printToString(format_hex(0x12, 3), 4));
|
||||
EXPECT_EQ("0x123", printToString(format_hex(0x123, 3), 5));
|
||||
EXPECT_EQ("0xffffffffffffffff",
|
||||
printToString(format_hex(UINT64_MAX, 18), 18));
|
||||
EXPECT_EQ("0x8000000000000000",
|
||||
printToString(format_hex((INT64_MIN), 18), 18));
|
||||
}
|
||||
|
||||
TEST(raw_ostreamTest, FormatDecimal) {
|
||||
EXPECT_EQ(" 0", printToString(format_decimal(0, 4), 4));
|
||||
EXPECT_EQ(" -1", printToString(format_decimal(-1, 4), 4));
|
||||
EXPECT_EQ(" -1", printToString(format_decimal(-1, 6), 6));
|
||||
EXPECT_EQ("1234567890", printToString(format_decimal(1234567890, 10), 10));
|
||||
EXPECT_EQ(" 9223372036854775807",
|
||||
printToString(format_decimal(INT64_MAX, 21), 21));
|
||||
EXPECT_EQ(" -9223372036854775808",
|
||||
printToString(format_decimal(INT64_MIN, 21), 21));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user