From: Cliff Woolley Date: Wed, 17 Jul 2002 00:01:03 +0000 (+0000) Subject: Add a couple of optimizations to the priority queue code: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bafd52d8e57b3a98cbb1b24e4d517fc412c02e17;p=apache Add a couple of optimizations to the priority queue code: * bubble_up and percolate_down do not need to do "swaps" -- they can just shift the existing items and reinsert the moving item once at the end * minchild() did not need that for loop -- a node can only ever have at most two children, and they are guaranteed to be adjacent git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@96089 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/experimental/cache_pqueue.c b/modules/experimental/cache_pqueue.c index 145be5b56b..424023e966 100644 --- a/modules/experimental/cache_pqueue.c +++ b/modules/experimental/cache_pqueue.c @@ -13,8 +13,8 @@ #include "cache_pqueue.h" #define left(i) (2*(i)) -#define right(i) ((2*i)+1) -#define parent(i) (i/2) +#define right(i) ((2*(i))+1) +#define parent(i) ((i)/2) /* * Priority queue structure */ @@ -67,60 +67,62 @@ apr_ssize_t cache_pq_size(cache_pqueue_t *q) return q->size; } -static void cache_pq_bubble_up(cache_pqueue_t*q, apr_ssize_t i) +static void cache_pq_bubble_up(cache_pqueue_t *q, apr_ssize_t i) { apr_ssize_t parent_node; - parent_node = parent(i); - - while (i > 1 && q->pri(q->d[parent_node]) < q->pri(q->d[i])) { - void *tmp; - tmp = q->d[i]; + void *moving_node = q->d[i]; + long moving_pri = q->pri(moving_node); + for (parent_node = parent(i); + ((i > 1) && (q->pri(q->d[parent_node]) < moving_pri)); + i = parent_node, parent_node = parent(i)) + { q->d[i] = q->d[parent_node]; - q->d[parent_node] = tmp; q->set(q->d[i], i); - q->set(q->d[parent_node], parent_node); - i = parent_node; - parent_node = parent(i); } + + q->d[i] = moving_node; + q->set(moving_node, i); } static apr_ssize_t minchild(cache_pqueue_t *q, apr_ssize_t i) { - apr_ssize_t y, minc; - minc = left(i); - if (minc >= q->size) - return -1; - - for (y = minc + 1; y <= right(i) && y < q->size; y++) { - if (q->pri(q->d[y]) > q->pri(q->d[minc])) - minc = y; + apr_ssize_t child_node = left(i); + + if (child_node >= q->size) + return 0; + + if ((child_node+1 < q->size) && + (q->pri(q->d[child_node+1]) > q->pri(q->d[child_node]))) + { + child_node++; /* use right child instead of left */ } - return minc; + + return child_node; } -static void cache_pq_percolate_down(cache_pqueue_t*q, apr_ssize_t i) +static void cache_pq_percolate_down(cache_pqueue_t *q, apr_ssize_t i) { - apr_ssize_t cx = minchild(q, i); - while ((cx != -1) && (q->pri(q->d[cx]) > q->pri(q->d[i]))) - { - void *tmp; + apr_ssize_t child_node; + void *moving_node = q->d[i]; + long moving_pri = q->pri(moving_node); - tmp = q->d[i]; - q->d[i] = q->d[cx]; - q->d[cx] = tmp; + while ((child_node = minchild(q, i)) && + (moving_pri < q->pri(q->d[child_node]))) + { + q->d[i] = q->d[child_node]; q->set(q->d[i], i); - q->set(q->d[cx], cx); - i = cx; - cx = minchild(q, i); + i = child_node; } + + q->d[i] = moving_node; + q->set(moving_node, i); } -apr_status_t cache_pq_insert(cache_pqueue_t *q, void* d) +apr_status_t cache_pq_insert(cache_pqueue_t *q, void *d) { void *tmp; apr_ssize_t i; - apr_ssize_t parent_node; apr_ssize_t newsize; if (!q) return APR_EGENERAL; @@ -137,26 +139,15 @@ apr_status_t cache_pq_insert(cache_pqueue_t *q, void* d) /* insert item */ i = q->size++; - parent_node = parent(i); - /* - * this is an optimization of the bubble-up as it doesn't - * have to swap the member around - */ - while ((i > 1) && q->pri(q->d[parent_node]) < q->pri(d)) { - q->d[i] = q->d[parent_node]; - q->set(q->d[i], i); - i = parent_node; - parent_node = parent(i); - } q->d[i] = d; - q->set(q->d[i], i); + cache_pq_bubble_up(q, i); return APR_SUCCESS; } /* * move a existing entry to a new priority */ -void cache_pq_change_priority(cache_pqueue_t*q, +void cache_pq_change_priority(cache_pqueue_t *q, long old_priority, long new_priority, void *d) @@ -170,7 +161,7 @@ void cache_pq_change_priority(cache_pqueue_t*q, cache_pq_percolate_down(q, posn); } -apr_status_t cache_pq_remove(cache_pqueue_t *q, void* d) +apr_status_t cache_pq_remove(cache_pqueue_t *q, void *d) { apr_ssize_t posn; void *popped = NULL; @@ -241,6 +232,7 @@ static void cache_pq_set_null( void*d, apr_ssize_t val) { /* do nothing */ } + /* * this is a debug function.. so it's EASY not fast */ @@ -260,6 +252,7 @@ void cache_pq_dump(cache_pqueue_t *q, print(out, q->d[i]); } } + /* * this is a debug function.. so it's EASY not fast */