NativeFormatting.cpp 4.9 KB

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