Coverage Report

Created: 2024-07-27 06:27

/src/leptonica/src/heap.c
Line
Count
Source (jump to first uncovered line)
1
/*====================================================================*
2
 -  Copyright (C) 2001 Leptonica.  All rights reserved.
3
 -
4
 -  Redistribution and use in source and binary forms, with or without
5
 -  modification, are permitted provided that the following conditions
6
 -  are met:
7
 -  1. Redistributions of source code must retain the above copyright
8
 -     notice, this list of conditions and the following disclaimer.
9
 -  2. Redistributions in binary form must reproduce the above
10
 -     copyright notice, this list of conditions and the following
11
 -     disclaimer in the documentation and/or other materials
12
 -     provided with the distribution.
13
 -
14
 -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15
 -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16
 -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17
 -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
18
 -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19
 -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
 -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21
 -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22
 -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23
 -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
 -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 *====================================================================*/
26
27
/*!
28
 * \file  heap.c
29
 * <pre>
30
 *
31
 *      Create/Destroy L_Heap
32
 *          L_HEAP         *lheapCreate()
33
 *          void            lheapDestroy()
34
 *
35
 *      Operations to add/remove to/from the heap
36
 *          l_int32         lheapAdd()
37
 *          static l_int32  lheapExtendArray()
38
 *          void           *lheapRemove()
39
 *
40
 *      Other accessors
41
 *          l_int32         lheapGetCount()
42
 *          void           *lheapGetElement()
43
 *
44
 *      Heap sort
45
 *          l_int32         lheapSort()
46
 *          l_int32         lheapSortStrictOrder()
47
 *
48
 *      Low-level heap operations
49
 *          static l_int32  lheapSwapUp()
50
 *          static l_int32  lheapSwapDown()
51
 *
52
 *      Debug output
53
 *          l_int32         lheapPrint()
54
 *
55
 *    The L_Heap is useful to implement a priority queue, that is sorted
56
 *    on a key in each element of the heap.  The heap is an array
57
 *    of nearly arbitrary structs, with a l_float32 the first field.
58
 *    This field is the key on which the heap is sorted.
59
 *
60
 *    Internally, we keep track of the heap size, n.  The item at the
61
 *    root of the heap is at the head of the array.  Items are removed
62
 *    from the head of the array and added to the end of the array.
63
 *    When an item is removed from the head, the item at the end
64
 *    of the array is moved to the head.  When items are either
65
 *    added or removed, it is usually necessary to swap array items
66
 *    to restore the heap order.  It is guaranteed that the number
67
 *    of swaps does not exceed log(n).
68
 *
69
 *    --------------------------  N.B.  ------------------------------
70
 *    The items on the heap (or, equivalently, in the array) are cast
71
 *    to void*.  Their key is a l_float32, and it is REQUIRED that the
72
 *    key be the first field in the struct.  That allows us to get the
73
 *    key by simply dereferencing the struct.  Alternatively, we could
74
 *    choose (but don't) to pass an application-specific comparison
75
 *    function into the heap operation functions.
76
 *    --------------------------  N.B.  ------------------------------
77
 * </pre>
78
 */
79
80
#ifdef HAVE_CONFIG_H
81
#include <config_auto.h>
82
#endif  /* HAVE_CONFIG_H */
83
84
#include <string.h>
85
#include "allheaders.h"
86
87
    /* Bounds on initial array size */
88
static const l_uint32  MaxPtrArraySize = 100000;
89
static const l_int32 InitialPtrArraySize = 20;      /*!< n'importe quoi */
90
91
0
#define SWAP_ITEMS(i, j)       { void *tempitem = lh->array[(i)]; \
92
0
                                 lh->array[(i)] = lh->array[(j)]; \
93
0
                                 lh->array[(j)] = tempitem; }
94
95
    /* Static functions */
96
static l_int32 lheapExtendArray(L_HEAP *lh);
97
static l_ok lheapSwapUp(L_HEAP *lh, l_int32 index);
98
static l_ok lheapSwapDown(L_HEAP *lh);
99
100
101
/*--------------------------------------------------------------------------*
102
 *                          L_Heap create/destroy                           *
103
 *--------------------------------------------------------------------------*/
104
/*!
105
 * \brief   lheapCreate()
106
 *
107
 * \param[in]    n           size of ptr array to be alloc'd; use 0 for default
108
 * \param[in]    direction   L_SORT_INCREASING, L_SORT_DECREASING
109
 * \return  lheap, or NULL on error
110
 */
