123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- //===- 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(static_cast<unsigned>(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);
- }
|