brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.6 KiB · 7a64730 Raw
265 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/NativeFormatting.h"10#include "llvm/ADT/ArrayRef.h"11#include "llvm/ADT/SmallString.h"12#include "llvm/ADT/StringExtras.h"13#include "llvm/Support/Format.h"14#include "llvm/Support/raw_ostream.h"15 16#include <cmath>17 18#if defined(_WIN32) && !defined(__MINGW32__)19#include <float.h> // For _fpclass in llvm::write_double.20#endif21 22using namespace llvm;23 24template<typename T, std::size_t N>25static int format_to_buffer(T Value, char (&Buffer)[N]) {26  char *EndPtr = std::end(Buffer);27  char *CurPtr = EndPtr;28 29  do {30    *--CurPtr = '0' + char(Value % 10);31    Value /= 10;32  } while (Value);33  return EndPtr - CurPtr;34}35 36static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {37  assert(!Buffer.empty());38 39  ArrayRef<char> ThisGroup;40  int InitialDigits = ((Buffer.size() - 1) % 3) + 1;41  ThisGroup = Buffer.take_front(InitialDigits);42  S.write(ThisGroup.data(), ThisGroup.size());43 44  Buffer = Buffer.drop_front(InitialDigits);45  assert(Buffer.size() % 3 == 0);46  while (!Buffer.empty()) {47    S << ',';48    ThisGroup = Buffer.take_front(3);49    S.write(ThisGroup.data(), 3);50    Buffer = Buffer.drop_front(3);51  }52}53 54template <typename T>55static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,56                                IntegerStyle Style, bool IsNegative) {57  static_assert(std::is_unsigned_v<T>, "Value is not unsigned!");58 59  char NumberBuffer[128];60  size_t 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 77template <typename T>78static 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  else85    write_unsigned_impl(S, N, MinDigits, Style, IsNegative);86}87 88template <typename T>89static void write_signed(raw_ostream &S, T N, size_t MinDigits,90                         IntegerStyle Style) {91  static_assert(std::is_signed_v<T>, "Value is not signed!");92 93  using UnsignedT = std::make_unsigned_t<T>;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 104void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,105                         IntegerStyle Style) {106  write_unsigned(S, N, MinDigits, Style);107}108 109void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,110                         IntegerStyle Style) {111  write_signed(S, N, MinDigits, Style);112}113 114void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,115                         IntegerStyle Style) {116  write_unsigned(S, N, MinDigits, Style);117}118 119void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,120                         IntegerStyle Style) {121  write_signed(S, N, MinDigits, Style);122}123 124void 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 129void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,130                         IntegerStyle Style) {131  write_signed(S, N, MinDigits, Style);132}133 134void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,135                     std::optional<size_t> Width) {136  const size_t kMaxWidth = 128u;137 138  size_t W = std::min(kMaxWidth, Width.value_or(0u));139 140  unsigned Nibbles = (llvm::bit_width(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', std::size(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 164void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,165                        std::optional<size_t> Precision) {166  size_t Prec = Precision.value_or(getDefaultPrecision(Style));167 168  if (std::isnan(N)) {169    S << "nan";170    return;171  } else if (std::isinf(N)) {172    S << (std::signbit(N) ? "-INF" : "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  else182    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 _WIN32190// On MSVCRT and compatible, output of %e is incompatible to Posix191// 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#else203    int fpcl = _fpclass(N);204 205    // negative zero206    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#endif214 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#endif238  }239 240  if (Style == FloatStyle::Percent)241    N *= 100.0;242 243  char Buf[32];244  format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));245  S << Buf;246  if (Style == FloatStyle::Percent)247    S << '%';248}249 250bool llvm::isPrefixedHexStyle(HexPrintStyle S) {251  return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);252}253 254size_t llvm::getDefaultPrecision(FloatStyle Style) {255  switch (Style) {256  case FloatStyle::Exponent:257  case FloatStyle::ExponentUpper:258    return 6; // Number of decimal places.259  case FloatStyle::Fixed:260  case FloatStyle::Percent:261    return 2; // Number of decimal places.262  }263  llvm_unreachable("Unknown FloatStyle enum");264}265