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