Leptonica 1.68
C Image Processing Library

ptra.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  *   ptra.c
00018  *
00019  *      Ptra creation and destruction
00020  *          L_PTRA      *ptraCreate()
00021  *          void        *ptraDestroy()
00022  *
00023  *      Add/insert/remove/replace generic ptr object
00024  *          l_int32      ptraAdd()
00025  *          l_int32      ptraExtendArray()
00026  *          l_int32      ptraInsert()
00027  *          void        *ptraGetHandle()
00028  *          void        *ptraRemove()
00029  *          void        *ptraRemoveLast()
00030  *          void        *ptraReplace()
00031  *          l_int32      ptraSwap()
00032  *          l_int32      ptraCompactArray()
00033  *
00034  *      Other array operations
00035  *          l_int32      ptraReverse()
00036  *          l_int32      ptraJoin()
00037  *
00038  *      Simple Ptra accessors
00039  *          l_int32      ptraGetMaxIndex()
00040  *          l_int32      ptraGetActualCount()
00041  *          void        *ptraGetPtrToItem()
00042  *
00043  *      Ptraa creation and destruction
00044  *          L_PTRAA     *ptraaCreate()
00045  *          void        *ptraaDestroy()
00046  *
00047  *      Ptraa accessors
00048  *          l_int32      ptraaGetSize()
00049  *          l_int32      ptraaInsertPtra()
00050  *          L_PTRA      *ptraaGetPtra()
00051  *
00052  *      Ptraa conversion
00053  *          L_PTRA      *ptraaFlattenToPtra()
00054  *
00055  *      Functions using L_PTRA
00056  *          NUMA        *numaGetBinSortIndex()
00057  *
00058  *    Notes on the Ptra:
00059  *
00060  *    (1) The Ptra is a struct, not an array.  Always use the accessors
00061  *        in this file, never the fields directly.
00062  *    (2) Items can be placed anywhere in the allocated ptr array,
00063  *        including one index beyond the last ptr (in which case the
00064  *        ptr array is realloc'd).
00065  *    (3) Thus, the items on the ptr array need not be compacted.  In
00066  *        general there will be null pointers in the ptr array.
00067  *    (4) A compacted array will remain compacted on removal if
00068  *        arbitrary items are removed with compaction, or if items
00069  *        are removed from the end of the array.
00070  *    (5) For addition to and removal from the end of the array, this
00071  *        functions exactly like a stack, and with the same O(1) cost.
00072  *    (6) This differs from the generic stack in that we allow
00073  *        random access for insertion, removal and replacement.
00074  *        Removal can be done without compacting the array.
00075  *        Insertion into a null ptr in the array has no effect on
00076  *        the other pointers, but insertion into a location already
00077  *        occupied by an item has a cost proportional to the
00078  *        distance to the next null ptr in the array.
00079  *    (7) Null ptrs are valid input args for both insertion and
00080  *        replacement; this allows arbitrary swapping.
00081  *    (8) The item in the array with the largest index is at pa->imax.
00082  *        This can be any value from -1 (initialized; all array ptrs
00083  *        are null) up to pa->nalloc - 1 (the last ptr in the array).
00084  *    (9) In referring to the array: the first ptr is the "top" or
00085  *        "beginning"; the last pointer is the "bottom" or "end";
00086  *        items are shifted "up" towards the top when compaction occurs;
00087  *        and items are shifted "down" towards the bottom when forced to
00088  *        move due to an insertion.
00089  *   (10) It should be emphasized that insertion, removal and replacement
00090  *        are general:
00091  *         * You can insert an item into any ptr location in the
00092  *           allocated ptr array, as well as into the next ptr address
00093  *           beyond the allocated array (in which case a realloc will occur).   
00094  *         * You can remove or replace an item from any ptr location
00095  *           in the allocated ptr array.
00096  *         * When inserting into an occupied location, you have
00097  *           three options for downshifting.
00098  *         * When removing, you can either leave the ptr null or
00099  *           compact the array.
00100  *
00101  *    Notes on the Ptraa:
00102  *
00103  *    (1) The Ptraa is a fixed size ptr array for holding Ptra.
00104  *        In that respect, it is different from other pointer arrays, which
00105  *        are extensible and grow using the *Add*() functions.
00106  *    (2) In general, the Ptra ptrs in the Ptraa can be randomly occupied.
00107  *        A typical usage is to allow an O(n) horizontal sort of Pix,
00108  *        where the size of the Ptra array is the width of the image,
00109  *        and each Ptra is an array of all the Pix at a specific x location.
00110  */
00111 
00112 #include <stdio.h>
00113 #include <stdlib.h>
00114 #include "allheaders.h"
00115 
00116 static const l_int32 INITIAL_PTR_ARRAYSIZE = 20;      /* n'importe quoi */
00117 
00118 
00119 /*--------------------------------------------------------------------------*
00120  *                       Ptra creation and destruction                      *
00121  *--------------------------------------------------------------------------*/
00122 /*!
00123  *  ptraCreate()
00124  *
00125  *      Input:  size of ptr array to be alloc'd (0 for default)
00126  *      Return: pa, or null on error
00127  */
00128 L_PTRA *
00129 ptraCreate(l_int32  n)
00130 {
00131 L_PTRA  *pa;
00132 
00133     PROCNAME("ptraCreate");
00134 
00135     if (n <= 0)
00136         n = INITIAL_PTR_ARRAYSIZE;
00137 
00138     if ((pa = (L_PTRA *)CALLOC(1, sizeof(L_PTRA))) == NULL)
00139         return (L_PTRA *)ERROR_PTR("pa not made", procName, NULL);
00140     if ((pa->array = (void **)CALLOC(n, sizeof(void *))) == NULL)
00141         return (L_PTRA *)ERROR_PTR("ptr array not made", procName, NULL);
00142 
00143     pa->nalloc = n;
00144     pa->imax = -1;
00145     pa->nactual = 0;
00146 
00147     return pa;
00148 }
00149 
00150 
00151 /*!
00152  *  ptraDestroy()
00153  *
00154  *      Input:  &ptra (<to be nulled>)
00155  *              freeflag (TRUE to free each remaining item in the array)
00156  *              warnflag (TRUE to warn if any remaining items are not destroyed)
00157  *      Return: void
00158  *
00159  *  Notes:
00160  *      (1) If @freeflag == TRUE, frees each item in the array.
00161  *      (2) If @freeflag == FALSE and warnflag == TRUE, and there are
00162  *          items on the array, this gives a warning and destroys the array.
00163  *          If these items are not owned elsewhere, this will cause
00164  *          a memory leak of all the items that were on the array.
00165  *          So if the items are not owned elsewhere and require their
00166  *          own destroy function, they must be destroyed before the ptra.
00167  *      (3) If warnflag == FALSE, no warnings will be issued.  This is
00168  *          useful if the items are owned elsewhere, such as a
00169  *          PixMemoryStore().
00170  *      (4) To destroy the ptra, we destroy the ptr array, then
00171  *          the ptra, and then null the contents of the input ptr.
00172  */
00173 void
00174 ptraDestroy(L_PTRA  **ppa,
00175             l_int32   freeflag,
00176             l_int32   warnflag)
00177 {
00178 l_int32  i, nactual;
00179 void    *item;
00180 L_PTRA  *pa;
00181 
00182     PROCNAME("ptraDestroy");
00183 
00184     if (ppa == NULL) {
00185         L_WARNING("ptr address is NULL", procName);
00186         return;
00187     }
00188     if ((pa = *ppa) == NULL)
00189         return;
00190 
00191     ptraGetActualCount(pa, &nactual);
00192     if (nactual > 0) {
00193         if (freeflag) {
00194             for (i = 0; i <= pa->imax; i++) {
00195                 if ((item = ptraRemove(pa, i, L_NO_COMPACTION)) != NULL)
00196                     FREE(item);
00197             }
00198         }
00199         else if (warnflag)
00200             L_WARNING_INT("potential memory leak of %d items in ptra",
00201                           procName, nactual);
00202     }
00203 
00204     FREE(pa->array);
00205     FREE(pa);
00206     *ppa = NULL;
00207     return;
00208 }
00209 
00210 
00211 /*--------------------------------------------------------------------------*
00212  *               Add/insert/remove/replace generic ptr object               *
00213  *--------------------------------------------------------------------------*/
00214 /*!
00215  *  ptraAdd()
00216  *
00217  *      Input:  ptra
00218  *              item  (generic ptr to a struct)
00219  *      Return: 0 if OK, 1 on error
00220  *
00221  *  Notes:
00222  *      (1) This adds the element to the next location beyond imax,
00223  *          which is the largest occupied ptr in the array.  This is
00224  *          what you expect from a stack, where all ptrs up to and
00225  *          including imax are occupied, but here the occuption of
00226  *          items in the array is entirely arbitrary.
00227  */
00228 l_int32
00229 ptraAdd(L_PTRA  *pa,
00230         void    *item)
00231 {
00232 l_int32  imax;
00233 
00234     PROCNAME("ptraAdd");
00235 
00236     if (!pa)
00237         return ERROR_INT("pa not defined", procName, 1);
00238     if (!item)
00239         return ERROR_INT("item not defined", procName, 1);
00240     
00241     ptraGetMaxIndex(pa, &imax);
00242     if (imax >= pa->nalloc - 1 && ptraExtendArray(pa))
00243         return ERROR_INT("extension failure", procName, 1);
00244     pa->array[imax + 1] = (void *)item;
00245     pa->imax++;
00246     pa->nactual++;
00247     return 0;
00248 }
00249 
00250 
00251 /*!
00252  *  ptraExtendArray()
00253  *
00254  *      Input:  ptra 
00255  *      Return: 0 if OK, 1 on error
00256  */
00257 l_int32
00258 ptraExtendArray(L_PTRA  *pa)
00259 {
00260     PROCNAME("ptraExtendArray");
00261 
00262     if (!pa)
00263         return ERROR_INT("pa not defined", procName, 1);
00264 
00265     if ((pa->array = (void **)reallocNew((void **)&pa->array,
00266                                 sizeof(void *) * pa->nalloc,
00267                                 2 * sizeof(void *) * pa->nalloc)) == NULL)
00268             return ERROR_INT("new ptr array not returned", procName, 1);
00269 
00270     pa->nalloc *= 2;
00271     return 0;
00272 }
00273 
00274 
00275 /*!
00276  *  ptraInsert()
00277  *
00278  *      Input:  ptra 
00279  *              index (location in ptra to insert new value)
00280  *              item  (generic ptr to a struct; can be null)
00281  *              shiftflag (L_AUTO_DOWNSHIFT, L_MIN_DOWNSHIFT, L_FULL_DOWNSHIFT)
00282  *      Return: 0 if OK, 1 on error
00283  *
00284  *  Notes:
00285  *      (1) This checks first to see if the location is valid, and
00286  *          then if there is presently an item there.  If there is not,
00287  *          it is simply inserted into that location.
00288  *      (2) If there is an item at the insert location, items must be
00289  *          moved down to make room for the insert.  In the downward
00290  *          shift there are three options, given by @shiftflag.
00291  *            - If @shiftflag == L_AUTO_DOWNSHIFT, a decision is made
00292  *              whether, in a cascade of items, to downshift a minimum
00293  *              amount or for all items above @index.  The decision is
00294  *              based on the expectation of finding holes (null ptrs)
00295  *              between @index and the bottom of the array.
00296  *              Assuming the holes are distributed uniformly, if 2 or more
00297  *              holes are expected, we do a minimum shift.
00298  *            - If @shiftflag == L_MIN_DOWNSHIFT, the downward shifting
00299  *              cascade of items progresses a minimum amount, until
00300  *              the first empty slot is reached.  This mode requires
00301  *              some computation before the actual shifting is done.
00302  *            - If @shiftflag == L_FULL_DOWNSHIFT, a shifting cascade is
00303  *              performed where pa[i] --> pa[i + 1] for all i >= index.
00304  *              Then, the item is inserted at pa[index].
00305  *      (3) If you are not using L_AUTO_DOWNSHIFT, the rule of thumb is
00306  *          to use L_FULL_DOWNSHIFT if the array is compacted (each
00307  *          element points to an item), and to use L_MIN_DOWNSHIFT
00308  *          if there are a significant number of null pointers.
00309  *          There is no penalty to using L_MIN_DOWNSHIFT for a
00310  *          compacted array, however, because the full shift is required
00311  *          and we don't do the O(n) computation to look for holes.
00312  *      (4) This should not be used repeatedly on large arrays,
00313  *          because the function is generally O(n).
00314  *      (5) However, it can be used repeatedly if we start with an empty
00315  *          ptr array and insert only once at each location.  For example,
00316  *          you can support an array of Numa, where at each ptr location
00317  *          you store either 0 or 1 Numa, and the Numa can be added
00318  *          randomly to the ptr array.
00319  */
00320 l_int32
00321 ptraInsert(L_PTRA  *pa,
00322            l_int32  index,
00323            void    *item,
00324            l_int32  shiftflag)
00325 {
00326 l_int32    i, ihole, imax;
00327 l_float32  nexpected;
00328 
00329     PROCNAME("ptraInsert");
00330 
00331     if (!pa)
00332         return ERROR_INT("pa not defined", procName, 1);
00333     if (index < 0 || index > pa->nalloc)
00334         return ERROR_INT("index not in [0 ... nalloc]", procName, 1);
00335     if (shiftflag != L_AUTO_DOWNSHIFT && shiftflag != L_MIN_DOWNSHIFT &&
00336         shiftflag != L_FULL_DOWNSHIFT)
00337         return ERROR_INT("invalid shiftflag", procName, 1);
00338 
00339     if (item) pa->nactual++;
00340     if (index == pa->nalloc) {  /* can happen when index == n */
00341         if (ptraExtendArray(pa))
00342             return ERROR_INT("extension failure", procName, 1);
00343     }
00344 
00345         /* We are inserting into a hole or adding to the end of the array.
00346          * No existing items are moved. */
00347     ptraGetMaxIndex(pa, &imax);
00348     if (pa->array[index] == NULL) {
00349         pa->array[index] = item;
00350         if (item && index > imax)  /* new item put beyond max so far */
00351             pa->imax = index;
00352         return 0;
00353     }
00354 
00355         /* We are inserting at the location of an existing item,
00356          * forcing the existing item and those below to shift down.
00357          * First, extend the array automatically if the last element
00358          * (nalloc - 1) is occupied (imax).  This may not be necessary
00359          * in every situation, but only an anomalous sequence of insertions
00360          * into the array would cause extra ptr allocation.  */
00361     if (imax >= pa->nalloc - 1 && ptraExtendArray(pa))
00362         return ERROR_INT("extension failure", procName, 1);
00363 
00364         /* If there are no holes, do a full downshift.
00365          * Otherwise, if L_AUTO_DOWNSHIFT, use the expected number
00366          * of holes between index and n to determine the shift mode */
00367     if (imax + 1 == pa->nactual)
00368         shiftflag = L_FULL_DOWNSHIFT;
00369     else if (shiftflag == L_AUTO_DOWNSHIFT) {
00370         if (imax < 10)
00371             shiftflag = L_FULL_DOWNSHIFT;  /* no big deal */
00372         else {
00373             nexpected = (l_float32)(imax - pa->nactual) *
00374                          (l_float32)((imax - index) / imax);
00375             shiftflag = (nexpected > 2.0) ? L_MIN_DOWNSHIFT : L_FULL_DOWNSHIFT;
00376         }
00377     }
00378 
00379     if (shiftflag == L_MIN_DOWNSHIFT) {  /* run down looking for a hole */
00380         for (ihole = index + 1; ihole <= imax; ihole++) {
00381              if (pa->array[ihole] == NULL)
00382                  break;
00383         }
00384     }
00385     else   /* L_FULL_DOWNSHIFT */
00386         ihole = imax + 1;
00387 
00388     for (i = ihole; i > index; i--)
00389         pa->array[i] = pa->array[i - 1];
00390     pa->array[index] = (void *)item;
00391     if (ihole == imax + 1)  /* the last item was shifted down */
00392         pa->imax++;
00393 
00394     return 0;
00395 }
00396 
00397 
00398 /*!
00399  *  ptraGetHandle()
00400  *
00401  *      Input:  ptra
00402  *              index (element to be retrieved)
00403  *      Return: item, or null on error
00404  *
00405  *  Notes:
00406  *      (1) This returns a ptr to the item.  You must cast it to
00407  *          the type of item.  Do not destroy it; the item belongs
00408  *          to the Ptra.
00409  *      (2) This can access all possible items on the ptr array.
00410  *          If an item doesn't exist, it returns null.
00411  */
00412 void *
00413 ptraGetHandle(L_PTRA  *pa,
00414               l_int32  index)
00415 {
00416     PROCNAME("ptraGetHandle");
00417 
00418     if (!pa)
00419         return (void *)ERROR_PTR("pa not defined", procName, NULL);
00420     if (index < 0 || index >= pa->nalloc)
00421         return (void *)ERROR_PTR("index not in [0 ... nalloc-1]",
00422                                  procName, NULL);
00423 
00424     return pa->array[index];
00425 }
00426 
00427 
00428 /*!
00429  *  ptraRemove()
00430  *
00431  *      Input:  ptra
00432  *              index (element to be removed)
00433  *              flag (L_NO_COMPACTION, L_COMPACTION)
00434  *      Return: item, or null on error
00435  *
00436  *  Notes:
00437  *      (1) If flag == L_NO_COMPACTION, this removes the item and
00438  *          nulls the ptr on the array.  If it takes the last item
00439  *          in the array, pa->n is reduced to the next item.
00440  *      (2) If flag == L_COMPACTION, this compacts the array for
00441  *          for all i >= index.  It should not be used repeatedly on
00442  *          large arrays, because compaction is O(n).
00443  *      (3) The ability to remove without automatic compaction allows
00444  *          removal with cost O(1).
00445  */
00446 void *
00447 ptraRemove(L_PTRA  *pa,
00448            l_int32  index,
00449            l_int32  flag)
00450 {
00451 l_int32  i, imax, fromend, icurrent;
00452 void    *item;
00453 
00454     PROCNAME("ptraRemove");
00455 
00456     if (!pa)
00457         return (void *)ERROR_PTR("pa not defined", procName, NULL);
00458     ptraGetMaxIndex(pa, &imax);
00459     if (index < 0 || index > imax)
00460         return (void *)ERROR_PTR("index not in [0 ... imax]", procName, NULL);
00461 
00462     item = pa->array[index];
00463     if (item)
00464         pa->nactual--;
00465     pa->array[index] = NULL;
00466   
00467         /* If we took the last item, need to reduce pa->n */
00468     fromend = (index == imax);
00469     if (fromend) {
00470         for (i = index - 1; i >= 0; i--) {
00471             if (pa->array[i])
00472                 break;
00473         }
00474         pa->imax = i;
00475         imax = i + 1;
00476     }
00477 
00478         /* Compact from index to the end of the array */
00479     if (!fromend && flag == L_COMPACTION) {
00480         for (icurrent = index, i = index + 1; i <= imax; i++) {
00481             if (pa->array[i])
00482                 pa->array[icurrent++] = pa->array[i];
00483         }
00484         pa->imax = icurrent - 1;
00485     }
00486     return item;
00487 }
00488 
00489 
00490 /*!
00491  *  ptraRemoveLast()
00492  *
00493  *      Input:  ptra
00494  *      Return: item, or null on error or if the array is empty
00495  */
00496 void *
00497 ptraRemoveLast(L_PTRA  *pa)
00498 {
00499 l_int32  imax;
00500 
00501     PROCNAME("ptraRemoveLast");
00502 
00503     if (!pa)
00504         return (void *)ERROR_PTR("pa not defined", procName, NULL);
00505 
00506         /* Remove the last item in the array.  No compaction is required. */
00507     ptraGetMaxIndex(pa, &imax);
00508     if (imax >= 0)
00509         return ptraRemove(pa, imax, L_NO_COMPACTION);
00510     else  /* empty */
00511         return NULL;
00512 }
00513 
00514 
00515 /*!
00516  *  ptraReplace()
00517  *
00518  *      Input:  ptra
00519  *              index (element to be replaced)
00520  *              item  (new generic ptr to a struct; can be null)
00521  *              freeflag (TRUE to free old item; FALSE to return it)
00522  *      Return: item  (old item, if it exists and is not freed),
00523  *                     or null on error
00524  */
00525 void *
00526 ptraReplace(L_PTRA  *pa,
00527             l_int32  index,
00528             void    *item,
00529             l_int32  freeflag)
00530 {
00531 l_int32  imax;
00532 void    *olditem;
00533 
00534     PROCNAME("ptraReplace");
00535 
00536     if (!pa)
00537         return (void *)ERROR_PTR("pa not defined", procName, NULL);
00538     ptraGetMaxIndex(pa, &imax);
00539     if (index < 0 || index > imax)
00540         return (void *)ERROR_PTR("index not in [0 ... imax]", procName, NULL);
00541 
00542     olditem = pa->array[index];
00543     pa->array[index] = item;
00544     if (!item && olditem)
00545         pa->nactual--;
00546     else if (item && !olditem)
00547         pa->nactual++;
00548 
00549     if (freeflag == FALSE)
00550         return olditem;
00551 
00552     if (olditem)
00553         FREE(olditem);
00554     return NULL;
00555 }
00556 
00557 
00558 /*!
00559  *  ptraSwap()
00560  *
00561  *      Input:  ptra
00562  *              index1
00563  *              index2
00564  *      Return: 0 if OK, 1 on error
00565  */
00566 l_int32
00567 ptraSwap(L_PTRA  *pa,
00568          l_int32  index1,
00569          l_int32  index2)
00570 {
00571 l_int32  imax;
00572 void    *item;
00573 
00574     PROCNAME("ptraSwap");
00575 
00576     if (!pa)
00577         return ERROR_INT("pa not defined", procName, 1);
00578     if (index1 == index2)
00579         return 0;
00580     ptraGetMaxIndex(pa, &imax);
00581     if (index1 < 0 || index1 > imax || index2 < 0 || index2 > imax)
00582         return ERROR_INT("invalid index: not in [0 ... imax]", procName, 1);
00583 
00584     item = ptraRemove(pa, index1, L_NO_COMPACTION);
00585     item = ptraReplace(pa, index2, item, FALSE);
00586     ptraInsert(pa, index1, item, L_MIN_DOWNSHIFT);
00587     return 0;
00588 }
00589 
00590 
00591 /*!
00592  *  ptraCompactArray()
00593  *
00594  *      Input:  ptra 
00595  *      Return: 0 if OK, 1 on error
00596  *
00597  *  Notes:
00598  *      (1) This compacts the items on the array, filling any empty ptrs.
00599  *      (2) This does not change the size of the array of ptrs.
00600  */
00601 l_int32
00602 ptraCompactArray(L_PTRA  *pa)
00603 {
00604 l_int32  i, imax, nactual, index;
00605 
00606     PROCNAME("ptraCompactArray");
00607 
00608     if (!pa)
00609         return ERROR_INT("pa not defined", procName, 1);
00610     ptraGetMaxIndex(pa, &imax);
00611     ptraGetActualCount(pa, &nactual);
00612     if (imax + 1 == nactual) return 0;
00613 
00614         /* Compact the array */
00615     for (i = 0, index = 0; i <= imax; i++) {
00616         if (pa->array[i])
00617              pa->array[index++] = pa->array[i];
00618     }
00619     pa->imax = index - 1;
00620     if (nactual != index)
00621         L_ERROR_INT("index = %d; != nactual", procName, index);
00622 
00623     return 0;
00624 }
00625 
00626 
00627 /*----------------------------------------------------------------------*
00628  *                        Other array operations                        *
00629  *----------------------------------------------------------------------*/
00630 /*!
00631  *  ptraReverse()
00632  *
00633  *      Input:  ptra
00634  *      Return: 0 if OK, 1 on error
00635  */
00636 l_int32
00637 ptraReverse(L_PTRA  *pa)
00638 {
00639 l_int32  i, imax;
00640 
00641     PROCNAME("ptraReverse");
00642 
00643     if (!pa)
00644         return ERROR_INT("pa not defined", procName, 1);
00645     ptraGetMaxIndex(pa, &imax);
00646 
00647     for (i = 0; i < (imax + 1) / 2; i++)
00648         ptraSwap(pa, i, imax - i);
00649     return 0;
00650 }
00651 
00652 
00653 /*!
00654  *  ptraJoin()
00655  *
00656  *      Input:  ptra1 (add to this one)
00657  *              ptra2 (appended to ptra1, and emptied of items; can be null)
00658  *      Return: 0 if OK, 1 on error
00659  */
00660 l_int32
00661 ptraJoin(L_PTRA  *pa1,
00662          L_PTRA  *pa2)
00663 {
00664 l_int32  i, imax;
00665 void    *item;
00666 
00667     PROCNAME("ptraJoin");
00668 
00669     if (!pa1)
00670         return ERROR_INT("pa1 not defined", procName, 1);
00671     if (!pa2)
00672         return 0;
00673 
00674     ptraGetMaxIndex(pa2, &imax);
00675     for (i = 0; i <= imax; i++) {
00676         item = ptraRemove(pa2, i, L_NO_COMPACTION);
00677         ptraAdd(pa1, item);
00678     }
00679     
00680     return 0;
00681 }
00682 
00683 
00684 
00685 /*----------------------------------------------------------------------*
00686  *                        Simple ptra accessors                         *
00687  *----------------------------------------------------------------------*/
00688 /*!
00689  *  ptraGetMaxIndex()
00690  *
00691  *      Input:  ptra
00692  *              &maxindex (<return> index of last item in the array);
00693  *      Return: 0 if OK; 1 on error
00694  *
00695  *  Notes:
00696  *      (1) The largest index to an item in the array is @maxindex.
00697  *          @maxindex is one less than the number of items that would be
00698  *          in the array if there were no null pointers between 0
00699  *          and @maxindex - 1.  However, because the internal ptr array
00700  *          need not be compacted, there may be null pointers at
00701  *          indices below @maxindex; for example, if items have
00702  *          been removed.
00703  *      (2) When an item is added to the end of the array, it goes
00704  *          into pa->array[maxindex + 1], and maxindex is then
00705  *          incremented by 1.
00706  *      (3) If there are no items in the array, this returns @maxindex = -1.
00707  */
00708 l_int32
00709 ptraGetMaxIndex(L_PTRA   *pa,
00710                 l_int32  *pmaxindex)
00711 {
00712     PROCNAME("ptraGetMaxIndex");
00713 
00714     if (!pa)
00715         return ERROR_INT("pa not defined", procName, 1);
00716     if (!pmaxindex)
00717         return ERROR_INT("&maxindex not defined", procName, 1);
00718     *pmaxindex = pa->imax;
00719     return 0;
00720 }
00721         
00722 
00723 /*!
00724  *  ptraGetActualCount()
00725  *
00726  *      Input:  ptra
00727  *              &count (<return> actual number of items on the ptr array)
00728  *      Return: 0 if OK; 1 on error
00729  *
00730  *  Notes:
00731  *      (1) The actual number of items on the ptr array, pa->nactual,
00732  *          will be smaller than pa->n if the array is not compacted.
00733  */
00734 l_int32
00735 ptraGetActualCount(L_PTRA   *pa,
00736                    l_int32  *pcount)
00737 {
00738     PROCNAME("ptraGetActualCount");
00739 
00740     if (!pa)
00741         return ERROR_INT("pa not defined", procName, 1);
00742     if (!pcount)
00743         return ERROR_INT("&count not defined", procName, 1);
00744     *pcount = pa->nactual;
00745 
00746     return 0;
00747 }
00748 
00749 
00750 /*!
00751  *  ptraGetPtrToItem()
00752  *
00753  *      Input:  ptra
00754  *              index (element to fetch pointer to)
00755  *      Return: item (just a pointer to it)
00756  *
00757  *  Notes:
00758  *      (1) The item remains on the Ptra and is 'owned' by it, so
00759  *          the item must not be destroyed.
00760  */
00761 void *
00762 ptraGetPtrToItem(L_PTRA  *pa,
00763                  l_int32  index)
00764 {
00765     PROCNAME("ptraGetPtrToItem");
00766 
00767     if (!pa)
00768         return (void *)ERROR_PTR("pa not defined", procName, NULL);
00769     if (index < 0 || index > pa->imax)
00770         return (void *)ERROR_PTR("index not in [0 ... imax]", procName, NULL);
00771 
00772     return pa->array[index];
00773 }
00774 
00775 
00776 /*--------------------------------------------------------------------------*
00777  *                      Ptraa creation and destruction                      *
00778  *--------------------------------------------------------------------------*/
00779 /*!
00780  *  ptraaCreate()
00781  *
00782  *      Input:  size of ptr array to be alloc'd
00783  *      Return: paa, or null on error
00784  *
00785  *  Notes:
00786  *      (1) The ptraa is generated with a fixed size, that can not change.
00787  *          The ptra can be generated and inserted randomly into this array.
00788  */
00789 L_PTRAA *
00790 ptraaCreate(l_int32  n)
00791 {
00792 L_PTRAA  *paa;
00793 
00794     PROCNAME("ptraaCreate");
00795 
00796     if (n <= 0)
00797         return (L_PTRAA *)ERROR_PTR("n must be > 0", procName, NULL);
00798 
00799     if ((paa = (L_PTRAA *)CALLOC(1, sizeof(L_PTRAA))) == NULL)
00800         return (L_PTRAA *)ERROR_PTR("paa not made", procName, NULL);
00801     if ((paa->ptra = (L_PTRA **)CALLOC(n, sizeof(L_PTRA *))) == NULL)
00802         return (L_PTRAA *)ERROR_PTR("ptr array not made", procName, NULL);
00803 
00804     paa->nalloc = n;
00805     return paa;
00806 }
00807 
00808 
00809 /*!
00810  *  ptraaDestroy()
00811  *
00812  *      Input:  &paa (<to be nulled>)
00813  *              freeflag (TRUE to free each remaining item in each ptra)
00814  *              warnflag (TRUE to warn if any remaining items are not destroyed)
00815  *      Return: void
00816  *
00817  *  Notes:
00818  *      (1) See ptraDestroy() for use of @freeflag and @warnflag.
00819  *      (2) To destroy the ptraa, we destroy each ptra, then the ptr array,
00820  *          then the ptraa, and then null the contents of the input ptr.
00821  */
00822 void
00823 ptraaDestroy(L_PTRAA  **ppaa,
00824              l_int32    freeflag,
00825              l_int32    warnflag)
00826 {
00827 l_int32   i, n;
00828 L_PTRA   *pa;
00829 L_PTRAA  *paa;
00830 
00831     PROCNAME("ptraaDestroy");
00832 
00833     if (ppaa == NULL) {
00834         L_WARNING("ptr address is NULL", procName);
00835         return;
00836     }
00837     if ((paa = *ppaa) == NULL)
00838         return;
00839 
00840     ptraaGetSize(paa, &n);
00841     for (i = 0; i < n; i++) {
00842         pa = ptraaGetPtra(paa, i, L_REMOVE);
00843         ptraDestroy(&pa, freeflag, warnflag);
00844     }
00845 
00846     FREE(paa->ptra);
00847     FREE(paa);
00848     *ppaa = NULL;
00849     return;
00850 }
00851 
00852 
00853 /*--------------------------------------------------------------------------*
00854  *                             Ptraa accessors                              *
00855  *--------------------------------------------------------------------------*/
00856 /*!
00857  *  ptraaGetSize()
00858  *
00859  *      Input:  ptraa
00860  *              &size (<return> size of ptr array)
00861  *      Return: 0 if OK; 1 on error
00862  */
00863 l_int32
00864 ptraaGetSize(L_PTRAA  *paa,
00865              l_int32  *psize)
00866 {
00867     PROCNAME("ptraaGetSize");
00868 
00869     if (!paa)
00870         return ERROR_INT("paa not defined", procName, 1);
00871     if (!psize)
00872         return ERROR_INT("&size not defined", procName, 1);
00873     *psize = paa->nalloc;
00874 
00875     return 0;
00876 }
00877 
00878 
00879 /*!
00880  *  ptraaInsertPtra()
00881  *
00882  *      Input:  ptraa
00883  *              index (location in array for insertion)
00884  *              ptra (to be inserted)
00885  *      Return: 0 if OK; 1 on error
00886  *
00887  *  Notes:
00888  *      (1) Caller should check return value.  On success, the Ptra
00889  *          is inserted in the Ptraa and is owned by it.  However,
00890  *          on error, the Ptra remains owned by the caller.
00891  */
00892 l_int32
00893 ptraaInsertPtra(L_PTRAA  *paa,
00894                 l_int32   index,
00895                 L_PTRA   *pa)
00896 {
00897 l_int32  n;
00898 
00899     PROCNAME("ptraaInsertPtra");
00900 
00901     if (!paa)
00902         return ERROR_INT("paa not defined", procName, 1);
00903     if (!pa)
00904         return ERROR_INT("pa not defined", procName, 1);
00905     ptraaGetSize(paa, &n);
00906     if (index < 0 || index >= n)
00907         return ERROR_INT("invalid index", procName, 1);
00908     if (paa->ptra[index] != NULL)
00909         return ERROR_INT("ptra alread stored at index", procName, 1);
00910 
00911     paa->ptra[index] = pa;
00912     return 0;
00913 }
00914 
00915 
00916 /*!
00917  *  ptraaGetPtra()
00918  *
00919  *      Input:  ptraa
00920  *              index (location in array)
00921  *              accessflag (L_HANDLE_ONLY, L_REMOVE)
00922  *      Return: ptra (at index location), or NULL on error or if there
00923  *              is no ptra there.
00924  *
00925  *  Notes:
00926  *      (1) This returns the ptra ptr.  If @accessflag == L_HANDLE_ONLY,
00927  *          the ptra is left on the ptraa.  If @accessflag == L_REMOVE,
00928  *          the ptr in the ptraa is set to NULL, and the caller
00929  *          is responsible for disposing of the ptra (either putting it
00930  *          back on the ptraa, or destroying it).
00931  *      (2) This returns NULL if there is no Ptra at the index location.
00932  */
00933 L_PTRA *
00934 ptraaGetPtra(L_PTRAA  *paa,
00935              l_int32   index,
00936              l_int32   accessflag)
00937 {
00938 l_int32  n;
00939 L_PTRA  *pa;
00940 
00941     PROCNAME("ptraaGetPtra");
00942 
00943     if (!paa)
00944         return (L_PTRA *)ERROR_PTR("paa not defined", procName, NULL);
00945     ptraaGetSize(paa, &n);
00946     if (index < 0 || index >= n)
00947         return (L_PTRA *)ERROR_PTR("invalid index", procName, NULL);
00948     if (accessflag != L_HANDLE_ONLY && accessflag != L_REMOVE)
00949         return (L_PTRA *)ERROR_PTR("invalid accessflag", procName, NULL);
00950 
00951     pa = paa->ptra[index];
00952     if (accessflag == L_REMOVE)
00953         paa->ptra[index] = NULL;
00954     return pa;
00955 }
00956 
00957 
00958 /*--------------------------------------------------------------------------*
00959  *                             Ptraa conversion                             *
00960  *--------------------------------------------------------------------------*/
00961 /*!
00962  *  ptraaFlattenToPtra()
00963  *
00964  *      Input:  ptraa
00965  *      Return: ptra, or null on error
00966  *
00967  *  Notes:
00968  *      (1) This 'flattens' the ptraa to a ptra, taking the items in
00969  *          each ptra, in order, starting with the first ptra, etc.
00970  *      (2) As a side-effect, the ptra are all removed from the ptraa
00971  *          and destroyed, leaving an empty ptraa.
00972  */
00973 L_PTRA *
00974 ptraaFlattenToPtra(L_PTRAA  *paa)
00975 {
00976 l_int32  i, n;
00977 L_PTRA    *pat, *pad;
00978 
00979     PROCNAME("ptraaFlattenToPtra");
00980 
00981     if (!paa)
00982         return (L_PTRA *)ERROR_PTR("paa not defined", procName, NULL);
00983 
00984     pad = ptraCreate(0);
00985     ptraaGetSize(paa, &n);
00986     for (i = 0; i < n; i++) {
00987         pat = ptraaGetPtra(paa, i, L_REMOVE);
00988         if (!pat) continue;
00989         ptraJoin(pad, pat);
00990         ptraDestroy(&pat, FALSE, FALSE);  /* they're all empty */
00991     }
00992 
00993     return pad;
00994 }
00995 
00996 
00997 /*--------------------------------------------------------------------------*
00998  *                          Functions using L_PTRA                          *
00999  *--------------------------------------------------------------------------*/
01000 /*!
01001  *  numaGetBinSortIndex()
01002  *
01003  *      Input:  na (of non-negative integers with a max that is typically
01004  *                  less than 50,000)
01005  *              sortorder (L_SORT_INCREASING or L_SORT_DECREASING)
01006  *      Return: na (sorted), or null on error
01007  *
01008  *  Notes:
01009  *      (1) This creates an array (or lookup table) that gives the
01010  *          sorted position of the elements in the input Numa.
01011  *      (2) Because it uses a bin sort with buckets of size 1, it
01012  *          is not appropriate for sorting either small arrays or
01013  *          arrays containing very large integer values.  For such
01014  *          arrays, use a standard general sort function like
01015  *          numaGetSortIndex().
01016  */
01017 NUMA *
01018 numaGetBinSortIndex(NUMA    *nas,
01019                     l_int32  sortorder)
01020 {
01021 l_int32    i, n, isize, ival, imax;
01022 l_float32  size;
01023 NUMA      *na, *nai, *nad;
01024 L_PTRA    *paindex;
01025 
01026     PROCNAME("numaGetBinSortIndex");
01027 
01028     if (!nas)
01029         return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
01030     if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
01031         return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
01032 
01033         /* Set up a ptra holding numa at indices for which there
01034          * are values in nas.  This effectively sorts the input
01035          * numbers. */
01036     numaGetMax(nas, &size, NULL);
01037     isize = (l_int32)size;
01038     if (isize > 50000)
01039         L_WARNING_INT("large array: %d elements", procName, isize);
01040     paindex = ptraCreate(isize + 1);
01041     n = numaGetCount(nas);
01042     for (i = 0; i < n; i++) {
01043         numaGetIValue(nas, i, &ival);
01044         nai = (NUMA *)ptraGetHandle(paindex, ival);
01045         if (!nai) {  /* make it; no shifting will occur */
01046             nai = numaCreate(1);
01047             ptraInsert(paindex, ival, nai, L_MIN_DOWNSHIFT);
01048         }
01049         numaAddNumber(nai, i);
01050     }
01051 
01052         /* Sort by pulling the numbers out of the numas, taken
01053          * successively in requested order. */
01054     ptraGetMaxIndex(paindex, &imax);
01055     nad = numaCreate(0);
01056     if (sortorder == L_SORT_INCREASING) {
01057         for (i = 0; i <= imax; i++) {
01058             na = (NUMA *)ptraRemove(paindex, i, L_NO_COMPACTION);
01059             numaJoin(nad, na, 0, 0);
01060             numaDestroy(&na);
01061         }
01062     } else {  /* L_SORT_DECREASING */
01063         for (i = imax; i >= 0; i--) {
01064             na = (NUMA *)ptraRemove(paindex, i, L_NO_COMPACTION);
01065             numaJoin(nad, na, 0, 0);
01066             numaDestroy(&na);
01067         }
01068     }
01069 
01070     ptraDestroy(&paindex, FALSE, FALSE);
01071     return nad;
01072 }
01073 
01074 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines