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