xref: /aosp_15_r20/external/llvm-libc/src/stdlib/str_from_util.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1*71db0c75SAndroid Build Coastguard Worker //===-- Implementation header for strfromx() utilitites -------------------===//
2*71db0c75SAndroid Build Coastguard Worker //
3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*71db0c75SAndroid Build Coastguard Worker //
7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*71db0c75SAndroid Build Coastguard Worker 
9*71db0c75SAndroid Build Coastguard Worker // According to the C23 standard, any input character sequences except a
10*71db0c75SAndroid Build Coastguard Worker // precision specifier and the usual floating point formats, namely
11*71db0c75SAndroid Build Coastguard Worker // %{a,A,e,E,f,F,g,G}, are not allowed and any code that does otherwise results
12*71db0c75SAndroid Build Coastguard Worker // in undefined behaviour(including use of a '%%' conversion specifier); which
13*71db0c75SAndroid Build Coastguard Worker // in this case is that the buffer string is simply populated with the format
14*71db0c75SAndroid Build Coastguard Worker // string. The case of the input being nullptr should be handled in the calling
15*71db0c75SAndroid Build Coastguard Worker // function (strfromf, strfromd, strfroml) itself.
16*71db0c75SAndroid Build Coastguard Worker 
17*71db0c75SAndroid Build Coastguard Worker #ifndef LLVM_LIBC_SRC_STDLIB_STRFROM_UTIL_H
18*71db0c75SAndroid Build Coastguard Worker #define LLVM_LIBC_SRC_STDLIB_STRFROM_UTIL_H
19*71db0c75SAndroid Build Coastguard Worker 
20*71db0c75SAndroid Build Coastguard Worker #include "src/__support/CPP/type_traits.h"
21*71db0c75SAndroid Build Coastguard Worker #include "src/__support/macros/config.h"
22*71db0c75SAndroid Build Coastguard Worker #include "src/__support/str_to_integer.h"
23*71db0c75SAndroid Build Coastguard Worker #include "src/stdio/printf_core/converter_atlas.h"
24*71db0c75SAndroid Build Coastguard Worker #include "src/stdio/printf_core/core_structs.h"
25*71db0c75SAndroid Build Coastguard Worker #include "src/stdio/printf_core/writer.h"
26*71db0c75SAndroid Build Coastguard Worker 
27*71db0c75SAndroid Build Coastguard Worker #include <stddef.h>
28*71db0c75SAndroid Build Coastguard Worker 
29*71db0c75SAndroid Build Coastguard Worker namespace LIBC_NAMESPACE_DECL {
30*71db0c75SAndroid Build Coastguard Worker namespace internal {
31*71db0c75SAndroid Build Coastguard Worker 
32*71db0c75SAndroid Build Coastguard Worker template <typename T>
33*71db0c75SAndroid Build Coastguard Worker using storage_type = typename fputil::FPBits<T>::StorageType;
34*71db0c75SAndroid Build Coastguard Worker 
35*71db0c75SAndroid Build Coastguard Worker template <typename T>
parse_format_string(const char * __restrict format,T fp)36*71db0c75SAndroid Build Coastguard Worker printf_core::FormatSection parse_format_string(const char *__restrict format,
37*71db0c75SAndroid Build Coastguard Worker                                                T fp) {
38*71db0c75SAndroid Build Coastguard Worker   printf_core::FormatSection section;
39*71db0c75SAndroid Build Coastguard Worker   size_t cur_pos = 0;
40*71db0c75SAndroid Build Coastguard Worker 
41*71db0c75SAndroid Build Coastguard Worker   // There is no typed conversion function to convert single precision float
42*71db0c75SAndroid Build Coastguard Worker   // to hex exponential format, and the function convert_float_hex_exp()
43*71db0c75SAndroid Build Coastguard Worker   // requires a double or long double value to work correctly.
44*71db0c75SAndroid Build Coastguard Worker   // To work around this, we convert fp to double if it is single precision, and
45*71db0c75SAndroid Build Coastguard Worker   // then use that double precision value in the %{A, a} conversion specifiers.
46*71db0c75SAndroid Build Coastguard Worker   [[maybe_unused]] double new_fp;
47*71db0c75SAndroid Build Coastguard Worker   bool t_is_single_prec_type = cpp::is_same<T, float>::value;
48*71db0c75SAndroid Build Coastguard Worker   if (t_is_single_prec_type)
49*71db0c75SAndroid Build Coastguard Worker     new_fp = (double)fp;
50*71db0c75SAndroid Build Coastguard Worker 
51*71db0c75SAndroid Build Coastguard Worker   if (format[cur_pos] == '%') {
52*71db0c75SAndroid Build Coastguard Worker     section.has_conv = true;
53*71db0c75SAndroid Build Coastguard Worker     ++cur_pos;
54*71db0c75SAndroid Build Coastguard Worker 
55*71db0c75SAndroid Build Coastguard Worker     // handle precision
56*71db0c75SAndroid Build Coastguard Worker     section.precision = -1;
57*71db0c75SAndroid Build Coastguard Worker     if (format[cur_pos] == '.') {
58*71db0c75SAndroid Build Coastguard Worker       ++cur_pos;
59*71db0c75SAndroid Build Coastguard Worker       section.precision = 0;
60*71db0c75SAndroid Build Coastguard Worker 
61*71db0c75SAndroid Build Coastguard Worker       // The standard does not allow the '*' (asterisk) operator for strfromx()
62*71db0c75SAndroid Build Coastguard Worker       // functions
63*71db0c75SAndroid Build Coastguard Worker       if (internal::isdigit(format[cur_pos])) {
64*71db0c75SAndroid Build Coastguard Worker         auto result = internal::strtointeger<int>(format + cur_pos, 10);
65*71db0c75SAndroid Build Coastguard Worker         section.precision += result.value;
66*71db0c75SAndroid Build Coastguard Worker         cur_pos += result.parsed_len;
67*71db0c75SAndroid Build Coastguard Worker       }
68*71db0c75SAndroid Build Coastguard Worker     }
69*71db0c75SAndroid Build Coastguard Worker 
70*71db0c75SAndroid Build Coastguard Worker     section.conv_name = format[cur_pos];
71*71db0c75SAndroid Build Coastguard Worker     switch (format[cur_pos]) {
72*71db0c75SAndroid Build Coastguard Worker     case 'a':
73*71db0c75SAndroid Build Coastguard Worker     case 'A':
74*71db0c75SAndroid Build Coastguard Worker       if (t_is_single_prec_type)
75*71db0c75SAndroid Build Coastguard Worker         section.conv_val_raw = cpp::bit_cast<storage_type<double>>(new_fp);
76*71db0c75SAndroid Build Coastguard Worker       else
77*71db0c75SAndroid Build Coastguard Worker         section.conv_val_raw = cpp::bit_cast<storage_type<T>>(fp);
78*71db0c75SAndroid Build Coastguard Worker       break;
79*71db0c75SAndroid Build Coastguard Worker     case 'e':
80*71db0c75SAndroid Build Coastguard Worker     case 'E':
81*71db0c75SAndroid Build Coastguard Worker     case 'f':
82*71db0c75SAndroid Build Coastguard Worker     case 'F':
83*71db0c75SAndroid Build Coastguard Worker     case 'g':
84*71db0c75SAndroid Build Coastguard Worker     case 'G':
85*71db0c75SAndroid Build Coastguard Worker       section.conv_val_raw = cpp::bit_cast<storage_type<T>>(fp);
86*71db0c75SAndroid Build Coastguard Worker       break;
87*71db0c75SAndroid Build Coastguard Worker     default:
88*71db0c75SAndroid Build Coastguard Worker       section.has_conv = false;
89*71db0c75SAndroid Build Coastguard Worker       while (format[cur_pos] != '\0')
90*71db0c75SAndroid Build Coastguard Worker         ++cur_pos;
91*71db0c75SAndroid Build Coastguard Worker       break;
92*71db0c75SAndroid Build Coastguard Worker     }
93*71db0c75SAndroid Build Coastguard Worker 
94*71db0c75SAndroid Build Coastguard Worker     if (format[cur_pos] != '\0')
95*71db0c75SAndroid Build Coastguard Worker       ++cur_pos;
96*71db0c75SAndroid Build Coastguard Worker   } else {
97*71db0c75SAndroid Build Coastguard Worker     section.has_conv = false;
98*71db0c75SAndroid Build Coastguard Worker     // We are looking for exactly one section, so no more '%'
99*71db0c75SAndroid Build Coastguard Worker     while (format[cur_pos] != '\0')
100*71db0c75SAndroid Build Coastguard Worker       ++cur_pos;
101*71db0c75SAndroid Build Coastguard Worker   }
102*71db0c75SAndroid Build Coastguard Worker 
103*71db0c75SAndroid Build Coastguard Worker   section.raw_string = {format, cur_pos};
104*71db0c75SAndroid Build Coastguard Worker   return section;
105*71db0c75SAndroid Build Coastguard Worker }
106*71db0c75SAndroid Build Coastguard Worker 
107*71db0c75SAndroid Build Coastguard Worker template <typename T>
strfromfloat_convert(printf_core::Writer * writer,const printf_core::FormatSection & section)108*71db0c75SAndroid Build Coastguard Worker int strfromfloat_convert(printf_core::Writer *writer,
109*71db0c75SAndroid Build Coastguard Worker                          const printf_core::FormatSection &section) {
110*71db0c75SAndroid Build Coastguard Worker   if (!section.has_conv)
111*71db0c75SAndroid Build Coastguard Worker     return writer->write(section.raw_string);
112*71db0c75SAndroid Build Coastguard Worker 
113*71db0c75SAndroid Build Coastguard Worker   auto res = static_cast<storage_type<T>>(section.conv_val_raw);
114*71db0c75SAndroid Build Coastguard Worker 
115*71db0c75SAndroid Build Coastguard Worker   fputil::FPBits<T> strfromfloat_bits(res);
116*71db0c75SAndroid Build Coastguard Worker   if (strfromfloat_bits.is_inf_or_nan())
117*71db0c75SAndroid Build Coastguard Worker     return convert_inf_nan(writer, section);
118*71db0c75SAndroid Build Coastguard Worker 
119*71db0c75SAndroid Build Coastguard Worker   switch (section.conv_name) {
120*71db0c75SAndroid Build Coastguard Worker   case 'f':
121*71db0c75SAndroid Build Coastguard Worker   case 'F':
122*71db0c75SAndroid Build Coastguard Worker     return convert_float_decimal_typed(writer, section, strfromfloat_bits);
123*71db0c75SAndroid Build Coastguard Worker   case 'e':
124*71db0c75SAndroid Build Coastguard Worker   case 'E':
125*71db0c75SAndroid Build Coastguard Worker     return convert_float_dec_exp_typed(writer, section, strfromfloat_bits);
126*71db0c75SAndroid Build Coastguard Worker   case 'a':
127*71db0c75SAndroid Build Coastguard Worker   case 'A':
128*71db0c75SAndroid Build Coastguard Worker     return convert_float_hex_exp(writer, section);
129*71db0c75SAndroid Build Coastguard Worker   case 'g':
130*71db0c75SAndroid Build Coastguard Worker   case 'G':
131*71db0c75SAndroid Build Coastguard Worker     return convert_float_dec_auto_typed(writer, section, strfromfloat_bits);
132*71db0c75SAndroid Build Coastguard Worker   default:
133*71db0c75SAndroid Build Coastguard Worker     return writer->write(section.raw_string);
134*71db0c75SAndroid Build Coastguard Worker   }
135*71db0c75SAndroid Build Coastguard Worker   return -1;
136*71db0c75SAndroid Build Coastguard Worker }
137*71db0c75SAndroid Build Coastguard Worker 
138*71db0c75SAndroid Build Coastguard Worker } // namespace internal
139*71db0c75SAndroid Build Coastguard Worker } // namespace LIBC_NAMESPACE_DECL
140*71db0c75SAndroid Build Coastguard Worker 
141*71db0c75SAndroid Build Coastguard Worker #endif // LLVM_LIBC_SRC_STDLIB_STRFROM_UTIL_H
142