/*====================================================================* - Copyright (C) 2001 Leptonica. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *====================================================================*/ /*! * \file ptra.c *
* * Ptra creation and destruction * L_PTRA *ptraCreate() * void *ptraDestroy() * * Add/insert/remove/replace generic ptr object * l_int32 ptraAdd() * static l_int32 ptraExtendArray() * l_int32 ptraInsert() * void *ptraRemove() * void *ptraRemoveLast() * void *ptraReplace() * l_int32 ptraSwap() * l_int32 ptraCompactArray() * * Other array operations * l_int32 ptraReverse() * l_int32 ptraJoin() * * Simple Ptra accessors * l_int32 ptraGetMaxIndex() * l_int32 ptraGetActualCount() * void *ptraGetPtrToItem() * * Ptraa creation and destruction * L_PTRAA *ptraaCreate() * void *ptraaDestroy() * * Ptraa accessors * l_int32 ptraaGetSize() * l_int32 ptraaInsertPtra() * L_PTRA *ptraaGetPtra() * * Ptraa conversion * L_PTRA *ptraaFlattenToPtra() * * Notes on the Ptra: * * (1) The Ptra is a struct, not an array. Always use the accessors * in this file, never the fields directly. * (2) Items can be placed anywhere in the allocated ptr array, * including one index beyond the last ptr (in which case the * ptr array is realloc'd). * (3) Thus, the items on the ptr array need not be compacted. In * general there will be null pointers in the ptr array. * (4) A compacted array will remain compacted on removal if * arbitrary items are removed with compaction, or if items * are removed from the end of the array. * (5) For addition to and removal from the end of the array, this * functions exactly like a stack, and with the same O(1) cost. * (6) This differs from the generic stack in that we allow * random access for insertion, removal and replacement. * Removal can be done without compacting the array. * Insertion into a null ptr in the array has no effect on * the other pointers, but insertion into a location already * occupied by an item has a cost proportional to the * distance to the next null ptr in the array. * (7) Null ptrs are valid input args for both insertion and * replacement; this allows arbitrary swapping. * (8) The item in the array with the largest index is at pa->imax. * This can be any value from -1 (initialized; all array ptrs * are null) up to pa->nalloc - 1 (the last ptr in the array). * (9) In referring to the array: the first ptr is the "top" or * "beginning"; the last pointer is the "bottom" or "end"; * items are shifted "up" towards the top when compaction occurs; * and items are shifted "down" towards the bottom when forced to * move due to an insertion. * (10) It should be emphasized that insertion, removal and replacement * are general: * * You can insert an item into any ptr location in the * allocated ptr array, as well as into the next ptr address * beyond the allocated array (in which case a realloc will occur). * * You can remove or replace an item from any ptr location * in the allocated ptr array. * * When inserting into an occupied location, you have * three options for downshifting. * * When removing, you can either leave the ptr null or * compact the array. * * Notes on the Ptraa: * * (1) The Ptraa is a fixed size ptr array for holding Ptra. * In that respect, it is different from other pointer arrays, which * are extensible and grow using the *Add*() functions. * (2) In general, the Ptra ptrs in the Ptraa can be randomly occupied. * A typical usage is to allow an O(n) horizontal sort of Pix, * where the size of the Ptra array is the width of the image, * and each Ptra is an array of all the Pix at a specific x location. **/ #include "allheaders.h" /* Bounds on initial array size */ static const l_uint32 MaxPtrArraySize = 100000; static const l_int32 InitialPtrArraySize = 20; /*!< n'importe quoi */ /* Static function */ static l_int32 ptraExtendArray(L_PTRA *pa); /*--------------------------------------------------------------------------* * Ptra creation and destruction * *--------------------------------------------------------------------------*/ /*! * \brief ptraCreate() * * \param[in] n size of ptr array to be alloc'd; use 0 for default * \return pa, or NULL on error */ L_PTRA * ptraCreate(l_int32 n) { L_PTRA *pa; PROCNAME("ptraCreate"); if (n <= 0 || n > MaxPtrArraySize) n = InitialPtrArraySize; pa = (L_PTRA *)LEPT_CALLOC(1, sizeof(L_PTRA)); if ((pa->array = (void **)LEPT_CALLOC(n, sizeof(void *))) == NULL) { ptraDestroy(&pa, 0, 0); return (L_PTRA *)ERROR_PTR("ptr array not made", procName, NULL); } pa->nalloc = n; pa->imax = -1; pa->nactual = 0; return pa; } /*! * \brief ptraDestroy() * * \param[in,out] ppa will be set to null before returning * \param[in] freeflag TRUE to free each remaining item in the array * \param[in] warnflag TRUE to warn if any remaining items * are not destroyed * \return void * *
* Notes: * (1) If %freeflag == TRUE, frees each item in the array. * (2) If %freeflag == FALSE and %warnflag == TRUE, and there are * items on the array, this gives a warning and destroys the array. * If these items are not owned elsewhere, this will cause * a memory leak of all the items that were on the array. * So if the items are not owned elsewhere and require their * own destroy function, they must be destroyed before the ptra. * (3) If %warnflag == FALSE, no warnings will be issued. This is * useful if the items are owned elsewhere, such as a * PixMemoryStore(). * (4) To destroy the ptra, we destroy the ptr array, then * the ptra, and then null the contents of the input ptr. **/ void ptraDestroy(L_PTRA **ppa, l_int32 freeflag, l_int32 warnflag) { l_int32 i, nactual; void *item; L_PTRA *pa; PROCNAME("ptraDestroy"); if (ppa == NULL) { L_WARNING("ptr address is NULL\n", procName); return; } if ((pa = *ppa) == NULL) return; ptraGetActualCount(pa, &nactual); if (nactual > 0) { if (freeflag) { for (i = 0; i <= pa->imax; i++) { if ((item = ptraRemove(pa, i, L_NO_COMPACTION)) != NULL) LEPT_FREE(item); } } else if (warnflag) { L_WARNING("potential memory leak of %d items in ptra\n", procName, nactual); } } LEPT_FREE(pa->array); LEPT_FREE(pa); *ppa = NULL; return; } /*--------------------------------------------------------------------------* * Add/insert/remove/replace generic ptr object * *--------------------------------------------------------------------------*/ /*! * \brief ptraAdd() * * \param[in] pa ptra * \param[in] item generic ptr to a struct * \return 0 if OK, 1 on error * *
* Notes: * (1) This adds the element to the next location beyond imax, * which is the largest occupied ptr in the array. This is * what you expect from a stack, where all ptrs up to and * including imax are occupied, but here the occuption of * items in the array is entirely arbitrary. **/ l_ok ptraAdd(L_PTRA *pa, void *item) { l_int32 imax; PROCNAME("ptraAdd"); if (!pa) return ERROR_INT("pa not defined", procName, 1); if (!item) return ERROR_INT("item not defined", procName, 1); ptraGetMaxIndex(pa, &imax); if (imax >= pa->nalloc - 1 && ptraExtendArray(pa)) return ERROR_INT("extension failure", procName, 1); pa->array[imax + 1] = (void *)item; pa->imax++; pa->nactual++; return 0; } /*! * \brief ptraExtendArray() * * \param[in] pa * \return 0 if OK, 1 on error */ static l_int32 ptraExtendArray(L_PTRA *pa) { PROCNAME("ptraExtendArray"); if (!pa) return ERROR_INT("pa not defined", procName, 1); if ((pa->array = (void **)reallocNew((void **)&pa->array, sizeof(void *) * pa->nalloc, 2 * sizeof(void *) * pa->nalloc)) == NULL) return ERROR_INT("new ptr array not returned", procName, 1); pa->nalloc *= 2; return 0; } /*! * \brief ptraInsert() * * \param[in] pa ptra * \param[in] index location in ptra to insert new value * \param[in] item generic ptr to a struct; can be null * \param[in] shiftflag L_AUTO_DOWNSHIFT, L_MIN_DOWNSHIFT, L_FULL_DOWNSHIFT * \return 0 if OK, 1 on error * *
* Notes: * (1) This checks first to see if the location is valid, and * then if there is presently an item there. If there is not, * it is simply inserted into that location. * (2) If there is an item at the insert location, items must be * moved down to make room for the insert. In the downward * shift there are three options, given by %shiftflag. * ~ If %shiftflag == L_AUTO_DOWNSHIFT, a decision is made * whether, in a cascade of items, to downshift a minimum * amount or for all items above %index. The decision is * based on the expectation of finding holes (null ptrs) * between %index and the bottom of the array. * Assuming the holes are distributed uniformly, if 2 or more * holes are expected, we do a minimum shift. * ~ If %shiftflag == L_MIN_DOWNSHIFT, the downward shifting * cascade of items progresses a minimum amount, until * the first empty slot is reached. This mode requires * some computation before the actual shifting is done. * ~ If %shiftflag == L_FULL_DOWNSHIFT, a shifting cascade is * performed where pa[i] --> pa[i + 1] for all i >= index. * Then, the item is inserted at pa[index]. * (3) If you are not using L_AUTO_DOWNSHIFT, the rule of thumb is * to use L_FULL_DOWNSHIFT if the array is compacted (each * element points to an item), and to use L_MIN_DOWNSHIFT * if there are a significant number of null pointers. * There is no penalty to using L_MIN_DOWNSHIFT for a * compacted array, however, because the full shift is required * and we don't do the O(n) computation to look for holes. * (4) This should not be used repeatedly on large arrays, * because the function is generally O(n). * (5) However, it can be used repeatedly if we start with an empty * ptr array and insert only once at each location. For example, * you can support an array of Numa, where at each ptr location * you store either 0 or 1 Numa, and the Numa can be added * randomly to the ptr array. **/ l_ok ptraInsert(L_PTRA *pa, l_int32 index, void *item, l_int32 shiftflag) { l_int32 i, ihole, imax; l_float32 nexpected; PROCNAME("ptraInsert"); if (!pa) return ERROR_INT("pa not defined", procName, 1); if (index < 0 || index > pa->nalloc) return ERROR_INT("index not in [0 ... nalloc]", procName, 1); if (shiftflag != L_AUTO_DOWNSHIFT && shiftflag != L_MIN_DOWNSHIFT && shiftflag != L_FULL_DOWNSHIFT) return ERROR_INT("invalid shiftflag", procName, 1); if (item) pa->nactual++; if (index == pa->nalloc) { /* can happen when index == n */ if (ptraExtendArray(pa)) return ERROR_INT("extension failure", procName, 1); } /* We are inserting into a hole or adding to the end of the array. * No existing items are moved. */ ptraGetMaxIndex(pa, &imax); if (pa->array[index] == NULL) { pa->array[index] = item; if (item && index > imax) /* new item put beyond max so far */ pa->imax = index; return 0; } /* We are inserting at the location of an existing item, * forcing the existing item and those below to shift down. * First, extend the array automatically if the last element * (nalloc - 1) is occupied (imax). This may not be necessary * in every situation, but only an anomalous sequence of insertions * into the array would cause extra ptr allocation. */ if (imax >= pa->nalloc - 1 && ptraExtendArray(pa)) return ERROR_INT("extension failure", procName, 1); /* If there are no holes, do a full downshift. * Otherwise, if L_AUTO_DOWNSHIFT, use the expected number * of holes between index and n to determine the shift mode */ if (imax + 1 == pa->nactual) { shiftflag = L_FULL_DOWNSHIFT; } else if (shiftflag == L_AUTO_DOWNSHIFT) { if (imax < 10) { shiftflag = L_FULL_DOWNSHIFT; /* no big deal */ } else { nexpected = (l_float32)(imax - pa->nactual) * (l_float32)((imax - index) / imax); shiftflag = (nexpected > 2.0) ? L_MIN_DOWNSHIFT : L_FULL_DOWNSHIFT; } } if (shiftflag == L_MIN_DOWNSHIFT) { /* run down looking for a hole */ for (ihole = index + 1; ihole <= imax; ihole++) { if (pa->array[ihole] == NULL) break; } } else { /* L_FULL_DOWNSHIFT */ ihole = imax + 1; } for (i = ihole; i > index; i--) pa->array[i] = pa->array[i - 1]; pa->array[index] = (void *)item; if (ihole == imax + 1) /* the last item was shifted down */ pa->imax++; return 0; } /*! * \brief ptraRemove() * * \param[in] pa ptra * \param[in] index element to be removed * \param[in] flag L_NO_COMPACTION, L_COMPACTION * \return item, or NULL on error * *
* Notes: * (1) If flag == L_NO_COMPACTION, this removes the item and * nulls the ptr on the array. If it takes the last item * in the array, pa->n is reduced to the next item. * (2) If flag == L_COMPACTION, this compacts the array for * for all i >= index. It should not be used repeatedly on * large arrays, because compaction is O(n). * (3) The ability to remove without automatic compaction allows * removal with cost O(1). **/ void * ptraRemove(L_PTRA *pa, l_int32 index, l_int32 flag) { l_int32 i, imax, fromend, icurrent; void *item; PROCNAME("ptraRemove"); if (!pa) return (void *)ERROR_PTR("pa not defined", procName, NULL); ptraGetMaxIndex(pa, &imax); if (index < 0 || index > imax) return (void *)ERROR_PTR("index not in [0 ... imax]", procName, NULL); item = pa->array[index]; if (item) pa->nactual--; pa->array[index] = NULL; /* If we took the last item, need to reduce pa->n */ fromend = (index == imax); if (fromend) { for (i = index - 1; i >= 0; i--) { if (pa->array[i]) break; } pa->imax = i; } /* Compact from index to the end of the array */ if (!fromend && flag == L_COMPACTION) { for (icurrent = index, i = index + 1; i <= imax; i++) { if (pa->array[i]) pa->array[icurrent++] = pa->array[i]; } pa->imax = icurrent - 1; } return item; } /*! * \brief ptraRemoveLast() * * \param[in] pa ptra * \return item, or NULL on error or if the array is empty */ void * ptraRemoveLast(L_PTRA *pa) { l_int32 imax; PROCNAME("ptraRemoveLast"); if (!pa) return (void *)ERROR_PTR("pa not defined", procName, NULL); /* Remove the last item in the array. No compaction is required. */ ptraGetMaxIndex(pa, &imax); if (imax >= 0) return ptraRemove(pa, imax, L_NO_COMPACTION); else /* empty */ return NULL; } /*! * \brief ptraReplace() * * \param[in] pa ptra * \param[in] index element to be replaced * \param[in] item new generic ptr to a struct; can be null * \param[in] freeflag TRUE to free old item; FALSE to return it * \return item old item, if it exists and is not freed, * or NULL on error */ void * ptraReplace(L_PTRA *pa, l_int32 index, void *item, l_int32 freeflag) { l_int32 imax; void *olditem; PROCNAME("ptraReplace"); if (!pa) return (void *)ERROR_PTR("pa not defined", procName, NULL); ptraGetMaxIndex(pa, &imax); if (index < 0 || index > imax) return (void *)ERROR_PTR("index not in [0 ... imax]", procName, NULL); olditem = pa->array[index]; pa->array[index] = item; if (!item && olditem) pa->nactual--; else if (item && !olditem) pa->nactual++; if (freeflag == FALSE) return olditem; if (olditem) LEPT_FREE(olditem); return NULL; } /*! * \brief ptraSwap() * * \param[in] pa ptra * \param[in] index1 * \param[in] index2 * \return 0 if OK, 1 on error */ l_ok ptraSwap(L_PTRA *pa, l_int32 index1, l_int32 index2) { l_int32 imax; void *item; PROCNAME("ptraSwap"); if (!pa) return ERROR_INT("pa not defined", procName, 1); if (index1 == index2) return 0; ptraGetMaxIndex(pa, &imax); if (index1 < 0 || index1 > imax || index2 < 0 || index2 > imax) return ERROR_INT("invalid index: not in [0 ... imax]", procName, 1); item = ptraRemove(pa, index1, L_NO_COMPACTION); item = ptraReplace(pa, index2, item, FALSE); ptraInsert(pa, index1, item, L_MIN_DOWNSHIFT); return 0; } /*! * \brief ptraCompactArray() * * \param[in] pa * \return 0 if OK, 1 on error * *
* Notes: * (1) This compacts the items on the array, filling any empty ptrs. * (2) This does not change the size of the array of ptrs. **/ l_ok ptraCompactArray(L_PTRA *pa) { l_int32 i, imax, nactual, index; PROCNAME("ptraCompactArray"); if (!pa) return ERROR_INT("pa not defined", procName, 1); ptraGetMaxIndex(pa, &imax); ptraGetActualCount(pa, &nactual); if (imax + 1 == nactual) return 0; /* Compact the array */ for (i = 0, index = 0; i <= imax; i++) { if (pa->array[i]) pa->array[index++] = pa->array[i]; } pa->imax = index - 1; if (nactual != index) L_ERROR("index = %d; != nactual\n", procName, index); return 0; } /*----------------------------------------------------------------------* * Other array operations * *----------------------------------------------------------------------*/ /*! * \brief ptraReverse() * * \param[in] pa ptra * \return 0 if OK, 1 on error */ l_ok ptraReverse(L_PTRA *pa) { l_int32 i, imax; PROCNAME("ptraReverse"); if (!pa) return ERROR_INT("pa not defined", procName, 1); ptraGetMaxIndex(pa, &imax); for (i = 0; i < (imax + 1) / 2; i++) ptraSwap(pa, i, imax - i); return 0; } /*! * \brief ptraJoin() * * \param[in] pa1 add to this one * \param[in] pa2 appended to pa1, and emptied of items; can be null * \return 0 if OK, 1 on error */ l_ok ptraJoin(L_PTRA *pa1, L_PTRA *pa2) { l_int32 i, imax; void *item; PROCNAME("ptraJoin"); if (!pa1) return ERROR_INT("pa1 not defined", procName, 1); if (!pa2) return 0; ptraGetMaxIndex(pa2, &imax); for (i = 0; i <= imax; i++) { item = ptraRemove(pa2, i, L_NO_COMPACTION); ptraAdd(pa1, item); } return 0; } /*----------------------------------------------------------------------* * Simple ptra accessors * *----------------------------------------------------------------------*/ /*! * \brief ptraGetMaxIndex() * * \param[in] pa ptra * \param[out] pmaxindex index of last item in the array; * \return 0 if OK; 1 on error * *
* Notes: * (1) The largest index to an item in the array is %maxindex. * %maxindex is one less than the number of items that would be * in the array if there were no null pointers between 0 * and %maxindex - 1. However, because the internal ptr array * need not be compacted, there may be NULL pointers at * indices below %maxindex; for example, if items have * been removed. * (2) When an item is added to the end of the array, it goes * into pa->array[maxindex + 1], and maxindex is then * incremented by 1. * (3) If there are no items in the array, this returns %maxindex = -1. **/ l_ok ptraGetMaxIndex(L_PTRA *pa, l_int32 *pmaxindex) { PROCNAME("ptraGetMaxIndex"); if (!pa) return ERROR_INT("pa not defined", procName, 1); if (!pmaxindex) return ERROR_INT("&maxindex not defined", procName, 1); *pmaxindex = pa->imax; return 0; } /*! * \brief ptraGetActualCount() * * \param[in] pa ptra * \param[out] pcount actual number of items on the ptr array * \return 0 if OK; 1 on error * *
* Notes: * (1) The actual number of items on the ptr array, pa->nactual, * will be smaller than pa->n if the array is not compacted. **/ l_ok ptraGetActualCount(L_PTRA *pa, l_int32 *pcount) { PROCNAME("ptraGetActualCount"); if (!pa) return ERROR_INT("pa not defined", procName, 1); if (!pcount) return ERROR_INT("&count not defined", procName, 1); *pcount = pa->nactual; return 0; } /*! * \brief ptraGetPtrToItem() * * \param[in] pa ptra * \param[in] index of element to be retrieved * \return a ptr to the element, or NULL on error * *
* Notes: * (1) This returns a ptr to the item. You must cast it to * the type of item. Do not destroy it; the item belongs * to the Ptra. * (2) This can access all possible items on the ptr array. * If an item doesn't exist, it returns null. **/ void * ptraGetPtrToItem(L_PTRA *pa, l_int32 index) { PROCNAME("ptraGetPtrToItem"); if (!pa) return (void *)ERROR_PTR("pa not defined", procName, NULL); if (index < 0 || index >= pa->nalloc) return (void *)ERROR_PTR("index not in [0 ... nalloc-1]", procName, NULL); return pa->array[index]; } /*--------------------------------------------------------------------------* * Ptraa creation and destruction * *--------------------------------------------------------------------------*/ /*! * \brief ptraaCreate() * * \param[in] n size of ptr array to be alloc'd * \return paa, or NULL on error * *
* Notes: * (1) The ptraa is generated with a fixed size, that can not change. * The ptra can be generated and inserted randomly into this array. **/ L_PTRAA * ptraaCreate(l_int32 n) { L_PTRAA *paa; PROCNAME("ptraaCreate"); if (n <= 0) return (L_PTRAA *)ERROR_PTR("n must be > 0", procName, NULL); paa = (L_PTRAA *)LEPT_CALLOC(1, sizeof(L_PTRAA)); if ((paa->ptra = (L_PTRA **)LEPT_CALLOC(n, sizeof(L_PTRA *))) == NULL) { ptraaDestroy(&paa, 0, 0); return (L_PTRAA *)ERROR_PTR("ptr array not made", procName, NULL); } paa->nalloc = n; return paa; } /*! * \brief ptraaDestroy() * * \param[in,out] ppaa will be set to null before returning * \param[in] freeflag TRUE to free each remaining item in each ptra * \param[in] warnflag TRUE to warn if any remaining items * are not destroyed * \return void * *
* Notes: * (1) See ptraDestroy() for use of %freeflag and %warnflag. * (2) To destroy the ptraa, we destroy each ptra, then the ptr array, * then the ptraa, and then null the contents of the input ptr. **/ void ptraaDestroy(L_PTRAA **ppaa, l_int32 freeflag, l_int32 warnflag) { l_int32 i, n; L_PTRA *pa; L_PTRAA *paa; PROCNAME("ptraaDestroy"); if (ppaa == NULL) { L_WARNING("ptr address is NULL\n", procName); return; } if ((paa = *ppaa) == NULL) return; ptraaGetSize(paa, &n); for (i = 0; i < n; i++) { pa = ptraaGetPtra(paa, i, L_REMOVE); ptraDestroy(&pa, freeflag, warnflag); } LEPT_FREE(paa->ptra); LEPT_FREE(paa); *ppaa = NULL; return; } /*--------------------------------------------------------------------------* * Ptraa accessors * *--------------------------------------------------------------------------*/ /*! * \brief ptraaGetSize() * * \param[in] paa * \param[out] psize size of ptr array * \return 0 if OK; 1 on error */ l_ok ptraaGetSize(L_PTRAA *paa, l_int32 *psize) { PROCNAME("ptraaGetSize"); if (!paa) return ERROR_INT("paa not defined", procName, 1); if (!psize) return ERROR_INT("&size not defined", procName, 1); *psize = paa->nalloc; return 0; } /*! * \brief ptraaInsertPtra() * * \param[in] paa ptraa * \param[in] index location in array for insertion * \param[in] pa to be inserted * \return 0 if OK; 1 on error * *
* Notes: * (1) Caller should check return value. On success, the Ptra * is inserted in the Ptraa and is owned by it. However, * on error, the Ptra remains owned by the caller. **/ l_ok ptraaInsertPtra(L_PTRAA *paa, l_int32 index, L_PTRA *pa) { l_int32 n; PROCNAME("ptraaInsertPtra"); if (!paa) return ERROR_INT("paa not defined", procName, 1); if (!pa) return ERROR_INT("pa not defined", procName, 1); ptraaGetSize(paa, &n); if (index < 0 || index >= n) return ERROR_INT("invalid index", procName, 1); if (paa->ptra[index] != NULL) return ERROR_INT("ptra already stored at index", procName, 1); paa->ptra[index] = pa; return 0; } /*! * \brief ptraaGetPtra() * * \param[in] paa ptraa * \param[in] index location in array * \param[in] accessflag L_HANDLE_ONLY, L_REMOVE * \return ptra at index location, or NULL on error or if there * is no ptra there. * *
* Notes: * (1) This returns the ptra ptr. If %accessflag == L_HANDLE_ONLY, * the ptra is left on the ptraa. If %accessflag == L_REMOVE, * the ptr in the ptraa is set to NULL, and the caller * is responsible for disposing of the ptra (either putting it * back on the ptraa, or destroying it). * (2) This returns NULL if there is no Ptra at the index location. **/ L_PTRA * ptraaGetPtra(L_PTRAA *paa, l_int32 index, l_int32 accessflag) { l_int32 n; L_PTRA *pa; PROCNAME("ptraaGetPtra"); if (!paa) return (L_PTRA *)ERROR_PTR("paa not defined", procName, NULL); ptraaGetSize(paa, &n); if (index < 0 || index >= n) return (L_PTRA *)ERROR_PTR("invalid index", procName, NULL); if (accessflag != L_HANDLE_ONLY && accessflag != L_REMOVE) return (L_PTRA *)ERROR_PTR("invalid accessflag", procName, NULL); pa = paa->ptra[index]; if (accessflag == L_REMOVE) paa->ptra[index] = NULL; return pa; } /*--------------------------------------------------------------------------* * Ptraa conversion * *--------------------------------------------------------------------------*/ /*! * \brief ptraaFlattenToPtra() * * \param[in] paa ptraa * \return ptra, or NULL on error * *
* Notes: * (1) This 'flattens' the ptraa to a ptra, taking the items in * each ptra, in order, starting with the first ptra, etc. * (2) As a side-effect, the ptra are all removed from the ptraa * and destroyed, leaving an empty ptraa. **/ L_PTRA * ptraaFlattenToPtra(L_PTRAA *paa) { l_int32 i, n; L_PTRA *pat, *pad; PROCNAME("ptraaFlattenToPtra"); if (!paa) return (L_PTRA *)ERROR_PTR("paa not defined", procName, NULL); pad = ptraCreate(0); ptraaGetSize(paa, &n); for (i = 0; i < n; i++) { pat = ptraaGetPtra(paa, i, L_REMOVE); if (!pat) continue; ptraJoin(pad, pat); ptraDestroy(&pat, FALSE, FALSE); /* they're all empty */ } return pad; }