1 | //===-- Core Structures 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_CORE_STRUCTS_H |
10 | #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CORE_STRUCTS_H |
11 | |
12 | #include "src/__support/macros/config.h" |
13 | |
14 | #include "src/__support/CPP/string_view.h" |
15 | #include "src/__support/CPP/type_traits.h" |
16 | #include "src/__support/FPUtil/FPBits.h" |
17 | #include "src/stdio/printf_core/printf_config.h" |
18 | |
19 | #include <inttypes.h> |
20 | #include <stddef.h> |
21 | |
22 | namespace LIBC_NAMESPACE { |
23 | namespace printf_core { |
24 | |
25 | // These length modifiers match the length modifiers in the format string, which |
26 | // is why they are formatted differently from the rest of the file. |
27 | enum class LengthModifier { hh, h, l, ll, j, z, t, L, w, wf, none }; |
28 | |
29 | struct LengthSpec { |
30 | LengthModifier lm; |
31 | size_t bit_width; |
32 | }; |
33 | |
34 | enum FormatFlags : uint8_t { |
35 | LEFT_JUSTIFIED = 0x01, // - |
36 | FORCE_SIGN = 0x02, // + |
37 | SPACE_PREFIX = 0x04, // space |
38 | ALTERNATE_FORM = 0x08, // # |
39 | LEADING_ZEROES = 0x10, // 0 |
40 | |
41 | // These flags come from the GNU extensions which aren't yet implemented. |
42 | // group_decimals = 0x20, // ' |
43 | // locale_digits = 0x40, // I |
44 | }; |
45 | |
46 | struct FormatSection { |
47 | bool has_conv; |
48 | |
49 | cpp::string_view raw_string; |
50 | |
51 | // Format Specifier Values |
52 | FormatFlags flags = FormatFlags(0); |
53 | LengthModifier length_modifier = LengthModifier::none; |
54 | size_t bit_width = 0; |
55 | int min_width = 0; |
56 | int precision = -1; |
57 | |
58 | // Needs to be large enough to hold a long double. |
59 | fputil::FPBits<long double>::StorageType conv_val_raw; |
60 | void *conv_val_ptr; |
61 | |
62 | char conv_name; |
63 | |
64 | // This operator is only used for testing and should be automatically |
65 | // optimized out for release builds. |
66 | LIBC_INLINE bool operator==(const FormatSection &other) const { |
67 | if (has_conv != other.has_conv) |
68 | return false; |
69 | |
70 | if (raw_string != other.raw_string) |
71 | return false; |
72 | |
73 | if (has_conv) { |
74 | if (!((static_cast<uint8_t>(flags) == |
75 | static_cast<uint8_t>(other.flags)) && |
76 | (min_width == other.min_width) && (precision == other.precision) && |
77 | (bit_width == other.bit_width) && |
78 | (length_modifier == other.length_modifier) && |
79 | (conv_name == other.conv_name))) |
80 | return false; |
81 | |
82 | if (conv_name == 'p' || conv_name == 'n' || conv_name == 's') |
83 | return (conv_val_ptr == other.conv_val_ptr); |
84 | else if (conv_name != '%') |
85 | return (conv_val_raw == other.conv_val_raw); |
86 | } |
87 | return true; |
88 | } |
89 | }; |
90 | |
91 | enum PrimaryType : uint8_t { |
92 | Unknown = 0, |
93 | Float = 1, |
94 | Pointer = 2, |
95 | Integer = 3, |
96 | FixedPoint = 4, |
97 | }; |
98 | |
99 | // TypeDesc stores the information about a type that is relevant to printf in |
100 | // a relatively compact manner. |
101 | struct TypeDesc { |
102 | uint8_t size; |
103 | PrimaryType primary_type; |
104 | LIBC_INLINE constexpr bool operator==(const TypeDesc &other) const { |
105 | return (size == other.size) && (primary_type == other.primary_type); |
106 | } |
107 | }; |
108 | |
109 | template <typename T> LIBC_INLINE constexpr TypeDesc type_desc_from_type() { |
110 | if constexpr (cpp::is_same_v<T, void>) { |
111 | return TypeDesc{.size: 0, .primary_type: PrimaryType::Unknown}; |
112 | } else { |
113 | constexpr bool IS_POINTER = cpp::is_pointer_v<T>; |
114 | constexpr bool IS_FLOAT = cpp::is_floating_point_v<T>; |
115 | #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT |
116 | constexpr bool IS_FIXED_POINT = cpp::is_fixed_point_v<T>; |
117 | #else |
118 | constexpr bool IS_FIXED_POINT = false; |
119 | #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT |
120 | |
121 | return TypeDesc{.size: sizeof(T), .primary_type: IS_POINTER ? PrimaryType::Pointer |
122 | : IS_FLOAT ? PrimaryType::Float |
123 | : IS_FIXED_POINT ? PrimaryType::FixedPoint |
124 | : PrimaryType::Integer}; |
125 | } |
126 | } |
127 | |
128 | // This is the value to be returned by conversions when no error has occurred. |
129 | constexpr int WRITE_OK = 0; |
130 | // These are the printf return values for when an error has occurred. They are |
131 | // all negative, and should be distinct. |
132 | constexpr int FILE_WRITE_ERROR = -1; |
133 | constexpr int FILE_STATUS_ERROR = -2; |
134 | constexpr int NULLPTR_WRITE_ERROR = -3; |
135 | constexpr int INT_CONVERSION_ERROR = -4; |
136 | constexpr int FIXED_POINT_CONVERSION_ERROR = -5; |
137 | |
138 | } // namespace printf_core |
139 | } // namespace LIBC_NAMESPACE |
140 | |
141 | #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CORE_STRUCTS_H |
142 | |