[llvm] r218463 - [Support] Add type-safe alternative to llvm::format()
David Majnemer
david.majnemer at gmail.com
Thu Sep 25 19:58:19 PDT 2014
On Thu, Sep 25, 2014 at 1:30 PM, Nick Kledzik <kledzik at apple.com> wrote:
> Author: kledzik
> Date: Thu Sep 25 15:30:58 2014
> New Revision: 218463
>
> URL: http://llvm.org/viewvc/llvm-project?rev=218463&view=rev
> Log:
> [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 "
>
>
> Modified:
> llvm/trunk/include/llvm/Support/Format.h
> llvm/trunk/include/llvm/Support/raw_ostream.h
> llvm/trunk/lib/Support/raw_ostream.cpp
> llvm/trunk/unittests/Support/raw_ostream_test.cpp
>
> Modified: llvm/trunk/include/llvm/Support/Format.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Format.h?rev=218463&r1=218462&r2=218463&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/Format.h (original)
> +++ llvm/trunk/include/llvm/Support/Format.h Thu Sep 25 15:30:58 2014
> @@ -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,
> 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
>
> Modified: llvm/trunk/include/llvm/Support/raw_ostream.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/raw_ostream.h?rev=218463&r1=218462&r2=218463&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/raw_ostream.h (original)
> +++ llvm/trunk/include/llvm/Support/raw_ostream.h Thu Sep 25 15:30:58 2014
> @@ -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);
>
>
> Modified: llvm/trunk/lib/Support/raw_ostream.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/raw_ostream.cpp?rev=218463&r1=218462&r2=218463&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Support/raw_ostream.cpp (original)
> +++ llvm/trunk/lib/Support/raw_ostream.cpp Thu Sep 25 15:30:58 2014
> @@ -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<<(con
> }
> }
>
> +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;
>
This has undefined behavior if FN.DecValue is INT64_MIN, fixed in r218496.
> + 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[] = " "
>
> Modified: llvm/trunk/unittests/Support/raw_ostream_test.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/raw_ostream_test.cpp?rev=218463&r1=218462&r2=218463&view=diff
>
> ==============================================================================
> --- llvm/trunk/unittests/Support/raw_ostream_test.cpp (original)
> +++ llvm/trunk/unittests/Support/raw_ostream_test.cpp Thu Sep 25 15:30:58
> 2014
> @@ -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));
> +}
> +
> +
> }
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140925/fd7cdb8e/attachment.html>
More information about the llvm-commits
mailing list