Iros
 
Loading...
Searching...
No Matches
format_parse_context.h
Go to the documentation of this file.
1#pragma once
2
6#include "di/parser/prelude.h"
11
12namespace di::format {
13template<concepts::Encoding Enc>
15private:
16 using Iter = meta::EncodingIterator<Enc>;
18 using CodePoint = meta::EncodingCodePoint<Enc>;
19
20 enum class IndexingMode {
21 Unknown,
22 Manual,
23 Automatic,
24 };
25
26public:
27 constexpr explicit FormatParseContext(View view, size_t arg_count) : m_view(view), m_arg_count(arg_count) {}
28
29 struct Argument {
31 size_t index;
32 };
33
35
36 struct Iterator : public container::IteratorBase<Iterator, InputIteratorTag, Value, ssize_t> {
37 private:
38 constexpr explicit Iterator(View data, FormatParseContext& parent)
39 : m_data(data), m_position(data.begin()), m_parent(util::addressof(parent)) {
41 }
42
43 friend class FormatParseContext;
44
45 public:
46 using Encoding = Enc;
47
48 Iterator() = default;
49
50 constexpr auto operator*() const -> Value&& { return util::move(m_parent->m_current_value); }
51
52 constexpr void advance_one() {
53 if (m_position == m_data.end()) {
54 m_at_end = true;
55 return;
56 }
57
58 auto start = m_position;
59
60 // Try to parse a format arguments.
61 if (*m_position == CodePoint('{')) {
62 ++m_position;
63
64 // Unclosed '{'.
65 if (m_position == m_data.end()) {
66 return set_error(BasicError::InvalidArgument);
67 }
68
69 // Escaped '{'.
70 if (*m_position == CodePoint('{')) {
71 set_value(m_data.substr(start, m_position));
72 ++m_position;
73 return;
74 }
75
76 // Find the closing '}', allowing inner nesting of '{' and'}' pairs.
77 size_t left_brace_count = 1;
78 for (; left_brace_count && m_position != m_data.end(); ++m_position) {
79 if (*m_position == CodePoint('{')) {
80 ++left_brace_count;
81 } else if (*m_position == CodePoint('}')) {
82 --left_brace_count;
83 }
84 }
85
86 if (left_brace_count > 0) {
87 return set_error(BasicError::InvalidArgument);
88 }
89
90 auto inside_view = m_data.substr(container::next(start), container::prev(m_position));
91
92 using namespace integral_set_literals;
93
94 auto inside_view_context = parser::StringViewParserContext<Enc>(inside_view);
95 size_t arg_index = 0;
96
97 // Handle manual format string indexing: '{0:...}' and '{15:...}'.
98 auto digit_parser = parser::match_zero_or_more('0'_m - '9'_m);
99 auto digit_result = *digit_parser.parse(inside_view_context);
100 if (!digit_result.empty()) {
101 auto index = parser::run_parser(parser::integer<size_t>(10), digit_result);
102 if (!index) {
103 return set_error(util::move(index).error());
104 }
105 auto result = m_parent->check_arg_index(*index);
106 if (!result) {
107 return set_error(util::move(result).error());
108 }
109 inside_view.replace_begin(digit_result.end());
110 arg_index = *index;
111 } else {
112 // Handle automatic index mode.
113 auto result = m_parent->next_arg_index();
114 if (!result) {
115 return set_error(util::move(result).error());
116 }
117 arg_index = *result;
118 }
119
120 // At this point, the inside view must either be empty or begin with a ':'.
121 if (!inside_view.empty() && !inside_view.starts_with(CodePoint(':'))) {
122 return set_error(BasicError::InvalidArgument);
123 }
124
125 // Skip over colon.
126 if (!inside_view.empty()) {
127 inside_view = inside_view.substr(container::next(inside_view.begin()));
128 }
129
130 // Return an object containing the interior of the format string, as well as
131 // the specified argument index.
132 return set_value(Argument { inside_view, arg_index });
133 }
134
135 // A '}' must be escaped.
136 if (*m_position == CodePoint('}')) {
137 ++m_position;
138
139 // Unclosed '}'.
140 if (m_position == m_data.end() || *m_position != CodePoint('}')) {
141 return set_error(BasicError::InvalidArgument);
142 }
143
144 set_value(m_data.substr(start, m_position));
145 ++m_position;
146 return;
147 }
148
149 // Literal string, advance until a '{', '}', or EOF is reached.
150 do {
151 ++m_position;
152 } while (m_position != m_data.end() && *m_position != CodePoint('{') && *m_position != CodePoint('}'));
153 set_value(m_data.substr(start, m_position));
154 }
155
156 private:
157 constexpr friend auto operator==(Iterator const& a, container::DefaultSentinel) -> bool { return a.m_at_end; }
158
159 constexpr void set_error(Error error) {
160#ifdef DI_CLANG
161#pragma GCC diagnostic push
162#pragma GCC diagnostic ignored "-Wredundant-consteval-if"
163#endif
164 if consteval {
165 util::compile_time_fail<FixedString { "Invalid format string." }>();
166 }
167#ifdef DI_CLANG
168#pragma GCC diagnostic pop
169#endif
170 m_position = m_data.end();
171 set_value(util::move(error));
172 }
173
174 constexpr void set_value(View view) { m_parent->m_current_value.emplace(c_<0ZU>, view); }
175 constexpr void set_value(Argument argument) {
176 m_parent->m_current_format_string = argument.format_string;
177 m_parent->m_current_value.emplace(c_<1ZU>, argument);
178 }
179 constexpr void set_value(Error error) { m_parent->m_current_value = Unexpected(util::move(error)); }
180
181 View m_data {};
182 Iter m_position {};
183 FormatParseContext* m_parent { nullptr };
184 bool m_at_end { false };
185 };
186
187 constexpr auto begin() { return Iterator(m_view, *this); }
188 constexpr auto end() const { return container::default_sentinel; }
189
190 constexpr void set_current_format_string(View view) { m_current_format_string = view; }
191 constexpr auto current_format_string() const -> View { return m_current_format_string; }
192
193 constexpr auto next_arg_index() -> Result<size_t> {
194 if (m_indexing_mode == IndexingMode::Manual) {
195 return Unexpected(BasicError::InvalidArgument);
196 }
197 m_indexing_mode = IndexingMode::Automatic;
198
199 auto index = m_next_arg_index++;
200 if (index >= m_arg_count) {
201 return Unexpected(BasicError::InvalidArgument);
202 }
203 return index;
204 }
205
206 constexpr auto check_arg_index(size_t index) -> Result<void> {
207 if (m_indexing_mode == IndexingMode::Automatic) {
208 return Unexpected(BasicError::InvalidArgument);
209 }
210 m_indexing_mode = IndexingMode::Manual;
211
212 if (index >= m_arg_count) {
213 return Unexpected(BasicError::InvalidArgument);
214 }
215 return {};
216 }
217
218private:
219 View m_view;
220 IndexingMode m_indexing_mode { IndexingMode::Unknown };
221 Value m_current_value;
222 View m_current_format_string;
223 size_t m_next_arg_index { 0 };
224 size_t m_arg_count { 0 };
225};
226}
227
228namespace di {
230}
Definition fixed_string.h:7
Definition view.h:35
constexpr auto end() const
Definition constant_string_interface.h:70
Definition string_view_impl_forward_declaration.h:7
Definition format_parse_context.h:14
constexpr auto current_format_string() const -> View
Definition format_parse_context.h:191
constexpr auto next_arg_index() -> Result< size_t >
Definition format_parse_context.h:193
Result< Variant< View, Argument > > Value
Definition format_parse_context.h:34
constexpr void set_current_format_string(View view)
Definition format_parse_context.h:190
constexpr FormatParseContext(View view, size_t arg_count)
Definition format_parse_context.h:27
constexpr auto end() const
Definition format_parse_context.h:188
constexpr auto check_arg_index(size_t index) -> Result< void >
Definition format_parse_context.h:206
constexpr auto begin()
Definition format_parse_context.h:187
Definition string_view_parser_context.h:8
Definition unexpected.h:14
constexpr auto prev
Definition prev.h:28
constexpr auto next
Definition next.h:35
View(Iter, Sent) -> View< Iter, Sent >
constexpr auto default_sentinel
Definition default_sentinel.h:6
Definition bounded_format_context.h:7
Definition integral_set.h:125
RemoveCVRef< T >::CodePoint EncodingCodePoint
Definition encoding.h:19
RemoveCVRef< T >::Iterator EncodingIterator
Definition encoding.h:22
constexpr auto run_parser
Definition run_parser.h:22
constexpr auto integer
Definition integer.h:212
constexpr auto match_zero_or_more
Definition match_zero_or_more.h:48
void compile_time_fail()
Definition compile_time_fail.h:7
Expected< T, Error > Result
Definition result.h:8
StatusCode< Erased< long > > Error
Definition error.h:8
Unexpected(E &&) -> Unexpected< meta::UnwrapRefDecay< E > >
Definition zstring_parser.h:9
constexpr auto c_
A value of type Constexpr<val>.
Definition constexpr.h:252
constexpr auto data
Definition data.h:51
Definition default_sentinel.h:4
Definition iterator_base.h:14
Definition format_parse_context.h:29
View format_string
Definition format_parse_context.h:30
size_t index
Definition format_parse_context.h:31
Definition format_parse_context.h:36
constexpr friend auto operator==(Iterator const &a, container::DefaultSentinel) -> bool
Definition format_parse_context.h:157
constexpr void advance_one()
Definition format_parse_context.h:52
constexpr auto operator*() const -> Value &&
Definition format_parse_context.h:50
friend class FormatParseContext
Definition format_parse_context.h:43
Enc Encoding
Definition format_parse_context.h:46