[llvm] r284436 - Resubmit "Add support for advanced number formatting."

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 17 15:49:25 PDT 2016


Author: zturner
Date: Mon Oct 17 17:49:24 2016
New Revision: 284436

URL: http://llvm.org/viewvc/llvm-project?rev=284436&view=rev
Log:
Resubmit "Add support for advanced number formatting."

This resubmits commits 284425 and r284428, which were reverted
in r284429 due to some infinite recursion caused by an incorrect
selection of function overloads.  Reproduced the failure on Linux
using GCC 4.8.4, and confirmed that with the new patch the tests
path on GCC as well as MSVC.  So hopefully this fixes everything.

Added:
    llvm/trunk/unittests/Support/NativeFormatTests.cpp
Modified:
    llvm/trunk/include/llvm/Support/NativeFormatting.h
    llvm/trunk/lib/Support/NativeFormatting.cpp
    llvm/trunk/lib/Support/raw_ostream.cpp
    llvm/trunk/unittests/Support/CMakeLists.txt

Modified: llvm/trunk/include/llvm/Support/NativeFormatting.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/NativeFormatting.h?rev=284436&r1=284435&r2=284436&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/NativeFormatting.h (original)
+++ llvm/trunk/include/llvm/Support/NativeFormatting.h Mon Oct 17 17:49:24 2016
@@ -10,22 +10,57 @@
 #ifndef LLVM_SUPPORT_NATIVE_FORMATTING_H
 #define LLVM_SUPPORT_NATIVE_FORMATTING_H
 
+#include "llvm/ADT/Optional.h"
 #include "llvm/Support/raw_ostream.h"
 
 #include <cstdint>
 
 namespace llvm {
-enum class FloatStyle { Exponent, Decimal };
+enum class FloatStyle { Exponent, ExponentUpper, Fixed, Percent };
+enum class IntegerStyle {
+  Exponent,
+  ExponentUpper,
+  Integer,
+  Fixed,
+  Number,
+  Percent,
+  HexUpperPrefix,
+  HexUpperNoPrefix,
+  HexLowerPrefix,
+  HexLowerNoPrefix
+};
+enum class HexStyle { Upper, Lower, PrefixUpper, PrefixLower };
 
-void write_ulong(raw_ostream &S, unsigned long N, std::size_t MinWidth);
-void write_long(raw_ostream &S, long N, std::size_t MinWidth);
-void write_ulonglong(raw_ostream &S, unsigned long long N,
-                     std::size_t MinWidth);
-void write_longlong(raw_ostream &S, long long N, std::size_t MinWidth);
-void write_hex(raw_ostream &S, unsigned long long N, std::size_t MinWidth,
-               bool Upper, bool Prefix);
-void write_double(raw_ostream &S, double D, std::size_t MinWidth,
-                  std::size_t MinDecimals, FloatStyle Style);
+IntegerStyle hexStyleToIntHexStyle(HexStyle S);
+
+size_t getDefaultPrecision(FloatStyle Style);
+size_t getDefaultPrecision(IntegerStyle Style);
+size_t getDefaultPrecision(HexStyle Style);
+
+void write_integer(raw_ostream &S, unsigned int N, IntegerStyle Style,
+                   Optional<size_t> Precision = None,
+                   Optional<int> Width = None);
+void write_integer(raw_ostream &S, int N, IntegerStyle Style,
+                   Optional<size_t> Precision = None,
+                   Optional<int> Width = None);
+void write_integer(raw_ostream &S, unsigned long N, IntegerStyle Style,
+                   Optional<size_t> Precision = None,
+                   Optional<int> Width = None);
+void write_integer(raw_ostream &S, long N, IntegerStyle Style,
+                   Optional<size_t> Precision = None,
+                   Optional<int> Width = None);
+void write_integer(raw_ostream &S, unsigned long long N, IntegerStyle Style,
+                   Optional<size_t> Precision = None,
+                   Optional<int> Width = None);
+void write_integer(raw_ostream &S, long long N, IntegerStyle Style,
+                   Optional<size_t> Precision = None,
+                   Optional<int> Width = None);
+
+void write_hex(raw_ostream &S, uint64_t N, HexStyle Style,
+               Optional<size_t> Precision = None, Optional<int> Width = None);
+void write_double(raw_ostream &S, double D, FloatStyle Style,
+                  Optional<size_t> Precision = None,
+                  Optional<int> Width = None);
 }
 
 #endif
\ No newline at end of file

Modified: llvm/trunk/lib/Support/NativeFormatting.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/NativeFormatting.cpp?rev=284436&r1=284435&r2=284436&view=diff
==============================================================================
--- llvm/trunk/lib/Support/NativeFormatting.cpp (original)
+++ llvm/trunk/lib/Support/NativeFormatting.cpp Mon Oct 17 17:49:24 2016
@@ -9,107 +9,251 @@
 
 #include "llvm/Support/NativeFormatting.h"
 
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Format.h"
 
 using namespace llvm;
 
