[raw_ostream] Raise some helper functions out of raw_ostream.
authorZachary Turner <zturner@google.com>
Tue, 11 Oct 2016 19:24:45 +0000 (19:24 +0000)
committerZachary Turner <zturner@google.com>
Tue, 11 Oct 2016 19:24:45 +0000 (19:24 +0000)
Low level functionality to format numbers were embedded in the
implementation of raw_ostream.  I have need to use these through
an interface other than the overloaded stream operators, so they
need to be raised to a level that they can be used from either
raw_ostream operators or other code.

llvm-svn: 283921

llvm/include/llvm/Support/NativeFormatting.h [new file with mode: 0644]
llvm/lib/Support/CMakeLists.txt
llvm/lib/Support/NativeFormatting.cpp [new file with mode: 0644]
llvm/lib/Support/raw_ostream.cpp

diff --git a/llvm/include/llvm/Support/NativeFormatting.h b/llvm/include/llvm/Support/NativeFormatting.h
new file mode 100644 (file)
index 0000000..6f7e077
--- /dev/null
@@ -0,0 +1,31 @@
+//===- NativeFormatting.h - Low level formatting helpers ---------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_NATIVE_FORMATTING_H
+#define LLVM_SUPPORT_NATIVE_FORMATTING_H
+
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstdint>
+
+namespace llvm {
+enum class FloatStyle { Exponent, Decimal };
+
+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);
+}
+
+#endif
\ No newline at end of file
index 9f75545..cf04016 100644 (file)
@@ -70,6 +70,7 @@ add_llvm_library(LLVMSupport
   MemoryBuffer.cpp
   MemoryObject.cpp
   MD5.cpp
+  NativeFormatting.cpp
   Options.cpp
   PluginLoader.cpp
   PrettyStackTrace.cpp
diff --git a/llvm/lib/Support/NativeFormatting.cpp b/llvm/lib/Support/NativeFormatting.cpp
new file mode 100644 (file)
index 0000000..84f6c39
--- /dev/null
@@ -0,0 +1,180 @@
+//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/NativeFormatting.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+
+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) {
+    *--CurPtr = '0' + char(Value % 10);
+    Value /= 10;
+  }
+  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;
+  }
+
+  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);
+}
+
+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);
+    return;
+  }
+
+  unsigned long UN = -(unsigned long)N;
+  if (MinWidth > 0)
+    --MinWidth;
+
+  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);
+}
+
+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;
+  }
+
+  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);
+}
+
+void llvm::write_longlong(raw_ostream &S, long long N, std::size_t MinWidth) {
+  if (N >= 0) {
+    write_ulonglong(S, static_cast<unsigned long long>(N), MinWidth);
+    return;
+  }
+
+  // Avoid undefined behavior on INT64_MIN with a cast.
+  unsigned long long UN = -(unsigned long long)N;
+  if (MinWidth > 0)
+    --MinWidth;
+
+  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_hex(raw_ostream &S, unsigned long long N, std::size_t MinWidth,
+                     bool Upper, bool Prefix) {
+  unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
+  unsigned PrefixChars = Prefix ? 2 : 0;
+  unsigned Width = std::max(MinWidth, std::max(1u, Nibbles) + PrefixChars);
+
+  char NumberBuffer[20] = "0x0000000000000000";
+  if (!Prefix)
+    NumberBuffer[1] = '0';
+  char *EndPtr = NumberBuffer + Width;
+  char *CurPtr = EndPtr;
+  while (N) {
+    unsigned char x = static_cast<unsigned char>(N) % 16;
+    *--CurPtr = hexdigit(x, !Upper);
+    N /= 16;
+  }
+
+  S.write(NumberBuffer, Width);
+}
+
+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';
+  SmallString<8> Spec;
+  llvm::raw_svector_ostream Out(Spec);
+  Out << '%';
+  if (MinWidth > 0)
+    Out << MinWidth;
+  if (MinDecimals > 0)
+    Out << '.' << MinDecimals;
+  Out << Letter;
+
+  if (Style == FloatStyle::Exponent) {
+#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"
+// FIXME: Implement our formatter to here or Support/Format.h!
+#if defined(__MINGW32__)
+    // FIXME: It should be generic to C++11.
+    if (N == 0.0 && std::signbit(N)) {
+      S << "-0.000000e+00";
+      return;
+    }
+#else
+    int fpcl = _fpclass(N);
+
+    // negative zero
+    if (fpcl == _FPCLASS_NZ) {
+      S << "-0.000000e+00";
+      return;
+    }
+#endif
+
+    char buf[16];
+    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') {
+        int cs = buf[len - 4];
+        if (cs == '+' || cs == '-') {
+          int c1 = buf[len - 2];
+          int c0 = buf[len - 1];
+          if (isdigit(static_cast<unsigned char>(c1)) &&
+              isdigit(static_cast<unsigned char>(c0))) {
+            // Trim leading '0': "...e+012" -> "...e+12\0"
+            buf[len - 3] = c1;
+            buf[len - 2] = c0;
+            buf[--len] = 0;
+          }
+        }
+      }
+      S << buf;
+      return;
+    }
+#endif
+  }
+
+  S << format(Spec.c_str(), N);
+}
index df4c8dc..8101bc1 100644 (file)
@@ -21,6 +21,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Support/NativeFormatting.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/Program.h"
 #include <algorithm>
@@ -28,8 +29,8 @@
 #include <cerrno>
 #include <cstdio>
 #include <iterator>
-#include <system_error>
 #include <sys/stat.h>
+#include <system_error>
 
 // <fcntl.h> may provide O_BINARY.
 #if defined(HAVE_FCNTL_H)
