Leptonica 1.68
C Image Processing Library
|
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