forked from OSchip/llvm-project
[Support] Add support for "advanced" number formatting.
raw_ostream has not afforded a lot of flexibility in terms of how to format numbers when outputting. Wrap this all up into a set of low level helper functions that can be used to output numbers with arbitrary precision, alignment, format, etc and then update raw_ostream to use these functions. This will be useful for upcoming improvements to llvm's string formatting libraries, but are still useful independently. Differential Revision: https://reviews.llvm.org/D25497 llvm-svn: 284425
This commit is contained in:
parent
523cd8290a
commit
99eef2d736
|
@ -10,22 +10,46 @@
|
|||
#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);
|
||||
size_t getDefaultPrecision(FloatStyle Style);
|
||||
size_t getDefaultPrecision(IntegerStyle Style);
|
||||
size_t getDefaultPrecision(HexStyle Style);
|
||||
|
||||
void write_ulong(raw_ostream &S, unsigned long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision = None, Optional<int> Width = None);
|
||||
void write_long(raw_ostream &S, long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision = None, Optional<int> Width = None);
|
||||
void write_ulonglong(raw_ostream &S, unsigned long long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision = None,
|
||||
Optional<int> Width = None);
|
||||
void write_longlong(raw_ostream &S, long long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision = None,
|
||||
Optional<int> Width = None);
|
||||
void write_hex(raw_ostream &S, unsigned long long 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
|
|
@ -9,107 +9,248 @@
|
|||
|
||||
#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;
|
||||
}
|
||||
|
||||
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 repeat_char(raw_ostream &S, char C, size_t Times) {
|
||||
for (size_t I = 0; I < Times; ++I)
|
||||
S << C;
|
||||
}
|
||||
|
||||
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);
|
||||
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, 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;
|
||||
}
|
||||
|
||||
unsigned long UN = -(unsigned long)N;
|
||||
if (MinWidth > 0)
|
||||
--MinWidth;
|
||||
size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
|
||||
char NumberBuffer[128];
|
||||
std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
Len += LeadingZeros;
|
||||
|
||||
// One for the decimal sign, one for each point of precision.
|
||||
size_t DecimalChars = WriteDecimal ? 1 + Prec : 0;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 << '%';
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_unsigned(raw_ostream &S, T N, IntegerStyle Style,
|
||||
Optional<size_t> Precision, Optional<int> Width,
|
||||
bool IsNegative = false) {
|
||||
write_unsigned_impl(S, N, Style, Precision, Width, IsNegative);
|
||||
}
|
||||
|
||||
static void write_unsigned(raw_ostream &S, uint64_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);
|
||||
return;
|
||||
}
|
||||
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_unsigned(S, static_cast<UnsignedT>(N), Style, Precision, Width);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void llvm::write_ulong(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_long(raw_ostream &S, long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision, Optional<int> Width) {
|
||||
write_signed(S, N, Style, Precision, Width);
|
||||
}
|
||||
|
||||
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);
|
||||
IntegerStyle Style, Optional<size_t> Precision,
|
||||
Optional<int> Width) {
|
||||
write_unsigned(S, N, Style, Precision, Width);
|
||||
}
|
||||
|
||||
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_longlong(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, unsigned long long 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 +258,37 @@ void llvm::write_hex(raw_ostream &S, unsigned long long N, std::size_t MinWidth,
|
|||
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 +296,9 @@ void llvm::write_double(raw_ostream &S, double N, std::size_t MinWidth,
|
|||
#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 +306,19 @@ void llvm::write_double(raw_ostream &S, double N, std::size_t MinWidth,
|
|||
|
||||
// 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 +332,61 @@ void llvm::write_double(raw_ostream &S, double N, std::size_t MinWidth,
|
|||
}
|
||||
}
|
||||
}
|
||||
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 << '%';
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -114,27 +114,27 @@ void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
|
|||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(unsigned long N) {
|
||||
write_ulong(*this, N, 0);
|
||||
write_ulong(*this, N, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(long N) {
|
||||
write_long(*this, N, 0);
|
||||
write_long(*this, N, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(unsigned long long N) {
|
||||
write_ulonglong(*this, N, 0);
|
||||
write_ulonglong(*this, N, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(long long N) {
|
||||
write_longlong(*this, N, 0);
|
||||
write_longlong(*this, 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(StringRef Str,
|
|||
}
|
||||
|
||||
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<<(const FormattedString &FS) {
|
|||
|
||||
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_longlong(*this, FN.DecValue, IntegerStyle::Integer, None,
|
||||
FN.Width);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ add_llvm_unittest(SupportTests
|
|||
MathExtrasTest.cpp
|
||||
MemoryBufferTest.cpp
|
||||
MemoryTest.cpp
|
||||
NativeFormatTests.cpp
|
||||
Path.cpp
|
||||
ProcessTest.cpp
|
||||
ProgramTest.cpp
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
//===- 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>
|
||||
typename std::enable_if<std::is_signed<T>::value, std::string>::type
|
||||
format_number(T N, IntegerStyle Style, Optional<size_t> Precision = None,
|
||||
Optional<int> Width = None) {
|
||||
return format_number(static_cast<long>(N), Style, Precision, Width);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_unsigned<T>::value, std::string>::type
|
||||
format_number(T N, IntegerStyle Style, Optional<size_t> Precision = None,
|
||||
Optional<int> Width = None) {
|
||||
return format_number(static_cast<unsigned long>(N), Style, Precision, Width);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
return format_number(reinterpret_cast<uintptr_t>(N), Style, Precision, Width);
|
||||
}
|
||||
|
||||
std::string format_number(unsigned long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision = None,
|
||||
Optional<int> Width = None) {
|
||||
std::string S;
|
||||
llvm::raw_string_ostream Str(S);
|
||||
write_ulong(Str, N, Style, Precision, Width);
|
||||
Str.flush();
|
||||
return S;
|
||||
}
|
||||
|
||||
std::string format_number(long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision = None,
|
||||
Optional<int> Width = None) {
|
||||
std::string S;
|
||||
llvm::raw_string_ostream Str(S);
|
||||
write_long(Str, N, Style, Precision, Width);
|
||||
Str.flush();
|
||||
return S;
|
||||
}
|
||||
|
||||
std::string format_number(unsigned long long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision = None,
|
||||
Optional<int> Width = None) {
|
||||
std::string S;
|
||||
llvm::raw_string_ostream Str(S);
|
||||
write_ulonglong(Str, N, Style, Precision, Width);
|
||||
Str.flush();
|
||||
return S;
|
||||
}
|
||||
|
||||
std::string format_number(long long N, IntegerStyle Style,
|
||||
Optional<size_t> Precision = None,
|
||||
Optional<int> Width = None) {
|
||||
std::string S;
|
||||
llvm::raw_string_ostream Str(S);
|
||||
write_longlong(Str, N, Style, Precision, Width);
|
||||
Str.flush();
|
||||
return S;
|
||||
}
|
||||
|
||||
std::string format_number(unsigned long long 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));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue