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 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