brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.5 KiB · 61e6ba2 Raw
142 lines · c
1//===-- Implementation header for strfromx() utilitites -------------------===//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// According to the C23 standard, any input character sequences except a10// precision specifier and the usual floating point formats, namely11// %{a,A,e,E,f,F,g,G}, are not allowed and any code that does otherwise results12// in undefined behaviour(including use of a '%%' conversion specifier); which13// in this case is that the buffer string is simply populated with the format14// string. The case of the input being nullptr should be handled in the calling15// function (strfromf, strfromd, strfroml) itself.16 17#ifndef LLVM_LIBC_SRC_STDLIB_STRFROM_UTIL_H18#define LLVM_LIBC_SRC_STDLIB_STRFROM_UTIL_H19 20#include "src/__support/CPP/type_traits.h"21#include "src/__support/macros/config.h"22#include "src/__support/str_to_integer.h"23#include "src/stdio/printf_core/converter_atlas.h"24#include "src/stdio/printf_core/core_structs.h"25#include "src/stdio/printf_core/writer.h"26 27#include <stddef.h>28 29namespace LIBC_NAMESPACE_DECL {30namespace internal {31 32template <typename T>33using storage_type = typename fputil::FPBits<T>::StorageType;34 35template <typename T>36printf_core::FormatSection parse_format_string(const char *__restrict format,37                                               T fp) {38  printf_core::FormatSection section;39  size_t cur_pos = 0;40 41  // There is no typed conversion function to convert single precision float42  // to hex exponential format, and the function convert_float_hex_exp()43  // requires a double or long double value to work correctly.44  // To work around this, we convert fp to double if it is single precision, and45  // then use that double precision value in the %{A, a} conversion specifiers.46  [[maybe_unused]] double new_fp;47  bool t_is_single_prec_type = cpp::is_same<T, float>::value;48  if (t_is_single_prec_type)49    new_fp = (double)fp;50 51  if (format[cur_pos] == '%') {52    section.has_conv = true;53    ++cur_pos;54 55    // handle precision56    section.precision = -1;57    if (format[cur_pos] == '.') {58      ++cur_pos;59      section.precision = 0;60 61      // The standard does not allow the '*' (asterisk) operator for strfromx()62      // functions63      if (internal::isdigit(format[cur_pos])) {64        auto result = internal::strtointeger<int>(format + cur_pos, 10);65        section.precision += result.value;66        cur_pos += result.parsed_len;67      }68    }69 70    section.conv_name = format[cur_pos];71    switch (format[cur_pos]) {72    case 'a':73    case 'A':74      if (t_is_single_prec_type)75        section.conv_val_raw = cpp::bit_cast<storage_type<double>>(new_fp);76      else77        section.conv_val_raw = cpp::bit_cast<storage_type<T>>(fp);78      break;79    case 'e':80    case 'E':81    case 'f':82    case 'F':83    case 'g':84    case 'G':85      section.conv_val_raw = cpp::bit_cast<storage_type<T>>(fp);86      break;87    default:88      section.has_conv = false;89      while (format[cur_pos] != '\0')90        ++cur_pos;91      break;92    }93 94    if (format[cur_pos] != '\0')95      ++cur_pos;96  } else {97    section.has_conv = false;98    // We are looking for exactly one section, so no more '%'99    while (format[cur_pos] != '\0')100      ++cur_pos;101  }102 103  section.raw_string = {format, cur_pos};104  return section;105}106 107template <typename T, printf_core::WriteMode write_mode>108int strfromfloat_convert(printf_core::Writer<write_mode> *writer,109                         const printf_core::FormatSection &section) {110  if (!section.has_conv)111    return writer->write(section.raw_string);112 113  auto res = static_cast<storage_type<T>>(section.conv_val_raw);114 115  fputil::FPBits<T> strfromfloat_bits(res);116  if (strfromfloat_bits.is_inf_or_nan())117    return convert_inf_nan(writer, section);118 119  switch (section.conv_name) {120  case 'f':121  case 'F':122    return convert_float_decimal_typed(writer, section, strfromfloat_bits);123  case 'e':124  case 'E':125    return convert_float_dec_exp_typed(writer, section, strfromfloat_bits);126  case 'a':127  case 'A':128    return convert_float_hex_exp(writer, section);129  case 'g':130  case 'G':131    return convert_float_dec_auto_typed(writer, section, strfromfloat_bits);132  default:133    return writer->write(section.raw_string);134  }135  return -1;136}137 138} // namespace internal139} // namespace LIBC_NAMESPACE_DECL140 141#endif // LLVM_LIBC_SRC_STDLIB_STRFROM_UTIL_H142