xref: /llvm-project/libcxx/include/__format/format_string.h (revision e99c4906e44ae3f921fa05356909d006cda8d954)
1d7444d9fSMark de Wever // -*- C++ -*-
2d7444d9fSMark de Wever //===----------------------------------------------------------------------===//
3d7444d9fSMark de Wever //
4d7444d9fSMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5d7444d9fSMark de Wever // See https://llvm.org/LICENSE.txt for license information.
6d7444d9fSMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7d7444d9fSMark de Wever //
8d7444d9fSMark de Wever //===----------------------------------------------------------------------===//
9d7444d9fSMark de Wever 
10d7444d9fSMark de Wever #ifndef _LIBCPP___FORMAT_FORMAT_STRING_H
11d7444d9fSMark de Wever #define _LIBCPP___FORMAT_FORMAT_STRING_H
12d7444d9fSMark de Wever 
13f87aa19bSLouis Dionne #include <__assert>
14d7444d9fSMark de Wever #include <__config>
15*e99c4906SNikolas Klauser #include <__cstddef/size_t.h>
16d7444d9fSMark de Wever #include <__format/format_error.h>
171562e514SLouis Dionne #include <__iterator/concepts.h>
18d5ce68afSIan Anderson #include <__iterator/iterator_traits.h> // iter_value_t
19d7444d9fSMark de Wever #include <cstdint>
20d7444d9fSMark de Wever 
21d7444d9fSMark de Wever #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22d7444d9fSMark de Wever #  pragma GCC system_header
23d7444d9fSMark de Wever #endif
24d7444d9fSMark de Wever 
25d7444d9fSMark de Wever _LIBCPP_BEGIN_NAMESPACE_STD
26d7444d9fSMark de Wever 
274f15267dSNikolas Klauser #if _LIBCPP_STD_VER >= 20
28d7444d9fSMark de Wever 
29d7444d9fSMark de Wever namespace __format {
30d7444d9fSMark de Wever 
311562e514SLouis Dionne template <contiguous_iterator _Iterator>
32d7444d9fSMark de Wever struct _LIBCPP_TEMPLATE_VIS __parse_number_result {
331562e514SLouis Dionne   _Iterator __last;
34d7444d9fSMark de Wever   uint32_t __value;
35d7444d9fSMark de Wever };
36d7444d9fSMark de Wever 
371562e514SLouis Dionne template <contiguous_iterator _Iterator>
381562e514SLouis Dionne __parse_number_result(_Iterator, uint32_t) -> __parse_number_result<_Iterator>;
39261b5abfSMark de Wever 
401562e514SLouis Dionne template <contiguous_iterator _Iterator>
419783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> __parse_number(_Iterator __begin, _Iterator __end);
42d7444d9fSMark de Wever 
43d7444d9fSMark de Wever /**
44d7444d9fSMark de Wever  * The maximum value of a numeric argument.
45d7444d9fSMark de Wever  *
46d7444d9fSMark de Wever  * This is used for:
47d7444d9fSMark de Wever  * * arg-id
48d7444d9fSMark de Wever  * * width as value or arg-id.
49d7444d9fSMark de Wever  * * precision as value or arg-id.
50d7444d9fSMark de Wever  *
51d7444d9fSMark de Wever  * The value is compatible with the maximum formatting width and precision
52d7444d9fSMark de Wever  * using the `%*` syntax on a 32-bit system.
53d7444d9fSMark de Wever  */
54d7444d9fSMark de Wever inline constexpr uint32_t __number_max = INT32_MAX;
55d7444d9fSMark de Wever 
56d7444d9fSMark de Wever namespace __detail {
571562e514SLouis Dionne template <contiguous_iterator _Iterator>
581562e514SLouis Dionne _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
591562e514SLouis Dionne __parse_zero(_Iterator __begin, _Iterator, auto& __parse_ctx) {
60d7444d9fSMark de Wever   __parse_ctx.check_arg_id(0);
61d7444d9fSMark de Wever   return {++__begin, 0}; // can never be larger than the maximum.
62d7444d9fSMark de Wever }
63d7444d9fSMark de Wever 
641562e514SLouis Dionne template <contiguous_iterator _Iterator>
651562e514SLouis Dionne _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
661562e514SLouis Dionne __parse_automatic(_Iterator __begin, _Iterator, auto& __parse_ctx) {
67d7444d9fSMark de Wever   size_t __value = __parse_ctx.next_arg_id();
689783f28cSLouis Dionne   _LIBCPP_ASSERT_UNCATEGORIZED(__value <= __number_max, "Compilers don't support this number of arguments");
69d7444d9fSMark de Wever 
70d7444d9fSMark de Wever   return {__begin, uint32_t(__value)};
71d7444d9fSMark de Wever }
72d7444d9fSMark de Wever 
731562e514SLouis Dionne template <contiguous_iterator _Iterator>
741562e514SLouis Dionne _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
751562e514SLouis Dionne __parse_manual(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
761562e514SLouis Dionne   __parse_number_result<_Iterator> __r = __format::__parse_number(__begin, __end);
77d7444d9fSMark de Wever   __parse_ctx.check_arg_id(__r.__value);
78d7444d9fSMark de Wever   return __r;
79d7444d9fSMark de Wever }
80d7444d9fSMark de Wever 
81d7444d9fSMark de Wever } // namespace __detail
82d7444d9fSMark de Wever 
83d7444d9fSMark de Wever /**
84d7444d9fSMark de Wever  * Parses a number.
85d7444d9fSMark de Wever  *
86d7444d9fSMark de Wever  * The number is used for the 31-bit values @em width and @em precision. This
87d7444d9fSMark de Wever  * allows a maximum value of 2147483647.
88d7444d9fSMark de Wever  */
891562e514SLouis Dionne template <contiguous_iterator _Iterator>
901562e514SLouis Dionne _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
911562e514SLouis Dionne __parse_number(_Iterator __begin, _Iterator __end_input) {
921562e514SLouis Dionne   using _CharT = iter_value_t<_Iterator>;
939783f28cSLouis Dionne   static_assert(__format::__number_max == INT32_MAX, "The algorithm is implemented based on this value.");
94d7444d9fSMark de Wever   /*
95d7444d9fSMark de Wever    * Limit the input to 9 digits, otherwise we need two checks during every
96d7444d9fSMark de Wever    * iteration:
97d7444d9fSMark de Wever    * - Are we at the end of the input?
98d7444d9fSMark de Wever    * - Does the value exceed width of an uint32_t? (Switching to uint64_t would
99d7444d9fSMark de Wever    *   have the same issue, but with a higher maximum.)
100d7444d9fSMark de Wever    */
1011562e514SLouis Dionne   _Iterator __end  = __end_input - __begin > 9 ? __begin + 9 : __end_input;
102d7444d9fSMark de Wever   uint32_t __value = *__begin - _CharT('0');
103d7444d9fSMark de Wever   while (++__begin != __end) {
104d7444d9fSMark de Wever     if (*__begin < _CharT('0') || *__begin > _CharT('9'))
105d7444d9fSMark de Wever       return {__begin, __value};
106d7444d9fSMark de Wever 
107d7444d9fSMark de Wever     __value = __value * 10 + *__begin - _CharT('0');
108d7444d9fSMark de Wever   }
109d7444d9fSMark de Wever 
1109783f28cSLouis Dionne   if (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')) {
111d7444d9fSMark de Wever     /*
112d7444d9fSMark de Wever      * There are more than 9 digits, do additional validations:
113d7444d9fSMark de Wever      * - Does the 10th digit exceed the maximum allowed value?
114d7444d9fSMark de Wever      * - Are there more than 10 digits?
115d7444d9fSMark de Wever      * (More than 10 digits always overflows the maximum.)
116d7444d9fSMark de Wever      */
117d7444d9fSMark de Wever     uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0');
1189783f28cSLouis Dionne     if (__v > __number_max || (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')))
119402eb2efSMark de Wever       std::__throw_format_error("The numeric value of the format specifier is too large");
120d7444d9fSMark de Wever 
121d7444d9fSMark de Wever     __value = __v;
122d7444d9fSMark de Wever   }
123d7444d9fSMark de Wever 
124d7444d9fSMark de Wever   return {__begin, __value};
125d7444d9fSMark de Wever }
126d7444d9fSMark de Wever 
127d7444d9fSMark de Wever /**
128d7444d9fSMark de Wever  * Multiplexer for all parse functions.
129d7444d9fSMark de Wever  *
130d7444d9fSMark de Wever  * The parser will return a pointer beyond the last consumed character. This
131d7444d9fSMark de Wever  * should be the closing '}' of the arg-id.
132d7444d9fSMark de Wever  */
1331562e514SLouis Dionne template <contiguous_iterator _Iterator>
1341562e514SLouis Dionne _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
1351562e514SLouis Dionne __parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
1361562e514SLouis Dionne   using _CharT = iter_value_t<_Iterator>;
137d7444d9fSMark de Wever   switch (*__begin) {
138d7444d9fSMark de Wever   case _CharT('0'):
139d7444d9fSMark de Wever     return __detail::__parse_zero(__begin, __end, __parse_ctx);
140d7444d9fSMark de Wever 
141d7444d9fSMark de Wever   case _CharT(':'):
142d7444d9fSMark de Wever     // This case is conditionally valid. It's allowed in an arg-id in the
143d7444d9fSMark de Wever     // replacement-field, but not in the std-format-spec. The caller can
144d7444d9fSMark de Wever     // provide a better diagnostic, so accept it here unconditionally.
145d7444d9fSMark de Wever   case _CharT('}'):
146d7444d9fSMark de Wever     return __detail::__parse_automatic(__begin, __end, __parse_ctx);
147d7444d9fSMark de Wever   }
148d7444d9fSMark de Wever   if (*__begin < _CharT('0') || *__begin > _CharT('9'))
149402eb2efSMark de Wever     std::__throw_format_error("The argument index starts with an invalid character");
150d7444d9fSMark de Wever 
151d7444d9fSMark de Wever   return __detail::__parse_manual(__begin, __end, __parse_ctx);
152d7444d9fSMark de Wever }
153d7444d9fSMark de Wever 
154d7444d9fSMark de Wever } // namespace __format
155d7444d9fSMark de Wever 
1564f15267dSNikolas Klauser #endif // _LIBCPP_STD_VER >= 20
157d7444d9fSMark de Wever 
158d7444d9fSMark de Wever _LIBCPP_END_NAMESPACE_STD
159d7444d9fSMark de Wever 
160d7444d9fSMark de Wever #endif // _LIBCPP___FORMAT_FORMAT_STRING_H
161