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