{"thread":{"id":"46236","subject":"[PATCH 0/3] wildmatch refactoring","startedAt":"2017-06-22T21:38:26Z","lastAt":"2017-06-24T18:13:37Z","messageCount":7,"participants":["Ævar Arnfjörð Bjarmason","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"322998","messageId":"20170622213810.14785-1-avarab@gmail.com","threadId":"46236","inReplyTo":null,"subject":"[PATCH 0/3] wildmatch refactoring","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-22T21:38:07Z","receivedAt":"2017-06-22T21:38:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The first patch here should be applied, but 2 & 3 trail along as RFCs\nto show where this is going.\n\nThe RFC patches work, but I'm sure there'll be critiques of the\ninterface / other suggestions, so they're being sent as RFC so Junio\ndoesn't need to worry about picking them up / tracking them.\n\nThis is prep work for a local series of mine which compiles the\nwildmatch pattern into JIT-ed PCRE v2 patterns. That may or may not\nend up going anywhere, but as 2/3 notes just making these changes\nmakes it easier to optimize wildmatch() further down the road.\n\nÆvar Arnfjörð Bjarmason (3):\n  wildmatch: remove unused wildopts parameter\n  wildmatch: add interface for precompiling wildmatch() patterns\n  wildmatch: make use of the interface for precompiling wildmatch()\n    patterns\n\n apply.c                   |  2 +-\n builtin/describe.c        |  4 ++--\n builtin/ls-remote.c       |  2 +-\n builtin/name-rev.c        |  6 +++++-\n builtin/reflog.c          |  2 +-\n builtin/replace.c         |  7 ++++---\n builtin/show-branch.c     |  2 +-\n config.c                  |  8 ++++++--\n diffcore-order.c          |  2 +-\n dir.c                     | 20 +++++++++++++++-----\n ref-filter.c              |  4 ++--\n refs.c                    |  7 ++++---\n revision.c                |  2 +-\n t/helper/test-wildmatch.c |  6 +++---\n wildmatch.c               | 23 +++++++++++++++++++++--\n wildmatch.h               | 13 +++++++++----\n 16 files changed, 77 insertions(+), 33 deletions(-)\n\n-- \n2.13.1.611.g7e3b11ae1\n\n"},{"id":"322999","messageId":"20170622213810.14785-2-avarab@gmail.com","threadId":"46236","inReplyTo":"20170622213810.14785-1-avarab@gmail.com","subject":"[PATCH 1/3] wildmatch: remove unused wildopts parameter","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-22T21:38:08Z","receivedAt":"2017-06-22T21:38:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the unused wildopts placeholder struct from being passed to all\nwildmatch() invocations, or rather remove all the boilerplate NULL\nparameters.\n\nThis parameter was added back in commit 9b3497cab9 (\"wildmatch: rename\nconstants and update prototype\", 2013-01-01) as a placeholder for\nfuture use. Over 4 years later nothing has made use of it, let's just\nremove it. It can be added in the future if we find some reason to\nstart using such a parameter.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n apply.c                   | 2 +-\n builtin/describe.c        | 4 ++--\n builtin/ls-remote.c       | 2 +-\n builtin/name-rev.c        | 2 +-\n builtin/reflog.c          | 2 +-\n builtin/replace.c         | 2 +-\n builtin/show-branch.c     | 2 +-\n config.c                  | 2 +-\n diffcore-order.c          | 2 +-\n dir.c                     | 8 +++-----\n ref-filter.c              | 4 ++--\n refs.c                    | 2 +-\n revision.c                | 2 +-\n t/helper/test-wildmatch.c | 6 +++---\n wildmatch.c               | 3 +--\n wildmatch.h               | 6 +-----\n 16 files changed, 22 insertions(+), 29 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 854faa6779..cc3278978a 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -2088,7 +2088,7 @@ static int use_patch(struct apply_state *state, struct patch *p)\n \t/* See if it matches any of exclude/include rule */\n \tfor (i = 0; i < state->limit_by_name.nr; i++) {\n \t\tstruct string_list_item *it = &state->limit_by_name.items[i];\n-\t\tif (!wildmatch(it->string, pathname, 0, NULL))\n+\t\tif (!wildmatch(it->string, pathname, 0))\n \t\t\treturn (it->util != NULL);\n \t}\n \ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 893c8789f4..2fe05f5324 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -142,7 +142,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi\n \t\t\treturn 0;\n \n \t\tfor_each_string_list_item(item, &exclude_patterns) {\n-\t\t\tif (!wildmatch(item->string, path + 10, 0, NULL))\n+\t\t\tif (!wildmatch(item->string, path + 10, 0))\n \t\t\t\treturn 0;\n \t\t}\n \t}\n@@ -158,7 +158,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi\n \t\t\treturn 0;\n \n \t\tfor_each_string_list_item(item, &patterns) {\n-\t\t\tif (!wildmatch(item->string, path + 10, 0, NULL))\n+\t\t\tif (!wildmatch(item->string, path + 10, 0))\n \t\t\t\tbreak;\n \n \t\t\t/* If we get here, no pattern matched. */\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex b2d7d5ce68..c4be98ab9e 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -24,7 +24,7 @@ static int tail_match(const char **pattern, const char *path)\n \n \tpathbuf = xstrfmt(\"/%s\", path);\n \twhile ((p = *(pattern++)) != NULL) {\n-\t\tif (!wildmatch(p, pathbuf, 0, NULL)) {\n+\t\tif (!wildmatch(p, pathbuf, 0)) {\n \t\t\tfree(pathbuf);\n \t\t\treturn 1;\n \t\t}\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 7fc7e66e85..d21a5002a7 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -129,7 +129,7 @@ static int subpath_matches(const char *path, const char *filter)\n \tconst char *subpath = path;\n \n \twhile (subpath) {\n-\t\tif (!wildmatch(filter, subpath, 0, NULL))\n+\t\tif (!wildmatch(filter, subpath, 0))\n \t\t\treturn subpath - path;\n \t\tsubpath = strchr(subpath, '/');\n \t\tif (subpath)\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 920c16dac0..96c82b4f5e 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -485,7 +485,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c\n \t\treturn; /* both given explicitly -- nothing to tweak */\n \n \tfor (ent = reflog_expire_cfg; ent; ent = ent->next) {\n-\t\tif (!wildmatch(ent->pattern, ref, 0, NULL)) {\n+\t\tif (!wildmatch(ent->pattern, ref, 0)) {\n \t\t\tif (!(slot & EXPIRE_TOTAL))\n \t\t\t\tcb->expire_total = ent->expire_total;\n \t\t\tif (!(slot & EXPIRE_UNREACH))\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex c921bc976f..89262df5a1 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -40,7 +40,7 @@ static int show_reference(const char *refname, const struct object_id *oid,\n {\n \tstruct show_data *data = cb_data;\n \n-\tif (!wildmatch(data->pattern, refname, 0, NULL)) {\n+\tif (!wildmatch(data->pattern, refname, 0)) {\n \t\tif (data->format == REPLACE_FORMAT_SHORT)\n \t\t\tprintf(\"%s\\n\", refname);\n \t\telse if (data->format == REPLACE_FORMAT_MEDIUM)\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 4a6cc6f490..bfce303cf9 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -444,7 +444,7 @@ static int append_matching_ref(const char *refname, const struct object_id *oid,\n \t\t\tslash--;\n \tif (!*tail)\n \t\treturn 0;\n-\tif (wildmatch(match_ref_pattern, tail, 0, NULL))\n+\tif (wildmatch(match_ref_pattern, tail, 0))\n \t\treturn 0;\n \tif (starts_with(refname, \"refs/heads/\"))\n \t\treturn append_head_ref(refname, oid, flag, cb_data);\ndiff --git a/config.c b/config.c\nindex 34a139c40b..260caf27b8 100644\n--- a/config.c\n+++ b/config.c\n@@ -245,7 +245,7 @@ static int include_by_gitdir(const struct config_options *opts,\n \t}\n \n \tret = !wildmatch(pattern.buf + prefix, text.buf + prefix,\n-\t\t\t icase ? WM_CASEFOLD : 0, NULL);\n+\t\t\t icase ? WM_CASEFOLD : 0);\n \n \tif (!ret && !already_tried_absolute) {\n \t\t/*\ndiff --git a/diffcore-order.c b/diffcore-order.c\nindex 1957f822a5..19e73311f9 100644\n--- a/diffcore-order.c\n+++ b/diffcore-order.c\n@@ -67,7 +67,7 @@ static int match_order(const char *path)\n \t\tstrbuf_addstr(&p, path);\n \t\twhile (p.buf[0]) {\n \t\t\tchar *cp;\n-\t\t\tif (!wildmatch(order[i], p.buf, 0, NULL))\n+\t\t\tif (!wildmatch(order[i], p.buf, 0))\n \t\t\t\treturn i;\n \t\t\tcp = strrchr(p.buf, '/');\n \t\t\tif (!cp)\ndiff --git a/dir.c b/dir.c\nindex 1759063817..544056b37a 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -82,13 +82,11 @@ int git_fnmatch(const struct pathspec_item *item,\n \tif (item->magic & PATHSPEC_GLOB)\n \t\treturn wildmatch(pattern, string,\n \t\t\t\t WM_PATHNAME |\n-\t\t\t\t (item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0),\n-\t\t\t\t NULL);\n+\t\t\t\t (item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0));\n \telse\n \t\t/* wildmatch has not learned no FNM_PATHNAME mode yet */\n \t\treturn wildmatch(pattern, string,\n-\t\t\t\t item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0,\n-\t\t\t\t NULL);\n+\t\t\t\t item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0);\n }\n \n static int fnmatch_icase_mem(const char *pattern, int patternlen,\n@@ -112,7 +110,7 @@ static int fnmatch_icase_mem(const char *pattern, int patternlen,\n \n \tif (ignore_case)\n \t\tflags |= WM_CASEFOLD;\n-\tmatch_status = wildmatch(use_pat, use_str, flags, NULL);\n+\tmatch_status = wildmatch(use_pat, use_str, flags);\n \n \tstrbuf_release(&pat_buf);\n \tstrbuf_release(&str_buf);\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ab32bc9c31..718def443a 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1624,7 +1624,7 @@ static int match_pattern(const struct ref_filter *filter, const char *refname)\n \t       skip_prefix(refname, \"refs/\", &refname));\n \n \tfor (; *patterns; patterns++) {\n-\t\tif (!wildmatch(*patterns, refname, flags, NULL))\n+\t\tif (!wildmatch(*patterns, refname, flags))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n@@ -1655,7 +1655,7 @@ static int match_name_as_path(const struct ref_filter *filter, const char *refna\n \t\t     refname[plen] == '/' ||\n \t\t     p[plen-1] == '/'))\n \t\t\treturn 1;\n-\t\tif (!wildmatch(p, refname, WM_PATHNAME, NULL))\n+\t\tif (!wildmatch(p, refname, WM_PATHNAME))\n \t\t\treturn 1;\n \t}\n \treturn 0;\ndiff --git a/refs.c b/refs.c\nindex f0685c9251..32626a4cd1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -229,7 +229,7 @@ static int filter_refs(const char *refname, const struct object_id *oid,\n {\n \tstruct ref_filter *filter = (struct ref_filter *)data;\n \n-\tif (wildmatch(filter->pattern, refname, 0, NULL))\n+\tif (wildmatch(filter->pattern, refname, 0))\n \t\treturn 0;\n \treturn filter->fn(refname, oid, flags, filter->cb_data);\n }\ndiff --git a/revision.c b/revision.c\nindex 12eb332350..dc075f0e48 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1142,7 +1142,7 @@ int ref_excluded(struct string_list *ref_excludes, const char *path)\n \tif (!ref_excludes)\n \t\treturn 0;\n \tfor_each_string_list_item(item, ref_excludes) {\n-\t\tif (!wildmatch(item->string, path, 0, NULL))\n+\t\tif (!wildmatch(item->string, path, 0))\n \t\t\treturn 1;\n \t}\n \treturn 0;\ndiff --git a/t/helper/test-wildmatch.c b/t/helper/test-wildmatch.c\nindex 52be876fed..921d7b3e7e 100644\n--- a/t/helper/test-wildmatch.c\n+++ b/t/helper/test-wildmatch.c\n@@ -11,11 +11,11 @@ int cmd_main(int argc, const char **argv)\n \t\t\targv[i] += 3;\n \t}\n \tif (!strcmp(argv[1], \"wildmatch\"))\n-\t\treturn !!wildmatch(argv[3], argv[2], WM_PATHNAME, NULL);\n+\t\treturn !!wildmatch(argv[3], argv[2], WM_PATHNAME);\n \telse if (!strcmp(argv[1], \"iwildmatch\"))\n-\t\treturn !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD, NULL);\n+\t\treturn !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD);\n \telse if (!strcmp(argv[1], \"pathmatch\"))\n-\t\treturn !!wildmatch(argv[3], argv[2], 0, NULL);\n+\t\treturn !!wildmatch(argv[3], argv[2], 0);\n \telse\n \t\treturn 1;\n }\ndiff --git a/wildmatch.c b/wildmatch.c\nindex 57c8765805..d074c1be10 100644\n--- a/wildmatch.c\n+++ b/wildmatch.c\n@@ -272,8 +272,7 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n }\n \n /* Match the \"pattern\" against the \"text\" string. */\n-int wildmatch(const char *pattern, const char *text,\n-\t      unsigned int flags, struct wildopts *wo)\n+int wildmatch(const char *pattern, const char *text, unsigned int flags)\n {\n \treturn dowild((const uchar*)pattern, (const uchar*)text, flags);\n }\ndiff --git a/wildmatch.h b/wildmatch.h\nindex 4090c8f4bb..b8c826aa68 100644\n--- a/wildmatch.h\n+++ b/wildmatch.h\n@@ -10,9 +10,5 @@\n #define WM_ABORT_ALL -1\n #define WM_ABORT_TO_STARSTAR -2\n \n-struct wildopts;\n-\n-int wildmatch(const char *pattern, const char *text,\n-\t      unsigned int flags,\n-\t      struct wildopts *wo);\n+int wildmatch(const char *pattern, const char *text, unsigned int flags);\n #endif\n-- \n2.13.1.611.g7e3b11ae1\n\n"},{"id":"323000","messageId":"20170622213810.14785-3-avarab@gmail.com","threadId":"46236","inReplyTo":"20170622213810.14785-1-avarab@gmail.com","subject":"[RFC/PATCH 2/3] wildmatch: add interface for precompiling wildmatch() patterns","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-22T21:38:09Z","receivedAt":"2017-06-22T21:38:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add the scaffolding necessary for precompiling wildmatch()\npatterns.\n\nThere is currently no point in doing this with the wildmatch()\nfunction we have now, since it can't make any use of precompiling the\npattern.\n\nBut adding this interface and making use of it will make it easy to\nrefactor the wildmatch() function to e.g. parse the pattern into\nopcode as the BSD glob() implementation does, or to drop an alternate\nwildmatch() backend in which trades parsing slowness for faster\nmatching.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n wildmatch.c | 20 ++++++++++++++++++++\n wildmatch.h |  9 +++++++++\n 2 files changed, 29 insertions(+)\n\ndiff --git a/wildmatch.c b/wildmatch.c\nindex d074c1be10..ba6a92a393 100644\n--- a/wildmatch.c\n+++ b/wildmatch.c\n@@ -276,3 +276,23 @@ int wildmatch(const char *pattern, const char *text, unsigned int flags)\n {\n \treturn dowild((const uchar*)pattern, (const uchar*)text, flags);\n }\n+\n+struct wildmatch_compiled *wildmatch_compile(const char *pattern, unsigned int flags)\n+{\n+\tstruct wildmatch_compiled *code = xmalloc(sizeof(struct wildmatch_compiled));\n+\tcode->pattern = xstrdup(pattern);\n+\tcode->flags = flags;\n+\n+\treturn code;\n+}\n+\n+int wildmatch_match(struct wildmatch_compiled *code, const char *text)\n+{\n+\treturn wildmatch(code->pattern, text, code->flags);\n+}\n+\n+void wildmatch_free(struct wildmatch_compiled *code)\n+{\n+\tfree((void *)code->pattern);\n+\tfree(code);\n+}\ndiff --git a/wildmatch.h b/wildmatch.h\nindex b8c826aa68..6156d46a33 100644\n--- a/wildmatch.h\n+++ b/wildmatch.h\n@@ -10,5 +10,14 @@\n #define WM_ABORT_ALL -1\n #define WM_ABORT_TO_STARSTAR -2\n \n+struct wildmatch_compiled {\n+\tconst char *pattern;\n+\tunsigned int flags;\n+};\n+\n int wildmatch(const char *pattern, const char *text, unsigned int flags);\n+struct wildmatch_compiled *wildmatch_compile(const char *pattern, unsigned int flags);\n+int wildmatch_match(struct wildmatch_compiled *code, const char *text);\n+void wildmatch_free(struct wildmatch_compiled *code);\n+\n #endif\n-- \n2.13.1.611.g7e3b11ae1\n\n"},{"id":"323001","messageId":"20170622213810.14785-4-avarab@gmail.com","threadId":"46236","inReplyTo":"20170622213810.14785-1-avarab@gmail.com","subject":"[RFC/PATCH 3/3] wildmatch: make use of the interface for precompiling wildmatch() patterns","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-22T21:38:10Z","receivedAt":"2017-06-22T21:38:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Make use of the batch wildmatch() interface. As noted in the comment\nhere the main hot codepath is not being touched, but some other\ninvocations where we repeatedly match the same glob against multiple\nstrings have been migrated.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/name-rev.c |  6 +++++-\n builtin/replace.c  |  7 ++++---\n config.c           |  8 ++++++--\n dir.c              | 12 ++++++++++++\n refs.c             |  7 ++++---\n 5 files changed, 31 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex d21a5002a7..a8f8010e1e 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -127,14 +127,18 @@ static void name_rev(struct commit *commit,\n static int subpath_matches(const char *path, const char *filter)\n {\n \tconst char *subpath = path;\n+\tstruct wildmatch_compiled *code = wildmatch_compile(filter, 0);\n \n \twhile (subpath) {\n-\t\tif (!wildmatch(filter, subpath, 0))\n+\t\tif (!wildmatch_match(code, subpath)) {\n+\t\t\twildmatch_free(code);\n \t\t\treturn subpath - path;\n+\t\t}\n \t\tsubpath = strchr(subpath, '/');\n \t\tif (subpath)\n \t\t\tsubpath++;\n \t}\n+\twildmatch_free(code);\n \treturn -1;\n }\n \ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex 89262df5a1..70e7af72ce 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -31,7 +31,7 @@ enum replace_format {\n };\n \n struct show_data {\n-\tconst char *pattern;\n+\tstruct wildmatch_compiled *code;\n \tenum replace_format format;\n };\n \n@@ -40,7 +40,7 @@ static int show_reference(const char *refname, const struct object_id *oid,\n {\n \tstruct show_data *data = cb_data;\n \n-\tif (!wildmatch(data->pattern, refname, 0)) {\n+\tif (!wildmatch_match(data->code, refname)) {\n \t\tif (data->format == REPLACE_FORMAT_SHORT)\n \t\t\tprintf(\"%s\\n\", refname);\n \t\telse if (data->format == REPLACE_FORMAT_MEDIUM)\n@@ -69,7 +69,7 @@ static int list_replace_refs(const char *pattern, const char *format)\n \n \tif (pattern == NULL)\n \t\tpattern = \"*\";\n-\tdata.pattern = pattern;\n+\tdata.code = wildmatch_compile(pattern, 0);\n \n \tif (format == NULL || *format == '\\0' || !strcmp(format, \"short\"))\n \t\tdata.format = REPLACE_FORMAT_SHORT;\n@@ -83,6 +83,7 @@ static int list_replace_refs(const char *pattern, const char *format)\n \t\t    format);\n \n \tfor_each_replace_ref(show_reference, (void *)&data);\n+\twildmatch_free(data.code);\n \n \treturn 0;\n }\ndiff --git a/config.c b/config.c\nindex 260caf27b8..2ec45e9790 100644\n--- a/config.c\n+++ b/config.c\n@@ -215,6 +215,7 @@ static int include_by_gitdir(const struct config_options *opts,\n \tint ret = 0, prefix;\n \tconst char *git_dir;\n \tint already_tried_absolute = 0;\n+\tstruct wildmatch_compiled *code = NULL;\n \n \tif (opts->git_dir)\n \t\tgit_dir = opts->git_dir;\n@@ -244,8 +245,10 @@ static int include_by_gitdir(const struct config_options *opts,\n \t\t\tgoto done;\n \t}\n \n-\tret = !wildmatch(pattern.buf + prefix, text.buf + prefix,\n-\t\t\t icase ? WM_CASEFOLD : 0);\n+\tif (!code)\n+\t\tcode = wildmatch_compile(pattern.buf + prefix,\n+\t\t\t\t\t icase ? WM_CASEFOLD : 0);\n+\tret = !wildmatch_match(code, text.buf + prefix);\n \n \tif (!ret && !already_tried_absolute) {\n \t\t/*\n@@ -264,6 +267,7 @@ static int include_by_gitdir(const struct config_options *opts,\n done:\n \tstrbuf_release(&pattern);\n \tstrbuf_release(&text);\n+\twildmatch_free(code);\n \treturn ret;\n }\n \ndiff --git a/dir.c b/dir.c\nindex 544056b37a..f4b5b93956 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -79,6 +79,18 @@ int git_fnmatch(const struct pathspec_item *item,\n \t\t\tps_strcmp(item, pattern,\n \t\t\t\t  string + string_len - pattern_len);\n \t}\n+\n+\t/*\n+\t * TODO: This is the main hot path, but untangling this whole\n+\t * munging of the prefix is a PITA. We take e.g. the pattern\n+\t * \"t/**.sh\" and then conclude that there's a directory \"t\",\n+\t * and then match its entries (recursively) against \"**.sh\".\n+\t *\n+\t * We should try to just always match the full glob against\n+\t * the full pattern. See my \"BUG: wildmatches ... don't match\n+\t * properly due to internal optimizations\" on the mailing list\n+\t * (<CACBZZX5u5fF4fJBJ3CwH0DmLBw4D32jN5o=Om-iqwQdPG93DFg@mail.gmail.com>).\n+\t */\n \tif (item->magic & PATHSPEC_GLOB)\n \t\treturn wildmatch(pattern, string,\n \t\t\t\t WM_PATHNAME |\ndiff --git a/refs.c b/refs.c\nindex 32626a4cd1..ce83b3fccf 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -194,7 +194,7 @@ char *resolve_refdup(const char *refname, int resolve_flags,\n \n /* The argument to filter_refs */\n struct ref_filter {\n-\tconst char *pattern;\n+\tstruct wildmatch_compiled *code;\n \teach_ref_fn *fn;\n \tvoid *cb_data;\n };\n@@ -229,7 +229,7 @@ static int filter_refs(const char *refname, const struct object_id *oid,\n {\n \tstruct ref_filter *filter = (struct ref_filter *)data;\n \n-\tif (wildmatch(filter->pattern, refname, 0))\n+\tif (wildmatch_match(filter->code, refname))\n \t\treturn 0;\n \treturn filter->fn(refname, oid, flags, filter->cb_data);\n }\n@@ -390,12 +390,13 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n \t\tstrbuf_addch(&real_pattern, '*');\n \t}\n \n-\tfilter.pattern = real_pattern.buf;\n+\tfilter.code = wildmatch_compile(real_pattern.buf, 0);\n \tfilter.fn = fn;\n \tfilter.cb_data = cb_data;\n \tret = for_each_ref(filter_refs, &filter);\n \n \tstrbuf_release(&real_pattern);\n+\twildmatch_free(filter.code);\n \treturn ret;\n }\n \n-- \n2.13.1.611.g7e3b11ae1\n\n"},{"id":"323178","messageId":"xmqqshiq9naq.fsf@gitster.mtv.corp.google.com","threadId":"46236","inReplyTo":"20170622213810.14785-3-avarab@gmail.com","subject":"Re: [RFC/PATCH 2/3] wildmatch: add interface for precompiling wildmatch() patterns","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-24T01:39:25Z","receivedAt":"2017-06-24T01:39:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +struct wildmatch_compiled *wildmatch_compile(const char *pattern, unsigned int flags)\n> +{\n> +\tstruct wildmatch_compiled *code = xmalloc(sizeof(struct wildmatch_compiled));\n> +\tcode->pattern = xstrdup(pattern);\n> +\tcode->flags = flags;\n> +\n> +\treturn code;\n> +}\n> +\n> +int wildmatch_match(struct wildmatch_compiled *code, const char *text)\n> +{\n> +\treturn wildmatch(code->pattern, text, code->flags);\n> +}\n\nIs the far-in-the-future vision to make this the other way around?\nThat is, this being scaffolding, wildmatch_match() which is supposed\nto be precompiled match actually uses wildmatch() as its underlying\nengine, but when a viable compilation machinery is plugged in, the\nwildmatch_match() that takes a precompiled pattern will call into\nthe machinery to execute the compiled pattern, and wildmatch() will\nbe reimplemented as \"compile, call wildmatch_match() once and\ndiscard\" sequence?\n\nOtherwise I'd be worried about wildmatch() vs wildmatch_match()\nintroducing subtle behaviour differences that leads to hard to debug\nproblems.\n\n"},{"id":"323181","messageId":"87zicx1wig.fsf@gmail.com","threadId":"46236","inReplyTo":"xmqqshiq9naq.fsf@gitster.mtv.corp.google.com","subject":"Re: [RFC/PATCH 2/3] wildmatch: add interface for precompiling wildmatch() patterns","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-24T10:59:51Z","receivedAt":"2017-06-24T11:00:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Jun 24 2017, Junio C. Hamano jotted:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> +struct wildmatch_compiled *wildmatch_compile(const char *pattern, unsigned int flags)\n>> +{\n>> +\tstruct wildmatch_compiled *code = xmalloc(sizeof(struct wildmatch_compiled));\n>> +\tcode->pattern = xstrdup(pattern);\n>> +\tcode->flags = flags;\n>> +\n>> +\treturn code;\n>> +}\n>> +\n>> +int wildmatch_match(struct wildmatch_compiled *code, const char *text)\n>> +{\n>> +\treturn wildmatch(code->pattern, text, code->flags);\n>> +}\n>\n> Is the far-in-the-future vision to make this the other way around?\n> That is, this being scaffolding, wildmatch_match() which is supposed\n> to be precompiled match actually uses wildmatch() as its underlying\n> engine, but when a viable compilation machinery is plugged in, the\n> wildmatch_match() that takes a precompiled pattern will call into\n> the machinery to execute the compiled pattern, and wildmatch() will\n> be reimplemented as \"compile, call wildmatch_match() once and\n> discard\" sequence?\n\nExactly there would be no functional difference in the results, only\nfixed overhead.\n\nwildmatch() would be the one-off lazy interface and\nwildmatch_{compile,match,free}(), just like how you can have a wrapper\nfunction that calls regcomp() followed by regexec() & regfree(), but\nit's better to structure your code so you're not compiling & freeing the\npattern all the time.\n\nRight now of course there's no difference in the behavior, and a\ntrivially more overhead with the extra xstrdup() & free(), but I wanted\nto split up the discussion of the semantics of the interface from any\nactual behavior change in wildmatch() which would make use of it further\ndown the line.\n\n> Otherwise I'd be worried about wildmatch() vs wildmatch_match()\n> introducing subtle behaviour differences that leads to hard to debug\n> problems.\n"},{"id":"323214","messageId":"xmqqo9td9rui.fsf@gitster.mtv.corp.google.com","threadId":"46236","inReplyTo":"87zicx1wig.fsf@gmail.com","subject":"Re: [RFC/PATCH 2/3] wildmatch: add interface for precompiling wildmatch() patterns","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-24T18:13:25Z","receivedAt":"2017-06-24T18:13:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Sat, Jun 24 2017, Junio C. Hamano jotted:\n>\n>> Is the far-in-the-future vision to make this the other way around?\n>> That is, this being scaffolding, wildmatch_match() which is supposed\n>> to be precompiled match actually uses wildmatch() as its underlying\n>> engine, but when a viable compilation machinery is plugged in, the\n>> wildmatch_match() that takes a precompiled pattern will call into\n>> the machinery to execute the compiled pattern, and wildmatch() will\n>> be reimplemented as \"compile, call wildmatch_match() once and\n>> discard\" sequence?\n>\n> Exactly there would be no functional difference in the results, only\n> fixed overhead.\n\nOK, good!\n\nThanks.\n\n"}]}