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
27namespace __format {
28
29template <class _CharT>
30struct _LIBCPP_TEMPLATE_VIS __parse_number_result {
31  const _CharT* __ptr;
32  uint32_t __value;
33};
34
35template <class _CharT>
36__parse_number_result(const _CharT*, uint32_t) -> __parse_number_result<_CharT>;
37
38template <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 */
53inline constexpr uint32_t __number_max = INT32_MAX;
54
55namespace __detail {
56template <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
63template <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
73template <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 */
89template <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 */
137template <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