+static bool isHexStyle(IntegerStyle S) {
+  switch (S) {
+  case IntegerStyle::HexLowerNoPrefix:
+  case IntegerStyle::HexLowerPrefix:
+  case IntegerStyle::HexUpperNoPrefix:
+  case IntegerStyle::HexUpperPrefix:
+    return true;
+  default:
+    return false;
+  }
+  LLVM_BUILTIN_UNREACHABLE;
+}
+
+static HexStyle intHexStyleToHexStyle(IntegerStyle S) {
+  assert(isHexStyle(S));
+  switch (S) {
+  case IntegerStyle::HexLowerNoPrefix:
+    return HexStyle::Lower;
+  case IntegerStyle::HexLowerPrefix:
+    return HexStyle::PrefixLower;
+  case IntegerStyle::HexUpperNoPrefix:
+    return HexStyle::Upper;
+  case IntegerStyle::HexUpperPrefix:
+    return HexStyle::PrefixUpper;
+  default:
+    break;
+  }
+  LLVM_BUILTIN_UNREACHABLE;
+}
+
+static void writePadding(raw_ostream &S, Optional<int> FieldWidth,
+                         size_t Chars) {
+  if (!FieldWidth.hasValue())
+    return;
+
+  int Pad = *FieldWidth - Chars;
+  if (Pad > 0)
+    S.indent(Pad);
+}
+
 template<typename T, std::size_t N>
 static int format_to_buffer(T Value, char (&Buffer)[N]) {
   char *EndPtr = std::end(Buffer);
   char *CurPtr = EndPtr;
 
-  while (Value) {
+  do {
     *--CurPtr = '0' + char(Value % 10);
     Value /= 10;
-  }
+  } while (Value);
   return EndPtr - CurPtr;
 }
 
-void llvm::write_ulong(raw_ostream &S, unsigned long N, std::size_t MinWidth) {
-  // Zero is a special case.
-  if (N == 0) {
-    if (MinWidth > 0)
-      S.indent(MinWidth - 1);
-    S << '0';
-    return;
-  }
+static void repeat_char(raw_ostream &S, char C, size_t Times) {
+  for (size_t I = 0; I < Times; ++I)
+    S << C;
+}
 
-  char NumberBuffer[20];
-  int Len = format_to_buffer(N, NumberBuffer);
-  int Pad = (MinWidth == 0) ? 0 : MinWidth - Len;
-  if (Pad > 0)
-    S.indent(Pad);
-  S.write(std::end(NumberBuffer) - Len, Len);
+static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
+  assert(!Buffer.empty());
+
+  ArrayRef<char> ThisGroup;
+  int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
+  ThisGroup = Buffer.take_front(InitialDigits);
+  S.write(ThisGroup.data(), ThisGroup.size());
+
+  Buffer = Buffer.drop_front(InitialDigits);
+  assert(Buffer.size() % 3 == 0);
+  while (!Buffer.empty()) {
+    S << ',';
+    ThisGroup = Buffer.take_front(3);
+    S.write(ThisGroup.data(), 3);
+    Buffer = Buffer.drop_front(3);
+  }
 }
 
