blob: 84f6c390b028073f5a142c74a2156048ea571afd [file] [log] [blame]
Zachary Turner733be512016-10-11 19:24:45 +00001//===- 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
16using namespace llvm;
17
18template<typename T, std::size_t N>
19static 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
30void 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
47void 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
66void 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
82void 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
102void 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(MinWidth, std::max(1u, Nibbles) + PrefixChars);
107
108 char NumberBuffer[20] = "0x0000000000000000";
109 if (!Prefix)
110 NumberBuffer[1] = '0';
111 char *EndPtr = NumberBuffer + Width;
112 char *CurPtr = EndPtr;
113 while (N) {
114 unsigned char x = static_cast<unsigned char>(N) % 16;
115 *--CurPtr = hexdigit(x, !Upper);
116 N /= 16;
117 }
118
119 S.write(NumberBuffer, Width);
120}
121
122void llvm::write_double(raw_ostream &S, double N, std::size_t MinWidth,
123 std::size_t MinDecimals, FloatStyle Style) {
124 char Letter = (Style == FloatStyle::Exponent) ? 'e' : 'f';
125 SmallString<8> Spec;
126 llvm::raw_svector_ostream Out(Spec);
127 Out << '%';
128 if (MinWidth > 0)
129 Out << MinWidth;
130 if (MinDecimals > 0)
131 Out << '.' << MinDecimals;
132 Out << Letter;
133
134 if (Style == FloatStyle::Exponent) {
135#ifdef _WIN32
136// On MSVCRT and compatible, output of %e is incompatible to Posix
137// by default. Number of exponent digits should be at least 2. "%+03d"
138// FIXME: Implement our formatter to here or Support/Format.h!
139#if defined(__MINGW32__)
140 // FIXME: It should be generic to C++11.
141 if (N == 0.0 && std::signbit(N)) {
142 S << "-0.000000e+00";
143 return;
144 }
145#else
146 int fpcl = _fpclass(N);
147
148 // negative zero
149 if (fpcl == _FPCLASS_NZ) {
150 S << "-0.000000e+00";
151 return;
152 }
153#endif
154
155 char buf[16];
156 unsigned len;
157 len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
158 if (len <= sizeof(buf) - 2) {
159 if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') {
160 int cs = buf[len - 4];
161 if (cs == '+' || cs == '-') {
162 int c1 = buf[len - 2];
163 int c0 = buf[len - 1];
164 if (isdigit(static_cast<unsigned char>(c1)) &&
165 isdigit(static_cast<unsigned char>(c0))) {
166 // Trim leading '0': "...e+012" -> "...e+12\0"
167 buf[len - 3] = c1;
168 buf[len - 2] = c0;
169 buf[--len] = 0;
170 }
171 }
172 }
173 S << buf;
174 return;
175 }
176#endif
177 }
178
179 S << format(Spec.c_str(), N);
180}