Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
priority_queue.c
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 /* ====================================================================
00037  * ====================================================================
00038  *
00039  *
00040  * Description:
00041  *
00042  *      Priority queue implementation
00043  *
00044  * ====================================================================
00045  * ====================================================================
00046  */
00047 
00048 #include "defs.h"
00049 #include "errors.h"
00050 #include "mempool.h"
00051 #include "priority_queue.h"
00052 
00057 #define PRQ_comparison_fn(x)    ((x)->comparison_fn)
00058 #define PRQ_mem_pool(x)         ((x)->mem_pool)
00059 #define PRQ_size(x)             ((x)->size)
00060 #define PRQ_allocated_size(x)   ((x)->allocated_size)
00061 #define PRQ_expansion_factor(x) ((x)->expansion_factor)
00062 #define PRQ_get_index_fn(x)     ((x)->get_index_fn)
00063 #define PRQ_set_index_fn(x)     ((x)->set_index_fn)
00064 #define PRQ_heap_vector(x)      ((x)->heap_vector)
00065 
00066 
00072 /* =======================================================================
00073  *
00074  *  PRQ_Ith
00075  *
00076  *  See interface description.
00077  *
00078  * =======================================================================
00079  */
00080 void*
00081 PRQ_Ith(
00082   PRQ*    prq,
00083   INT32   i
00084 )
00085 {
00086   return PRQ_heap_vector(prq)[i-1];
00087 }
00088 
00089 /* =======================================================================
00090  *
00091  *  PRQ_Set_Ith
00092  *
00093  *  See interface description.
00094  *
00095  * =======================================================================
00096  */
00097 extern INT32
00098 PRQ_Size(
00099     PRQ*    prq
00100 )
00101 {
00102   return PRQ_size(prq);
00103 }
00104 
00105 /* =======================================================================
00106  *
00107  *  PRQ_Set_Ith
00108  *
00109  *  Make 'element' the 'i'-th element of 'prq'.
00110  *
00111  * =======================================================================
00112  */
00113 static void
00114 PRQ_Set_Ith(
00115   PRQ*   prq,
00116   INT32  i,
00117   void*  element
00118 )
00119 {
00120   if ( PRQ_set_index_fn(prq) != NULL ) {
00121     PRQ_set_index_fn(prq)(element,i);
00122   }
00123 
00124   PRQ_heap_vector(prq)[i-1] = element;
00125 }
00126 
00127 
00137 /* =======================================================================
00138  *
00139  *  PRQ_Upheap
00140  *
00141  *  Sifts the heap_element at position 'index' in the heap (1-based) up to
00142  *  its appropriate position in the heap.  If the heap element should not
00143  *  move closer to the root ("up"), it is not moved.  The the new index of
00144  *  the heap_element is returned.
00145  *
00146  * =======================================================================
00147  */
00148 static INT32
00149 PRQ_Upheap(
00150   PRQ*  prq,
00151   INT32 index
00152 )
00153 {
00154   void* element;
00155 
00156   FmtAssert(index <= PRQ_size(prq) && index > 0,
00157             ("PRQ_Upheap:  index %d out of bounds %d",
00158              index,PRQ_size(prq)));
00159 
00160   element = PRQ_Ith(prq,index);
00161 
00162   /* Note we do not perform a complete interchange in the body of the
00163    * loop.  We wait until we have found the correct position for
00164    * 'element' before setting it.
00165    */
00166   while ( index > 1 ) {
00167     INT32 parent_index = index / 2;
00168     void* parent       = PRQ_Ith(prq,parent_index);
00169 
00170     if ( ! PRQ_comparison_fn(prq)(element,parent) )
00171       break;
00172 
00173     PRQ_Set_Ith(prq,index,parent);
00174     index = parent_index;
00175   }
00176 
00177   PRQ_Set_Ith(prq,index,element);
00178 
00179   return index;
00180 }
00181 
00182 
00183 /* =======================================================================
00184  *
00185  *  PRQ_Downheap
00186  *
00187  *  Sifts the heap element at position 'index' in the heap (1-based) down
00188  *  to its appropriate position in the heap.  If the heap element should
00189  *  not move further from the root ("down"), it is not moved.  The the new
00190  *  index of the heap_element is returned.
00191  *
00192  * =======================================================================
00193  */
00194 static INT32
00195 PRQ_Downheap(
00196   PRQ*  prq,
00197   INT32 index
00198 )
00199 {
00200   void* element;
00201 
00202   FmtAssert(index <= PRQ_size(prq) && index > 0,
00203             ("PRQ_down:  index %d out of bounds %d",
00204              index,PRQ_size(prq)));
00205 
00206   element = PRQ_Ith(prq,index);
00207 
00208   /* Note we do not perform a complete interchange in the body of the
00209    * loop.  We wait until we have found the correct position for
00210    * 'element' before setting it.
00211    */
00212 
00213   for(;;) {
00214     void* left_child;
00215     INT32 left_child_index  = index * 2;
00216     INT32 right_child_index = left_child_index + 1;
00217 
00218     if ( left_child_index > PRQ_size(prq) ) break;
00219 
00220     left_child = PRQ_Ith(prq,left_child_index);
00221 
00222     /* If the right child is in the heap, and is "larger" than the left,
00223      * try to interchange 'element' with the right child.  If the
00224      * interchange test fails, 'index' is the correct position for
00225      * element.
00226      */
00227     if (    right_child_index <= PRQ_size(prq)
00228          && PRQ_comparison_fn(prq)(PRQ_Ith(prq,right_child_index),
00229                                    left_child)
00230     ) {
00231       void* right_child = PRQ_Ith(prq,right_child_index);
00232 
00233       if ( PRQ_comparison_fn(prq)(right_child,element) ) {
00234         PRQ_Set_Ith(prq,index,right_child);
00235         index = right_child_index;
00236       }
00237       else
00238         break;
00239     }
00240     else if ( PRQ_comparison_fn(prq)(left_child,element) ) {
00241       /* interchange with left child */
00242       PRQ_Set_Ith(prq,index,left_child);
00243       index = left_child_index;
00244     }
00245     else
00246       break;
00247   }
00248 
00249   PRQ_Set_Ith(prq,index,element);
00250 
00251   return index;
00252 }
00253 
00254 
00261 /* =======================================================================
00262  *
00263  *  PRQ_Initialize
00264  *
00265  *  See interface description.
00266  *
00267  * =======================================================================
00268  */
00269 void
00270 PRQ_Initialize(
00271     PRQ*                        prq,
00272     PRQ_COMPARISON_FUNCTION     comparison_fn,
00273     PRQ_GET_INDEX_FUNCTION      get_fn,
00274     PRQ_SET_INDEX_FUNCTION      set_fn,
00275     MEM_POOL*                   pool,
00276     INT32                       initial_size,
00277     INT32                       expansion_factor
00278 )
00279 {
00280   if ( initial_size <= 0 ) {
00281     DevWarn("Non positive priority queue initial size %d.  Using 200",
00282             initial_size);
00283     initial_size = 200;
00284   }
00285 
00286   if ( expansion_factor <= 100 ) {
00287     DevWarn("Priority queue expansion factor should be at least 100.  "
00288             "Was %d using 200",expansion_factor);
00289     expansion_factor = 200;
00290   }
00291 
00292   PRQ_comparison_fn(prq) = comparison_fn;
00293   PRQ_get_index_fn(prq) = get_fn;
00294   PRQ_set_index_fn(prq) = set_fn;
00295   PRQ_mem_pool(prq) = pool;
00296   PRQ_size(prq) = 0;
00297   PRQ_allocated_size(prq) = initial_size;
00298   PRQ_expansion_factor(prq) = expansion_factor;
00299   PRQ_heap_vector(prq) = TYPE_MEM_POOL_ALLOC_N(void*,pool,initial_size);
00300 }
00301 
00302 
00303 /* =======================================================================
00304  *
00305  *  PRQ_DeleteTop
00306  *
00307  *  See interface description.
00308  *
00309  * =======================================================================
00310  */
00311 void*
00312 PRQ_Delete_Top( PRQ* prq )
00313 {
00314   void* top_element;
00315 
00316   FmtAssert(PRQ_size(prq) > 0,("Deleting from empty heap"));
00317 
00318   top_element = PRQ_Ith(prq,1);
00319   if ( PRQ_size(prq) == 1 )
00320     PRQ_size(prq) = 0;
00321   else {
00322     /* Move the bottom element to the top nad sift it down to its proper
00323      * position in the heap.
00324      */
00325     void* bottom_element = PRQ_Ith(prq,PRQ_size(prq));
00326 
00327     --PRQ_size(prq);
00328     PRQ_Set_Ith(prq,1,bottom_element);
00329     (void) PRQ_Downheap(prq,1);
00330   }
00331 
00332   return top_element;
00333 }
00334 
00335 
00336 
00337 /* =======================================================================
00338  *
00339  *  PRQ_Top
00340  *
00341  *  See interface description.
00342  *
00343  * =======================================================================
00344  */
00345 void*
00346 PRQ_Top( PRQ* prq )
00347 {
00348   FmtAssert(PRQ_size(prq) > 0,("Topping empty queue"));
00349 
00350   return PRQ_Ith(prq,1);
00351 }
00352 
00353 
00354 /* =======================================================================
00355  *
00356  *  PRQ_InsertElement
00357  *
00358  *  See interface description.
00359  *
00360  * =======================================================================
00361  */
00362 void
00363 PRQ_Insert(
00364   PRQ*  prq,
00365   void* element
00366 )
00367 {
00368   /* Grow 'heap_vector' if necessary.
00369    */
00370   if ( PRQ_size(prq) == PRQ_allocated_size(prq) ) {
00371     INT32 new_size = (PRQ_size(prq) * PRQ_expansion_factor(prq)) / 100;
00372 
00373     if ( new_size <= PRQ_size(prq) ) {
00374       DevWarn("Priority queue expansion failed -- forcing expansion by 10");
00375       new_size = PRQ_size(prq) + 10;
00376     }
00377 
00378     PRQ_heap_vector(prq) =
00379       TYPE_MEM_POOL_REALLOC_N(void*,PRQ_mem_pool(prq),PRQ_heap_vector(prq),
00380                                                       PRQ_allocated_size(prq),
00381                                                       new_size);
00382     PRQ_allocated_size(prq) = new_size;
00383   }
00384 
00385   /* Add element to bottom of heap, and sift it up to its appropriate
00386    * position.
00387    */
00388   ++PRQ_size(prq);
00389   PRQ_Set_Ith(prq,PRQ_size(prq),element);
00390   (void) PRQ_Upheap(prq,PRQ_size(prq));
00391 }
00392 
00393 
00394 /* =======================================================================
00395  *
00396  *  PRQ_RemoveElement
00397  *
00398  *  See interface description.
00399  *
00400  * =======================================================================
00401  */
00402 void
00403 PRQ_Remove(
00404   PRQ*  prq,
00405   void* element
00406 )
00407 {
00408   INT32 index = UNDEFINED;
00409 
00410   FmtAssert(PRQ_size(prq) > 0,("PRQ_RemoveElement -- empty queue"));
00411 
00412   /* Find the index of 'element' in the heap.If we have an index function,
00413    * we can get the index of the element directly.  Otherwise we search
00414    * for it.
00415    */
00416 
00417   if ( PRQ_get_index_fn(prq) ) {
00418     index =  PRQ_get_index_fn(prq)(element);
00419     FmtAssert(element == PRQ_Ith(prq,index),
00420               ("Invalid priority queue index %d",index));
00421   }
00422   else {
00423     INT32 i;
00424 
00425     for ( i = 1; i <= PRQ_size(prq); ++i ) {
00426       if ( PRQ_Ith(prq,i) == element ) {
00427         index = i;
00428         break;
00429       }
00430     }
00431   }
00432 
00433   FmtAssert(index != UNDEFINED,("Remove a PRQ element not in queue"));
00434 
00435   /* If element is the bottom elment in the heap, simply decrement the
00436    * size, and we are done.
00437    */
00438   if ( index == PRQ_size(prq) )
00439     --PRQ_size(prq);
00440   else {
00441     /* Replace 'element' at position 'index' with the bottom element of
00442      * the heap.  Then try to sift the newly placed 'bottom_element' up
00443      * and then down,to make sure it is in its correct position.
00444      */
00445     void* bottom_element = PRQ_Ith(prq,PRQ_size(prq));
00446 
00447     /* Reposition bottom_element.
00448      */
00449     --PRQ_size(prq);
00450     PRQ_Set_Ith(prq,index,bottom_element);
00451     
00452     /* Try to move it up.  If it moves we know it has found its
00453      * appropriate position.  Otherwise, try to move it down.
00454      */
00455     if ( index == PRQ_Upheap(prq,index) )
00456       (void) PRQ_Downheap(prq,index);
00457   }
00458 }
00459 
00460 
00461 /* =======================================================================
00462  *
00463  *  PRQ_Reset
00464  *
00465  *  See interface description.
00466  *
00467  * =======================================================================
00468  */
00469 void
00470 PRQ_Reset( PRQ* prq )
00471 {
00472   PRQ_size(prq) = 0;
00473 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines