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