1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___FORMAT_FORMAT_STRING_H 11 #define _LIBCPP___FORMAT_FORMAT_STRING_H 12 13 #include <__assert> 14 #include <__config> 15 #include <__format/format_error.h> 16 #include <cstddef> 17 #include <cstdint> 18 19 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 20 # pragma GCC system_header 21 #endif 22 23 _LIBCPP_BEGIN_NAMESPACE_STD 24 25 #if _LIBCPP_STD_VER > 17 26 27 namespace __format { 28 29 template <class _CharT> 30 struct _LIBCPP_TEMPLATE_VIS __parse_number_result { 31 const _CharT* __ptr; 32 uint32_t __value; 33 }; 34 35 template <class _CharT> 36 _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT> 37 __parse_number(const _CharT* __begin, const _CharT* __end); 38 39 /** 40 * The maximum value of a numeric argument. 41 * 42 * This is used for: 43 * * arg-id 44 * * width as value or arg-id. 45 * * precision as value or arg-id. 46 * 47 * The value is compatible with the maximum formatting width and precision 48 * using the `%*` syntax on a 32-bit system. 49 */ 50 inline constexpr uint32_t __number_max = INT32_MAX; 51 52 namespace __detail { 53 template <class _CharT> 54 _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT> 55 __parse_zero(const _CharT* __begin, const _CharT*, auto& __parse_ctx) { 56 __parse_ctx.check_arg_id(0); 57 return {++__begin, 0}; // can never be larger than the maximum. 58 } 59 60 template <class _CharT> 61 _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT> 62 __parse_automatic(const _CharT* __begin, const _CharT*, auto& __parse_ctx) { 63 size_t __value = __parse_ctx.next_arg_id(); 64 _LIBCPP_ASSERT(__value <= __number_max, 65 "Compilers don't support this number of arguments"); 66 67 return {__begin, uint32_t(__value)}; 68 } 69 70 template <class _CharT> 71 _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT> 72 __parse_manual(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) { 73 __parse_number_result<_CharT> __r = __parse_number(__begin, __end); 74 __parse_ctx.check_arg_id(__r.__value); 75 return __r; 76 } 77 78 } // namespace __detail 79 80 /** 81 * Parses a number. 82 * 83 * The number is used for the 31-bit values @em width and @em precision. This 84 * allows a maximum value of 2147483647. 85 */ 86 template <class _CharT> 87 _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT> 88 __parse_number(const _CharT* __begin, const _CharT* __end_input) { 89 static_assert(__format::__number_max == INT32_MAX, 90 "The algorithm is implemented based on this value."); 91 /* 92 * Limit the input to 9 digits, otherwise we need two checks during every 93 * iteration: 94 * - Are we at the end of the input? 95 * - Does the value exceed width of an uint32_t? (Switching to uint64_t would 96 * have the same issue, but with a higher maximum.) 97 */ 98 const _CharT* __end = __end_input - __begin > 9 ? __begin + 9 : __end_input; 99 uint32_t __value = *__begin - _CharT('0'); 100 while (++__begin != __end) { 101 if (*__begin < _CharT('0') || *__begin > _CharT('9')) 102 return {__begin, __value}; 103 104 __value = __value * 10 + *__begin - _CharT('0'); 105 } 106 107 if (__begin != __end_input && *__begin >= _CharT('0') && 108 *__begin <= _CharT('9')) { 109 110 /* 111 * There are more than 9 digits, do additional validations: 112 * - Does the 10th digit exceed the maximum allowed value? 113 * - Are there more than 10 digits? 114 * (More than 10 digits always overflows the maximum.) 115 */ 116 uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0'); 117 if (__v > __number_max || 118 (__begin != __end_input && *__begin >= _CharT('0') && 119 *__begin <= _CharT('9'))) 120 __throw_format_error("The numeric value of the format-spec is too large"); 121 122 __value = __v; 123 } 124 125 return {__begin, __value}; 126 } 127 128 /** 129 * Multiplexer for all parse functions. 130 * 131 * The parser will return a pointer beyond the last consumed character. This 132 * should be the closing '}' of the arg-id. 133 */ 134 template <class _CharT> 135 _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT> 136 __parse_arg_id(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) { 137 switch (*__begin) { 138 case _CharT('0'): 139 return __detail::__parse_zero(__begin, __end, __parse_ctx); 140 141 case _CharT(':'): 142 // This case is conditionally valid. It's allowed in an arg-id in the 143 // replacement-field, but not in the std-format-spec. The caller can 144 // provide a better diagnostic, so accept it here unconditionally. 145 case _CharT('}'): 146 return __detail::__parse_automatic(__begin, __end, __parse_ctx); 147 } 148 if (*__begin < _CharT('0') || *__begin > _CharT('9')) 149 __throw_format_error( 150 "The arg-id of the format-spec starts with an invalid character"); 151 152 return __detail::__parse_manual(__begin, __end, __parse_ctx); 153 } 154 155 } // namespace __format 156 157 #endif //_LIBCPP_STD_VER > 17 158 159 _LIBCPP_END_NAMESPACE_STD 160 161 #endif // _LIBCPP___FORMAT_FORMAT_STRING_H 162