1349cc55cSDimitry Andric // -*- C++ -*-
2349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
3349cc55cSDimitry Andric //
4349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7349cc55cSDimitry Andric //
8349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
9349cc55cSDimitry Andric
10349cc55cSDimitry Andric #ifndef _LIBCPP___FORMAT_FORMAT_STRING_H
11349cc55cSDimitry Andric #define _LIBCPP___FORMAT_FORMAT_STRING_H
12349cc55cSDimitry Andric
1381ad6265SDimitry Andric #include <__assert>
14349cc55cSDimitry Andric #include <__config>
15349cc55cSDimitry Andric #include <__format/format_error.h>
1606c3fb27SDimitry Andric #include <__iterator/concepts.h>
1706c3fb27SDimitry Andric #include <__iterator/iterator_traits.h> // iter_value_t
18349cc55cSDimitry Andric #include <cstddef>
19349cc55cSDimitry Andric #include <cstdint>
20349cc55cSDimitry Andric
21349cc55cSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22349cc55cSDimitry Andric # pragma GCC system_header
23349cc55cSDimitry Andric #endif
24349cc55cSDimitry Andric
25349cc55cSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
26349cc55cSDimitry Andric
2706c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
28349cc55cSDimitry Andric
29349cc55cSDimitry Andric namespace __format {
30349cc55cSDimitry Andric
3106c3fb27SDimitry Andric template <contiguous_iterator _Iterator>
32349cc55cSDimitry Andric struct _LIBCPP_TEMPLATE_VIS __parse_number_result {
3306c3fb27SDimitry Andric _Iterator __last;
34349cc55cSDimitry Andric uint32_t __value;
35349cc55cSDimitry Andric };
36349cc55cSDimitry Andric
3706c3fb27SDimitry Andric template <contiguous_iterator _Iterator>
3806c3fb27SDimitry Andric __parse_number_result(_Iterator, uint32_t) -> __parse_number_result<_Iterator>;
39bdd1243dSDimitry Andric
4006c3fb27SDimitry Andric template <contiguous_iterator _Iterator>
41*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> __parse_number(_Iterator __begin, _Iterator __end);
42349cc55cSDimitry Andric
43349cc55cSDimitry Andric /**
44349cc55cSDimitry Andric * The maximum value of a numeric argument.
45349cc55cSDimitry Andric *
46349cc55cSDimitry Andric * This is used for:
47349cc55cSDimitry Andric * * arg-id
48349cc55cSDimitry Andric * * width as value or arg-id.
49349cc55cSDimitry Andric * * precision as value or arg-id.
50349cc55cSDimitry Andric *
51349cc55cSDimitry Andric * The value is compatible with the maximum formatting width and precision
52349cc55cSDimitry Andric * using the `%*` syntax on a 32-bit system.
53349cc55cSDimitry Andric */
54349cc55cSDimitry Andric inline constexpr uint32_t __number_max = INT32_MAX;
55349cc55cSDimitry Andric
56349cc55cSDimitry Andric namespace __detail {
5706c3fb27SDimitry Andric template <contiguous_iterator _Iterator>
5806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
__parse_zero(_Iterator __begin,_Iterator,auto & __parse_ctx)5906c3fb27SDimitry Andric __parse_zero(_Iterator __begin, _Iterator, auto& __parse_ctx) {
60349cc55cSDimitry Andric __parse_ctx.check_arg_id(0);
61349cc55cSDimitry Andric return {++__begin, 0}; // can never be larger than the maximum.
62349cc55cSDimitry Andric }
63349cc55cSDimitry Andric
6406c3fb27SDimitry Andric template <contiguous_iterator _Iterator>
6506c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
__parse_automatic(_Iterator __begin,_Iterator,auto & __parse_ctx)6606c3fb27SDimitry Andric __parse_automatic(_Iterator __begin, _Iterator, auto& __parse_ctx) {
67349cc55cSDimitry Andric size_t __value = __parse_ctx.next_arg_id();
68*cb14a3feSDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__value <= __number_max, "Compilers don't support this number of arguments");
69349cc55cSDimitry Andric
70349cc55cSDimitry Andric return {__begin, uint32_t(__value)};
71349cc55cSDimitry Andric }
72349cc55cSDimitry Andric
7306c3fb27SDimitry Andric template <contiguous_iterator _Iterator>
7406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
__parse_manual(_Iterator __begin,_Iterator __end,auto & __parse_ctx)7506c3fb27SDimitry Andric __parse_manual(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
7606c3fb27SDimitry Andric __parse_number_result<_Iterator> __r = __format::__parse_number(__begin, __end);
77349cc55cSDimitry Andric __parse_ctx.check_arg_id(__r.__value);
78349cc55cSDimitry Andric return __r;
79349cc55cSDimitry Andric }
80349cc55cSDimitry Andric
81349cc55cSDimitry Andric } // namespace __detail
82349cc55cSDimitry Andric
83349cc55cSDimitry Andric /**
84349cc55cSDimitry Andric * Parses a number.
85349cc55cSDimitry Andric *
86349cc55cSDimitry Andric * The number is used for the 31-bit values @em width and @em precision. This
87349cc55cSDimitry Andric * allows a maximum value of 2147483647.
88349cc55cSDimitry Andric */
8906c3fb27SDimitry Andric template <contiguous_iterator _Iterator>
9006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
__parse_number(_Iterator __begin,_Iterator __end_input)9106c3fb27SDimitry Andric __parse_number(_Iterator __begin, _Iterator __end_input) {
9206c3fb27SDimitry Andric using _CharT = iter_value_t<_Iterator>;
93*cb14a3feSDimitry Andric static_assert(__format::__number_max == INT32_MAX, "The algorithm is implemented based on this value.");
94349cc55cSDimitry Andric /*
95349cc55cSDimitry Andric * Limit the input to 9 digits, otherwise we need two checks during every
96349cc55cSDimitry Andric * iteration:
97349cc55cSDimitry Andric * - Are we at the end of the input?
98349cc55cSDimitry Andric * - Does the value exceed width of an uint32_t? (Switching to uint64_t would
99349cc55cSDimitry Andric * have the same issue, but with a higher maximum.)
100349cc55cSDimitry Andric */
10106c3fb27SDimitry Andric _Iterator __end = __end_input - __begin > 9 ? __begin + 9 : __end_input;
102349cc55cSDimitry Andric uint32_t __value = *__begin - _CharT('0');
103349cc55cSDimitry Andric while (++__begin != __end) {
104349cc55cSDimitry Andric if (*__begin < _CharT('0') || *__begin > _CharT('9'))
105349cc55cSDimitry Andric return {__begin, __value};
106349cc55cSDimitry Andric
107349cc55cSDimitry Andric __value = __value * 10 + *__begin - _CharT('0');
108349cc55cSDimitry Andric }
109349cc55cSDimitry Andric
110*cb14a3feSDimitry Andric if (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')) {
111349cc55cSDimitry Andric /*
112349cc55cSDimitry Andric * There are more than 9 digits, do additional validations:
113349cc55cSDimitry Andric * - Does the 10th digit exceed the maximum allowed value?
114349cc55cSDimitry Andric * - Are there more than 10 digits?
115349cc55cSDimitry Andric * (More than 10 digits always overflows the maximum.)
116349cc55cSDimitry Andric */
117349cc55cSDimitry Andric uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0');
118*cb14a3feSDimitry Andric if (__v > __number_max || (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')))
11906c3fb27SDimitry Andric std::__throw_format_error("The numeric value of the format specifier is too large");
120349cc55cSDimitry Andric
121349cc55cSDimitry Andric __value = __v;
122349cc55cSDimitry Andric }
123349cc55cSDimitry Andric
124349cc55cSDimitry Andric return {__begin, __value};
125349cc55cSDimitry Andric }
126349cc55cSDimitry Andric
127349cc55cSDimitry Andric /**
128349cc55cSDimitry Andric * Multiplexer for all parse functions.
129349cc55cSDimitry Andric *
130349cc55cSDimitry Andric * The parser will return a pointer beyond the last consumed character. This
131349cc55cSDimitry Andric * should be the closing '}' of the arg-id.
132349cc55cSDimitry Andric */
13306c3fb27SDimitry Andric template <contiguous_iterator _Iterator>
13406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
__parse_arg_id(_Iterator __begin,_Iterator __end,auto & __parse_ctx)13506c3fb27SDimitry Andric __parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
13606c3fb27SDimitry Andric using _CharT = iter_value_t<_Iterator>;
137349cc55cSDimitry Andric switch (*__begin) {
138349cc55cSDimitry Andric case _CharT('0'):
139349cc55cSDimitry Andric return __detail::__parse_zero(__begin, __end, __parse_ctx);
140349cc55cSDimitry Andric
141349cc55cSDimitry Andric case _CharT(':'):
142349cc55cSDimitry Andric // This case is conditionally valid. It's allowed in an arg-id in the
143349cc55cSDimitry Andric // replacement-field, but not in the std-format-spec. The caller can
144349cc55cSDimitry Andric // provide a better diagnostic, so accept it here unconditionally.
145349cc55cSDimitry Andric case _CharT('}'):
146349cc55cSDimitry Andric return __detail::__parse_automatic(__begin, __end, __parse_ctx);
147349cc55cSDimitry Andric }
148349cc55cSDimitry Andric if (*__begin < _CharT('0') || *__begin > _CharT('9'))
14906c3fb27SDimitry Andric std::__throw_format_error("The argument index starts with an invalid character");
150349cc55cSDimitry Andric
151349cc55cSDimitry Andric return __detail::__parse_manual(__begin, __end, __parse_ctx);
152349cc55cSDimitry Andric }
153349cc55cSDimitry Andric
154349cc55cSDimitry Andric } // namespace __format
155349cc55cSDimitry Andric
15606c3fb27SDimitry Andric #endif //_LIBCPP_STD_VER >= 20
157349cc55cSDimitry Andric
158349cc55cSDimitry Andric _LIBCPP_END_NAMESPACE_STD
159349cc55cSDimitry Andric
160349cc55cSDimitry Andric #endif // _LIBCPP___FORMAT_FORMAT_STRING_H
161