161 lines · c
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP___FORMAT_FORMAT_STRING_H11#define _LIBCPP___FORMAT_FORMAT_STRING_H12 13#include <__assert>14#include <__config>15#include <__cstddef/size_t.h>16#include <__format/format_error.h>17#include <__iterator/concepts.h>18#include <__iterator/iterator_traits.h> // iter_value_t19#include <cstdint>20 21#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)22# pragma GCC system_header23#endif24 25_LIBCPP_BEGIN_NAMESPACE_STD26 27#if _LIBCPP_STD_VER >= 2028 29namespace __format {30 31template <contiguous_iterator _Iterator>32struct __parse_number_result {33 _Iterator __last;34 uint32_t __value;35};36 37template <contiguous_iterator _Iterator>38__parse_number_result(_Iterator, uint32_t) -> __parse_number_result<_Iterator>;39 40template <contiguous_iterator _Iterator>41_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> __parse_number(_Iterator __begin, _Iterator __end);42 43/**44 * The maximum value of a numeric argument.45 *46 * This is used for:47 * * arg-id48 * * width as value or arg-id.49 * * precision as value or arg-id.50 *51 * The value is compatible with the maximum formatting width and precision52 * using the `%*` syntax on a 32-bit system.53 */54inline constexpr uint32_t __number_max = INT32_MAX;55 56namespace __detail {57template <contiguous_iterator _Iterator>58_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>59__parse_zero(_Iterator __begin, _Iterator, auto& __parse_ctx) {60 __parse_ctx.check_arg_id(0);61 return {++__begin, 0}; // can never be larger than the maximum.62}63 64template <contiguous_iterator _Iterator>65_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>66__parse_automatic(_Iterator __begin, _Iterator, auto& __parse_ctx) {67 size_t __value = __parse_ctx.next_arg_id();68 _LIBCPP_ASSERT_UNCATEGORIZED(__value <= __number_max, "Compilers don't support this number of arguments");69 70 return {__begin, uint32_t(__value)};71}72 73template <contiguous_iterator _Iterator>74_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>75__parse_manual(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {76 __parse_number_result<_Iterator> __r = __format::__parse_number(__begin, __end);77 __parse_ctx.check_arg_id(__r.__value);78 return __r;79}80 81} // namespace __detail82 83/**84 * Parses a number.85 *86 * The number is used for the 31-bit values @em width and @em precision. This87 * allows a maximum value of 2147483647.88 */89template <contiguous_iterator _Iterator>90_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>91__parse_number(_Iterator __begin, _Iterator __end_input) {92 using _CharT = iter_value_t<_Iterator>;93 static_assert(__format::__number_max == INT32_MAX, "The algorithm is implemented based on this value.");94 /*95 * Limit the input to 9 digits, otherwise we need two checks during every96 * iteration:97 * - Are we at the end of the input?98 * - Does the value exceed width of an uint32_t? (Switching to uint64_t would99 * have the same issue, but with a higher maximum.)100 */101 _Iterator __end = __end_input - __begin > 9 ? __begin + 9 : __end_input;102 uint32_t __value = *__begin - _CharT('0');103 while (++__begin != __end) {104 if (*__begin < _CharT('0') || *__begin > _CharT('9'))105 return {__begin, __value};106 107 __value = __value * 10 + *__begin - _CharT('0');108 }109 110 if (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')) {111 /*112 * There are more than 9 digits, do additional validations:113 * - Does the 10th digit exceed the maximum allowed value?114 * - Are there more than 10 digits?115 * (More than 10 digits always overflows the maximum.)116 */117 uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0');118 if (__v > __number_max || (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')))119 std::__throw_format_error("The numeric value of the format specifier is too large");120 121 __value = __v;122 }123 124 return {__begin, __value};125}126 127/**128 * Multiplexer for all parse functions.129 *130 * The parser will return a pointer beyond the last consumed character. This131 * should be the closing '}' of the arg-id.132 */133template <contiguous_iterator _Iterator>134_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>135__parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {136 using _CharT = iter_value_t<_Iterator>;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 the143 // replacement-field, but not in the std-format-spec. The caller can144 // 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 std::__throw_format_error("The argument index starts with an invalid character");150 151 return __detail::__parse_manual(__begin, __end, __parse_ctx);152}153 154} // namespace __format155 156#endif // _LIBCPP_STD_VER >= 20157 158_LIBCPP_END_NAMESPACE_STD159 160#endif // _LIBCPP___FORMAT_FORMAT_STRING_H161