diff options
author | Zachary Turner <zturner@google.com> | 2016-10-11 19:24:45 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2016-10-11 19:24:45 +0000 |
commit | 733be51dcdf4ec40171c5d747b59f6dfa010b0a1 (patch) | |
tree | 7c8febe1ff5726615776a2e84ec3dd98440845cb /llvm/lib/Support/NativeFormatting.cpp | |
parent | 7186a4323e142301fbd858abc79a6174d83cfac9 (diff) | |
download | bcm5719-llvm-733be51dcdf4ec40171c5d747b59f6dfa010b0a1.tar.gz bcm5719-llvm-733be51dcdf4ec40171c5d747b59f6dfa010b0a1.zip |
[raw_ostream] Raise some helper functions out of raw_ostream.
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
Diffstat (limited to 'llvm/lib/Support/NativeFormatting.cpp')
-rw-r--r-- | llvm/lib/Support/NativeFormatting.cpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/llvm/lib/Support/NativeFormatting.cpp b/llvm/lib/Support/NativeFormatting.cpp new file mode 100644 index 00000000000..84f6c390b02 --- /dev/null +++ b/llvm/lib/Support/NativeFormatting.cpp @@ -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); +} |