@@ -132,6 +132,106 @@ constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, c
132
132
return evaluate (begin, result.position , end, consumed_something (f, sizeof ...(String) > 0 ), captures, ctll::list<Tail...>());
133
133
}
134
134
135
+ template <typename Ty>
136
+ constexpr bool is_prefix (Ty* word, size_t wordlen, ptrdiff_t pos) {
137
+ ptrdiff_t suffixlen = wordlen - pos;
138
+ for (int i = 0 ; i < suffixlen; i++) {
139
+ if (word[i] != word[pos + i]) {
140
+ return false ;
141
+ }
142
+ }
143
+ return true ;
144
+ }
145
+
146
+ template <typename Ty>
147
+ constexpr size_t suffix_length (Ty* word, size_t wordlen, ptrdiff_t pos) {
148
+ size_t i = 0 ;
149
+ // increment suffix length i to the first mismatch or beginning of the word
150
+ for (; (word[pos - i] == word[wordlen - 1 - i]) && (i < pos); i++);
151
+ return i;
152
+ }
153
+ // MSVC workaround, array operator[] blows up in face if constexpr, use pointers instead
154
+ template <typename Ty, auto ... String>
155
+ constexpr auto make_delta_2 (string<String...>) {
156
+ std::array<Ty, sizeof ...(String)> chars{ String... };
157
+ std::array<ptrdiff_t , sizeof ...(String)> table;
158
+ constexpr size_t patlen = sizeof ...(String);
159
+ size_t p = 0 ;
160
+ size_t last_prefix_index = patlen - 1 ;
161
+
162
+ for (p = patlen - 1 ; p < patlen; p--) {
163
+ if (is_prefix (chars.data (), patlen, p + 1 )) {
164
+ last_prefix_index = p + 1 ;
165
+ }
166
+ table.data ()[p] = last_prefix_index + (patlen - 1 - p);
167
+ }
168
+
169
+ for (p = 0 ; p < patlen - 1 ; p++) {
170
+ size_t slen = suffix_length (chars.data (), patlen, p);
171
+ if (chars.data ()[p - slen] != chars.data ()[patlen - 1 - slen]) {
172
+ table.data ()[patlen - 1 - slen] = patlen - 1 - p + slen;
173
+ }
174
+ }
175
+
176
+ return table;
177
+ }
178
+
179
+ template <typename Iterator, typename EndIterator, auto ... String>
180
+ constexpr CTRE_FORCE_INLINE string_match_result<Iterator> evaluate_search_string (Iterator current, const EndIterator end, string<String...>) {
181
+ if constexpr (sizeof ...(String) > 2 && ::std::is_convertible_v<typename ::std::iterator_traits<Iterator>::iterator_category, ::std::random_access_iterator_tag>) {
182
+ constexpr std::array<typename ::std::iterator_traits<Iterator>::value_type, sizeof ...(String)> chars{ String... };
183
+ constexpr std::array<ptrdiff_t , sizeof ...(String)> delta_2 = make_delta_2<typename ::std::iterator_traits<Iterator>::value_type>(string<String...>());
184
+
185
+ size_t str_size = std::distance (current, end);
186
+ if (str_size < sizeof ...(String)) { // quick exit no way to match
187
+ return { current, false };
188
+ }
189
+
190
+ size_t i = sizeof ...(String) - 1 ; // index over to the starting location
191
+ for (; i < str_size;) {
192
+ size_t j = sizeof ...(String) - 1 ;
193
+ for (; *(current + i) == *(chars.data () + j); --i, --j) { // match string in reverse
194
+ if (j == 0 ) {
195
+ return { current + i, true };
196
+ }
197
+ }
198
+ size_t shift = enumeration<String...>::match_char (*(current + i)) ? static_cast <size_t >(*(delta_2.data () + j)) : sizeof ...(String);
199
+ i += shift;
200
+ }
201
+
202
+ return { current + str_size, false };
203
+ } else if (sizeof ...(String)) {
204
+ // fallback to plain string matching
205
+ constexpr std::array<typename ::std::iterator_traits<Iterator>::value_type, sizeof ...(String)> chars{ String... };
206
+ constexpr typename ::std::iterator_traits<Iterator>::value_type first_char = chars.data ()[0 ];
207
+ while (current != end) {
208
+ while (current != end && *current != first_char) {
209
+ current++;
210
+ }
211
+ auto result = evaluate_match_string<String...>(current, end, std::make_index_sequence<sizeof ...(String)>());
212
+ if (result.match ) {
213
+ return result;
214
+ } else {
215
+ ++current;
216
+ }
217
+ }
218
+ return { current, false };
219
+ } else {
220
+ return { current, true };
221
+ }
222
+ }
223
+
224
+ template <typename R, typename Iterator, typename EndIterator, auto ... String, typename ... Tail>
225
+ constexpr CTRE_FORCE_INLINE R evaluate (const Iterator begin, Iterator current, const EndIterator end, [[maybe_unused]] const flags& f, R captures, ctll::list<string_search<String...>, Tail...>) noexcept {
226
+ auto result = evaluate_search_string (current, end, string<String...>());
227
+
228
+ if (!result.matched ) {
229
+ return not_matched;
230
+ }
231
+
232
+ return evaluate (begin, std::advance (result.position , sizeof ...(String)), end, consumed_something (f, sizeof ...(String) > 0 ), captures, ctll::list<Tail...>());
233
+ }
234
+
135
235
// matching select in patterns
136
236
template <typename R, typename Iterator, typename EndIterator, typename HeadOptions, typename ... TailOptions, typename ... Tail>
137
237
constexpr CTRE_FORCE_INLINE R evaluate (const Iterator begin, Iterator current, const EndIterator end, const flags & f, R captures, ctll::list<select<HeadOptions, TailOptions...>, Tail...>) noexcept {
0 commit comments