@@ -113,73 +114,28 @@ void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
 }
 
 raw_ostream &raw_ostream::operator<<(unsigned long N) {
-  // Zero is a special case.
-  if (N == 0)
-    return *this << '0';
-
-  char NumberBuffer[20];
-  char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
-  char *CurPtr = EndPtr;
-
-  while (N) {
-    *--CurPtr = '0' + char(N % 10);
-    N /= 10;
-  }
-  return write(CurPtr, EndPtr-CurPtr);
+  write_ulong(*this, N, 0);
+  return *this;
 }
 
 raw_ostream &raw_ostream::operator<<(long N) {
-  if (N <  0) {
-    *this << '-';
-    // Avoid undefined behavior on LONG_MIN with a cast.
-    N = -(unsigned long)N;
-  }
-
-  return this->operator<<(static_cast<unsigned long>(N));
+  write_long(*this, N, 0);
+  return *this;
 }
 
 raw_ostream &raw_ostream::operator<<(unsigned long long N) {
-  // Output using 32-bit div/mod when possible.
-  if (N == static_cast<unsigned long>(N))
-    return this->operator<<(static_cast<unsigned long>(N));
-
-  char NumberBuffer[20];
-  char *EndPtr = std::end(NumberBuffer);
-  char *CurPtr = EndPtr;
-
-  while (N) {
-    *--CurPtr = '0' + char(N % 10);
-    N /= 10;
-  }
-  return write(CurPtr, EndPtr-CurPtr);
+  write_ulonglong(*this, N, 0);
+  return *this;
 }
 
 raw_ostream &raw_ostream::operator<<(long long N) {
-  if (N < 0) {
-    *this << '-';
-    // Avoid undefined behavior on INT64_MIN with a cast.
-    N = -(unsigned long long)N;
-  }
-
-  return this->operator<<(static_cast<unsigned long long>(N));
+  write_longlong(*this, N, 0);
+  return *this;
 }
 
 raw_ostream &raw_ostream::write_hex(unsigned long long N) {
-  // Zero is a special case.
-  if (N == 0)
-    return *this << '0';
-
-  char NumberBuffer[16];
-  char *EndPtr = std::end(NumberBuffer);
-  char *CurPtr = EndPtr;
-
-  while (N) {
-    unsigned char x = static_cast<unsigned char>(N) % 16;
-    *--CurPtr = hexdigit(x, /*LowerCase*/true);
-    N /= 16;
-  }
-
-  return write(CurPtr, EndPtr-CurPtr);
+  llvm::write_hex(*this, N, 0, false, false);
+  return *this;
 }
 
 raw_ostream &raw_ostream::write_escaped(StringRef Str,
@@ -223,50 +179,13 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str,
 }
 
 raw_ostream &raw_ostream::operator<<(const void *P) {
-  *this << '0' << 'x';
-
-  return write_hex((uintptr_t) P);
+  llvm::write_hex(*this, (uintptr_t)P, 0, false, true);
+  return *this;
 }
 
 raw_ostream &raw_ostream::operator<<(double N) {
-#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"
-  // FIXME: Implement our formatter to here or Support/Format.h!
-#if defined(__MINGW32__)
-  // FIXME: It should be generic to C++11.
-  if (N == 0.0 && std::signbit(N))
-    return *this << "-0.000000e+00";
-#else
-  int fpcl = _fpclass(N);
-
-  // negative zero
-  if (fpcl == _FPCLASS_NZ)
-    return *this << "-0.000000e+00";
-#endif
-
-  char buf[16];
-  unsigned len;
-  len = format("%e", N).snprint(buf, sizeof(buf));
-  if (len <= sizeof(buf) - 2) {
-    if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') {
-      int cs = buf[len - 4];
-      if (cs == '+' || cs == '-') {
-        int c1 = buf[len - 2];
-        int c0 = buf[len - 1];
-        if (isdigit(static_cast<unsigned char>(c1)) &&
-            isdigit(static_cast<unsigned char>(c0))) {
-          // Trim leading '0': "...e+012" -> "...e+12\0"
-          buf[len - 3] = c1;
-          buf[len - 2] = c0;
-          buf[--len] = 0;
-        }
-      }
-    }
-    return this->operator<<(buf);
-  }
-#endif
-  return this->operator<<(format("%e", N));
+  llvm::write_double(*this, N, 0, 0, FloatStyle::Exponent);
+  return *this;
 }
 
 void raw_ostream::flush_nonempty() {
@@ -412,48 +331,11 @@ raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
 
 raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
   if (FN.Hex) {
-    unsigned Nibbles = (64 - countLeadingZeros(FN.HexValue)+3)/4;
-    unsigned PrefixChars = FN.HexPrefix ? 2 : 0;
-    unsigned Width = std::max(FN.Width, Nibbles + PrefixChars);
-
-    char NumberBuffer[20] = "0x0000000000000000";
-    if (!FN.HexPrefix)
-      NumberBuffer[1] = '0';
-    char *EndPtr = NumberBuffer+Width;
-    char *CurPtr = EndPtr;
-    unsigned long long N = FN.HexValue;
-    while (N) {
-      unsigned char x = static_cast<unsigned char>(N) % 16;
-      *--CurPtr = hexdigit(x, !FN.Upper);
-      N /= 16;
-    }
-
-    return write(NumberBuffer, Width);
+    llvm::write_hex(*this, FN.HexValue, FN.Width, FN.Upper, FN.HexPrefix);
   } 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 ? -static_cast<uint64_t>(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);
+    llvm::write_longlong(*this, FN.DecValue, FN.Width);
   }
+  return *this;
 }
 
 /// indent - Insert 'NumSpaces' spaces.