111
L_HEAP *
112
lheapCreate(l_int32  n,
113
            l_int32  direction)
114
0
{
115
0
L_HEAP  *lh;
116
117
0
    if (n < InitialPtrArraySize || n > MaxPtrArraySize)
118
0
        n = InitialPtrArraySize;
119
120
        /* Allocate ptr array and initialize counters. */
121
0
    lh = (L_HEAP *)LEPT_CALLOC(1, sizeof(L_HEAP));
122
0
    if ((lh->array = (void **)LEPT_CALLOC(n, sizeof(void *))) == NULL) {
123
0
        lheapDestroy(&lh, FALSE);
124
0
        return (L_HEAP *)ERROR_PTR("ptr array not made", __func__, NULL);
125
0
    }
126
0
    lh->nalloc = n;
127
0
    lh->n = 0;
128
0
    lh->direction = direction;
129
0
    return lh;
130
0
}
131
132
133
/*!
134
 * \brief   lheapDestroy()
135
 *
136
 * \param[in,out]   plh        will be set to null before returning
137
 * \param[in]       freeflag   TRUE to free each remaining struct in the array
138
 * \return  void
139
 *
140
 * <pre>
141
 * Notes:
142
 *      (1) Use %freeflag == TRUE when the items in the array can be
143
 *          simply destroyed using free.  If those items require their
144
 *          own destroy function, they must be destroyed before
145
 *          calling this function, and then this function is called
146
 *          with %freeflag == FALSE.
147
 *      (2) To destroy the lheap, we destroy the ptr array, then
148
 *          the lheap, and then null the contents of the input ptr.
149
 * </pre>
150
 */
151
void
152
lheapDestroy(L_HEAP  **plh,
153
             l_int32   freeflag)
154
0
{
155
0
l_int32  i;
156
0
L_HEAP  *lh;
157
158
0
    if (plh == NULL) {
159
0
        L_WARNING("ptr address is NULL\n", __func__);
160
0
        return;
161
0
    }
162
0
    if ((lh = *plh) == NULL)
163
0
        return;
164
165
0
    if (freeflag) {  /* free each struct in the array */
166
0
        for (i = 0; i < lh->n; i++)
167
0
            LEPT_FREE(lh->array[i]);
168
0
    } else if (lh->n > 0) {  /* freeflag == FALSE but elements exist on array */
169
0
        L_WARNING("memory leak of %d items in lheap!\n", __func__, lh->n);
170
0
    }
171
172
0
    if (lh->array)
173
0
        LEPT_FREE(lh->array);
174
0
    LEPT_FREE(lh);
175
0
    *plh = NULL;
176
0
}
177
178
/*--------------------------------------------------------------------------*
179
 *                Operations to add/remove to/from the heap                 *
180
 *--------------------------------------------------------------------------*/
181
/*!
182
 * \brief   lheapAdd()
183
 *
184
 * \param[in]    lh      heap
185
 * \param[in]    item    to be added to the tail of the heap
186
 * \return  0 if OK, 1 on error
187
 */
188
l_ok
189
lheapAdd(L_HEAP  *lh,
190
         void    *item)
191
0
{
192
0
    if (!lh)
193
0
        return ERROR_INT("lh not defined", __func__, 1);
194
0
    if (!item)
195
0
        return ERROR_INT("item not defined", __func__, 1);
196
197
        /* If necessary, expand the allocated array by a factor of 2 */
198
0
    if (lh->n >= lh->nalloc) {
199
0
        if (lheapExtendArray(lh))
200
0
            return ERROR_INT("extension failed", __func__, 1);
201
0
    }
202
203
        /* Add the item */
204
0
    lh->array[lh->n] = item;
205
0
    lh->n++;
206
207
        /* Restore the heap */
208
0
    lheapSwapUp(lh, lh->n - 1);
209
0
    return 0;
210
0
}
211
212
213
/*!
214
 * \brief   lheapExtendArray()
215
 *
216
 * \param[in]    lh    heap
217
 * \return  0 if OK, 1 on error
218
 */
