From: Marco Bettini Date: Wed, 9 Nov 2022 15:29:39 +0000 (+0000) Subject: lib-storage: mail_search_args_simplify_drop_redundant_args() - Apply Absorptive law... X-Git-Tag: 2.3.20~18 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f41286b8f114c16bc9f20fe11c96e925a0053049;p=thirdparty%2Fdovecot%2Fcore.git lib-storage: mail_search_args_simplify_drop_redundant_args() - Apply Absorptive law versus all terms, not just the 1st --- diff --git a/src/lib-storage/mail-search-args-simplify.c b/src/lib-storage/mail-search-args-simplify.c index 9c86811b13..2a1cace6d6 100644 --- a/src/lib-storage/mail-search-args-simplify.c +++ b/src/lib-storage/mail-search-args-simplify.c @@ -383,62 +383,73 @@ mail_search_args_have_all_equal(struct mail_search_arg *parent_arg, return TRUE; } -static unsigned int -mail_search_args_count(const struct mail_search_arg *args) -{ - unsigned int count; +/* Absorptive Law - This law enables a reduction in a complicated expression to + a simpler one by absorbing like terms. - for (count = 0; args != NULL; count++) - args = args->next; - return count; -} + A + (A.B) = (A.1) + (A.B) = A(1 + B) = A (OR Absorption Law) + A(A + B) = (A + 0).(A + B) = A + (0.B) = A (AND Absorption Law) + + Cases with multiple shared terms (duals appy as well) + A + B + (A.C) + (B.C) = (A + (A.C)) + (B + B.C)) (apply law to sides of external sum)) + = A + B + A + B + (A.B.C) = (A + (A.(B.C))) + B (X = B.C) + = (A + (A.(X)) + B (apply law to X) + = A + B +*/ static bool mail_search_args_simplify_drop_redundant_args(struct mail_search_args *all_args, struct mail_search_arg **argsp, bool and_arg) { - struct mail_search_arg *arg, **argp, one_arg, *lowest_arg = NULL; + if (*argsp == NULL || (*argsp)->next == NULL) + return FALSE; + + struct mail_search_arg *arg, **argp; enum mail_search_arg_type child_subargs_type; - unsigned int count, lowest_count = UINT_MAX; - bool ret = FALSE; + bool changed = FALSE; - if (*argsp == NULL) - return FALSE; + ARRAY(const struct mail_search_arg *) candidates; + t_array_init(&candidates, 1); child_subargs_type = and_arg ? SEARCH_OR : SEARCH_SUB; - - /* find the arg which has the lowest number of child args */ for (arg = *argsp; arg != NULL; arg = arg->next) { - if (arg->type != child_subargs_type) { - one_arg = *arg; - one_arg.next = NULL; - lowest_arg = &one_arg; - break; - } - count = mail_search_args_count(arg->value.subargs); - if (count < lowest_count) { - lowest_arg = arg->value.subargs; - lowest_count = count; + if (arg->type == child_subargs_type) { + const struct mail_search_arg *entry = arg->value.subargs; + if (entry == NULL || + array_lsearch(&candidates, &entry, + mail_search_arg_equals_p) != NULL) + continue; + array_push_back(&candidates, &entry); + } else { + struct mail_search_arg *copy = t_new(struct mail_search_arg, 1); + *copy = *arg; + copy->next = NULL; + const struct mail_search_arg *entry = copy; + array_push_back(&candidates, &entry); } } - i_assert(lowest_arg != NULL); - - /* if there are any args that include lowest_arg, drop the arg since - it's redundant. (non-SUB duplicates are dropped elsewhere.) */ - for (argp = argsp; *argp != NULL; ) { - if (*argp != lowest_arg && (*argp)->type == child_subargs_type && - (*argp)->value.subargs != lowest_arg && - mail_search_args_have_all_equal(*argp, lowest_arg)) { - if (all_args->init_refcount > 0) - mail_search_arg_one_deinit(*argp); - *argp = (*argp)->next; - ret = TRUE; - } else { - argp = &(*argp)->next; + + const struct mail_search_arg *candidate; + array_foreach_elem(&candidates, candidate) { + /* if there are any args that include the candidate - EXCEPT the + one that originally contained it - drop the arg, since it is + redundant. (non-SUB duplicates are dropped elsewhere.) */ + for (argp = argsp; *argp != NULL; ) { + if (*argp != candidate && + (*argp)->type == child_subargs_type && + (*argp)->value.subargs != candidate && + mail_search_args_have_all_equal(*argp, candidate)) { + if (all_args->init_refcount > 0) + mail_search_arg_one_deinit(*argp); + *argp = (*argp)->next; + changed = TRUE; + } else { + argp = &(*argp)->next; + } } } - return ret; + return changed; } static bool diff --git a/src/lib-storage/mail-search.c b/src/lib-storage/mail-search.c index 1b14b67d48..fc426533ec 100644 --- a/src/lib-storage/mail-search.c +++ b/src/lib-storage/mail-search.c @@ -733,6 +733,14 @@ bool mail_search_arg_equals(const struct mail_search_arg *arg1, return arg1 == NULL && arg2 == NULL; } +int mail_search_arg_equals_p(const struct mail_search_arg *const *arg1, + const struct mail_search_arg *const *arg2) +{ + if (arg1 == NULL && arg2 == NULL) return 0; + if (arg1 == NULL) return 1; + return mail_search_arg_equals(*arg1, *arg2) ? 0 : 1; +} + bool mail_search_args_equal(const struct mail_search_args *args1, const struct mail_search_args *args2) { diff --git a/src/lib-storage/mail-search.h b/src/lib-storage/mail-search.h index 2147175b13..8224e9ef2e 100644 --- a/src/lib-storage/mail-search.h +++ b/src/lib-storage/mail-search.h @@ -207,6 +207,8 @@ bool mail_search_args_equal(const struct mail_search_args *args1, structs. All the siblings of arg1 and arg2 are also compared. */ bool mail_search_arg_equals(const struct mail_search_arg *arg1, const struct mail_search_arg *arg2); +int mail_search_arg_equals_p(const struct mail_search_arg *const *arg1, + const struct mail_search_arg *const *arg2); /* Same as mail_search_arg_equals(), but don't compare siblings. */ bool mail_search_arg_one_equals(const struct mail_search_arg *arg1, const struct mail_search_arg *arg2); diff --git a/src/lib-storage/test-mail-search-args-simplify.c b/src/lib-storage/test-mail-search-args-simplify.c index a8b165b8bf..dcde23665b 100644 --- a/src/lib-storage/test-mail-search-args-simplify.c +++ b/src/lib-storage/test-mail-search-args-simplify.c @@ -218,6 +218,17 @@ static const struct { { "( OR TEXT unique1 TEXT unique2 ) ( OR TEXT unique3 TEXT unique4 )", "OR TEXT unique1 TEXT unique2 OR TEXT unique3 TEXT unique4" }, { "( OR TEXT common1 TEXT unique1 ) ( OR TEXT common1 TEXT unique2 ) TEXT unique3", "OR TEXT common1 TEXT unique1 OR TEXT common1 TEXT unique2 TEXT unique3" }, { "( OR TEXT common1 TEXT unique1 ) ( OR TEXT common1 TEXT common2 ) ( OR TEXT common2 TEXT unique2 )", "OR TEXT common1 TEXT unique1 OR TEXT common1 TEXT common2 OR TEXT common2 TEXT unique2" }, + + /* extra for simplifications on 2nd and later terms */ + { "( OR BODY z BODY x ) BODY x BODY y", "BODY x BODY y" }, + { "( OR BODY x BODY y ) ( OR BODY x BODY z )", "OR (BODY y BODY z) BODY x" }, + { "( OR BODY z BODY x ) BODY x BODY y", "BODY x BODY y" }, + { "( OR BODY z NOT BODY x ) BODY x BODY y", "OR BODY z NOT BODY x BODY x BODY y" }, + + { "( OR BODY z BODY y ) BODY x BODY y", "BODY x BODY y" }, + { "( OR BODY z BODY y ) ( OR BODY z BODY w ) BODY x BODY y BODY w", "BODY x BODY y BODY w" }, + + { "subject y", "SUBJECT y"}, }; static struct mail_search_args *