Leptonica 1.68
C Image Processing Library

queue.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  *   queue.c
00018  *
00019  *      Create/Destroy L_Queue
00020  *          L_QUEUE    *lqueueCreate()
00021  *          void       *lqueueDestroy()
00022  *
00023  *      Operations to add/remove to/from a L_Queue
00024  *          l_int32     lqueueAdd()
00025  *          l_int32     lqueueExtendArray()
00026  *          void       *lqueueRemove()
00027  *
00028  *      Accessors
00029  *          l_int32     lqueueGetCount()
00030  *
00031  *      Debug output
00032  *          l_int32     lqueuePrint()
00033  *
00034  *    The lqueue is a fifo that implements a queue of void* pointers.
00035  *    It can be used to hold a queue of any type of struct.
00036  *    Internally, it maintains two counters: 
00037  *        nhead:  location of head (in ptrs) from the beginning
00038  *                of the buffer
00039  *        nelem:  number of ptr elements stored in the queue
00040  *    As items are added to the queue, nelem increases.
00041  *    As items are removed, nhead increases and nelem decreases.
00042  *    Any time the tail reaches the end of the allocated buffer,
00043  *      all the pointers are shifted to the left, so that the head
00044  *      is at the beginning of the array.
00045  *    If the buffer becomes more than 3/4 full, it doubles in size.
00046  *
00047  *    [A circular queue would allow us to skip the shifting and
00048  *    to resize only when the buffer is full.  For most applications,
00049  *    the extra work we do for a linear queue is not significant.]
00050  */
00051 
00052 #include <stdio.h>
00053 #include <string.h>
00054 #include <stdlib.h>
00055 #include "allheaders.h"
00056 
00057 static const l_int32  MIN_BUFFER_SIZE = 20;             /* n'importe quoi */
00058 static const l_int32  INITIAL_BUFFER_ARRAYSIZE = 1024;  /* n'importe quoi */
00059 
00060 
00061 /*--------------------------------------------------------------------------*
00062  *                         L_Queue create/destroy                           *
00063  *--------------------------------------------------------------------------*/
00064 /*!
00065  *  lqueueCreate()
00066  *
00067  *      Input:  size of ptr array to be alloc'd (0 for default)
00068  *      Return: lqueue, or null on error
00069  *
00070  *  Notes:
00071  *      (1) Allocates a ptr array of given size, and initializes counters.
00072  */
00073 L_QUEUE *
00074 lqueueCreate(l_int32  nalloc)
00075 {
00076 L_QUEUE  *lq;
00077 
00078     PROCNAME("lqueueCreate");
00079 
00080     if (nalloc < MIN_BUFFER_SIZE)
00081         nalloc = INITIAL_BUFFER_ARRAYSIZE;
00082 
00083     if ((lq = (L_QUEUE *)CALLOC(1, sizeof(L_QUEUE))) == NULL)
00084         return (L_QUEUE *)ERROR_PTR("lq not made", procName, NULL);
00085     if ((lq->array = (void **)CALLOC(nalloc, sizeof(void *))) == NULL)
00086         return (L_QUEUE *)ERROR_PTR("ptr array not made", procName, NULL);
00087     lq->nalloc = nalloc;
00088     lq->nhead = lq->nelem = 0;
00089     return lq;
00090 }
00091 
00092 
00093 /*!
00094  *  lqueueDestroy()
00095  *
00096  *      Input:  &lqueue  (<to be nulled>)
00097  *              freeflag (TRUE to free each remaining struct in the array)
00098  *      Return: void
00099  *
00100  *  Notes:
00101  *      (1) If freeflag is TRUE, frees each struct in the array.
00102  *      (2) If freeflag is FALSE but there are elements on the array,
00103  *          gives a warning and destroys the array.  This will
00104  *          cause a memory leak of all the items that were on the queue.
00105  *          So if the items require their own destroy function, they
00106  *          must be destroyed before the queue.  The same applies to the
00107  *          auxiliary stack, if it is used.
00108  *      (3) To destroy the L_Queue, we destroy the ptr array, then
00109  *          the lqueue, and then null the contents of the input ptr.
00110  */
00111 void
00112 lqueueDestroy(L_QUEUE  **plq,
00113               l_int32    freeflag)
00114 {
00115 void     *item;
00116 L_QUEUE  *lq;
00117 
00118     PROCNAME("lqueueDestroy");
00119 
00120     if (plq == NULL) {
00121         L_WARNING("ptr address is NULL", procName);
00122         return;
00123     }
00124     if ((lq = *plq) == NULL)
00125         return;
00126 
00127     if (freeflag) {
00128         while(lq->nelem > 0) {
00129             item = lqueueRemove(lq);
00130             FREE(item);
00131         }
00132     }
00133     else if (lq->nelem > 0)
00134         L_WARNING_INT("memory leak of %d items in lqueue!",
00135                       procName, lq->nelem);
00136 
00137     if (lq->array)
00138         FREE(lq->array);
00139     if (lq->stack)
00140         lstackDestroy(&lq->stack, freeflag);
00141     FREE(lq);
00142     *plq = NULL;
00143 
00144     return;
00145 }
00146 
00147 
00148 /*--------------------------------------------------------------------------*
00149  *                                  Accessors                               *
00150  *--------------------------------------------------------------------------*/
00151 /*!
00152  *  lqueueAdd()
00153  *
00154  *      Input:  lqueue
00155  *              item to be added to the tail of the queue
00156  *      Return: 0 if OK, 1 on error
00157  *
00158  *  Notes:
00159  *      (1) The algorithm is as follows.  If the queue is populated
00160  *          to the end of the allocated array, shift all ptrs toward
00161  *          the beginning of the array, so that the head of the queue
00162  *          is at the beginning of the array.  Then, if the array is
00163  *          more than 0.75 full, realloc with double the array size.
00164  *          Finally, add the item to the tail of the queue.
00165  */
00166 l_int32
00167 lqueueAdd(L_QUEUE  *lq,
00168           void     *item)
00169 {
00170     PROCNAME("lqueueAdd");
00171 
00172     if (!lq)
00173         return ERROR_INT("lq not defined", procName, 1);
00174     if (!item)
00175         return ERROR_INT("item not defined", procName, 1);
00176     
00177         /* If filled to the end and the ptrs can be shifted to the left,
00178          * shift them. */
00179     if ((lq->nhead + lq->nelem >= lq->nalloc) && (lq->nhead != 0)) {
00180         memmove(lq->array, lq->array + lq->nhead, sizeof(void *) * lq->nelem);
00181         lq->nhead = 0;
00182     }
00183 
00184         /* If necessary, expand the allocated array by a factor of 2 */
00185     if (lq->nelem > 0.75 * lq->nalloc)
00186         lqueueExtendArray(lq);
00187 
00188         /* Now add the item */
00189     lq->array[lq->nhead + lq->nelem] = (void *)item;
00190     lq->nelem++;
00191 
00192     return 0;
00193 }
00194 
00195 
00196 /*!
00197  *  lqueueExtendArray()
00198  *
00199  *      Input:  lqueue
00200  *      Return: 0 if OK, 1 on error
00201  */
00202 l_int32
00203 lqueueExtendArray(L_QUEUE  *lq)
00204 {
00205     PROCNAME("lqueueExtendArray");
00206 
00207     if (!lq)
00208         return ERROR_INT("lq not defined", procName, 1);
00209 
00210     if ((lq->array = (void **)reallocNew((void **)&lq->array,
00211                                 sizeof(void *) * lq->nalloc,
00212                                 2 * sizeof(void *) * lq->nalloc)) == NULL)
00213         return ERROR_INT("new ptr array not returned", procName, 1);
00214 
00215     lq->nalloc = 2 * lq->nalloc;
00216     return 0;
00217 }
00218 
00219 
00220 /*!
00221  *  lqueueRemove()
00222  *
00223  *      Input:  lqueue
00224  *      Return: ptr to item popped from the head of the queue,
00225  *              or null if the queue is empty or on error
00226  *
00227  *  Notes:
00228  *      (1) If this is the last item on the queue, so that the queue
00229  *          becomes empty, nhead is reset to the beginning of the array.
00230  */
00231 void *
00232 lqueueRemove(L_QUEUE  *lq)
00233 {
00234 void  *item;
00235 
00236     PROCNAME("lqueueRemove");
00237 
00238     if (!lq)
00239         return (void *)ERROR_PTR("lq not defined", procName, NULL);
00240 
00241     if (lq->nelem == 0)
00242         return NULL;
00243     item = lq->array[lq->nhead];
00244     lq->array[lq->nhead] = NULL;
00245     if (lq->nelem == 1) 
00246         lq->nhead = 0;  /* reset head ptr */
00247     else
00248         (lq->nhead)++;  /* can't go off end of array because nelem > 1 */
00249     lq->nelem--;
00250     return item;
00251 }
00252        
00253 
00254 /*!
00255  *  lqueueGetCount()
00256  *
00257  *      Input:  lqueue
00258  *      Return: count, or 0 on error
00259  */
00260 l_int32
00261 lqueueGetCount(L_QUEUE  *lq)
00262 {
00263     PROCNAME("lqueueGetCount");
00264 
00265     if (!lq)
00266         return ERROR_INT("lq not defined", procName, 0);
00267 
00268     return lq->nelem;
00269 }
00270         
00271 
00272 /*---------------------------------------------------------------------*
00273  *                            Debug output                             *
00274  *---------------------------------------------------------------------*/
00275 /*!
00276  *  lqueuePrint()
00277  *  
00278  *      Input:  stream
00279  *              lqueue 
00280  *      Return: 0 if OK; 1 on error
00281  */
00282 l_int32
00283 lqueuePrint(FILE     *fp,
00284             L_QUEUE  *lq)
00285 {
00286 l_int32  i;
00287 
00288     PROCNAME("lqueuePrint");
00289 
00290     if (!fp)
00291         return ERROR_INT("stream not defined", procName, 1);
00292     if (!lq)
00293         return ERROR_INT("lq not defined", procName, 1);
00294 
00295     fprintf(fp, "\n L_Queue: nalloc = %d, nhead = %d, nelem = %d, array = %p\n",
00296             lq->nalloc, lq->nhead, lq->nelem, lq->array);
00297     for (i = lq->nhead; i < lq->nhead + lq->nelem; i++)
00298     fprintf(fp,   "array[%d] = %p\n", i, lq->array[i]);
00299 
00300     return 0;
00301 }
00302 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines