xref: /aosp_15_r20/external/llvm-libc/src/stdio/printf_core/core_structs.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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_DECL {
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 
type_desc_from_type()109 template <typename T> LIBC_INLINE constexpr TypeDesc type_desc_from_type() {
110   if constexpr (cpp::is_same_v<T, void>) {
111     return TypeDesc{0, 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{sizeof(T), 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 constexpr int ALLOCATION_ERROR = -6;
138 } // namespace printf_core
139 } // namespace LIBC_NAMESPACE_DECL
140 
141 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CORE_STRUCTS_H
142