3 #include "fly/concepts/concepts.hpp"
5 #include "fly/types/string/concepts.hpp"
6 #include "fly/types/string/detail/format_parameter_type.hpp"
7 #include "fly/types/string/detail/format_parse_context.hpp"
8 #include "fly/types/string/detail/format_specifier.hpp"
9 #include "fly/types/string/detail/traits.hpp"
10 #include "fly/types/string/formatters.hpp"
11 #include "fly/types/string/lexer.hpp"
12 #include "fly/types/string/literals.hpp"
18 #include <type_traits>
20 namespace fly::detail {
34 template <fly::StandardCharacter CharType,
typename... ParameterTypes>
44 template <std::
size_t N>
80 template <std::
size_t N = 0>
81 constexpr
void parse_user_defined_specifier(
FormatSpecifier &specifier);
83 static constexpr
const auto s_left_brace = FLY_CHR(CharType,
'{');
84 static constexpr
const auto s_right_brace = FLY_CHR(CharType,
'}');
85 static constexpr
const auto s_colon = FLY_CHR(CharType,
':');
87 static constexpr std::array<ParameterType,
sizeof...(ParameterTypes)> s_parameters {
88 infer_parameter_type<ParameterTypes>()...};
92 std::array<FormatSpecifier, 64> m_specifiers;
93 std::size_t m_specifier_count {0};
94 std::size_t m_specifier_index {0};
98 template <fly::StandardCharacter CharType,
typename... ParameterTypes>
99 template <std::
size_t N>
101 const CharType (&format)[N]) noexcept :
102 m_context(format, s_parameters.data(), s_parameters.size())
104 std::optional<CharType> ch;
106 while (!m_context.has_error() && (ch = m_context.lexer().consume()))
108 if (ch == s_left_brace)
110 if (m_context.lexer().consume_if(s_left_brace))
114 else if (m_specifier_count >= m_specifiers.size())
116 m_context.on_error(
"Exceeded maximum allowed number of specifiers");
120 m_specifiers[m_specifier_count++] = parse_specifier();
123 else if (ch == s_right_brace)
125 if (m_context.lexer().consume_if(s_right_brace))
130 m_context.on_error(
"Closing brace } must be escaped");
136 template <fly::StandardCharacter CharType,
typename... ParameterTypes>
144 template <fly::StandardCharacter CharType,
typename... ParameterTypes>
146 -> std::optional<FormatSpecifier>
148 if (m_specifier_index >= m_specifier_count)
153 return std::move(m_specifiers[m_specifier_index++]);
157 template <fly::StandardCharacter CharType,
typename... ParameterTypes>
161 const auto starting_position = m_context.lexer().position() - 1;
163 FormatSpecifier specifier(m_context);
164 specifier.m_parse_index = m_context.lexer().position();
166 if (m_context.lexer().consume_if(s_colon))
168 specifier.m_parse_index = m_context.lexer().position();
170 if (m_context.parameter_type(specifier.m_position) == ParameterType::UserDefined)
172 parse_user_defined_specifier(specifier);
176 specifier.parse(m_context);
179 else if (!m_context.lexer().consume_if(s_right_brace))
181 m_context.on_error(
"Detected unclosed replacement field - must end with }");
184 specifier.m_size = m_context.lexer().position() - starting_position;
189 template <fly::StandardCharacter CharType,
typename... ParameterTypes>
190 template <std::
size_t N>
191 constexpr
void BasicFormatString<CharType, ParameterTypes...>::parse_user_defined_specifier(
192 FormatSpecifier &specifier)
194 if constexpr (N <
sizeof...(ParameterTypes))
196 if (N != specifier.m_position)
198 parse_user_defined_specifier<N + 1>(specifier);
202 using T = std::tuple_element_t<N, std::tuple<std::remove_cvref_t<ParameterTypes>...>>;
205 if constexpr (fly::FormattableWithParsing<FormatParseContext, Formatter>)
208 formatter.
parse(m_context);
210 if constexpr (fly::DerivedFrom<Formatter, FormatSpecifier>)
212 formatter.copy_formatting_options_into(specifier);
217 if (!m_context.lexer().consume_if(s_right_brace))
220 "User-defined formatter without a parser may not have formatting options");
Definition: format_parse_context.hpp:22