1 | //===-- Inf or Nan Converter for printf -------------------------*- 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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_INF_NAN_CONVERTER_H |
10 | #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_INF_NAN_CONVERTER_H |
11 | |
12 | #include "src/__support/FPUtil/FPBits.h" |
13 | #include "src/stdio/printf_core/converter_utils.h" |
14 | #include "src/stdio/printf_core/core_structs.h" |
15 | #include "src/stdio/printf_core/writer.h" |
16 | |
17 | #include <inttypes.h> |
18 | #include <stddef.h> |
19 | |
20 | namespace LIBC_NAMESPACE { |
21 | namespace printf_core { |
22 | |
23 | using StorageType = fputil::FPBits<long double>::StorageType; |
24 | |
25 | LIBC_INLINE int convert_inf_nan(Writer *writer, const FormatSection &to_conv) { |
26 | // All of the letters will be defined relative to variable a, which will be |
27 | // the appropriate case based on the case of the conversion. |
28 | const char a = (to_conv.conv_name & 32) | 'A'; |
29 | |
30 | bool is_negative; |
31 | StorageType mantissa; |
32 | if (to_conv.length_modifier == LengthModifier::L) { |
33 | fputil::FPBits<long double>::StorageType float_raw = to_conv.conv_val_raw; |
34 | fputil::FPBits<long double> float_bits(float_raw); |
35 | is_negative = float_bits.is_neg(); |
36 | mantissa = float_bits.get_mantissa(); |
37 | } else { |
38 | fputil::FPBits<double>::StorageType float_raw = |
39 | static_cast<fputil::FPBits<double>::StorageType>(to_conv.conv_val_raw); |
40 | fputil::FPBits<double> float_bits(float_raw); |
41 | is_negative = float_bits.is_neg(); |
42 | mantissa = float_bits.get_mantissa(); |
43 | } |
44 | |
45 | char sign_char = 0; |
46 | |
47 | if (is_negative) |
48 | sign_char = '-'; |
49 | else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) |
50 | sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX |
51 | else if ((to_conv.flags & FormatFlags::SPACE_PREFIX) == |
52 | FormatFlags::SPACE_PREFIX) |
53 | sign_char = ' '; |
54 | |
55 | // Both "inf" and "nan" are the same number of characters, being 3. |
56 | int padding = to_conv.min_width - (sign_char > 0 ? 1 : 0) - 3; |
57 | |
58 | // The right justified pattern is (spaces), (sign), inf/nan |
59 | // The left justified pattern is (sign), inf/nan, (spaces) |
60 | |
61 | if (padding > 0 && ((to_conv.flags & FormatFlags::LEFT_JUSTIFIED) != |
62 | FormatFlags::LEFT_JUSTIFIED)) |
63 | RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); |
64 | |
65 | if (sign_char) |
66 | RET_IF_RESULT_NEGATIVE(writer->write(sign_char)); |
67 | if (mantissa == 0) { // inf |
68 | RET_IF_RESULT_NEGATIVE(writer->write(a == 'a' ? "inf" : "INF" )); |
69 | } else { // nan |
70 | RET_IF_RESULT_NEGATIVE(writer->write(a == 'a' ? "nan" : "NAN" )); |
71 | } |
72 | |
73 | if (padding > 0 && ((to_conv.flags & FormatFlags::LEFT_JUSTIFIED) == |
74 | FormatFlags::LEFT_JUSTIFIED)) |
75 | RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); |
76 | |
77 | return WRITE_OK; |
78 | } |
79 | |
80 | } // namespace printf_core |
81 | } // namespace LIBC_NAMESPACE |
82 | |
83 | #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_INF_NAN_CONVERTER_H |
84 | |