1 //===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/NativeFormatting.h" 11 12 #include "llvm/ADT/SmallString.h" 13 #include "llvm/ADT/StringExtras.h" 14 #include "llvm/Support/Format.h" 15 16 using namespace llvm; 17 18 template<typename T, std::size_t N> 19 static int format_to_buffer(T Value, char (&Buffer)[N]) { 20 char *EndPtr = std::end(Buffer); 21 char *CurPtr = EndPtr; 22 23 while (Value) { 24 *--CurPtr = '0' + char(Value % 10); 25 Value /= 10; 26 } 27 return EndPtr - CurPtr; 28 } 29 30 void llvm::write_ulong(raw_ostream &S, unsigned long N, std::size_t MinWidth) { 31 // Zero is a special case. 32 if (N == 0) { 33 if (MinWidth > 0) 34 S.indent(MinWidth - 1); 35 S << '0'; 36 return; 37 } 38 39 char NumberBuffer[20]; 40 int Len = format_to_buffer(N, NumberBuffer); 41 int Pad = (MinWidth == 0) ? 0 : MinWidth - Len; 42 if (Pad > 0) 43 S.indent(Pad); 44 S.write(std::end(NumberBuffer) - Len, Len); 45 } 46 47 void llvm::write_long(raw_ostream &S, long N, std::size_t MinWidth) { 48 if (N >= 0) { 49 write_ulong(S, static_cast<unsigned long>(N), MinWidth); 50 return; 51 } 52 53 unsigned long UN = -(unsigned long)N; 54 if (MinWidth > 0) 55 --MinWidth; 56 57 char NumberBuffer[20]; 58 int Len = format_to_buffer(UN, NumberBuffer); 59 int Pad = (MinWidth == 0) ? 0 : MinWidth - Len; 60 if (Pad > 0) 61 S.indent(Pad); 62 S.write('-'); 63 S.write(std::end(NumberBuffer) - Len, Len); 64 } 65 66 void llvm::write_ulonglong(raw_ostream &S, unsigned long long N, 67 std::size_t MinWidth) { 68 // Output using 32-bit div/mod when possible. 69 if (N == static_cast<unsigned long>(N)) { 70 write_ulong(S, static_cast<unsigned long>(N), MinWidth); 71 return; 72 } 73 74 char NumberBuffer[32]; 75 int Len = format_to_buffer(N, NumberBuffer); 76 int Pad = (MinWidth == 0) ? 0 : MinWidth - Len; 77 if (Pad > 0) 78 S.indent(Pad); 79 S.write(std::end(NumberBuffer) - Len, Len); 80 } 81 82 void llvm::write_longlong(raw_ostream &S, long long N, std::size_t MinWidth) { 83 if (N >= 0) { 84 write_ulonglong(S, static_cast<unsigned long long>(N), MinWidth); 85 return; 86 } 87 88 // Avoid undefined behavior on INT64_MIN with a cast. 89 unsigned long long UN = -(unsigned long long)N; 90 if (MinWidth > 0) 91 --MinWidth; 92 93 char NumberBuffer[32]; 94 int Len = format_to_buffer(UN, NumberBuffer); 95 int Pad = (MinWidth == 0) ? 0 : MinWidth - Len; 96 if (Pad > 0) 97 S.indent(Pad); 98 S.write('-'); 99 S.write(std::end(NumberBuffer) - Len, Len); 100 } 101 102 void llvm::write_hex(raw_ostream &S, unsigned long long N, std::size_t MinWidth, 103 bool Upper, bool Prefix) { 104 unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4; 105 unsigned PrefixChars = Prefix ? 2 : 0; 106 unsigned Width = std::max(static_cast<unsigned>(MinWidth), 107 std::max(1u, Nibbles) + PrefixChars); 108 109 char NumberBuffer[20] = "0x0000000000000000"; 110 if (!Prefix) 111 NumberBuffer[1] = '0'; 112 char *EndPtr = NumberBuffer + Width; 113 char *CurPtr = EndPtr; 114 while (N) { 115 unsigned char x = static_cast<unsigned char>(N) % 16; 116 *--CurPtr = hexdigit(x, !Upper); 117 N /= 16; 118 } 119 120 S.write(NumberBuffer, Width); 121 } 122 123 void llvm::write_double(raw_ostream &S, double N, std::size_t MinWidth, 124 std::size_t MinDecimals, FloatStyle Style) { 125 char Letter = (Style == FloatStyle::Exponent) ? 'e' : 'f'; 126 SmallString<8> Spec; 127 llvm::raw_svector_ostream Out(Spec); 128 Out << '%'; 129 if (MinWidth > 0) 130 Out << MinWidth; 131 if (MinDecimals > 0) 132 Out << '.' << MinDecimals; 133 Out << Letter; 134 135 if (Style == FloatStyle::Exponent) { 136 #ifdef _WIN32 137 // On MSVCRT and compatible, output of %e is incompatible to Posix 138 // by default. Number of exponent digits should be at least 2. "%+03d" 139 // FIXME: Implement our formatter to here or Support/Format.h! 140 #if defined(__MINGW32__) 141 // FIXME: It should be generic to C++11. 142 if (N == 0.0 && std::signbit(N)) { 143 S << "-0.000000e+00"; 144 return; 145 } 146 #else 147 int fpcl = _fpclass(N); 148 149 // negative zero 150 if (fpcl == _FPCLASS_NZ) { 151 S << "-0.000000e+00"; 152 return; 153 } 154 #endif 155 156 char buf[16]; 157 unsigned len; 158 len = format(Spec.c_str(), N).snprint(buf, sizeof(buf)); 159 if (len <= sizeof(buf) - 2) { 160 if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') { 161 int cs = buf[len - 4]; 162 if (cs == '+' || cs == '-') { 163 int c1 = buf[len - 2]; 164 int c0 = buf[len - 1]; 165 if (isdigit(static_cast<unsigned char>(c1)) && 166 isdigit(static_cast<unsigned char>(c0))) { 167 // Trim leading '0': "...e+012" -> "...e+12\0" 168 buf[len - 3] = c1; 169 buf[len - 2] = c0; 170 buf[--len] = 0; 171 } 172 } 173 } 174 S << buf; 175 return; 176 } 177 #endif 178 } 179 180 S << format(Spec.c_str(), N); 181 } 182