219
static l_int32
220
lheapExtendArray(L_HEAP  *lh)
221
0
{
222
0
    if (!lh)
223
0
        return ERROR_INT("lh not defined", __func__, 1);
224
225
0
    if ((lh->array = (void **)reallocNew((void **)&lh->array,
226
0
                                sizeof(void *) * lh->nalloc,
227
0
                                2 * sizeof(void *) * lh->nalloc)) == NULL)
228
0
        return ERROR_INT("new ptr array not returned", __func__, 1);
229
230
0
    lh->nalloc = 2 * lh->nalloc;
231
0
    return 0;
232
0
}
233
234
235
/*!
236
 * \brief   lheapRemove()
237
 *
238
 * \param[in]    lh    heap
239
 * \return  ptr to item popped from the root of the heap,
240
 *              or NULL if the heap is empty or on error
241
 */
242
void *
243
lheapRemove(L_HEAP  *lh)
244
0
{
245
0
void   *item;
246
247
0
    if (!lh)
248
0
        return (void *)ERROR_PTR("lh not defined", __func__, NULL);
249
250
0
    if (lh->n == 0)
251
0
        return NULL;
252
253
0
    item = lh->array[0];
254
0
    lh->array[0] = lh->array[lh->n - 1];  /* move last to the head */
255
0
    lh->array[lh->n - 1] = NULL;  /* set ptr to null */
256
0
    lh->n--;
257
258
0
    lheapSwapDown(lh);  /* restore the heap */
259
0
    return item;
260
0
}
261
262
263
/*--------------------------------------------------------------------------*
264
 *                            Other accessors                               *
265
 *--------------------------------------------------------------------------*/
266
/*!
267
 * \brief   lheapGetCount()
268
 *
269
 * \param[in]    lh    heap
270
 * \return  count, or 0 on error
271
 */
272
l_int32
273
lheapGetCount(L_HEAP  *lh)
274
0
{
275
0
    if (!lh)
276
0
        return ERROR_INT("lh not defined", __func__, 0);
277
278
0
    return lh->n;
279
0
}
280
281
282
/*!
283
 * \brief   lheapGetElement()
284
 *
285
 * \param[in]    lh       heap
286
 * \param[in]    index    into the internal heap array
287
 * \return  ptr to the element at array[index], or NULL on error
288
 *
289
 * <pre>
290
 * Notes:
291
 *      (1) This is useful for retrieving an arbitrary element in the
292
 *          heap array without disturbing the heap.  It allows all the
293
 *          elements on the heap to be queried in linear time; for
294
 *          example, to find the min or max of some value.
295
 *      (2) The retrieved element is owned by the heap.  Do not destroy it.
296
 * </pre>
297
 */
298
void *
299
lheapGetElement(L_HEAP  *lh,
300
                l_int32  index)
301
0
{
302
0
    if (!lh)
303
0
        return ERROR_PTR("lh not defined", __func__, NULL);
304
0
    if (index < 0 || index >= lh->n)
305
0
        return ERROR_PTR("invalid index", __func__, NULL);
306
307
0
    return (void *)lh->array[index];
308
0
}
309
310
311
/*--------------------------------------------------------------------------*
312
 *                                 Heap sort                                *
313
 *--------------------------------------------------------------------------*/
314
/*!
315
 * \brief   lheapSort()
316
 *
317
 * \param[in]    lh    heap, with internal array
318
 * \return  0 if OK, 1 on error
319
 *
320
 * <pre>
321
 * Notes:
322
 *      (1) This sorts an array into heap order.  If the heap is already
323
 *          in heap order for the direction given, this has no effect.
324
 * </pre>
325
 */
326
l_ok
327
lheapSort(L_HEAP  *lh)
328
0
{
329
0
l_int32  i;
330
331
0
  if (!lh)
332
0
      return ERROR_INT("lh not defined", __func__, 1);
333
334
0
  for (i = 0; i < lh->n; i++)
335
0
      lheapSwapUp(lh, i);
336
337
0
  return 0;
338
0
}
339
340
341
/*!
342
 * \brief   lheapSortStrictOrder()
343
 *
344
 * \param[in]    lh    heap, with internal array
345
 * \return  0 if OK, 1 on error
346
 *
347
 * <pre>
348
 * Notes:
349
 *      (1) This sorts a heap into strict order.
350
 *      (2) For each element, starting at the end of the array and
351
 *          working forward, the element is swapped with the head
352
 *          element and then allowed to swap down onto a heap of
353
 *          size reduced by one.  The result is that the heap is
354
 *          reversed but in strict order.  The array elements are
355
 *          then reversed to put it in the original order.
356
 * </pre>
357
 */
