127{
128
129 static constexpr int recursionLimit = 10;
130 ++recursionCount;
131 if (recursionCount >= recursionLimit) {
132 return false;
133 }
134
135
136 if (pattern == patternEnd || str == strEnd) {
137 return false;
138 }
139
140
141 bool recursiveMatch = false;
142 uint8_t bestRecursiveMatches[256];
143 int bestRecursiveScore = 0;
144
145
146 bool first_match = true;
147 while (pattern != patternEnd && str != strEnd) {
148
149 if (pattern->toLower() == str->toLower()) {
150
151 if (nextMatch >= maxMatches) {
152 return false;
153 }
154
155
156 if (first_match && srcMatches) {
157 memcpy(matches, srcMatches, nextMatch);
158 first_match = false;
159 }
160
161
162 uint8_t recursiveMatches[256];
163 int recursiveScore;
164 auto strNextChar = std::next(str);
166 strNextChar,
167 recursiveScore,
168 strBegin,
169 strEnd,
170 patternEnd,
171 matches,
172 recursiveMatches,
173 sizeof(recursiveMatches),
174 nextMatch,
175 recursionCount)) {
176
177 if (!recursiveMatch || recursiveScore > bestRecursiveScore) {
178 memcpy(bestRecursiveMatches, recursiveMatches, 256);
179 bestRecursiveScore = recursiveScore;
180 }
181 recursiveMatch = true;
182 }
183
184
185 matches[nextMatch++] = (uint8_t)(std::distance(strBegin, str));
186 ++pattern;
187 }
188 ++str;
189 }
190
191
192 bool matched = pattern == patternEnd ? true : false;
193
194
195 if (matched) {
196 int sequential_bonus = seqBonus;
197 static constexpr int separator_bonus = 30;
198 static constexpr int camel_bonus = 30;
199 static constexpr int first_letter_bonus = 15;
200
201 static constexpr int leading_letter_penalty = -5;
202 static constexpr int max_leading_letter_penalty = -15;
203 static constexpr int unmatched_letter_penalty = -1;
204
205
206 while (str != strEnd) {
207 ++str;
208 }
209
210
211 outScore = 100;
212
213
214 int penalty = leading_letter_penalty * matches[0];
215 if (penalty < max_leading_letter_penalty) {
216 penalty = max_leading_letter_penalty;
217 }
218 outScore += penalty;
219
220
221 const int unmatched = (int)(std::distance(strBegin, str)) - nextMatch;
222 outScore += unmatched_letter_penalty * unmatched;
223
224
225 for (int i = 0; i < nextMatch; ++i) {
226 uint8_t currIdx = matches[i];
227
228 if (i > 0) {
229 uint8_t prevIdx = matches[i - 1];
230
231
232 if (currIdx == (prevIdx + 1)) {
233 outScore += sequential_bonus;
234 }
235 }
236
237
238 if (currIdx > 0) {
239
240 QChar neighbor = *(strBegin + currIdx - 1);
241 QChar curr = *(strBegin + currIdx);
242 if (neighbor.isLower() && curr.isUpper()) {
243 outScore += camel_bonus;
244 }
245
246
247 bool neighborSeparator = neighbor == QLatin1Char('_') || neighbor == QLatin1Char(' ');
248 if (neighborSeparator) {
249 outScore += separator_bonus;
250 }
251 } else {
252
253 outScore += first_letter_bonus;
254 }
255 }
256 }
257
258
259 if (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {
260
261 memcpy(matches, bestRecursiveMatches, maxMatches);
262 outScore = bestRecursiveScore;
263 return true;
264 } else if (matched) {
265
266 return true;
267 } else {
268
269 return false;
270 }
271}
static bool fuzzy_match_recursive(QString::const_iterator pattern, QString::const_iterator str, int &outScore, const QString::const_iterator strBegin, const QString::const_iterator strEnd, const QString::const_iterator patternEnd, uint8_t const *srcMatches, uint8_t *newMatches, int maxMatches, int nextMatch, int &recursionCount, int seqBonus=15)