NativeFormatting.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/Support/NativeFormatting.h"
  9. #include "llvm/ADT/ArrayRef.h"
  10. #include "llvm/ADT/SmallString.h"
  11. #include "llvm/ADT/StringExtras.h"
  12. #include "llvm/Support/Format.h"
  13. #include "llvm/Support/MathExtras.h"
  14. #include "llvm/Support/raw_ostream.h"
  15. #include <float.h>
  16. using namespace llvm;
  17. template<typename T, std::size_t N>
  18. static int format_to_buffer(T Value, char (&Buffer)[N]) {
  19. char *EndPtr = std::end(Buffer);
  20. char *CurPtr = EndPtr;
  21. do {
  22. *--CurPtr = '0' + char(Value % 10);
  23. Value /= 10;
  24. } while (Value);
  25. return EndPtr - CurPtr;
  26. }
  27. static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
  28. assert(!Buffer.empty());
  29. ArrayRef<char> ThisGroup;
  30. int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
  31. ThisGroup = Buffer.take_front(InitialDigits);
  32. S.write(ThisGroup.data(), ThisGroup.size());
  33. Buffer = Buffer.drop_front(InitialDigits);
  34. assert(Buffer.size() % 3 == 0);
  35. while (!Buffer.empty()) {
  36. S << ',';
  37. ThisGroup = Buffer.take_front(3);
  38. S.write(ThisGroup.data(), 3);
  39. Buffer = Buffer.drop_front(3);
  40. }
  41. }
  42. template <typename T>
  43. static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
  44. IntegerStyle Style, bool IsNegative) {
  45. static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
  46. char NumberBuffer[128];
  47. std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
  48. size_t Len = 0;
  49. Len = format_to_buffer(N, NumberBuffer);
  50. if (IsNegative)
  51. S << '-';
  52. if (Len < MinDigits && Style != IntegerStyle::Number) {
  53. for (size_t I = Len; I < MinDigits; ++I)
  54. S << '0';
  55. }
  56. if (Style == IntegerStyle::Number) {
  57. writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
  58. } else {
  59. S.write(std::end(NumberBuffer) - Len, Len);
  60. }
  61. }
  62. template <typename T>
  63. static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
  64. IntegerStyle Style, bool IsNegative = false) {
  65. // Output using 32-bit div/mod if possible.
  66. if (N == static_cast<uint32_t>(N))
  67. write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
  68. IsNegative);
  69. else
  70. write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
  71. }
  72. template <typename T>
  73. static void write_signed(raw_ostream &S, T N, size_t MinDigits,
  74. IntegerStyle Style) {
  75. static_assert(std::is_signed<T>::value, "Value is not signed!");
  76. using UnsignedT = std::make_unsigned_t<T>;
  77. if (N >= 0) {
  78. write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
  79. return;
  80. }
  81. UnsignedT UN = -(UnsignedT)N;
  82. write_unsigned(S, UN, MinDigits, Style, true);
  83. }
  84. void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
  85. IntegerStyle Style) {
  86. write_unsigned(S, N, MinDigits, Style);
  87. }
  88. void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,
  89. IntegerStyle Style) {
  90. write_signed(S, N, MinDigits, Style);
  91. }
  92. void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
  93. IntegerStyle Style) {
  94. write_unsigned(S, N, MinDigits, Style);
  95. }
  96. void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
  97. IntegerStyle Style) {
  98. write_signed(S, N, MinDigits, Style);
  99. }
  100. void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
  101. IntegerStyle Style) {
  102. write_unsigned(S, N, MinDigits, Style);
  103. }
  104. void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,
  105. IntegerStyle Style) {
  106. write_signed(S, N, MinDigits, Style);
  107. }
  108. void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
  109. Optional<size_t> Width) {
  110. const size_t kMaxWidth = 128u;
  111. size_t W = std::min(kMaxWidth, Width.getValueOr(0u));
  112. unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
  113. bool Prefix = (Style == HexPrintStyle::PrefixLower ||
  114. Style == HexPrintStyle::PrefixUpper);
  115. bool Upper =
  116. (Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
  117. unsigned PrefixChars = Prefix ? 2 : 0;
  118. unsigned NumChars =
  119. std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
  120. char NumberBuffer[kMaxWidth];
  121. ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
  122. if (Prefix)
  123. NumberBuffer[1] = 'x';
  124. char *EndPtr = NumberBuffer + NumChars;
  125. char *CurPtr = EndPtr;
  126. while (N) {
  127. unsigned char x = static_cast<unsigned char>(N) % 16;
  128. *--CurPtr = hexdigit(x, !Upper);
  129. N /= 16;
  130. }
  131. S.write(NumberBuffer, NumChars);
  132. }
  133. void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
  134. Optional<size_t> Precision) {
  135. size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
  136. if (std::isnan(N)) {
  137. S << "nan";
  138. return;
  139. } else if (std::isinf(N)) {
  140. S << (std::signbit(N) ? "-INF" : "INF");
  141. return;
  142. }
  143. char Letter;
  144. if (Style == FloatStyle::Exponent)
  145. Letter = 'e';
  146. else if (Style == FloatStyle::ExponentUpper)
  147. Letter = 'E';
  148. else
  149. Letter = 'f';
  150. SmallString<8> Spec;
  151. llvm::raw_svector_ostream Out(Spec);
  152. Out << "%." << Prec << Letter;
  153. if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
  154. #ifdef _WIN32
  155. // On MSVCRT and compatible, output of %e is incompatible to Posix
  156. // by default. Number of exponent digits should be at least 2. "%+03d"
  157. // FIXME: Implement our formatter to here or Support/Format.h!
  158. #if defined(__MINGW32__)
  159. // FIXME: It should be generic to C++11.
  160. if (N == 0.0 && std::signbit(N)) {
  161. char NegativeZero[] = "-0.000000e+00";
  162. if (Style == FloatStyle::ExponentUpper)
  163. NegativeZero[strlen(NegativeZero) - 4] = 'E';
  164. S << NegativeZero;
  165. return;
  166. }
  167. #else
  168. int fpcl = _fpclass(N);
  169. // negative zero
  170. if (fpcl == _FPCLASS_NZ) {
  171. char NegativeZero[] = "-0.000000e+00";
  172. if (Style == FloatStyle::ExponentUpper)
  173. NegativeZero[strlen(NegativeZero) - 4] = 'E';
  174. S << NegativeZero;
  175. return;
  176. }
  177. #endif
  178. char buf[32];
  179. unsigned len;
  180. len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
  181. if (len <= sizeof(buf) - 2) {
  182. if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
  183. buf[len - 3] == '0') {
  184. int cs = buf[len - 4];
  185. if (cs == '+' || cs == '-') {
  186. int c1 = buf[len - 2];
  187. int c0 = buf[len - 1];
  188. if (isdigit(static_cast<unsigned char>(c1)) &&
  189. isdigit(static_cast<unsigned char>(c0))) {
  190. // Trim leading '0': "...e+012" -> "...e+12\0"
  191. buf[len - 3] = c1;
  192. buf[len - 2] = c0;
  193. buf[--len] = 0;
  194. }
  195. }
  196. }
  197. S << buf;
  198. return;
  199. }
  200. #endif
  201. }
  202. if (Style == FloatStyle::Percent)
  203. N *= 100.0;
  204. char Buf[32];
  205. format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
  206. S << Buf;
  207. if (Style == FloatStyle::Percent)
  208. S << '%';
  209. }
  210. bool llvm::isPrefixedHexStyle(HexPrintStyle S) {
  211. return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
  212. }
  213. size_t llvm::getDefaultPrecision(FloatStyle Style) {
  214. switch (Style) {
  215. case FloatStyle::Exponent:
  216. case FloatStyle::ExponentUpper:
  217. return 6; // Number of decimal places.
  218. case FloatStyle::Fixed:
  219. case FloatStyle::Percent:
  220. return 2; // Number of decimal places.
  221. }
  222. LLVM_BUILTIN_UNREACHABLE;
  223. }