Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

wildmatch: advance faster in <asterisk> + <literal> patterns

Normally when we match "*X" on "abcX", we call dowild("X", "abcX"),
dowild("X", "bcX"), dowild("X", "cX") and dowild("X", "X"). Only the
last call may have a chance of matching. By skipping the text before
"X", we can eliminate the first three useless calls.

compat, '*/*/*' on linux-2.6.git file list 2000 times, before:
wildmatch 7s 985049us
fnmatch   2s 735541us or 34.26% faster

and after:
wildmatch 4s 492549us
fnmatch   0s 888263us or 19.77% slower

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information...
commit 6f1a31f0aae6dbd5414b81fb6c0f4ff087146fc5 1 parent 4698344
Nguyễn Thái Ngọc Duy authored January 01, 2013 gitster committed January 01, 2013
8  t/t3070-wildmatch.sh
@@ -207,6 +207,11 @@ match 0 x foo '*/*/*'
207 207
 match 0 x foo/bar '*/*/*'
208 208
 match 1 x foo/bba/arr '*/*/*'
209 209
 match 0 x foo/bb/aa/rr '*/*/*'
  210
+match 1 x foo/bb/aa/rr '**/**/**'
  211
+match 1 x abcXdefXghi '*X*i'
  212
+match 0 x ab/cXd/efXg/hi '*X*i'
  213
+match 1 x ab/cXd/efXg/hi '*/*X*/*/*i'
  214
+match 1 x ab/cXd/efXg/hi '**/*X*/**/*i'
210 215
 
211 216
 pathmatch 1 foo foo
212 217
 pathmatch 0 foo fo
@@ -226,5 +231,8 @@ pathmatch 0 foo '*/*/*'
226 231
 pathmatch 0 foo/bar '*/*/*'
227 232
 pathmatch 1 foo/bba/arr '*/*/*'
228 233
 pathmatch 1 foo/bb/aa/rr '*/*/*'
  234
+pathmatch 1 abcXdefXghi '*X*i'
  235
+pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'
  236
+pathmatch 1 ab/cXd/efXg/hi '*Xg*i'
229 237
 
230 238
 test_done
23  wildmatch.c
@@ -133,6 +133,29 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
133 133
 			while (1) {
134 134
 				if (t_ch == '\0')
135 135
 					break;
  136
+				/*
  137
+				 * Try to advance faster when an asterisk is
  138
+				 * followed by a literal. We know in this case
  139
+				 * that the the string before the literal
  140
+				 * must belong to "*".
  141
+				 * If match_slash is false, do not look past
  142
+				 * the first slash as it cannot belong to '*'.
  143
+				 */
  144
+				if (!is_glob_special(*p)) {
  145
+					p_ch = *p;
  146
+					if ((flags & WM_CASEFOLD) && ISUPPER(p_ch))
  147
+						p_ch = tolower(p_ch);
  148
+					while ((t_ch = *text) != '\0' &&
  149
+					       (match_slash || t_ch != '/')) {
  150
+						if ((flags & WM_CASEFOLD) && ISUPPER(t_ch))
  151
+							t_ch = tolower(t_ch);
  152
+						if (t_ch == p_ch)
  153
+							break;
  154
+						text++;
  155
+					}
  156
+					if (t_ch != p_ch)
  157
+						return WM_NOMATCH;
  158
+				}
136 159
 				if ((matched = dowild(p, text, flags)) != WM_NOMATCH) {
137 160
 					if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
138 161
 						return matched;

0 notes on commit 6f1a31f

Please sign in to comment.
Something went wrong with that request. Please try again.