358
l_ok
359
lheapSortStrictOrder(L_HEAP  *lh)
360
0
{
361
0
l_int32  i, index, size;
362
363
0
  if (!lh)
364
0
      return ERROR_INT("lh not defined", __func__, 1);
365
366
      /* Start from a sorted heap */
367
0
  lheapSort(lh);
368
369
0
  size = lh->n;  /* save the actual size */
370
0
  for (i = 0; i < size; i++) {
371
0
      index = size - i;
372
0
      SWAP_ITEMS(0, index - 1);
373
0
      lh->n--;  /* reduce the apparent heap size by 1 */
374
0
      lheapSwapDown(lh);
375
0
  }
376
0
  lh->n = size;  /* restore the size */
377
378
0
  for (i = 0; i < size / 2; i++)  /* reverse */
379
0
      SWAP_ITEMS(i, size - i - 1);
380
381
0
  return 0;
382
0
}
383
384
385
/*--------------------------------------------------------------------------*
386
 *                         Low-level heap operations                        *
387
 *--------------------------------------------------------------------------*/
388
/*!
389
 * \brief   lheapSwapUp()
390
 *
391
 * \param[in]    lh      heap
392
 * \param[in]    index   of array corresponding to node to be swapped up
393
 * \return  0 if OK, 1 on error
394
 *
395
 * <pre>
396
 * Notes:
397
 *      (1) This is called after a new item is put on the heap, at the
398
 *          bottom of a complete tree.
399
 *      (2) To regain the heap order, we let it bubble up,
400
 *          iteratively swapping with its parent, until it either
401
 *          reaches the root of the heap or it finds a parent that
402
 *          is in the correct position already vis-a-vis the child.
403
 * </pre>
404
 */
405
static l_ok
406
lheapSwapUp(L_HEAP  *lh,
407
            l_int32  index)
408
0
{
409
0
l_int32    ip;  /* index to heap for parent; 1 larger than array index */
410
0
l_int32    ic;  /* index into heap for child */
411
0
l_float32  valp, valc;
412
413
0
  if (!lh)
414
0
      return ERROR_INT("lh not defined", __func__, 1);
415
0
  if (index < 0 || index >= lh->n)
416
0
      return ERROR_INT("invalid index", __func__, 1);
417
418
0
  ic = index + 1;  /* index into heap: add 1 to array index */
419
0
  if (lh->direction == L_SORT_INCREASING) {
420
0
      while (1) {
421
0
          if (ic == 1)  /* root of heap */
422
0
              break;
423
0
          ip = ic / 2;
424
0
          valc = *(l_float32 *)(lh->array[ic - 1]);
425
0
          valp = *(l_float32 *)(lh->array[ip - 1]);
426
0
          if (valp <= valc)
427
0
             break;
428
0
          SWAP_ITEMS(ip - 1, ic - 1);
429
0
          ic = ip;
430
0
      }
431
0
  } else {  /* lh->direction == L_SORT_DECREASING */
432
0
      while (1) {
433
0
          if (ic == 1)  /* root of heap */
434
0
              break;
435
0
          ip = ic / 2;
436
0
          valc = *(l_float32 *)(lh->array[ic - 1]);
437
0
          valp = *(l_float32 *)(lh->array[ip - 1]);
438
0
          if (valp >= valc)
439
0
             break;
440
0
          SWAP_ITEMS(ip - 1, ic - 1);
441
0
          ic = ip;
442
0
      }
443
0
  }
444
0
  return 0;
445
0
}
446
447
448
/*!
449
 * \brief   lheapSwapDown()
450
 *
451
 * \param[in]    lh   heap
452
 * \return  0 if OK, 1 on error
453
 *
454
 * <pre>
455
 * Notes:
456
 *      (1) This is called after an item has been popped off the
457
 *          root of the heap, and the last item in the heap has
458
 *          been placed at the root.
459
 *      (2) To regain the heap order, we let it bubble down,
460
 *          iteratively swapping with one of its children.  For a
461
 *          decreasing sort, it swaps with the largest child; for
462
 *          an increasing sort, the smallest.  This continues until
463
 *          it either reaches the lowest level in the heap, or the
464
 *          parent finds that neither child should swap with it
465
 *          (e.g., for a decreasing heap, the parent is larger
466
 *          than or equal to both children).
467
 * </pre>
468
 */
