86 lines
3.4 KiB
Diff
86 lines
3.4 KiB
Diff
--- a/postfix/src/util/match_list.c
|
|
+++ b/postfix/src/util/match_list.c
|
|
@@ -50,6 +50,7 @@
|
|
#include <argv.h>
|
|
#include <dict.h>
|
|
#include <match_list.h>
|
|
+#include <htable.h>
|
|
|
|
/* Application-specific */
|
|
|
|
@@ -132,6 +132,7 @@ MATCH_LIST *match_list_init(const char *pname, int flags,
|
|
list->match_count = match_count;
|
|
list->match_func =
|
|
(MATCH_LIST_FN *) mymalloc(match_count * sizeof(MATCH_LIST_FN));
|
|
list->match_args =
|
|
(const char **) mymalloc(match_count * sizeof(const char *));
|
|
va_start(ap, match_count);
|
|
for (i = 0; i < match_count; i++)
|
|
list->match_func[i] = va_arg(ap, MATCH_LIST_FN);
|
|
va_end(ap);
|
|
list->error = 0;
|
|
list->fold_buf = vstring_alloc(20);
|
|
+ list->string_cache = htable_create(8);
|
|
|
|
#define DO_MATCH 1
|
|
|
|
@@ -140,6 +141,12 @@ MATCH_LIST *match_list_init(const char *pname, int flags,
|
|
list->patterns = match_list_parse(list, argv_alloc(1), saved_patterns,
|
|
DO_MATCH);
|
|
argv_terminate(list->patterns);
|
|
+ /* Pre-index all inline string patterns (no '!' negation, no ':' dict) */
|
|
+ {
|
|
+ char **cpp;
|
|
+ for (cpp = list->patterns->argv; *cpp != 0; cpp++) {
|
|
+ char *p = *cpp;
|
|
+ int neg = 0;
|
|
+ while (*p == '!') { neg = !neg; p++; }
|
|
+ if (strchr(p, ':') == 0 && *p != '/') /* plain string pattern */
|
|
+ htable_enter(list->string_cache, p, (char *)(neg ? (void*)1 : (void*)2));
|
|
+ }
|
|
+ }
|
|
myfree(saved_patterns);
|
|
return (list);
|
|
}
|
|
@@ -160,6 +167,21 @@ int match_list_match(MATCH_LIST *list,...)
|
|
list->error = 0;
|
|
|
|
/*
|
|
+ * Fast path: O(1) hash lookup for the common case where all patterns
|
|
+ * are plain strings (no wildcards, no file includes, no type:table).
|
|
+ * Fall through to the linear scan only when non-string patterns exist.
|
|
+ */
|
|
+ if (list->match_count == 1 && htable_used(list->string_cache) > 0) {
|
|
+ casefold(list->fold_buf, list->match_args[0]);
|
|
+ HTABLE_INFO *entry = htable_find(list->string_cache, STR(list->fold_buf));
|
|
+ if (entry) {
|
|
+ /* value 2 = positive match, value 1 = negated (no match) */
|
|
+ return (entry->value == (char*)2) ? 1 : 0;
|
|
+ }
|
|
+ /* Not found in hash — could still match a non-string pattern below */
|
|
+ if (list->patterns->argc == (int)htable_used(list->string_cache))
|
|
+ return 0; /* all patterns are plain strings and none matched */
|
|
+ }
|
|
+
|
|
+ /*
|
|
* Iterate over all patterns in the list, stop at the first match.
|
|
*/
|
|
for (cpp = list->patterns->argv; (pat = *cpp) != 0; cpp++) {
|
|
@@ -185,5 +207,6 @@ void match_list_free(MATCH_LIST *list)
|
|
argv_free(list->patterns);
|
|
myfree((void *) list->match_func);
|
|
myfree((void *) list->match_args);
|
|
+ htable_free(list->string_cache, (void (*)(char *)) 0);
|
|
vstring_free(list->fold_buf);
|
|
myfree((void *) list);
|
|
}
|
|
--- a/postfix/src/util/match_list.h
|
|
+++ b/postfix/src/util/match_list.h
|
|
@@ -38,6 +38,7 @@ typedef int (*MATCH_LIST_FN) (struct MATCH_LIST *, const char *, const char *);
|
|
typedef struct MATCH_LIST {
|
|
const char *pname; /* parameter name for error reports */
|
|
int flags; /* MATCH_FLAG_XXX */
|
|
+ struct HTABLE *string_cache; /* O(1) index for inline string patterns */
|
|
ARGV *patterns; /* one pattern per element */
|
|
int match_count; /* number of match functions */
|
|
MATCH_LIST_FN *match_func; /* match functions */
|