-void llvm::write_long(raw_ostream &S, long N, std::size_t MinWidth) {
-  if (N >= 0) {
-    write_ulong(S, static_cast<unsigned long>(N), MinWidth);
+template <typename T>
+static void write_unsigned_impl(raw_ostream &S, T N, IntegerStyle Style,
+                                Optional<size_t> Precision, Optional<int> Width,
+                                bool IsNegative) {
+  static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
+
+  if (Style == IntegerStyle::Exponent) {
+    write_double(S, static_cast<double>(N), FloatStyle::Exponent, Precision,
+                 Width);
+    return;
+  } else if (Style == IntegerStyle::ExponentUpper) {
+    write_double(S, static_cast<double>(N), FloatStyle::ExponentUpper,
+                 Precision, Width);
     return;
+  } else if (isHexStyle(Style)) {
+    write_hex(S, N, intHexStyleToHexStyle(Style), Precision, Width);
+    return;
+  }
+
+  size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
+  char NumberBuffer[128];
+  std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
+
+  size_t Len = 0;
+  Len = format_to_buffer(N, NumberBuffer);
+
+  bool WriteDecimal =
+      ((Style == IntegerStyle::Fixed || Style == IntegerStyle::Percent) &&
+       Prec > 0);
+
+  size_t LeadingZeros = 0;
+  if ((Style == IntegerStyle::Integer || Style == IntegerStyle::Number) &&
+      Prec > 0) {
+    if (Prec > Len)
+      LeadingZeros = Prec - Len;
   }
 
-  unsigned long UN = -(unsigned long)N;
-  if (MinWidth > 0)
-    --MinWidth;
+  Len += LeadingZeros;
 
-  char NumberBuffer[20];
-  int Len = format_to_buffer(UN, NumberBuffer);
-  int Pad = (MinWidth == 0) ? 0 : MinWidth - Len;
-  if (Pad > 0)
-    S.indent(Pad);
-  S.write('-');
-  S.write(std::end(NumberBuffer) - Len, Len);
-}
+  // One for the decimal sign, one for each point of precision.
+  size_t DecimalChars = WriteDecimal ? 1 + Prec : 0;
 
-void llvm::write_ulonglong(raw_ostream &S, unsigned long long N,
-                           std::size_t MinWidth) {
-  // Output using 32-bit div/mod when possible.
-  if (N == static_cast<unsigned long>(N)) {
-    write_ulong(S, static_cast<unsigned long>(N), MinWidth);
-    return;
+  // One character for the negative sign.
+  size_t Neg = (IsNegative) ? 1 : 0;
+
+  // One comma for each group of 3 digits.
+  size_t Commas = (Style != IntegerStyle::Number) ? 0 : (Len - 1) / 3;
+
+  size_t PercentChars = 0;
+  if (Style == IntegerStyle::Percent) {
+    // For all numbers except 0, we append two additional 0s.
+    PercentChars = (N == 0) ? 1 : 3;
   }
 
-  char NumberBuffer[32];
-  int Len = format_to_buffer(N, NumberBuffer);
-  int Pad = (MinWidth == 0) ? 0 : MinWidth - Len;
-  if (Pad > 0)
-    S.indent(Pad);
-  S.write(std::end(NumberBuffer) - Len, Len);
+  writePadding(S, Width, Len + DecimalChars + Neg + Commas + PercentChars);
+
+  if (IsNegative)
+    S << '-';
+  if (Style == IntegerStyle::Number) {
+    writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
+  } else {
+    S.write(std::end(NumberBuffer) - Len, Len);
+    if (Style == IntegerStyle::Percent && N != 0) {
+      // Rather than multiply by 100, write the characters manually, in case the
+      // multiplication would overflow.
+      S << "00";
+    }
+  }
+
+  if (WriteDecimal) {
+    S << '.';
+    repeat_char(S, '0', Prec);
+  }
+  if (Style == IntegerStyle::Percent)
+    S << '%';
 }
 
-void llvm::write_longlong(raw_ostream &S, long long N, std::size_t MinWidth) {
+template <typename T>
+static void write_unsigned(raw_ostream &S, T N, IntegerStyle Style,
+                           Optional<size_t> Precision, Optional<int> Width,
+                           bool IsNegative = false) {
+  // Output using 32-bit div/mod if possible.
+  if (N == static_cast<uint32_t>(N))
+    write_unsigned_impl(S, static_cast<uint32_t>(N), Style, Precision, Width,
+                        IsNegative);
+  else
+    write_unsigned_impl(S, N, Style, Precision, Width, IsNegative);
+}
+
+template <typename T>
+static void write_signed(raw_ostream &S, T N, IntegerStyle Style,
+                         Optional<size_t> Precision, Optional<int> Width) {
+  static_assert(std::is_signed<T>::value, "Value is not signed!");
+
+  using UnsignedT = typename std::make_unsigned<T>::type;
+
   if (N >= 0) {
-    write_ulonglong(S, static_cast<unsigned long long>(N), MinWidth);
+    write_unsigned(S, static_cast<UnsignedT>(N), Style, Precision, Width);
     return;
   }
 
-  // Avoid undefined behavior on INT64_MIN with a cast.
-  unsigned long long UN = -(unsigned long long)N;
-  if (MinWidth > 0)
-    --MinWidth;
+  UnsignedT UN = -(UnsignedT)N;
+  if (isHexStyle(Style)) {
+    static_assert(sizeof(UnsignedT) == sizeof(T),
+                  "Types do not have the same size!");
+    std::memcpy(&UN, &N, sizeof(N));
+    write_hex(S, UN, intHexStyleToHexStyle(Style), Precision, Width);
+    return;
+  }
+  write_unsigned(S, UN, Style, Precision, Width, true);
+}
 
-  char NumberBuffer[32];
-  int Len = format_to_buffer(UN, NumberBuffer);
-  int Pad = (MinWidth == 0) ? 0 : MinWidth - Len;
-  if (Pad > 0)
-    S.indent(Pad);
-  S.write('-');
-  S.write(std::end(NumberBuffer) - Len, Len);
+void llvm::write_integer(raw_ostream &S, unsigned int N, IntegerStyle Style,
+                         Optional<size_t> Precision, Optional<int> Width) {
+  write_unsigned(S, N, Style, Precision, Width);
+}
+
+void llvm::write_integer(raw_ostream &S, int N, IntegerStyle Style,
+                         Optional<size_t> Precision, Optional<int> Width) {
+  write_signed(S, N, Style, Precision, Width);
+}
+
+void llvm::write_integer(raw_ostream &S, unsigned long N, IntegerStyle Style,
+                         Optional<size_t> Precision, Optional<int> Width) {
+  write_unsigned(S, N, Style, Precision, Width);
+}
+
+void llvm::write_integer(raw_ostream &S, long N, IntegerStyle Style,
+                         Optional<size_t> Precision, Optional<int> Width) {
+  write_signed(S, N, Style, Precision, Width);
+}
+
+void llvm::write_integer(raw_ostream &S, unsigned long long N,
+                         IntegerStyle Style, Optional<size_t> Precision,
+                         Optional<int> Width) {
+  write_unsigned(S, N, Style, Precision, Width);
+}
+
+void llvm::write_integer(raw_ostream &S, long long N, IntegerStyle Style,
+                         Optional<size_t> Precision, Optional<int> Width) {
+  write_signed(S, N, Style, Precision, Width);
 }
 
-void llvm::write_hex(raw_ostream &S, unsigned long long N, std::size_t MinWidth,
-                     bool Upper, bool Prefix) {
+void llvm::write_hex(raw_ostream &S, uint64_t N, HexStyle Style,
+                     Optional<size_t> Precision, Optional<int> Width) {
+  constexpr size_t kMaxWidth = 128u;
+
+  size_t Prec =
+      std::min(kMaxWidth, Precision.getValueOr(getDefaultPrecision(Style)));
+
   unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
+  bool Prefix =
+      (Style == HexStyle::PrefixLower || Style == HexStyle::PrefixUpper);
+  bool Upper = (Style == HexStyle::Upper || Style == HexStyle::PrefixUpper);
   unsigned PrefixChars = Prefix ? 2 : 0;
-  unsigned Width = std::max(static_cast<unsigned>(MinWidth),
-                            std::max(1u, Nibbles) + PrefixChars);
+  unsigned NumChars = std::max(static_cast<unsigned>(Prec),
+                               std::max(1u, Nibbles) + PrefixChars);
 
-  char NumberBuffer[20] = "0x0000000000000000";
-  if (!Prefix)
-    NumberBuffer[1] = '0';
-  char *EndPtr = NumberBuffer + Width;
+  char NumberBuffer[kMaxWidth];
+  ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
+  if (Prefix)
+    NumberBuffer[1] = 'x';
+  char *EndPtr = NumberBuffer + NumChars;
   char *CurPtr = EndPtr;
   while (N) {
     unsigned char x = static_cast<unsigned char>(N) % 16;
@@ -117,22 +261,37 @@ void llvm::write_hex(raw_ostream &S, uns
     N /= 16;
   }
 
-  S.write(NumberBuffer, Width);
+  writePadding(S, Width, NumChars);
+  S.write(NumberBuffer, NumChars);
 }
 
-void llvm::write_double(raw_ostream &S, double N, std::size_t MinWidth,
-                        std::size_t MinDecimals, FloatStyle Style) {
-  char Letter = (Style == FloatStyle::Exponent) ? 'e' : 'f';
+void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
+                        Optional<size_t> Precision, Optional<int> Width) {
+  size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
+
+  if (std::isnan(N)) {
+    writePadding(S, Width, 3);
+    S << "nan";
+    return;
+  } else if (std::isinf(N)) {
+    writePadding(S, Width, 3);
+    S << "INF";
+    return;
+  }
+
+  char Letter;
+  if (Style == FloatStyle::Exponent)
+    Letter = 'e';
+  else if (Style == FloatStyle::ExponentUpper)
+    Letter = 'E';
+  else
+    Letter = 'f';
+
   SmallString<8> Spec;
   llvm::raw_svector_ostream Out(Spec);
-  Out << '%';
-  if (MinWidth > 0)
-    Out << MinWidth;
-  if (MinDecimals > 0)
-    Out << '.' << MinDecimals;
-  Out << Letter;
+  Out << "%." << Prec << Letter;
 
-  if (Style == FloatStyle::Exponent) {
+  if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
 #ifdef _WIN32
 // On MSVCRT and compatible, output of %e is incompatible to Posix
 // by default. Number of exponent digits should be at least 2. "%+03d"
@@ -140,7 +299,9 @@ void llvm::write_double(raw_ostream &S,
 #if defined(__MINGW32__)
     // FIXME: It should be generic to C++11.
     if (N == 0.0 && std::signbit(N)) {
-      S << "-0.000000e+00";
+      const char *NegativeZero = "-0.000000e+00";
+      writePadding(S, Width, strlen(NegativeZero));
+      S << NegativeZero;
       return;
     }
 #else
@@ -148,16 +309,19 @@ void llvm::write_double(raw_ostream &S,
 
     // negative zero
     if (fpcl == _FPCLASS_NZ) {
-      S << "-0.000000e+00";
+      const char *NegativeZero = "-0.000000e+00";
+      writePadding(S, Width, strlen(NegativeZero));
+      S << NegativeZero;
       return;
     }
 #endif
 
-    char buf[16];
+    char buf[32];
     unsigned len;
     len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
     if (len <= sizeof(buf) - 2) {
-      if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') {
+      if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
+          buf[len - 3] == '0') {
         int cs = buf[len - 4];
         if (cs == '+' || cs == '-') {
           int c1 = buf[len - 2];
@@ -171,11 +335,75 @@ void llvm::write_double(raw_ostream &S,
           }
         }
       }
+      writePadding(S, Width, len);
       S << buf;
       return;
     }
 #endif
   }
 
-  S << format(Spec.c_str(), N);
+  if (Style == FloatStyle::Percent)
+    N *= 100.0;
+
+  char Buf[32];
+  unsigned Len;
+  Len = format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
+  if (Style == FloatStyle::Percent)
+    ++Len;
+  writePadding(S, Width, Len);
+  S << Buf;
+  if (Style == FloatStyle::Percent)
+    S << '%';
+}
+
+IntegerStyle llvm::hexStyleToIntHexStyle(HexStyle S) {
+  switch (S) {
+  case HexStyle::Upper:
+    return IntegerStyle::HexUpperNoPrefix;
+  case HexStyle::Lower:
+    return IntegerStyle::HexLowerNoPrefix;
+  case HexStyle::PrefixUpper:
+    return IntegerStyle::HexUpperPrefix;
+  case HexStyle::PrefixLower:
+    return IntegerStyle::HexLowerPrefix;
+  }
+  LLVM_BUILTIN_UNREACHABLE;
+}
+
+size_t llvm::getDefaultPrecision(FloatStyle Style) {
+  switch (Style) {
+  case FloatStyle::Exponent:
+  case FloatStyle::ExponentUpper:
+    return 6; // Number of decimal places.
+  case FloatStyle::Fixed:
+  case FloatStyle::Percent:
+    return 2; // Number of decimal places.
+  }
+  LLVM_BUILTIN_UNREACHABLE;
+}
+
+size_t llvm::getDefaultPrecision(IntegerStyle Style) {
+  switch (Style) {
+  case IntegerStyle::Exponent:
+  case IntegerStyle::ExponentUpper:
+    return 6; // Number of decimal places.
+  case IntegerStyle::Number:
+  case IntegerStyle::Integer:
+    return 0; // Minimum number of digits required.
+  case IntegerStyle::Fixed:
+    return 2; // Number of decimal places.
+  case IntegerStyle::Percent:
+    return 0; // Number of decimal places.
+  case IntegerStyle::HexLowerNoPrefix:
+  case IntegerStyle::HexLowerPrefix:
+  case IntegerStyle::HexUpperNoPrefix:
+  case IntegerStyle::HexUpperPrefix:
+    return getDefaultPrecision(intHexStyleToHexStyle(Style));
+  }
+  LLVM_BUILTIN_UNREACHABLE;
+}
+
+size_t llvm::getDefaultPrecision(HexStyle) {
+  // Number of digits in the resulting string.
+  return 0;
 }

Modified: llvm/trunk/lib/Support/raw_ostream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/raw_ostream.cpp?rev=284436&r1=284435&r2=284436&view=diff
==============================================================================
--- llvm/trunk/lib/Support/raw_ostream.cpp (original)
+++ llvm/trunk/lib/Support/raw_ostream.cpp Mon Oct 17 17:49:24 2016
@@ -114,27 +114,27 @@ void raw_ostream::SetBufferAndMode(char
 }
 
 raw_ostream &raw_ostream::operator<<(unsigned long N) {
-  write_ulong(*this, N, 0);
+  write_integer(*this, static_cast<uint64_t>(N), IntegerStyle::Integer);
   return *this;
 }
 
 raw_ostream &raw_ostream::operator<<(long N) {
-  write_long(*this, N, 0);
+  write_integer(*this, static_cast<int64_t>(N), IntegerStyle::Integer);
   return *this;
 }
 
 raw_ostream &raw_ostream::operator<<(unsigned long long N) {
-  write_ulonglong(*this, N, 0);
+  write_integer(*this, static_cast<uint64_t>(N), IntegerStyle::Integer);
   return *this;
 }
 
 raw_ostream &raw_ostream::operator<<(long long N) {
-  write_longlong(*this, N, 0);
+  write_integer(*this, static_cast<int64_t>(N), IntegerStyle::Integer);
   return *this;
 }
 
 raw_ostream &raw_ostream::write_hex(unsigned long long N) {
-  llvm::write_hex(*this, N, 0, false, false);
+  llvm::write_hex(*this, N, HexStyle::Lower);
   return *this;
 }
 
@@ -179,12 +179,12 @@ raw_ostream &raw_ostream::write_escaped(
 }
 
 raw_ostream &raw_ostream::operator<<(const void *P) {
-  llvm::write_hex(*this, (uintptr_t)P, 0, false, true);
+  llvm::write_hex(*this, (uintptr_t)P, HexStyle::PrefixLower);
   return *this;
 }
 
 raw_ostream &raw_ostream::operator<<(double N) {
-  llvm::write_double(*this, N, 0, 0, FloatStyle::Exponent);
+  llvm::write_double(*this, N, FloatStyle::Exponent);
   return *this;
 }
 
@@ -331,9 +331,19 @@ raw_ostream &raw_ostream::operator<<(con
 
 raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
   if (FN.Hex) {
-    llvm::write_hex(*this, FN.HexValue, FN.Width, FN.Upper, FN.HexPrefix);
+    HexStyle Style;
+    if (FN.Upper && FN.HexPrefix)
+      Style = HexStyle::PrefixUpper;
+    else if (FN.Upper && !FN.HexPrefix)
+      Style = HexStyle::Upper;
+    else if (!FN.Upper && FN.HexPrefix)
+      Style = HexStyle::PrefixLower;
+    else
+      Style = HexStyle::Lower;
+    llvm::write_hex(*this, FN.HexValue, Style, FN.Width, None);
   } else {
-    llvm::write_longlong(*this, FN.DecValue, FN.Width);
+    llvm::write_integer(*this, FN.DecValue, IntegerStyle::Integer, None,
+                        FN.Width);
   }
   return *this;
 }

Modified: llvm/trunk/unittests/Support/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/CMakeLists.txt?rev=284436&r1=284435&r2=284436&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/CMakeLists.txt (original)
+++ llvm/trunk/unittests/Support/CMakeLists.txt Mon Oct 17 17:49:24 2016
@@ -28,6 +28,7 @@ add_llvm_unittest(SupportTests
   MathExtrasTest.cpp
   MemoryBufferTest.cpp
   MemoryTest.cpp
+  NativeFormatTests.cpp
   Path.cpp
   ProcessTest.cpp
   ProgramTest.cpp

Added: llvm/trunk/unittests/Support/NativeFormatTests.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/NativeFormatTests.cpp?rev=284436&view=auto
==============================================================================
--- llvm/trunk/unittests/Support/NativeFormatTests.cpp (added)
+++ llvm/trunk/unittests/Support/NativeFormatTests.cpp Mon Oct 17 17:49:24 2016
@@ -0,0 +1,343 @@
+//===- llvm/unittest/Support/NativeFormatTests.cpp - formatting tests -----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/NativeFormatting.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+#include <type_traits>
+
+using namespace llvm;
+
+namespace {
+
+template <typename T>
+std::string format_number(T N, IntegerStyle Style,
+                          Optional<size_t> Precision = None,
+                          Optional<int> Width = None) {
+  std::string S;
+  llvm::raw_string_ostream Str(S);
+  write_integer(Str, N, Style, Precision, Width);
+  Str.flush();
+  return S;
+}
+
+template <typename T>
+typename std::enable_if<std::is_pointer<T>::value, std::string>::type
+format_number(T N, HexStyle Style, Optional<size_t> Precision = None,
+              Optional<int> Width = None) {
+  IntegerStyle IS = hexStyleToIntHexStyle(Style);
+  return format_number(reinterpret_cast<uintptr_t>(N), IS, Precision, Width);
+}
+
+std::string format_number(uint64_t N, HexStyle Style,
+                          Optional<size_t> Precision = None,
+                          Optional<int> Width = None) {
+  std::string S;
+  llvm::raw_string_ostream Str(S);
+  write_hex(Str, N, Style, Precision, Width);
+  Str.flush();
+  return S;
+}
+
+std::string format_number(double D, FloatStyle Style,
+                          Optional<size_t> Precision = None,
+                          Optional<int> Width = None) {
+  std::string S;
+  llvm::raw_string_ostream Str(S);
+  write_double(Str, D, Style, Precision, Width);
+  Str.flush();
+  return S;
+}
+
+// Test basic number formatting with various styles and default width and
+// precision.
+TEST(NativeFormatTest, BasicIntegerTests) {
+  // Simple fixed point integers.  Default precision is 2.
+  EXPECT_EQ("0.00", format_number(0, IntegerStyle::Fixed));
+  EXPECT_EQ("2425.00", format_number(2425, IntegerStyle::Fixed));
+  EXPECT_EQ("-2425.00", format_number(-2425, IntegerStyle::Fixed));
+
+  EXPECT_EQ("0.00", format_number(0LL, IntegerStyle::Fixed));
+  EXPECT_EQ("257257257235709.00",
+            format_number(257257257235709LL, IntegerStyle::Fixed));
+  EXPECT_EQ("-257257257235709.00",
+            format_number(-257257257235709LL, IntegerStyle::Fixed));
+
+  // Simple integers with no decimal.  Default precision is 0.
+  EXPECT_EQ("0", format_number(0, IntegerStyle::Integer));
+  EXPECT_EQ("2425", format_number(2425, IntegerStyle::Integer));
+  EXPECT_EQ("-2425", format_number(-2425, IntegerStyle::Integer));
+
+  EXPECT_EQ("0", format_number(0LL, IntegerStyle::Integer));
+  EXPECT_EQ("257257257235709",
+            format_number(257257257235709LL, IntegerStyle::Integer));
+  EXPECT_EQ("-257257257235709",
+            format_number(-257257257235709LL, IntegerStyle::Integer));
+
+  // Exponent based integers.  Default precision is 6.
+  EXPECT_EQ("3.700000e+01", format_number(37, IntegerStyle::Exponent));
+  EXPECT_EQ("4.238000e+03", format_number(4238, IntegerStyle::Exponent));
+  EXPECT_EQ("3.700000E+01", format_number(37, IntegerStyle::ExponentUpper));
+  EXPECT_EQ("4.238000E+03", format_number(4238, IntegerStyle::ExponentUpper));
+
+  // Number formatting.  Default precision is 0.
+  EXPECT_EQ("0", format_number(0, IntegerStyle::Number));
+  EXPECT_EQ("2,425", format_number(2425, IntegerStyle::Number));
+  EXPECT_EQ("-2,425", format_number(-2425, IntegerStyle::Number));
+  EXPECT_EQ("257,257,257,235,709",
+            format_number(257257257235709LL, IntegerStyle::Number));
+  EXPECT_EQ("-257,257,257,235,709",
+            format_number(-257257257235709LL, IntegerStyle::Number));
+
+  // Percent formatting.  Default precision is 0.
+  EXPECT_EQ("0%", format_number(0, IntegerStyle::Percent));
+  EXPECT_EQ("100%", format_number(1, IntegerStyle::Percent));
+  EXPECT_EQ("-100%", format_number(-1, IntegerStyle::Percent));
+
+  // Hex formatting.  Default precision is 0.
+  // lower case, prefix.
+  EXPECT_EQ("0x0", format_number(0, HexStyle::PrefixLower));
+  EXPECT_EQ("0xbeef", format_number(0xbeefLL, HexStyle::PrefixLower));
+  EXPECT_EQ("0xdeadbeef", format_number(0xdeadbeefLL, HexStyle::PrefixLower));
+
+  // upper-case, prefix.
+  EXPECT_EQ("0x0", format_number(0, HexStyle::PrefixUpper));
+  EXPECT_EQ("0xBEEF", format_number(0xbeefLL, HexStyle::PrefixUpper));
+  EXPECT_EQ("0xDEADBEEF", format_number(0xdeadbeefLL, HexStyle::PrefixUpper));
+
+  // lower-case, no prefix
+  EXPECT_EQ("0", format_number(0, HexStyle::Lower));
+  EXPECT_EQ("beef", format_number(0xbeefLL, HexStyle::Lower));
+  EXPECT_EQ("deadbeef", format_number(0xdeadbeefLL, HexStyle::Lower));
+
+  // upper-case, no prefix.
+  EXPECT_EQ("0", format_number(0, HexStyle::Upper));
+  EXPECT_EQ("BEEF", format_number(0xbeef, HexStyle::Upper));
+  EXPECT_EQ("DEADBEEF", format_number(0xdeadbeef, HexStyle::Upper));
+
+  EXPECT_EQ("0xFFFFFFFF", format_number(-1, IntegerStyle::HexUpperPrefix));
+}
+
+// Test pointer type formatting with various styles and default width and
+// precision.
+TEST(NativeFormatTest, BasicPointerTests) {
+  // lower-case, prefix
+  EXPECT_EQ("0x0", format_number((void *)nullptr, HexStyle::PrefixLower));
+  EXPECT_EQ("0xbeef", format_number((void *)0xbeefLL, HexStyle::PrefixLower));
+  EXPECT_EQ("0xdeadbeef",
+            format_number((void *)0xdeadbeefLL, HexStyle::PrefixLower));
+
+  // upper-case, prefix.
+  EXPECT_EQ("0x0", format_number((void *)nullptr, HexStyle::PrefixUpper));
+  EXPECT_EQ("0xBEEF", format_number((void *)0xbeefLL, HexStyle::PrefixUpper));
+  EXPECT_EQ("0xDEADBEEF",
+            format_number((void *)0xdeadbeefLL, HexStyle::PrefixUpper));
+
+  // lower-case, no prefix
+  EXPECT_EQ("0", format_number((void *)nullptr, HexStyle::Lower));
+  EXPECT_EQ("beef", format_number((void *)0xbeefLL, HexStyle::Lower));
+  EXPECT_EQ("deadbeef", format_number((void *)0xdeadbeefLL, HexStyle::Lower));
+
+  // upper-case, no prefix.
+  EXPECT_EQ("0", format_number((void *)nullptr, HexStyle::Upper));
+  EXPECT_EQ("BEEF", format_number((void *)0xbeefLL, HexStyle::Upper));
+  EXPECT_EQ("DEADBEEF", format_number((void *)0xdeadbeefLL, HexStyle::Upper));
+}
+
+// Test basic floating point formatting with various styles and default width
+// and precision.
+TEST(NativeFormatTest, BasicFloatingPointTests) {
+  // Double
+  EXPECT_EQ("0.000000e+00", format_number(0.0, FloatStyle::Exponent));
+  EXPECT_EQ("-0.000000e+00", format_number(-0.0, FloatStyle::Exponent));
+  EXPECT_EQ("1.100000e+00", format_number(1.1, FloatStyle::Exponent));
+  EXPECT_EQ("1.100000E+00", format_number(1.1, FloatStyle::ExponentUpper));
+
+  // Default precision is 2 for floating points.
+  EXPECT_EQ("1.10", format_number(1.1, FloatStyle::Fixed));
+  EXPECT_EQ("1.34", format_number(1.34, FloatStyle::Fixed));
+  EXPECT_EQ("1.34", format_number(1.344, FloatStyle::Fixed));
+  EXPECT_EQ("1.35", format_number(1.346, FloatStyle::Fixed));
+}
+
+// Test common boundary cases and min/max conditions.
+TEST(NativeFormatTest, BoundaryTests) {
+  // Min and max.
+  EXPECT_EQ("18446744073709551615",
+            format_number(UINT64_MAX, IntegerStyle::Integer));
+
+  EXPECT_EQ("9223372036854775807",
+            format_number(INT64_MAX, IntegerStyle::Integer));
+  EXPECT_EQ("-9223372036854775808",
+            format_number(INT64_MIN, IntegerStyle::Integer));
+
+  EXPECT_EQ("4294967295", format_number(UINT32_MAX, IntegerStyle::Integer));
+  EXPECT_EQ("2147483647", format_number(INT32_MAX, IntegerStyle::Integer));
+  EXPECT_EQ("-2147483648", format_number(INT32_MIN, IntegerStyle::Integer));
+
+  EXPECT_EQ("nan", format_number(std::numeric_limits<double>::quiet_NaN(),
+                                 FloatStyle::Fixed));
+  EXPECT_EQ("INF", format_number(std::numeric_limits<double>::infinity(),
+                                 FloatStyle::Fixed));
+}
+
+TEST(NativeFormatTest, HexTests) {
+  // Test hex formatting with different widths and precisions.
+
+  // Precision less than the value should print the full value anyway.
+  EXPECT_EQ("0x0", format_number(0, IntegerStyle::HexLowerPrefix, 0));
+  EXPECT_EQ("0xabcde", format_number(0xABCDE, IntegerStyle::HexLowerPrefix, 3));
+
+  // Precision greater than the value should pad with 0s.
+  // TODO: The prefix should not be counted in the precision.  But unfortunately
+  // it is and we have to live with it unless we fix all existing users of
+  // prefixed hex formatting.
+  EXPECT_EQ("0x000", format_number(0, IntegerStyle::HexLowerPrefix, 5));
+  EXPECT_EQ("0x0abcde",
+            format_number(0xABCDE, IntegerStyle::HexLowerPrefix, 8));
+
+  EXPECT_EQ("00000", format_number(0, IntegerStyle::HexLowerNoPrefix, 5));
+  EXPECT_EQ("000abcde",
+            format_number(0xABCDE, IntegerStyle::HexLowerNoPrefix, 8));
+
+  // Try printing more digits than can fit in a uint64.
+  EXPECT_EQ("0x00000000000000abcde",
+            format_number(0xABCDE, IntegerStyle::HexLowerPrefix, 21));
+
+  // Width less than the amount to be printed should print the full amount.
+  EXPECT_EQ("0x0", format_number(0, IntegerStyle::HexLowerPrefix, 0, 0));
+  EXPECT_EQ("0xabcde",
+            format_number(0xABCDE, IntegerStyle::HexLowerPrefix, 0, 0));
+
+  // Width greater than the value should pad with spaces.
+  EXPECT_EQ("  0x0", format_number(0, IntegerStyle::HexLowerPrefix, 0, 5));
+  EXPECT_EQ(" 0xabcde",
+            format_number(0xABCDE, IntegerStyle::HexLowerPrefix, 0, 8));
+
+  // Should also work with no prefix.
+  EXPECT_EQ("  000", format_number(0, IntegerStyle::HexLowerNoPrefix, 3, 5));
+  EXPECT_EQ("   0abcde",
+            format_number(0xABCDE, IntegerStyle::HexLowerNoPrefix, 6, 9));
+
+  // And with pointers.
+  EXPECT_EQ("  0x000",
+            format_number((void *)nullptr, HexStyle::PrefixLower, 5, 7));
+
+  // Try printing more digits than can fit in a uint64.
+  EXPECT_EQ("     0x000abcde",
+            format_number(0xABCDE, IntegerStyle::HexLowerPrefix, 10, 15));
+}
+
+TEST(NativeFormatTest, IntegerTests) {
+  // Test plain integer formatting with non-default widths and precisions.
+
+  // Too low precision should print the whole number.
+  EXPECT_EQ("-10", format_number(-10, IntegerStyle::Integer, 1));
+
+  // Additional precision should padd with 0s.
+  EXPECT_EQ("-00010", format_number(-10, IntegerStyle::Integer, 5));
+  EXPECT_EQ("-00100", format_number(-100, IntegerStyle::Integer, 5));
+  EXPECT_EQ("-01000", format_number(-1000, IntegerStyle::Integer, 5));
+  EXPECT_EQ("-001234567890",
+            format_number(-1234567890, IntegerStyle::Integer, 12));
+  EXPECT_EQ("00010", format_number(10, IntegerStyle::Integer, 5));
+  EXPECT_EQ("00100", format_number(100, IntegerStyle::Integer, 5));
+  EXPECT_EQ("01000", format_number(1000, IntegerStyle::Integer, 5));
+  EXPECT_EQ("001234567890",
+            format_number(1234567890, IntegerStyle::Integer, 12));
+
+  // Too low width should print the full number.
+  EXPECT_EQ("-10", format_number(-10, IntegerStyle::Integer, None, 2));
+
+  // Additional width should padd with spaces.
+  EXPECT_EQ("  -00010", format_number(-10, IntegerStyle::Integer, 5, 8));
+  EXPECT_EQ("  -00100", format_number(-100, IntegerStyle::Integer, 5, 8));
+  EXPECT_EQ("  -01000", format_number(-1000, IntegerStyle::Integer, 5, 8));
+  EXPECT_EQ(" -001234567890",
+            format_number(-1234567890, IntegerStyle::Integer, 12, 14));
+  EXPECT_EQ("   00010", format_number(10, IntegerStyle::Integer, 5, 8));
+  EXPECT_EQ("   00100", format_number(100, IntegerStyle::Integer, 5, 8));
+  EXPECT_EQ("   01000", format_number(1000, IntegerStyle::Integer, 5, 8));
+  EXPECT_EQ("  001234567890",
+            format_number(1234567890, IntegerStyle::Integer, 12, 14));
+}
+
+TEST(NativeFormatTest, CommaTests) {
+  // Test comma grouping with default widths and precisions.
+  EXPECT_EQ("0", format_number(0, IntegerStyle::Number));
+  EXPECT_EQ("10", format_number(10, IntegerStyle::Number));
+  EXPECT_EQ("100", format_number(100, IntegerStyle::Number));
+  EXPECT_EQ("1,000", format_number(1000, IntegerStyle::Number));
+  EXPECT_EQ("1,234,567,890", format_number(1234567890, IntegerStyle::Number));
+
+  // Test comma grouping with non-default widths and precisions.
+  EXPECT_EQ("-10", format_number(-10, IntegerStyle::Number));
+  EXPECT_EQ("-100", format_number(-100, IntegerStyle::Number));
+  EXPECT_EQ("-1,000", format_number(-1000, IntegerStyle::Number));
+  EXPECT_EQ("-1,234,567,890", format_number(-1234567890, IntegerStyle::Number));
+
+  EXPECT_EQ("  1,000", format_number(1000, IntegerStyle::Number, None, 7));
+  EXPECT_EQ(" -1,000", format_number(-1000, IntegerStyle::Number, None, 7));
+  EXPECT_EQ(" -0,001,000", format_number(-1000, IntegerStyle::Number, 7, 11));
+  EXPECT_EQ("  0,001,000", format_number(1000, IntegerStyle::Number, 7, 11));
+}
+
+TEST(NativeFormatTest, PercentTests) {
+  // Integer percents.
+  EXPECT_EQ("0%", format_number(0, IntegerStyle::Percent));
+  EXPECT_EQ("0.00%", format_number(0, IntegerStyle::Percent, 2));
+  EXPECT_EQ("  0.00%", format_number(0, IntegerStyle::Percent, 2, 7));
+
+  EXPECT_EQ(" 100.00%", format_number(1, IntegerStyle::Percent, 2, 8));
+
+  EXPECT_EQ("    100%", format_number(1, IntegerStyle::Percent, None, 8));
+  EXPECT_EQ(" 100.000%", format_number(1, IntegerStyle::Percent, 3, 9));
+
+  // Floating point percents.  Default precision is 2 for floating point types,
+  // even for 0.
+  EXPECT_EQ("0.00%", format_number(0.0, FloatStyle::Percent));
+  EXPECT_EQ("0%", format_number(0.0, FloatStyle::Percent, 0));
+  EXPECT_EQ(" 0.00%", format_number(0.0, FloatStyle::Percent, 2, 6));
+  EXPECT_EQ(" 4.2%", format_number(.042379, FloatStyle::Percent, 1, 5));
+  EXPECT_EQ("4.24%", format_number(.042379, FloatStyle::Percent, 2, 5));
+  EXPECT_EQ("4.238%", format_number(.042379, FloatStyle::Percent, 3, 5));
+  EXPECT_EQ("  0.424%", format_number(.0042379, FloatStyle::Percent, 3, 8));
+  EXPECT_EQ(" -0.424%", format_number(-.0042379, FloatStyle::Percent, 3, 8));
+}
+
+TEST(NativeFormatTest, FixedTests) {
+  // Integer fixed numbers.  Default precision is 2.  Make sure no decimal
+  // is printed with 0 precision.
+  EXPECT_EQ("1.00", format_number(1, IntegerStyle::Fixed));
+  EXPECT_EQ("1", format_number(1, IntegerStyle::Fixed, 0));
+  EXPECT_EQ("  1.00", format_number(1, IntegerStyle::Fixed, 2, 6));
+  EXPECT_EQ("-1.00", format_number(-1, IntegerStyle::Fixed));
+  EXPECT_EQ("-1.00", format_number(-1, IntegerStyle::Fixed, 2));
+  EXPECT_EQ(" -1.00", format_number(-1, IntegerStyle::Fixed, 2, 6));
+
+  // Float fixed numbers.  Default precision is 2.
+  EXPECT_EQ("0.00", format_number(0.0, FloatStyle::Fixed));
+  EXPECT_EQ("1.00", format_number(1.0, FloatStyle::Fixed));
+
+  // But can be forced to 0
+  EXPECT_EQ("0", format_number(0.0, FloatStyle::Fixed, 0));
+
+  // It should round up when appropriate.
+  EXPECT_EQ("3.14", format_number(3.1415, FloatStyle::Fixed, 2));
+  EXPECT_EQ("3.142", format_number(3.1415, FloatStyle::Fixed, 3));
+
+  // Padding should work properly with both positive and negative numbers.
+  EXPECT_EQ("   3.14", format_number(3.1415, FloatStyle::Fixed, 2, 7));
+  EXPECT_EQ("  3.142", format_number(3.1415, FloatStyle::Fixed, 3, 7));
+  EXPECT_EQ("  -3.14", format_number(-3.1415, FloatStyle::Fixed, 2, 7));
+  EXPECT_EQ(" -3.142", format_number(-3.1415, FloatStyle::Fixed, 3, 7));
+}
+}




More information about the llvm-commits mailing list