469
static l_ok
470
lheapSwapDown(L_HEAP  *lh)
471
0
{
472
0
l_int32    ip;  /* index to heap for parent; 1 larger than array index */
473
0
l_int32    icr, icl;  /* index into heap for left/right children */
474
0
l_float32  valp, valcl, valcr;
475
476
0
  if (!lh)
477
0
      return ERROR_INT("lh not defined", __func__, 1);
478
0
  if (lheapGetCount(lh) < 1)
479
0
      return 0;
480
481
0
  ip = 1;  /* index into top of heap: corresponds to array[0] */
482
0
  if (lh->direction == L_SORT_INCREASING) {
483
0
      while (1) {
484
0
          icl = 2 * ip;
485
0
          if (icl > lh->n)
486
0
             break;
487
0
          valp = *(l_float32 *)(lh->array[ip - 1]);
488
0
          valcl = *(l_float32 *)(lh->array[icl - 1]);
489
0
          icr = icl + 1;
490
0
          if (icr > lh->n) {  /* only a left child; no iters below */
491
0
              if (valp > valcl)
492
0
                  SWAP_ITEMS(ip - 1, icl - 1);
493
0
              break;
494
0
          } else {  /* both children exist; swap with the smallest if bigger */
495
0
              valcr = *(l_float32 *)(lh->array[icr - 1]);
496
0
              if (valp <= valcl && valp <= valcr)  /* smaller than both */
497
0
                  break;
498
0
              if (valcl <= valcr) {  /* left smaller; swap */
499
0
                  SWAP_ITEMS(ip - 1, icl - 1);
500
0
                  ip = icl;
501
0
              } else { /* right smaller; swap */
502
0
                  SWAP_ITEMS(ip - 1, icr - 1);
503
0
                  ip = icr;
504
0
              }
505
0
          }
506
0
      }
507
0
  } else {  /* lh->direction == L_SORT_DECREASING */
508
0
      while (1) {
509
0
          icl = 2 * ip;
510
0
          if (icl > lh->n)
511
0
             break;
512
0
          valp = *(l_float32 *)(lh->array[ip - 1]);
513
0
          valcl = *(l_float32 *)(lh->array[icl - 1]);
514
0
          icr = icl + 1;
515
0
          if (icr > lh->n) {  /* only a left child; no iters below */
516
0
              if (valp < valcl)
517
0
                  SWAP_ITEMS(ip - 1, icl - 1);
518
0
              break;
519
0
          } else {  /* both children exist; swap with the biggest if smaller */
520
0
              valcr = *(l_float32 *)(lh->array[icr - 1]);
521
0
              if (valp >= valcl && valp >= valcr)  /* bigger than both */
522
0
                  break;
523
0
              if (valcl >= valcr) {  /* left bigger; swap */
524
0
                  SWAP_ITEMS(ip - 1, icl - 1);
525
0
                  ip = icl;
526
0
              } else {  /* right bigger; swap */
527
0
                  SWAP_ITEMS(ip - 1, icr - 1);
528
0
                  ip = icr;
529
0
              }
530
0
          }
531
0
      }
532
0
  }
533
534
0
  return 0;
535
0
}
536
537
538
/*---------------------------------------------------------------------*
539
 *                            Debug output                             *
540
 *---------------------------------------------------------------------*/
541
/*!
542
 * \brief   lheapPrint()
543
 *
544
 * \param[in]    fp    file stream
545
 * \param[in]    lh    heap
546
 * \return  0 if OK; 1 on error
547
 */
548
l_ok
549
lheapPrint(FILE    *fp,
550
           L_HEAP  *lh)
551
0
{
552
0
l_int32  i;
553
554
0
    if (!fp)
555
0
        return ERROR_INT("stream not defined", __func__, 1);
556
0
    if (!lh)
557
0
        return ERROR_INT("lh not defined", __func__, 1);
558
559
0
    fprintf(fp, "\n L_Heap: nalloc = %d, n = %d, array = %p\n",
560
0
            lh->nalloc, lh->n, lh->array);
561
0
    for (i = 0; i < lh->n; i++)
562
0
        fprintf(fp,   "keyval[%d] = %f\n", i, *(l_float32 *)lh->array[i]);
563
564
0
    return 0;
565
0
}