xref: /llvm-project/libc/src/stdio/printf_core/float_inf_nan_converter.h (revision a0c4f854cad2b97e44a1b58dc1fd982e1c4d60f3)
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/ctype_utils.h"
14 #include "src/__support/macros/config.h"
15 #include "src/stdio/printf_core/converter_utils.h"
16 #include "src/stdio/printf_core/core_structs.h"
17 #include "src/stdio/printf_core/writer.h"
18 
19 #include <inttypes.h>
20 #include <stddef.h>
21 
22 namespace LIBC_NAMESPACE_DECL {
23 namespace printf_core {
24 
25 using StorageType = fputil::FPBits<long double>::StorageType;
26 
27 LIBC_INLINE int convert_inf_nan(Writer *writer, const FormatSection &to_conv) {
28   // All of the letters will be defined relative to variable a, which will be
29   // the appropriate case based on the case of the conversion.
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(
69         writer->write(internal::islower(to_conv.conv_name) ? "inf" : "INF"));
70   } else { // nan
71     RET_IF_RESULT_NEGATIVE(
72         writer->write(internal::islower(to_conv.conv_name) ? "nan" : "NAN"));
73   }
74 
75   if (padding > 0 && ((to_conv.flags & FormatFlags::LEFT_JUSTIFIED) ==
76                       FormatFlags::LEFT_JUSTIFIED))
77     RET_IF_RESULT_NEGATIVE(writer->write(' ', padding));
78 
79   return WRITE_OK;
80 }
81 
82 } // namespace printf_core
83 } // namespace LIBC_NAMESPACE_DECL
84 
85 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_INF_NAN_CONVERTER_H
86