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