From: Igor Putovny Date: Mon, 29 Jan 2024 12:13:06 +0000 (+0100) Subject: Refactor functions for comparing buckets and computing union and intersection of... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d6d8b1adb91895a96b883133deb2faaf64c28ce;p=thirdparty%2Fbird.git Refactor functions for comparing buckets and computing union and intersection of buckets --- diff --git a/proto/aggregator/aggregator.c b/proto/aggregator/aggregator.c index 461fb9082..a742b24be 100644 --- a/proto/aggregator/aggregator.c +++ b/proto/aggregator/aggregator.c @@ -218,151 +218,147 @@ first_pass(struct trie_node *node, slab *trie_slab) first_pass(node->child[1], trie_slab); } -/* - * Compare two bucket pointers. - */ static int -aggregator_bucket_compare(const void *a, const void *b) +aggregator_bucket_compare(const struct aggregator_bucket *a, const struct aggregator_bucket *b) { assert(a != NULL); assert(b != NULL); - if (a == NULL && b == NULL) - return 0; - - if (a == NULL) + if ((uintptr_t)a < (uintptr_t)b) return -1; - if (b == NULL) + if ((uintptr_t)a > (uintptr_t)b) return 1; - const struct aggregator_bucket *fst = (struct aggregator_bucket *)a; - const struct aggregator_bucket *snd = (struct aggregator_bucket *)b; + return 0; +} - /* There is linear ordering on pointers */ - if (fst < snd) - return -1; +static int +aggregator_bucket_compare_wrapper(const void *a, const void *b) +{ + assert(a != NULL); + assert(b != NULL); - if (fst > snd) - return 1; + const struct aggregator_bucket *fst = *(struct aggregator_bucket **)a; + const struct aggregator_bucket *snd = *(struct aggregator_bucket **)b; - return 0; + return aggregator_bucket_compare(fst, snd); } /* - * Compute intersection of two sets of potential buckets in @left and @right and put result in @node + * Compute union of two sets of potential buckets in @left and @right and put result in @node */ -static void -aggregator_bucket_intersect(const struct trie_node *left, const struct trie_node *right, struct trie_node *node) +static void unionize_buckets(const struct trie_node *left, const struct trie_node *right, struct trie_node *node) { - assert(node != NULL); - assert(left != NULL); + assert(left != NULL); assert(right != NULL); + assert(node != NULL); - int i = 0; - int j = 0; + struct aggregator_bucket *input_buckets[64] = { 0 }; + int input_count = 0; - while (i < left->potential_buckets_count && j < right->potential_buckets_count) + for (int i = 0; i < left->potential_buckets_count; i++) + input_buckets[input_count++] = left->potential_buckets[i]; + + for (int i = 0; i < right->potential_buckets_count; i++) + input_buckets[input_count++] = right->potential_buckets[i]; + + qsort(input_buckets, input_count, sizeof(struct aggregator_bucket *), aggregator_bucket_compare_wrapper); + + struct aggregator_bucket *output_buckets[64] = { 0 }; + int output_count = 0; + + for (int i = 0; i < input_count; i++) { - if (node->potential_buckets_count >= MAX_POTENTIAL_BUCKETS_COUNT) - return; - int res = aggregator_bucket_compare(left->potential_buckets[i], right->potential_buckets[j]); + if (output_count != 0 && output_buckets[output_count - 1] == input_buckets[i]) + continue; - if (res == 0) - { - node->potential_buckets[node->potential_buckets_count++] = left->potential_buckets[i]; - i++; - j++; - } - else if (res == -1) - i++; - else if (res == 1) - j++; - else - bug("Impossible"); + output_buckets[output_count++] = input_buckets[i]; + } + + // strictly greater + for (int i = 1; i < output_count; i++) + assert(output_buckets[i - 1] < output_buckets[i]); + + // duplicates + for (int i = 0; i < output_count; i++) + for (int j = i + 1; j < output_count; j++) + assert(output_buckets[i] != output_buckets[j]); + + for (int i = 0; i < output_count; i++) + { + if (node->potential_buckets_count >= MAX_POTENTIAL_BUCKETS_COUNT) + break; - assert(node->potential_buckets_count <= MAX_POTENTIAL_BUCKETS_COUNT); + node->potential_buckets[node->potential_buckets_count++] = output_buckets[i]; } } /* - * Compute union of two sets of potential buckets in @left and @right and put result in @node + * Compute intersection of two sets of potential buckets in @left and @right and put result in @node */ static void -aggregator_bucket_unionize(const struct trie_node *left, const struct trie_node *right, struct trie_node *node) +intersect_buckets(const struct trie_node *left, const struct trie_node *right, struct trie_node *node) { - assert(node != NULL); - assert(left != NULL); + assert(left != NULL); assert(right != NULL); + assert(node != NULL); - int i = 0; - int j = 0; - - while (i < left->potential_buckets_count && j < right->potential_buckets_count) - { - if (node->potential_buckets_count >= MAX_POTENTIAL_BUCKETS_COUNT) - return; + struct aggregator_bucket *fst[64] = { 0 }; + struct aggregator_bucket *snd[64] = { 0 }; - int res = aggregator_bucket_compare(left->potential_buckets[i], right->potential_buckets[j]); + int fst_count = 0; + int snd_count = 0; - switch (res) - { - case 0: - /* - * If there is no element yet or if the last and new elements are not equal - * (which means elements do not repeat), insert new element to the set. - */ - if (node->potential_buckets_count == 0 || node->potential_buckets[node->potential_buckets_count - 1] != left->potential_buckets[i]) - node->potential_buckets[node->potential_buckets_count++] = left->potential_buckets[i]; + for (int i = 0; i < left->potential_buckets_count; i++) + fst[fst_count++] = left->potential_buckets[i]; - i++; - j++; - break; + for (int i = 0; i < right->potential_buckets_count; i++) + snd[snd_count++] = right->potential_buckets[i]; - case -1: - if (node->potential_buckets_count == 0 || node->potential_buckets[node->potential_buckets_count - 1] != left->potential_buckets[i]) - node->potential_buckets[node->potential_buckets_count++] = left->potential_buckets[i]; + qsort(fst, fst_count, sizeof(struct aggregator_bucket *), aggregator_bucket_compare_wrapper); + qsort(snd, snd_count, sizeof(struct aggregator_bucket *), aggregator_bucket_compare_wrapper); - i++; - break; + struct aggregator_bucket *output[64] = { 0 }; + int output_count = 0; - case 1: - if (node->potential_buckets_count == 0 || node->potential_buckets[node->potential_buckets_count - 1] != right->potential_buckets[j]) - node->potential_buckets[node->potential_buckets_count++] = right->potential_buckets[j]; + int i = 0; + int j = 0; - j++; - break; + while (i < left->potential_buckets_count && j < right->potential_buckets_count) + { + int res = aggregator_bucket_compare(left->potential_buckets[i], right->potential_buckets[j]); - default: - bug("Impossible"); + if (res == 0) + { + output[output_count++] = left->potential_buckets[i]; + i++; + j++; } - - assert(node->potential_buckets_count <= MAX_POTENTIAL_BUCKETS_COUNT); + else if (res == -1) + i++; + else if (res == 1) + j++; + else + bug("Impossible"); } - while (i < left->potential_buckets_count) - { - if (node->potential_buckets_count >= MAX_POTENTIAL_BUCKETS_COUNT) - return; - - if (node->potential_buckets_count == 0 || node->potential_buckets[node->potential_buckets_count - 1] != left->potential_buckets[i]) - node->potential_buckets[node->potential_buckets_count++] = left->potential_buckets[i]; + // strictly greater + for (int k = 1; k < output_count; k++) + assert(output[k - 1] < output[k]); - i++; - assert(node->potential_buckets_count <= MAX_POTENTIAL_BUCKETS_COUNT); - } + // duplicates + for (int k = 0; k < output_count; k++) + for (int l = k + 1; l < output_count; l++) + assert(output[k] != output[l]); - while (j < right->potential_buckets_count) + for (int k = 0; k < output_count; k++) { if (node->potential_buckets_count >= MAX_POTENTIAL_BUCKETS_COUNT) - return; - - if (node->potential_buckets_count == 0 || node->potential_buckets[node->potential_buckets_count - 1] != right->potential_buckets[j]) - node->potential_buckets[node->potential_buckets_count++] = right->potential_buckets[j]; + break; - j++; - assert(node->potential_buckets_count <= MAX_POTENTIAL_BUCKETS_COUNT); + node->potential_buckets[node->potential_buckets_count++] = output[k]; } } @@ -376,7 +372,10 @@ bucket_sets_are_disjoint(const struct trie_node *left, const struct trie_node *r assert(right != NULL); if (left->potential_buckets_count == 0 || right->potential_buckets_count == 0) + { + log("Buckets are disjoint"); return 1; + } int i = 0; int j = 0; @@ -426,8 +425,17 @@ second_pass(struct trie_node *node) second_pass(left); second_pass(right); - qsort(left->potential_buckets, left->potential_buckets_count, sizeof(struct aggregator_bucket *), aggregator_bucket_compare); - qsort(right->potential_buckets, right->potential_buckets_count, sizeof(struct aggregator_bucket *), aggregator_bucket_compare); + // duplicates + for (int i = 0; i < left->potential_buckets_count; i++) + for (int j = i + 1; j < left->potential_buckets_count; j++) + assert(left->potential_buckets[i] != left->potential_buckets[j]); + + for (int i = 0; i < right->potential_buckets_count; i++) + for (int j = i + 1; j < right->potential_buckets_count; j++) + assert(right->potential_buckets[i] != right->potential_buckets[j]); + + qsort(left->potential_buckets, left->potential_buckets_count, sizeof(struct aggregator_bucket *), aggregator_bucket_compare_wrapper); + qsort(right->potential_buckets, right->potential_buckets_count, sizeof(struct aggregator_bucket *), aggregator_bucket_compare_wrapper); for (int i = 1; i < left->potential_buckets_count; i++) { @@ -440,9 +448,9 @@ second_pass(struct trie_node *node) } if (bucket_sets_are_disjoint(left, right)) - aggregator_bucket_unionize(left, right, node); + unionize_buckets(left, right, node); else - aggregator_bucket_intersect(left, right, node); + intersect_buckets(left, right, node); } /*