xref: /freebsd-src/contrib/llvm-project/libcxx/include/__format/format_string.h (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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