<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Sep 25, 2014 at 1:30 PM, Nick Kledzik <span dir="ltr"><<a href="mailto:kledzik@apple.com" target="_blank">kledzik@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Author: kledzik<br>
Date: Thu Sep 25 15:30:58 2014<br>
New Revision: 218463<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=218463&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=218463&view=rev</a><br>
Log:<br>
[Support] Add type-safe alternative to llvm::format()<br>
<br>
llvm::format() is somewhat unsafe. The compiler does not check that integer<br>
parameter size matches the %x or %d size and it does not complain when a<br>
StringRef is passed for a %s. And correctly using a StringRef with format() is<br>
ugly because you have to convert it to a std::string then call c_str().<br>
<br>
The cases where llvm::format() is useful is controlling how numbers and<br>
strings are printed, especially when you want fixed width output. This<br>
patch adds some new formatting functions to raw_streams to format numbers<br>
and StringRefs in a type safe manner. Some examples:<br>
<br>
OS << format_hex(255, 6) => "0x00ff"<br>
OS << format_hex(255, 4) => "0xff"<br>
OS << format_decimal(0, 5) => " 0"<br>
OS << format_decimal(255, 5) => " 255"<br>
OS << right_justify(Str, 5) => " foo"<br>
OS << left_justify(Str, 5) => "foo "<br>
<br>
<br>
Modified:<br>
llvm/trunk/include/llvm/Support/Format.h<br>
llvm/trunk/include/llvm/Support/raw_ostream.h<br>
llvm/trunk/lib/Support/raw_ostream.cpp<br>
llvm/trunk/unittests/Support/raw_ostream_test.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/Support/Format.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Format.h?rev=218463&r1=218462&r2=218463&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Format.h?rev=218463&r1=218462&r2=218463&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/Format.h (original)<br>
+++ llvm/trunk/include/llvm/Support/Format.h Thu Sep 25 15:30:58 2014<br>
@@ -23,6 +23,8 @@<br>
#ifndef LLVM_SUPPORT_FORMAT_H<br>
#define LLVM_SUPPORT_FORMAT_H<br>
<br>
+#include "llvm/ADT/StringRef.h"<br>
+<br>
#include <cassert><br>
#include <cstdio><br>
#ifdef _MSC_VER<br>
@@ -225,6 +227,66 @@ format(const char *Fmt, const T1 &Val1,<br>
Val5, Val6);<br>
}<br>
<br>
+/// This is a helper class used for left_justify() and right_justify().<br>
+class FormattedString {<br>
+ StringRef Str;<br>
+ unsigned Width;<br>
+ bool RightJustify;<br>
+ friend class raw_ostream;<br>
+public:<br>
+ FormattedString(StringRef S, unsigned W, bool R)<br>
+ : Str(S), Width(W), RightJustify(R) { }<br>
+};<br>
+<br>
+/// left_justify - append spaces after string so total output is<br>
+/// \p Width characters. If \p Str is larger that \p Width, full string<br>
+/// is written with no padding.<br>
+inline FormattedString left_justify(StringRef Str, unsigned Width) {<br>
+ return FormattedString(Str, Width, false);<br>
+}<br>
+<br>
+/// right_justify - add spaces before string so total output is<br>
+/// \p Width characters. If \p Str is larger that \p Width, full string<br>
+/// is written with no padding.<br>
+inline FormattedString right_justify(StringRef Str, unsigned Width) {<br>
+ return FormattedString(Str, Width, true);<br>
+}<br>
+<br>
+/// This is a helper class used for format_hex() and format_decimal().<br>
+class FormattedNumber {<br>
+ uint64_t HexValue;<br>
+ int64_t DecValue;<br>
+ unsigned Width;<br>
+ bool Hex;<br>
+ bool Upper;<br>
+ friend class raw_ostream;<br>
+public:<br>
+ FormattedNumber(uint64_t HV, int64_t DV, unsigned W, bool H, bool U)<br>
+ : HexValue(HV), DecValue(DV), Width(W), Hex(H), Upper(U) { }<br>
+};<br>
+<br>
+/// format_hex - Output \p N as a fixed width hexadecimal. If number will not<br>
+/// fit in width, full number is still printed. Examples:<br>
+/// OS << format_hex(255, 4) => 0xff<br>
+/// OS << format_hex(255, 4, true) => 0xFF<br>
+/// OS << format_hex(255, 6) => 0x00ff<br>
+/// OS << format_hex(255, 2) => 0xff<br>
+inline FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false) {<br>
+ assert(Width <= 18 && "hex width must be <= 18");<br>
+ return FormattedNumber(N, 0, Width, true, Upper);<br>
+}<br>
+<br>
+/// format_decimal - Output \p N as a right justified, fixed-width decimal. If<br>
+/// number will not fit in width, full number is still printed. Examples:<br>
+/// OS << format_decimal(0, 5) => " 0"<br>
+/// OS << format_decimal(255, 5) => " 255"<br>
+/// OS << format_decimal(-1, 3) => " -1"<br>
+/// OS << format_decimal(12345, 3) => "12345"<br>
+inline FormattedNumber format_decimal(int64_t N, unsigned Width) {<br>
+ return FormattedNumber(0, N, Width, false, false);<br>
+}<br>
+<br>
+<br>
} // end namespace llvm<br>
<br>
#endif<br>
<br>
Modified: llvm/trunk/include/llvm/Support/raw_ostream.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/raw_ostream.h?rev=218463&r1=218462&r2=218463&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/raw_ostream.h?rev=218463&r1=218462&r2=218463&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/raw_ostream.h (original)<br>
+++ llvm/trunk/include/llvm/Support/raw_ostream.h Thu Sep 25 15:30:58 2014<br>
@@ -21,6 +21,8 @@<br>
<br>
namespace llvm {<br>
class format_object_base;<br>
+ class FormattedString;<br>
+ class FormattedNumber;<br>
template <typename T><br>
class SmallVectorImpl;<br>
<br>
@@ -211,6 +213,12 @@ public:<br>
// Formatted output, see the format() function in Support/Format.h.<br>
raw_ostream &operator<<(const format_object_base &Fmt);<br>
<br>
+ // Formatted output, see the leftJustify() function in Support/Format.h.<br>
+ raw_ostream &operator<<(const FormattedString &);<br>
+<br>
+ // Formatted output, see the formatHex() function in Support/Format.h.<br>
+ raw_ostream &operator<<(const FormattedNumber &);<br>
+<br>
/// indent - Insert 'NumSpaces' spaces.<br>
raw_ostream &indent(unsigned NumSpaces);<br>
<br>
<br>
Modified: llvm/trunk/lib/Support/raw_ostream.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/raw_ostream.cpp?rev=218463&r1=218462&r2=218463&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/raw_ostream.cpp?rev=218463&r1=218462&r2=218463&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Support/raw_ostream.cpp (original)<br>
+++ llvm/trunk/lib/Support/raw_ostream.cpp Thu Sep 25 15:30:58 2014<br>
@@ -20,6 +20,7 @@<br>
#include "llvm/Support/ErrorHandling.h"<br>
#include "llvm/Support/FileSystem.h"<br>
#include "llvm/Support/Format.h"<br>
+#include "llvm/Support/MathExtras.h"<br>
#include "llvm/Support/Process.h"<br>
#include "llvm/Support/Program.h"<br>
#include <cctype><br>
@@ -394,6 +395,62 @@ raw_ostream &raw_ostream::operator<<(con<br>
}<br>
}<br>
<br>
+raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {<br>
+ unsigned Len = FS.Str.size();<br>
+ int PadAmount = FS.Width - Len;<br>
+ if (FS.RightJustify && (PadAmount > 0))<br>
+ this->indent(PadAmount);<br>
+ this->operator<<(FS.Str);<br>
+ if (!FS.RightJustify && (PadAmount > 0))<br>
+ this->indent(PadAmount);<br>
+ return *this;<br>
+}<br>
+<br>
+raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {<br>
+ if (FN.Hex) {<br>
+ unsigned Nibbles = (64 - countLeadingZeros(FN.HexValue)+3)/4;<br>
+ unsigned Width = (FN.Width > Nibbles+2) ? FN.Width : Nibbles+2;<br>
+<br>
+ char NumberBuffer[20] = "0x0000000000000000";<br>
+ char *EndPtr = NumberBuffer+Width;<br>
+ char *CurPtr = EndPtr;<br>
+ const char A = FN.Upper ? 'A' : 'a';<br>
+ unsigned long long N = FN.HexValue;<br>
+ while (N) {<br>
+ uintptr_t x = N % 16;<br>
+ *--CurPtr = (x < 10 ? '0' + x : A + x - 10);<br>
+ N /= 16;<br>
+ }<br>
+<br>
+ return write(NumberBuffer, Width);<br>
+ } else {<br>
+ // Zero is a special case.<br>
+ if (FN.DecValue == 0) {<br>
+ this->indent(FN.Width-1);<br>
+ return *this << '0';<br>
+ }<br>
+ char NumberBuffer[32];<br>
+ char *EndPtr = NumberBuffer+sizeof(NumberBuffer);<br>
+ char *CurPtr = EndPtr;<br>
+ bool Neg = (FN.DecValue < 0);<br>
+ uint64_t N = Neg ? -FN.DecValue : FN.DecValue;<br></blockquote><div><br></div><div>This has undefined behavior if FN.DecValue is INT64_MIN, fixed in r218496.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+ while (N) {<br>
+ *--CurPtr = '0' + char(N % 10);<br>
+ N /= 10;<br>
+ }<br>
+ int Len = EndPtr - CurPtr;<br>
+ int Pad = FN.Width - Len;<br>
+ if (Neg)<br>
+ --Pad;<br>
+ if (Pad > 0)<br>
+ this->indent(Pad);<br>
+ if (Neg)<br>
+ *this << '-';<br>
+ return write(CurPtr, Len);<br>
+ }<br>
+}<br>
+<br>
+<br>
/// indent - Insert 'NumSpaces' spaces.<br>
raw_ostream &raw_ostream::indent(unsigned NumSpaces) {<br>
static const char Spaces[] = " "<br>
<br>
Modified: llvm/trunk/unittests/Support/raw_ostream_test.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/raw_ostream_test.cpp?rev=218463&r1=218462&r2=218463&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/raw_ostream_test.cpp?rev=218463&r1=218462&r2=218463&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/Support/raw_ostream_test.cpp (original)<br>
+++ llvm/trunk/unittests/Support/raw_ostream_test.cpp Thu Sep 25 15:30:58 2014<br>
@@ -143,4 +143,41 @@ TEST(raw_ostreamTest, WriteEscaped) {<br>
EXPECT_EQ("\\001\\010\\200", Str);<br>
}<br>
<br>
+TEST(raw_ostreamTest, Justify) {<br>
+ EXPECT_EQ("xyz ", printToString(left_justify("xyz", 6), 6));<br>
+ EXPECT_EQ("abc", printToString(left_justify("abc", 3), 3));<br>
+ EXPECT_EQ("big", printToString(left_justify("big", 1), 3));<br>
+ EXPECT_EQ(" xyz", printToString(right_justify("xyz", 6), 6));<br>
+ EXPECT_EQ("abc", printToString(right_justify("abc", 3), 3));<br>
+ EXPECT_EQ("big", printToString(right_justify("big", 1), 3));<br>
+}<br>
+<br>
+TEST(raw_ostreamTest, FormatHex) {<br>
+ EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 6), 6));<br>
+ EXPECT_EQ("0x001234", printToString(format_hex(0x1234, 8), 8));<br>
+ EXPECT_EQ("0x00001234", printToString(format_hex(0x1234, 10), 10));<br>
+ EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 4), 6));<br>
+ EXPECT_EQ("0xff", printToString(format_hex(255, 4), 4));<br>
+ EXPECT_EQ("0xFF", printToString(format_hex(255, 4, true), 4));<br>
+ EXPECT_EQ("0x1", printToString(format_hex(1, 3), 3));<br>
+ EXPECT_EQ("0x12", printToString(format_hex(0x12, 3), 4));<br>
+ EXPECT_EQ("0x123", printToString(format_hex(0x123, 3), 5));<br>
+ EXPECT_EQ("0xffffffffffffffff",<br>
+ printToString(format_hex(UINT64_MAX, 18), 18));<br>
+ EXPECT_EQ("0x8000000000000000",<br>
+ printToString(format_hex((INT64_MIN), 18), 18));<br>
+}<br>
+<br>
+TEST(raw_ostreamTest, FormatDecimal) {<br>
+ EXPECT_EQ(" 0", printToString(format_decimal(0, 4), 4));<br>
+ EXPECT_EQ(" -1", printToString(format_decimal(-1, 4), 4));<br>
+ EXPECT_EQ(" -1", printToString(format_decimal(-1, 6), 6));<br>
+ EXPECT_EQ("1234567890", printToString(format_decimal(1234567890, 10), 10));<br>
+ EXPECT_EQ(" 9223372036854775807",<br>
+ printToString(format_decimal(INT64_MAX, 21), 21));<br>
+ EXPECT_EQ(" -9223372036854775808",<br>
+ printToString(format_decimal(INT64_MIN, 21), 21));<br>
+}<br>
+<br>
+<br>
}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>