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