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/ArrayRef.h"
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/Support/Format.h"
16 
17 using namespace llvm;
18 
19 static bool isHexStyle(IntegerStyle S) {
20   switch (S) {
21   case IntegerStyle::HexLowerNoPrefix:
22   case IntegerStyle::HexLowerPrefix:
23   case IntegerStyle::HexUpperNoPrefix:
24   case IntegerStyle::HexUpperPrefix:
25     return true;
26   default:
27     return false;
28   }
29   LLVM_BUILTIN_UNREACHABLE;
30 }
31 
32 static HexStyle intHexStyleToHexStyle(IntegerStyle S) {
33   assert(isHexStyle(S));
34   switch (S) {
35   case IntegerStyle::HexLowerNoPrefix:
36     return HexStyle::Lower;
37   case IntegerStyle::HexLowerPrefix:
38     return HexStyle::PrefixLower;
39   case IntegerStyle::HexUpperNoPrefix:
40     return HexStyle::Upper;
41   case IntegerStyle::HexUpperPrefix:
42     return HexStyle::PrefixUpper;
43   default:
44     break;
45   }
46   LLVM_BUILTIN_UNREACHABLE;
47 }
48 
49 static void writePadding(raw_ostream &S, Optional<int> FieldWidth,
50                          size_t Chars) {
51   if (!FieldWidth.hasValue())
52     return;
53 
54   int Pad = *FieldWidth - Chars;
55   if (Pad > 0)
56     S.indent(Pad);
57 }
58 
59 template<typename T, std::size_t N>
60 static int format_to_buffer(T Value, char (&Buffer)[N]) {
61   char *EndPtr = std::end(Buffer);
62   char *CurPtr = EndPtr;
63 
64   do {
65     *--CurPtr = '0' + char(Value % 10);
66     Value /= 10;
67   } while (Value);
68   return EndPtr - CurPtr;
69 }
70 
71 static void repeat_char(raw_ostream &S, char C, size_t Times) {
72   for (size_t I = 0; I < Times; ++I)
73     S << C;
74 }
75 
76 static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
77   assert(!Buffer.empty());
78 
79   ArrayRef<char> ThisGroup;
80   int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
81   ThisGroup = Buffer.take_front(InitialDigits);
82   S.write(ThisGroup.data(), ThisGroup.size());
83 
84   Buffer = Buffer.drop_front(InitialDigits);
85   assert(Buffer.size() % 3 == 0);
86   while (!Buffer.empty()) {
87     S << ',';
88     ThisGroup = Buffer.take_front(3);
89     S.write(ThisGroup.data(), 3);
90     Buffer = Buffer.drop_front(3);
91   }
92 }
93 
94 template <typename T>
95 static void write_unsigned_impl(raw_ostream &S, T N, IntegerStyle Style,
96                                 Optional<size_t> Precision, Optional<int> Width,
97                                 bool IsNegative) {
98   static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
99 
100   if (Style == IntegerStyle::Exponent) {
101     write_double(S, static_cast<double>(N), FloatStyle::Exponent, Precision,
102                  Width);
103     return;
104   } else if (Style == IntegerStyle::ExponentUpper) {
105     write_double(S, static_cast<double>(N), FloatStyle::ExponentUpper,
106                  Precision, Width);
107     return;
108   } else if (isHexStyle(Style)) {
109     write_hex(S, N, intHexStyleToHexStyle(Style), Precision, Width);
110     return;
111   }
112 
113   size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
114   char NumberBuffer[128];
115   std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
116 
117   size_t Len = 0;
118   Len = format_to_buffer(N, NumberBuffer);
119 
120   bool WriteDecimal =
121       ((Style == IntegerStyle::Fixed || Style == IntegerStyle::Percent) &&
122        Prec > 0);
123 
124   size_t LeadingZeros = 0;
125   if ((Style == IntegerStyle::Integer || Style == IntegerStyle::Number) &&
126       Prec > 0) {
127     if (Prec > Len)
128       LeadingZeros = Prec - Len;
129   }
130 
131   Len += LeadingZeros;
132 
133   // One for the decimal sign, one for each point of precision.
134   size_t DecimalChars = WriteDecimal ? 1 + Prec : 0;
135 
136   // One character for the negative sign.
137   size_t Neg = (IsNegative) ? 1 : 0;
138 
139   // One comma for each group of 3 digits.
140   size_t Commas = (Style != IntegerStyle::Number) ? 0 : (Len - 1) / 3;
141 
142   size_t PercentChars = 0;
143   if (Style == IntegerStyle::Percent) {
144     // For all numbers except 0, we append two additional 0s.
145     PercentChars = (N == 0) ? 1 : 3;
146   }
147 
148   writePadding(S, Width, Len + DecimalChars + Neg + Commas + PercentChars);
149 
150   if (IsNegative)
151     S << '-';
152   if (Style == IntegerStyle::Number) {
153     writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
154   } else {
155     S.write(std::end(NumberBuffer) - Len, Len);
156     if (Style == IntegerStyle::Percent && N != 0) {
157       // Rather than multiply by 100, write the characters manually, in case the
158       // multiplication would overflow.
159       S << "00";
160     }
161   }
162 
163   if (WriteDecimal) {
164     S << '.';
165     repeat_char(S, '0', Prec);
166   }
167   if (Style == IntegerStyle::Percent)
168     S << '%';
169 }
170 
171 template <typename T>
172 static void write_unsigned(raw_ostream &S, T N, IntegerStyle Style,
173                            Optional<size_t> Precision, Optional<int> Width,
174                            bool IsNegative = false) {
175   write_unsigned_impl(S, N, Style, Precision, Width, IsNegative);
176 }
177 
178 static void write_unsigned(raw_ostream &S, uint64_t N, IntegerStyle Style,
179                            Optional<size_t> Precision, Optional<int> Width,
180                            bool IsNegative = false) {
181   // Output using 32-bit div/mod if possible.
182   if (N == static_cast<uint32_t>(N)) {
183     write_unsigned_impl(S, static_cast<uint32_t>(N), Style, Precision, Width,
184                         IsNegative);
185     return;
186   }
187   write_unsigned_impl(S, N, Style, Precision, Width, IsNegative);
188 }
189 
190 template <typename T>
191 static void write_signed(raw_ostream &S, T N, IntegerStyle Style,
192                          Optional<size_t> Precision, Optional<int> Width) {
193   static_assert(std::is_signed<T>::value, "Value is not signed!");
194 
195   using UnsignedT = typename std::make_unsigned<T>::type;
196 
197   if (N >= 0) {
198     write_unsigned(S, static_cast<UnsignedT>(N), Style, Precision, Width);
199     return;
200   }
201 
202   UnsignedT UN = -(UnsignedT)N;
203   if (isHexStyle(Style)) {
204     static_assert(sizeof(UnsignedT) == sizeof(T),
205                   "Types do not have the same size!");
206     std::memcpy(&UN, &N, sizeof(N));
207     write_hex(S, UN, intHexStyleToHexStyle(Style), Precision, Width);
208     return;
209   }
210   write_unsigned(S, UN, Style, Precision, Width, true);
211 }
212 
213 void llvm::write_ulong(raw_ostream &S, unsigned long N, IntegerStyle Style,
214                        Optional<size_t> Precision, Optional<int> Width) {
215   write_unsigned(S, N, Style, Precision, Width);
216 }
217 
218 void llvm::write_long(raw_ostream &S, long N, IntegerStyle Style,
219                       Optional<size_t> Precision, Optional<int> Width) {
220   write_signed(S, N, Style, Precision, Width);
221 }
222 
223 void llvm::write_ulonglong(raw_ostream &S, unsigned long long N,
224                            IntegerStyle Style, Optional<size_t> Precision,
225                            Optional<int> Width) {
226   write_unsigned(S, N, Style, Precision, Width);
227 }
228 
229 void llvm::write_longlong(raw_ostream &S, long long N, IntegerStyle Style,
230                           Optional<size_t> Precision, Optional<int> Width) {
231   write_signed(S, N, Style, Precision, Width);
232 }
233 
234 void llvm::write_hex(raw_ostream &S, unsigned long long N, HexStyle Style,
235                      Optional<size_t> Precision, Optional<int> Width) {
236   constexpr size_t kMaxWidth = 128u;
237 
238   size_t Prec =
239       std::min(kMaxWidth, Precision.getValueOr(getDefaultPrecision(Style)));
240 
241   unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
242   bool Prefix =
243       (Style == HexStyle::PrefixLower || Style == HexStyle::PrefixUpper);
244   bool Upper = (Style == HexStyle::Upper || Style == HexStyle::PrefixUpper);
245   unsigned PrefixChars = Prefix ? 2 : 0;
246   unsigned NumChars = std::max(static_cast<unsigned>(Prec),
247                                std::max(1u, Nibbles) + PrefixChars);
248 
249   char NumberBuffer[kMaxWidth];
250   ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
251   if (Prefix)
252     NumberBuffer[1] = 'x';
253   char *EndPtr = NumberBuffer + NumChars;
254   char *CurPtr = EndPtr;
255   while (N) {
256     unsigned char x = static_cast<unsigned char>(N) % 16;
257     *--CurPtr = hexdigit(x, !Upper);
258     N /= 16;
259   }
260 
261   writePadding(S, Width, NumChars);
262   S.write(NumberBuffer, NumChars);
263 }
264 
265 void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
266                         Optional<size_t> Precision, Optional<int> Width) {
267   size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
268 
269   if (std::isnan(N)) {
270     writePadding(S, Width, 3);
271     S << "nan";
272     return;
273   } else if (std::isinf(N)) {
274     writePadding(S, Width, 3);
275     S << "INF";
276     return;
277   }
278 
279   char Letter;
280   if (Style == FloatStyle::Exponent)
281     Letter = 'e';
282   else if (Style == FloatStyle::ExponentUpper)
283     Letter = 'E';
284   else
285     Letter = 'f';
286 
287   SmallString<8> Spec;
288   llvm::raw_svector_ostream Out(Spec);
289   Out << "%." << Prec << Letter;
290 
291   if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
292 #ifdef _WIN32
293 // On MSVCRT and compatible, output of %e is incompatible to Posix
294 // by default. Number of exponent digits should be at least 2. "%+03d"
295 // FIXME: Implement our formatter to here or Support/Format.h!
296 #if defined(__MINGW32__)
297     // FIXME: It should be generic to C++11.
298     if (N == 0.0 && std::signbit(N)) {
299       const char *NegativeZero = "-0.000000e+00";
300       writePadding(S, Width, strlen(NegativeZero));
301       S << NegativeZero;
302       return;
303     }
304 #else
305     int fpcl = _fpclass(N);
306 
307     // negative zero
308     if (fpcl == _FPCLASS_NZ) {
309       const char *NegativeZero = "-0.000000e+00";
310       writePadding(S, Width, strlen(NegativeZero));
311       S << NegativeZero;
312       return;
313     }
314 #endif
315 
316     char buf[32];
317     unsigned len;
318     len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
319     if (len <= sizeof(buf) - 2) {
320       if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
321           buf[len - 3] == '0') {
322         int cs = buf[len - 4];
323         if (cs == '+' || cs == '-') {
324           int c1 = buf[len - 2];
325           int c0 = buf[len - 1];
326           if (isdigit(static_cast<unsigned char>(c1)) &&
327               isdigit(static_cast<unsigned char>(c0))) {
328             // Trim leading '0': "...e+012" -> "...e+12\0"
329             buf[len - 3] = c1;
330             buf[len - 2] = c0;
331             buf[--len] = 0;
332           }
333         }
334       }
335       writePadding(S, Width, len);
336       S << buf;
337       return;
338     }
339 #endif
340   }
341 
342   if (Style == FloatStyle::Percent)
343     N *= 100.0;
344 
345   char Buf[32];
346   unsigned Len;
347   Len = format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
348   if (Style == FloatStyle::Percent)
349     ++Len;
350   writePadding(S, Width, Len);
351   S << Buf;
352   if (Style == FloatStyle::Percent)
353     S << '%';
354 }
355 
356 size_t llvm::getDefaultPrecision(FloatStyle Style) {
357   switch (Style) {
358   case FloatStyle::Exponent:
359   case FloatStyle::ExponentUpper:
360     return 6; // Number of decimal places.
361   case FloatStyle::Fixed:
362   case FloatStyle::Percent:
363     return 2; // Number of decimal places.
364   }
365   LLVM_BUILTIN_UNREACHABLE;
366 }
367 
368 size_t llvm::getDefaultPrecision(IntegerStyle Style) {
369   switch (Style) {
370   case IntegerStyle::Exponent:
371   case IntegerStyle::ExponentUpper:
372     return 6; // Number of decimal places.
373   case IntegerStyle::Number:
374   case IntegerStyle::Integer:
375     return 0; // Minimum number of digits required.
376   case IntegerStyle::Fixed:
377     return 2; // Number of decimal places.
378   case IntegerStyle::Percent:
379     return 0; // Number of decimal places.
380   case IntegerStyle::HexLowerNoPrefix:
381   case IntegerStyle::HexLowerPrefix:
382   case IntegerStyle::HexUpperNoPrefix:
383   case IntegerStyle::HexUpperPrefix:
384     return getDefaultPrecision(intHexStyleToHexStyle(Style));
385   }
386   LLVM_BUILTIN_UNREACHABLE;
387 }
388 
389 size_t llvm::getDefaultPrecision(HexStyle) {
390   // Number of digits in the resulting string.
391   return 0;
392 }
393