mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
1cad744181
This introduces a new type-safe general purpose formatting library. It provides compile-time type safety, does not require a format specifier (since the type is deduced), and provides mechanisms for extending the format capability to user defined types, and overriding the formatting behavior for existing types. This patch additionally adds documentation for the API to the LLVM programmer's manual. Mailing List Thread: http://lists.llvm.org/pipermail/llvm-dev/2016-October/105836.html Differential Revision: https://reviews.llvm.org/D25587 llvm-svn: 286682
266 lines
7.5 KiB
C++
266 lines
7.5 KiB
C++
//===- 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/ArrayRef.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;
|
|
|
|
do {
|
|
*--CurPtr = '0' + char(Value % 10);
|
|
Value /= 10;
|
|
} while (Value);
|
|
return EndPtr - CurPtr;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
|
|
IntegerStyle Style, bool IsNegative) {
|
|
static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
|
|
|
|
char NumberBuffer[128];
|
|
std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
|
|
|
|
size_t Len = 0;
|
|
Len = format_to_buffer(N, NumberBuffer);
|
|
|
|
if (IsNegative)
|
|
S << '-';
|
|
|
|
if (Len < MinDigits && Style != IntegerStyle::Number) {
|
|
for (size_t I = Len; I < MinDigits; ++I)
|
|
S << '0';
|
|
}
|
|
|
|
if (Style == IntegerStyle::Number) {
|
|
writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
|
|
} else {
|
|
S.write(std::end(NumberBuffer) - Len, Len);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
|
|
IntegerStyle Style, 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), MinDigits, Style,
|
|
IsNegative);
|
|
else
|
|
write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
|
|
}
|
|
|
|
template <typename T>
|
|
static void write_signed(raw_ostream &S, T N, size_t MinDigits,
|
|
IntegerStyle Style) {
|
|
static_assert(std::is_signed<T>::value, "Value is not signed!");
|
|
|
|
using UnsignedT = typename std::make_unsigned<T>::type;
|
|
|
|
if (N >= 0) {
|
|
write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
|
|
return;
|
|
}
|
|
|
|
UnsignedT UN = -(UnsignedT)N;
|
|
write_unsigned(S, UN, MinDigits, Style, true);
|
|
}
|
|
|
|
void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
|
|
IntegerStyle Style) {
|
|
write_unsigned(S, N, MinDigits, Style);
|
|
}
|
|
|
|
void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,
|
|
IntegerStyle Style) {
|
|
write_signed(S, N, MinDigits, Style);
|
|
}
|
|
|
|
void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
|
|
IntegerStyle Style) {
|
|
write_unsigned(S, N, MinDigits, Style);
|
|
}
|
|
|
|
void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
|
|
IntegerStyle Style) {
|
|
write_signed(S, N, MinDigits, Style);
|
|
}
|
|
|
|
void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
|
|
IntegerStyle Style) {
|
|
write_unsigned(S, N, MinDigits, Style);
|
|
}
|
|
|
|
void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,
|
|
IntegerStyle Style) {
|
|
write_signed(S, N, MinDigits, Style);
|
|
}
|
|
|
|
void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
|
|
Optional<size_t> Width) {
|
|
const size_t kMaxWidth = 128u;
|
|
|
|
size_t W = std::min(kMaxWidth, Width.getValueOr(0u));
|
|
|
|
unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
|
|
bool Prefix = (Style == HexPrintStyle::PrefixLower ||
|
|
Style == HexPrintStyle::PrefixUpper);
|
|
bool Upper =
|
|
(Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
|
|
unsigned PrefixChars = Prefix ? 2 : 0;
|
|
unsigned NumChars =
|
|
std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
|
|
|
|
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;
|
|
*--CurPtr = hexdigit(x, !Upper);
|
|
N /= 16;
|
|
}
|
|
|
|
S.write(NumberBuffer, NumChars);
|
|
}
|
|
|
|
void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
|
|
Optional<size_t> Precision) {
|
|
size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
|
|
|
|
if (std::isnan(N)) {
|
|
S << "nan";
|
|
return;
|
|
} else if (std::isinf(N)) {
|
|
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 << "%." << Prec << Letter;
|
|
|
|
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"
|
|
// 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)) {
|
|
char NegativeZero[] = "-0.000000e+00";
|
|
if (Style == FloatStyle::ExponentUpper)
|
|
NegativeZero[strlen(NegativeZero) - 4] = 'E';
|
|
S << NegativeZero;
|
|
return;
|
|
}
|
|
#else
|
|
int fpcl = _fpclass(N);
|
|
|
|
// negative zero
|
|
if (fpcl == _FPCLASS_NZ) {
|
|
char NegativeZero[] = "-0.000000e+00";
|
|
if (Style == FloatStyle::ExponentUpper)
|
|
NegativeZero[strlen(NegativeZero) - 4] = 'E';
|
|
S << NegativeZero;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
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 - 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
|
|
}
|
|
|
|
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;
|
|
S << Buf;
|
|
if (Style == FloatStyle::Percent)
|
|
S << '%';
|
|
}
|
|
|
|
bool llvm::isPrefixedHexStyle(HexPrintStyle S) {
|
|
return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
|
|
}
|
|
|
|
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;
|
|
}
|