1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 /*
17  *   numabasic.c
18  *
19  *      Numa creation, destruction, copy, clone, etc.
20  *          NUMA        *numaCreate()
21  *          NUMA        *numaCreateFromIArray()
22  *          void        *numaDestroy()
23  *          NUMA        *numaCopy()
24  *          NUMA        *numaClone()
25  *          l_int32      numaEmpty()
26  *
27  *      Add/remove number (float or integer)
28  *          l_int32      numaAddNumber()
29  *          l_int32      numaExtendArray()
30  *          l_int32      numaInsertNumber()
31  *          l_int32      numaRemoveNumber()
32  *          l_int32      numaReplaceNumber()
33  *
34  *      Numa accessors
35  *          l_int32      numaGetCount()
36  *          l_int32      numaSetCount()
37  *          l_int32      numaGetIValue()
38  *          l_int32      numaGetFValue()
39  *          l_int32      numaSetValue()
40  *          l_int32      numaShiftValue()
41  *          l_int32     *numaGetIArray()
42  *          l_float32   *numaGetFArray()
43  *          l_int32      numaGetRefcount()
44  *          l_int32      numaChangeRefcount()
45  *          l_int32      numaGetXParameters()
46  *          l_int32      numaSetXParameters()
47  *          l_int32      numaCopyXParameters()
48  *
49  *      Serialize numa for I/O
50  *          l_int32      numaRead()
51  *          l_int32      numaReadStream()
52  *          l_int32      numaWrite()
53  *          l_int32      numaWriteStream()
54  *
55  *      Numaa creation, destruction
56  *          NUMAA       *numaaCreate()
57  *          void        *numaaDestroy()
58  *
59  *      Add Numa to Numaa
60  *          l_int32      numaaAddNuma()
61  *          l_int32      numaaExtendArray()
62  *
63  *      Numaa accessors
64  *          l_int32      numaaGetCount()
65  *          l_int32      numaaGetNumberCount()
66  *          NUMA       **numaaGetPtrArray()
67  *          NUMA        *numaaGetNuma()
68  *          NUMA        *numaaReplaceNuma()
69  *          l_int32      numaaAddNumber()
70  *
71  *      Serialize numaa for I/O
72  *          l_int32      numaaRead()
73  *          l_int32      numaaReadStream()
74  *          l_int32      numaaWrite()
75  *          l_int32      numaaWriteStream()
76  *
77  *      Numa2d creation, destruction
78  *          NUMA2D      *numa2dCreate()
79  *          void        *numa2dDestroy()
80  *
81  *      Numa2d Accessors
82  *          l_int32      numa2dAddNumber()
83  *          l_int32      numa2dGetCount()
84  *          NUMA        *numa2dGetNuma()
85  *          l_int32      numa2dGetFValue()
86  *          l_int32      numa2dGetIValue()
87  *
88  *      NumaHash creation, destruction
89  *          NUMAHASH    *numaHashCreate()
90  *          void        *numaHashDestroy()
91  *
92  *      NumaHash Accessors
93  *          NUMA        *numaHashGetNuma()
94  *          void        *numaHashAdd()
95  *
96  *    (1) The numa is a struct, not an array.  Always use the accessors
97  *        in this file, never the fields directly.
98  *
99  *    (2) The number array holds l_float32 values.  It can also
100  *        be used to store l_int32 values.
101  *
102  *    (3) Storing and retrieving numbers:
103  *
104  *       * to append a new number to the array, use numaAddNumber().  If
105  *         the number is an int, it will will automatically be converted
106  *         to l_float32 and stored.
107  *
108  *       * to reset a value stored in the array, use numaSetValue().
109  *
110  *       * to increment or decrement a value stored in the array,
111  *         use numaShiftValue().
112  *
113  *       * to obtain a value from the array, use either numaGetIValue()
114  *         or numaGetFValue(), depending on whether you are retrieving
115  *         an integer or a float.  This avoids doing an explicit cast,
116  *         such as
117  *           (a) return a l_float32 and cast it to an l_int32
118  *           (b) cast the return directly to (l_float32 *) to
119  *               satisfy the function prototype, as in
120  *                 numaGetFValue(na, index, (l_float32 *)&ival);   [ugly!]
121  *
122  *    (4) int <--> float conversions:
123  *
124  *        Tradition dictates that type conversions go automatically from
125  *        l_int32 --> l_float32, even though it is possible to lose
126  *        precision for large integers, whereas you must cast (l_int32)
127  *        to go from l_float32 --> l_int32 because you're truncating
128  *        to the integer value.
129  *
130  *    (5) As with other arrays in leptonica, the numa has both an allocated
131  *        size and a count of the stored numbers.  When you add a number, it
132  *        goes on the end of the array, and causes a realloc if the array
133  *        is already filled.  However, in situations where you want to
134  *        add numbers randomly into an array, such as when you build a
135  *        histogram, you must set the count of stored numbers in advance.
136  *        This is done with numaSetCount().  If you set a count larger
137  *        than the allocated array, it does a realloc to the size requested.
138  *
139  *    (6) In situations where the data in a numa correspond to a function
140  *        y(x), the values can be either at equal spacings in x or at
141  *        arbitrary spacings.  For the former, we can represent all x values
142  *        by two parameters: startx (corresponding to y[0]) and delx
143  *        for the change in x for adjacent values y[i] and y[i+1].
144  *        startx and delx are initialized to 0.0 and 1.0, rsp.
145  *        For arbitrary spacings, we use a second numa, and the two
146  *        numas are typically denoted nay and nax.
147  *
148  *    (7) The numa is also the basic struct used for histograms.  Every numa
149  *        has startx and delx fields, initialized to 0.0 and 1.0, that can
150  *        be used to represent the "x" value for the location of the
151  *        first bin and the bin width, respectively.  Accessors are the
152  *        numa*XParameters() functions.  All functions that make numa
153  *        histograms must set these fields properly, and many functions
154  *        that use numa histograms rely on the correctness of these values.
155  */
156 
157 #include <stdio.h>
158 #include <string.h>
159 #include <stdlib.h>
160 #include <math.h>
161 #include "allheaders.h"
162 
163 static const l_int32 INITIAL_PTR_ARRAYSIZE = 50;      /* n'importe quoi */
164 
165 
166 /*--------------------------------------------------------------------------*
167  *               Numa creation, destruction, copy, clone, etc.              *
168  *--------------------------------------------------------------------------*/
169 /*!
170  *  numaCreate()
171  *
172  *      Input:  size of number array to be alloc'd (0 for default)
173  *      Return: na, or null on error
174  */
175 NUMA *
numaCreate(l_int32 n)176 numaCreate(l_int32  n)
177 {
178 NUMA  *na;
179 
180     PROCNAME("numaCreate");
181 
182     if (n <= 0)
183         n = INITIAL_PTR_ARRAYSIZE;
184 
185     if ((na = (NUMA *)CALLOC(1, sizeof(NUMA))) == NULL)
186         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
187     if ((na->array = (l_float32 *)CALLOC(n, sizeof(l_float32))) == NULL)
188         return (NUMA *)ERROR_PTR("number array not made", procName, NULL);
189 
190     na->nalloc = n;
191     na->n = 0;
192     na->refcount = 1;
193     na->startx = 0.0;
194     na->delx = 1.0;
195 
196     return na;
197 }
198 
199 
200 /*!
201  *  numaCreateFromIArray()
202  *
203  *      Input:  int array
204  *              size (of the array)
205  *      Return: na, or null on error
206  *
207  *  Notes:
208  *      (1) This just copies the data from the int array into the numa.
209  *      (2) The input array is NOT owned by the numa.
210  */
211 NUMA *
numaCreateFromIArray(l_int32 * array,l_int32 size)212 numaCreateFromIArray(l_int32  *array,
213                      l_int32   size)
214 {
215 l_int32  i;
216 NUMA    *na;
217 
218     PROCNAME("numaCreateFromIArray");
219 
220     if (!array)
221         return (NUMA *)ERROR_PTR("array not defined", procName, NULL);
222 
223     na = numaCreate(size);
224     for (i = 0; i < size; i++)
225         numaAddNumber(na, array[i]);
226 
227     return na;
228 }
229 
230 
231 /*!
232  *  numaDestroy()
233  *
234  *      Input:  &na (<to be nulled if it exists>)
235  *      Return: void
236  *
237  *  Notes:
238  *      (1) Decrements the ref count and, if 0, destroys the numa.
239  *      (2) Always nulls the input ptr.
240  */
241 void
numaDestroy(NUMA ** pna)242 numaDestroy(NUMA  **pna)
243 {
244 NUMA  *na;
245 
246     PROCNAME("numaDestroy");
247 
248     if (pna == NULL) {
249         L_WARNING("ptr address is NULL", procName);
250         return;
251     }
252 
253     if ((na = *pna) == NULL)
254         return;
255 
256         /* Decrement the ref count.  If it is 0, destroy the numa. */
257     numaChangeRefcount(na, -1);
258     if (numaGetRefcount(na) <= 0) {
259         if (na->array)
260             FREE(na->array);
261         FREE(na);
262     }
263 
264     *pna = NULL;
265     return;
266 }
267 
268 
269 /*!
270  *  numaCopy()
271  *
272  *      Input:  na
273  *      Return: copy of numa, or null on error
274  */
275 NUMA *
numaCopy(NUMA * na)276 numaCopy(NUMA  *na)
277 {
278 l_int32  i;
279 NUMA    *cna;
280 
281     PROCNAME("numaCopy");
282 
283     if (!na)
284         return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
285 
286     if ((cna = numaCreate(na->nalloc)) == NULL)
287         return (NUMA *)ERROR_PTR("cna not made", procName, NULL);
288     cna->startx = na->startx;
289     cna->delx = na->delx;
290 
291     for (i = 0; i < na->n; i++)
292         numaAddNumber(cna, na->array[i]);
293 
294     return cna;
295 }
296 
297 
298 /*!
299  *  numaClone()
300  *
301  *      Input:  na
302  *      Return: ptr to same numa, or null on error
303  */
304 NUMA *
numaClone(NUMA * na)305 numaClone(NUMA  *na)
306 {
307     PROCNAME("numaClone");
308 
309     if (!na)
310         return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
311 
312     numaChangeRefcount(na, 1);
313     return na;
314 }
315 
316 
317 /*!
318  *  numaEmpty()
319  *
320  *      Input:  na
321  *      Return: 0 if OK; 1 on error
322  *
323  *  Notes:
324  *      (1) This does not change the allocation of the array.
325  *          It just clears the number of stored numbers, so that
326  *          the array appears to be empty.
327  */
328 l_int32
numaEmpty(NUMA * na)329 numaEmpty(NUMA  *na)
330 {
331     PROCNAME("numaEmpty");
332 
333     if (!na)
334         return ERROR_INT("na not defined", procName, 1);
335 
336     na->n = 0;
337     return 0;
338 }
339 
340 
341 
342 /*--------------------------------------------------------------------------*
343  *                 Number array: add number and extend array                *
344  *--------------------------------------------------------------------------*/
345 /*!
346  *  numaAddNumber()
347  *
348  *      Input:  na
349  *              val  (float or int to be added; stored as a float)
350  *      Return: 0 if OK, 1 on error
351  */
352 l_int32
numaAddNumber(NUMA * na,l_float32 val)353 numaAddNumber(NUMA      *na,
354               l_float32  val)
355 {
356 l_int32  n;
357 
358     PROCNAME("numaAddNumber");
359 
360     if (!na)
361         return ERROR_INT("na not defined", procName, 1);
362 
363     n = numaGetCount(na);
364     if (n >= na->nalloc)
365         numaExtendArray(na);
366     na->array[n] = val;
367     na->n++;
368     return 0;
369 }
370 
371 
372 /*!
373  *  numaExtendArray()
374  *
375  *      Input:  na
376  *      Return: 0 if OK, 1 on error
377  */
378 l_int32
numaExtendArray(NUMA * na)379 numaExtendArray(NUMA  *na)
380 {
381     PROCNAME("numaExtendArray");
382 
383     if (!na)
384         return ERROR_INT("na not defined", procName, 1);
385 
386     if ((na->array = (l_float32 *)reallocNew((void **)&na->array,
387                                 sizeof(l_float32) * na->nalloc,
388                                 2 * sizeof(l_float32) * na->nalloc)) == NULL)
389             return ERROR_INT("new ptr array not returned", procName, 1);
390 
391     na->nalloc *= 2;
392     return 0;
393 }
394 
395 
396 /*!
397  *  numaInsertNumber()
398  *
399  *      Input:  na
400  *              index (location in na to insert new value)
401  *              val  (float32 or integer to be added)
402  *      Return: 0 if OK, 1 on error
403  *
404  *  Notes:
405  *      (1) This shifts na[i] --> na[i + 1] for all i >= index,
406  *          and then inserts val as na[index].
407  *      (2) It should not be used repeatedly on large arrays,
408  *          because the function is O(n).
409  *
410  */
411 l_int32
numaInsertNumber(NUMA * na,l_int32 index,l_float32 val)412 numaInsertNumber(NUMA      *na,
413                  l_int32    index,
414                  l_float32  val)
415 {
416 l_int32  i, n;
417 
418     PROCNAME("numaInsertNumber");
419 
420     if (!na)
421         return ERROR_INT("na not defined", procName, 1);
422     n = numaGetCount(na);
423     if (index < 0 || index > n)
424         return ERROR_INT("index not in {0...n}", procName, 1);
425 
426     if (n >= na->nalloc)
427         numaExtendArray(na);
428     for (i = n; i > index; i--)
429         na->array[i] = na->array[i - 1];
430     na->array[index] = val;
431     na->n++;
432     return 0;
433 }
434 
435 
436 /*!
437  *  numaRemoveNumber()
438  *
439  *      Input:  na
440  *              index (element to be removed)
441  *      Return: 0 if OK, 1 on error
442  *
443  *  Notes:
444  *      (1) This shifts na[i] --> na[i - 1] for all i > index.
445  *      (2) It should not be used repeatedly on large arrays,
446  *          because the function is O(n).
447  */
448 l_int32
numaRemoveNumber(NUMA * na,l_int32 index)449 numaRemoveNumber(NUMA    *na,
450                  l_int32  index)
451 {
452 l_int32  i, n;
453 
454     PROCNAME("numaRemoveNumber");
455 
456     if (!na)
457         return ERROR_INT("na not defined", procName, 1);
458     n = numaGetCount(na);
459     if (index < 0 || index >= n)
460         return ERROR_INT("index not in {0...n - 1}", procName, 1);
461 
462     for (i = index + 1; i < n; i++)
463         na->array[i - 1] = na->array[i];
464     na->n--;
465     return 0;
466 }
467 
468 
469 /*!
470  *  numaReplaceNumber()
471  *
472  *      Input:  na
473  *              index (element to be replaced)
474  *              val (new value to replace old one)
475  *      Return: 0 if OK, 1 on error
476  */
477 l_int32
numaReplaceNumber(NUMA * na,l_int32 index,l_float32 val)478 numaReplaceNumber(NUMA      *na,
479                   l_int32    index,
480                   l_float32  val)
481 {
482 l_int32  n;
483 
484     PROCNAME("numaReplaceNumber");
485 
486     if (!na)
487         return ERROR_INT("na not defined", procName, 1);
488     n = numaGetCount(na);
489     if (index < 0 || index >= n)
490         return ERROR_INT("index not in {0...n - 1}", procName, 1);
491 
492     na->array[index] = val;
493     return 0;
494 }
495 
496 
497 /*----------------------------------------------------------------------*
498  *                            Numa accessors                            *
499  *----------------------------------------------------------------------*/
500 /*!
501  *  numaGetCount()
502  *
503  *      Input:  na
504  *      Return: count, or 0 if no numbers or on error
505  */
506 l_int32
numaGetCount(NUMA * na)507 numaGetCount(NUMA  *na)
508 {
509     PROCNAME("numaGetCount");
510 
511     if (!na)
512         return ERROR_INT("na not defined", procName, 0);
513     return na->n;
514 }
515 
516 
517 /*!
518  *  numaSetCount()
519  *
520  *      Input:  na
521  *              newcount
522  *      Return: 0 if OK, 1 on error
523  *
524  *  Notes:
525  *      (1) If newcount <= na->nalloc, this resets na->n.
526  *          Using newcount = 0 is equivalent to numaEmpty().
527  *      (2) If newcount > na->nalloc, this causes a realloc
528  *          to a size na->nalloc = newcount.
529  *      (3) All the previously unused values in na are set to 0.0.
530  */
531 l_int32
numaSetCount(NUMA * na,l_int32 newcount)532 numaSetCount(NUMA    *na,
533              l_int32  newcount)
534 {
535     PROCNAME("numaSetCount");
536 
537     if (!na)
538         return ERROR_INT("na not defined", procName, 1);
539     if (newcount > na->nalloc) {
540         if ((na->array = (l_float32 *)reallocNew((void **)&na->array,
541                          sizeof(l_float32) * na->nalloc,
542                          sizeof(l_float32) * newcount)) == NULL)
543             return ERROR_INT("new ptr array not returned", procName, 1);
544         na->nalloc = newcount;
545     }
546     na->n = newcount;
547     return 0;
548 }
549 
550 
551 /*!
552  *  numaGetFValue()
553  *
554  *      Input:  na
555  *              index (into numa)
556  *              &val  (<return> float value; 0.0 on error)
557  *      Return: 0 if OK; 1 on error
558  *
559  *  Notes:
560  *      (1) Caller may need to check the function return value to
561  *          decide if a 0.0 in the returned ival is valid.
562  */
563 l_int32
numaGetFValue(NUMA * na,l_int32 index,l_float32 * pval)564 numaGetFValue(NUMA       *na,
565               l_int32     index,
566               l_float32  *pval)
567 {
568     PROCNAME("numaGetFValue");
569 
570     if (!pval)
571         return ERROR_INT("&val not defined", procName, 1);
572     *pval = 0.0;
573     if (!na)
574         return ERROR_INT("na not defined", procName, 1);
575 
576     if (index < 0 || index >= na->n)
577         return ERROR_INT("index not valid", procName, 1);
578 
579     *pval = na->array[index];
580     return 0;
581 }
582 
583 
584 /*!
585  *  numaGetIValue()
586  *
587  *      Input:  na
588  *              index (into numa)
589  *              &ival  (<return> integer value; 0 on error)
590  *      Return: 0 if OK; 1 on error
591  *
592  *  Notes:
593  *      (1) Caller may need to check the function return value to
594  *          decide if a 0 in the returned ival is valid.
595  */
596 l_int32
numaGetIValue(NUMA * na,l_int32 index,l_int32 * pival)597 numaGetIValue(NUMA     *na,
598               l_int32   index,
599               l_int32  *pival)
600 {
601 l_float32  val;
602 
603     PROCNAME("numaGetIValue");
604 
605     if (!pival)
606         return ERROR_INT("&ival not defined", procName, 1);
607     *pival = 0;
608     if (!na)
609         return ERROR_INT("na not defined", procName, 1);
610 
611     if (index < 0 || index >= na->n)
612         return ERROR_INT("index not valid", procName, 1);
613 
614     val = na->array[index];
615     *pival = (l_int32)(val + L_SIGN(val) * 0.5);
616     return 0;
617 }
618 
619 
620 /*!
621  *  numaSetValue()
622  *
623  *      Input:  na
624  *              index   (to element to be set)
625  *              val  (to set element)
626  *      Return: 0 if OK; 1 on error
627  */
628 l_int32
numaSetValue(NUMA * na,l_int32 index,l_float32 val)629 numaSetValue(NUMA      *na,
630              l_int32    index,
631              l_float32  val)
632 {
633     PROCNAME("numaSetValue");
634 
635     if (!na)
636         return ERROR_INT("na not defined", procName, 1);
637     if (index < 0 || index >= na->n)
638         return ERROR_INT("index not valid", procName, 1);
639 
640     na->array[index] = val;
641     return 0;
642 }
643 
644 
645 /*!
646  *  numaShiftValue()
647  *
648  *      Input:  na
649  *              index (to element to change relative to the current value)
650  *              diff  (increment if diff > 0 or decrement if diff < 0)
651  *      Return: 0 if OK; 1 on error
652  */
653 l_int32
numaShiftValue(NUMA * na,l_int32 index,l_float32 diff)654 numaShiftValue(NUMA      *na,
655                l_int32    index,
656                l_float32  diff)
657 {
658     PROCNAME("numaShiftValue");
659 
660     if (!na)
661         return ERROR_INT("na not defined", procName, 1);
662     if (index < 0 || index >= na->n)
663         return ERROR_INT("index not valid", procName, 1);
664 
665     na->array[index] += diff;
666     return 0;
667 }
668 
669 
670 /*!
671  *  numaGetIArray()
672  *
673  *      Input:  na
674  *      Return: a copy of the bare internal array, integerized
675  *              by rounding, or null on error
676  *  Notes:
677  *      (1) A copy of the array is always made, because we need to
678  *          generate an integer array from the bare float array.
679  *          The caller is responsible for freeing the array.
680  *      (2) The array size is determined by the number of stored numbers,
681  *          not by the size of the allocated array in the Numa.
682  *      (3) This function is provided to simplify calculations
683  *          using the bare internal array, rather than continually
684  *          calling accessors on the numa.  It is typically used
685  *          on an array of size 256.
686  */
687 l_int32 *
numaGetIArray(NUMA * na)688 numaGetIArray(NUMA  *na)
689 {
690 l_int32   i, n, ival;
691 l_int32  *array;
692 
693     PROCNAME("numaGetIArray");
694 
695     if (!na)
696         return (l_int32 *)ERROR_PTR("na not defined", procName, NULL);
697 
698     n = numaGetCount(na);
699     if ((array = (l_int32 *)CALLOC(n, sizeof(l_int32))) == NULL)
700         return (l_int32 *)ERROR_PTR("array not made", procName, NULL);
701     for (i = 0; i < n; i++) {
702         numaGetIValue(na, i, &ival);
703         array[i] = ival;
704     }
705 
706     return array;
707 }
708 
709 
710 /*!
711  *  numaGetFArray()
712  *
713  *      Input:  na
714  *              copyflag (L_NOCOPY or L_COPY)
715  *      Return: either the bare internal array or a copy of it,
716  *              or null on error
717  *
718  *  Notes:
719  *      (1) If copyflag == L_COPY, it makes a copy which the caller
720  *          is responsible for freeing.  Otherwise, it operates
721  *          directly on the bare array of the numa.
722  *      (2) Very important: for L_NOCOPY, any writes to the array
723  *          will be in the numa.  Do not write beyond the size of
724  *          the count field, because it will not be accessable
725  *          from the numa!  If necessary, be sure to set the count
726  *          field to a larger number (such as the alloc size)
727  *          BEFORE calling this function.  Creating with numaMakeConstant()
728  *          is another way to insure full initialization.
729  */
730 l_float32 *
numaGetFArray(NUMA * na,l_int32 copyflag)731 numaGetFArray(NUMA    *na,
732               l_int32  copyflag)
733 {
734 l_int32     i, n;
735 l_float32  *array;
736 
737     PROCNAME("numaGetFArray");
738 
739     if (!na)
740         return (l_float32 *)ERROR_PTR("na not defined", procName, NULL);
741 
742     if (copyflag == L_NOCOPY)
743         array = na->array;
744     else {  /* copyflag == L_COPY */
745         n = numaGetCount(na);
746         if ((array = (l_float32 *)CALLOC(n, sizeof(l_float32))) == NULL)
747             return (l_float32 *)ERROR_PTR("array not made", procName, NULL);
748         for (i = 0; i < n; i++)
749             array[i] = na->array[i];
750     }
751 
752     return array;
753 }
754 
755 
756 /*!
757  *  numaGetRefCount()
758  *
759  *      Input:  na
760  *      Return: refcount, or UNDEF on error
761  */
762 l_int32
numaGetRefcount(NUMA * na)763 numaGetRefcount(NUMA  *na)
764 {
765     PROCNAME("numaGetRefcount");
766 
767     if (!na)
768         return ERROR_INT("na not defined", procName, UNDEF);
769     return na->refcount;
770 }
771 
772 
773 /*!
774  *  numaChangeRefCount()
775  *
776  *      Input:  na
777  *              delta (change to be applied)
778  *      Return: 0 if OK, 1 on error
779  */
780 l_int32
numaChangeRefcount(NUMA * na,l_int32 delta)781 numaChangeRefcount(NUMA    *na,
782                    l_int32  delta)
783 {
784     PROCNAME("numaChangeRefcount");
785 
786     if (!na)
787         return ERROR_INT("na not defined", procName, 1);
788     na->refcount += delta;
789     return 0;
790 }
791 
792 
793 /*!
794  *  numaGetXParameters()
795  *
796  *      Input:  na
797  *              &startx (<optional return> startx)
798  *              &delx (<optional return> delx)
799  *      Return: 0 if OK, 1 on error
800  */
801 l_int32
numaGetXParameters(NUMA * na,l_float32 * pstartx,l_float32 * pdelx)802 numaGetXParameters(NUMA       *na,
803                    l_float32  *pstartx,
804                    l_float32  *pdelx)
805 {
806     PROCNAME("numaGetXParameters");
807 
808     if (!na)
809         return ERROR_INT("na not defined", procName, 1);
810 
811     if (pstartx) *pstartx = na->startx;
812     if (pdelx) *pdelx = na->delx;
813     return 0;
814 }
815 
816 
817 /*!
818  *  numaSetXParameters()
819  *
820  *      Input:  na
821  *              startx (x value corresponding to na[0])
822  *              delx (difference in x values for the situation where the
823  *                    elements of na correspond to the evaulation of a
824  *                    function at equal intervals of size @delx)
825  *      Return: 0 if OK, 1 on error
826  */
827 l_int32
numaSetXParameters(NUMA * na,l_float32 startx,l_float32 delx)828 numaSetXParameters(NUMA      *na,
829                    l_float32  startx,
830                    l_float32  delx)
831 {
832     PROCNAME("numaSetXParameters");
833 
834     if (!na)
835         return ERROR_INT("na not defined", procName, 1);
836 
837     na->startx = startx;
838     na->delx = delx;
839     return 0;
840 }
841 
842 
843 /*!
844  *  numaCopyXParameters()
845  *
846  *      Input:  nad (destination Numa)
847  *              nas (source Numa)
848  *      Return: 0 if OK, 1 on error
849  */
850 l_int32
numaCopyXParameters(NUMA * nad,NUMA * nas)851 numaCopyXParameters(NUMA  *nad,
852                     NUMA  *nas)
853 {
854 l_float32  start, binsize;
855 
856     PROCNAME("numaCopyXParameters");
857 
858     if (!nas || !nad)
859         return ERROR_INT("nas and nad not both defined", procName, 1);
860 
861     numaGetXParameters(nas, &start, &binsize);
862     numaSetXParameters(nad, start, binsize);
863     return 0;
864 }
865 
866 
867 /*----------------------------------------------------------------------*
868  *                       Serialize numa for I/O                         *
869  *----------------------------------------------------------------------*/
870 /*!
871  *  numaRead()
872  *
873  *      Input:  filename
874  *      Return: na, or null on error
875  */
876 NUMA *
numaRead(const char * filename)877 numaRead(const char  *filename)
878 {
879 FILE  *fp;
880 NUMA  *na;
881 
882     PROCNAME("numaRead");
883 
884     if (!filename)
885         return (NUMA *)ERROR_PTR("filename not defined", procName, NULL);
886 
887     if ((fp = fopenReadStream(filename)) == NULL)
888         return (NUMA *)ERROR_PTR("stream not opened", procName, NULL);
889 
890     if ((na = numaReadStream(fp)) == NULL) {
891         fclose(fp);
892         return (NUMA *)ERROR_PTR("na not read", procName, NULL);
893     }
894 
895     fclose(fp);
896     return na;
897 }
898 
899 
900 /*!
901  *  numaReadStream()
902  *
903  *      Input:  stream
904  *      Return: numa, or null on error
905  */
906 NUMA *
numaReadStream(FILE * fp)907 numaReadStream(FILE  *fp)
908 {
909 l_int32    i, n, index, ret, version;
910 l_float32  val, startx, delx;
911 NUMA      *na;
912 
913     PROCNAME("numaReadStream");
914 
915     if (!fp)
916         return (NUMA *)ERROR_PTR("stream not defined", procName, NULL);
917 
918     ret = fscanf(fp, "\nNuma Version %d\n", &version);
919     if (ret != 1)
920         return (NUMA *)ERROR_PTR("not a numa file", procName, NULL);
921     if (version != NUMA_VERSION_NUMBER)
922         return (NUMA *)ERROR_PTR("invalid numa version", procName, NULL);
923     fscanf(fp, "Number of numbers = %d\n", &n);
924 
925     if ((na = numaCreate(n)) == NULL)
926         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
927 
928     for (i = 0; i < n; i++) {
929         if ((fscanf(fp, "  [%d] = %f\n", &index, &val)) != 2)
930             return (NUMA *)ERROR_PTR("bad input data", procName, NULL);
931         numaAddNumber(na, val);
932     }
933 
934         /* Optional data */
935     if ((fscanf(fp, "startx = %f, delx = %f\n", &startx, &delx)) == 2)
936         numaSetXParameters(na, startx, delx);
937 
938     return na;
939 }
940 
941 
942 /*!
943  *  numaWrite()
944  *
945  *      Input:  filename, na
946  *      Return: 0 if OK, 1 on error
947  */
948 l_int32
numaWrite(const char * filename,NUMA * na)949 numaWrite(const char  *filename,
950           NUMA        *na)
951 {
952 FILE  *fp;
953 
954     PROCNAME("numaWrite");
955 
956     if (!filename)
957         return ERROR_INT("filename not defined", procName, 1);
958     if (!na)
959         return ERROR_INT("na not defined", procName, 1);
960 
961     if ((fp = fopen(filename, "w")) == NULL)
962         return ERROR_INT("stream not opened", procName, 1);
963     if (numaWriteStream(fp, na))
964         return ERROR_INT("na not written to stream", procName, 1);
965     fclose(fp);
966 
967     return 0;
968 }
969 
970 
971 /*!
972  *  numaWriteStream()
973  *
974  *      Input:  stream, na
975  *      Return: 0 if OK, 1 on error
976  */
977 l_int32
numaWriteStream(FILE * fp,NUMA * na)978 numaWriteStream(FILE  *fp,
979                 NUMA  *na)
980 {
981 l_int32    i, n;
982 l_float32  startx, delx;
983 
984     PROCNAME("numaWriteStream");
985 
986     if (!fp)
987         return ERROR_INT("stream not defined", procName, 1);
988     if (!na)
989         return ERROR_INT("na not defined", procName, 1);
990 
991     n = numaGetCount(na);
992     fprintf(fp, "\nNuma Version %d\n", NUMA_VERSION_NUMBER);
993     fprintf(fp, "Number of numbers = %d\n", n);
994     for (i = 0; i < n; i++)
995         fprintf(fp, "  [%d] = %f\n", i, na->array[i]);
996     fprintf(fp, "\n");
997 
998         /* Optional data */
999     numaGetXParameters(na, &startx, &delx);
1000     if (startx != 0.0 || delx != 1.0)
1001         fprintf(fp, "startx = %f, delx = %f\n", startx, delx);
1002 
1003     return 0;
1004 }
1005 
1006 
1007 
1008 /*--------------------------------------------------------------------------*
1009  *                     Numaa creation, destruction                          *
1010  *--------------------------------------------------------------------------*/
1011 /*!
1012  *  numaaCreate()
1013  *
1014  *      Input:  size of numa ptr array to be alloc'd (0 for default)
1015  *      Return: naa, or null on error
1016  *
1017  */
1018 NUMAA *
numaaCreate(l_int32 n)1019 numaaCreate(l_int32  n)
1020 {
1021 NUMAA  *naa;
1022 
1023     PROCNAME("numaaCreate");
1024 
1025     if (n <= 0)
1026         n = INITIAL_PTR_ARRAYSIZE;
1027 
1028     if ((naa = (NUMAA *)CALLOC(1, sizeof(NUMAA))) == NULL)
1029         return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
1030     if ((naa->numa = (NUMA **)CALLOC(n, sizeof(NUMA *))) == NULL)
1031         return (NUMAA *)ERROR_PTR("numa ptr array not made", procName, NULL);
1032 
1033     naa->nalloc = n;
1034     naa->n = 0;
1035 
1036     return naa;
1037 }
1038 
1039 
1040 /*!
1041  *  numaaDestroy()
1042  *
1043  *      Input: &numaa <to be nulled if it exists>
1044  *      Return: void
1045  */
1046 void
numaaDestroy(NUMAA ** pnaa)1047 numaaDestroy(NUMAA  **pnaa)
1048 {
1049 l_int32  i;
1050 NUMAA   *naa;
1051 
1052     PROCNAME("numaaDestroy");
1053 
1054     if (pnaa == NULL) {
1055         L_WARNING("ptr address is NULL!", procName);
1056         return;
1057     }
1058 
1059     if ((naa = *pnaa) == NULL)
1060         return;
1061 
1062     for (i = 0; i < naa->n; i++)
1063         numaDestroy(&naa->numa[i]);
1064     FREE(naa->numa);
1065     FREE(naa);
1066     *pnaa = NULL;
1067 
1068     return;
1069 }
1070 
1071 
1072 
1073 /*--------------------------------------------------------------------------*
1074  *                              Add Numa to Numaa                           *
1075  *--------------------------------------------------------------------------*/
1076 /*!
1077  *  numaaAddNuma()
1078  *
1079  *      Input:  naa
1080  *              na   (to be added)
1081  *              copyflag  (L_INSERT, L_COPY, L_CLONE)
1082  *      Return: 0 if OK, 1 on error
1083  */
1084 l_int32
numaaAddNuma(NUMAA * naa,NUMA * na,l_int32 copyflag)1085 numaaAddNuma(NUMAA   *naa,
1086              NUMA    *na,
1087              l_int32  copyflag)
1088 {
1089 l_int32  n;
1090 NUMA    *nac;
1091 
1092     PROCNAME("numaaAddNuma");
1093 
1094     if (!naa)
1095         return ERROR_INT("naa not defined", procName, 1);
1096     if (!na)
1097         return ERROR_INT("na not defined", procName, 1);
1098 
1099     if (copyflag == L_INSERT)
1100         nac = na;
1101     else if (copyflag == L_COPY) {
1102         if ((nac = numaCopy(na)) == NULL)
1103             return ERROR_INT("nac not made", procName, 1);
1104     }
1105     else if (copyflag == L_CLONE)
1106         nac = numaClone(na);
1107     else
1108         return ERROR_INT("invalid copyflag", procName, 1);
1109 
1110     n = numaaGetCount(naa);
1111     if (n >= naa->nalloc)
1112         numaaExtendArray(naa);
1113     naa->numa[n] = nac;
1114     naa->n++;
1115     return 0;
1116 }
1117 
1118 
1119 /*!
1120  *  numaaExtendArray()
1121  *
1122  *      Input:  naa
1123  *      Return: 0 if OK, 1 on error
1124  */
1125 l_int32
numaaExtendArray(NUMAA * naa)1126 numaaExtendArray(NUMAA  *naa)
1127 {
1128     PROCNAME("numaaExtendArray");
1129 
1130     if (!naa)
1131         return ERROR_INT("naa not defined", procName, 1);
1132 
1133     if ((naa->numa = (NUMA **)reallocNew((void **)&naa->numa,
1134                               sizeof(NUMA *) * naa->nalloc,
1135                               2 * sizeof(NUMA *) * naa->nalloc)) == NULL)
1136             return ERROR_INT("new ptr array not returned", procName, 1);
1137 
1138     naa->nalloc *= 2;
1139     return 0;
1140 }
1141 
1142 
1143 /*----------------------------------------------------------------------*
1144  *                           Numaa accessors                            *
1145  *----------------------------------------------------------------------*/
1146 /*!
1147  *  numaaGetCount()
1148  *
1149  *      Input:  naa
1150  *      Return: count (number of numa), or 0 if no numa or on error
1151  */
1152 l_int32
numaaGetCount(NUMAA * naa)1153 numaaGetCount(NUMAA  *naa)
1154 {
1155     PROCNAME("numaaGetCount");
1156 
1157     if (!naa)
1158         return ERROR_INT("naa not defined", procName, 0);
1159     return naa->n;
1160 }
1161 
1162 
1163 /*!
1164  *  numaaGetNumberCount()
1165  *
1166  *      Input:  naa
1167  *      Return: count (number of numbers), or 0 if no numbers or on error
1168  */
1169 l_int32
numaaGetNumberCount(NUMAA * naa)1170 numaaGetNumberCount(NUMAA  *naa)
1171 {
1172 NUMA    *na;
1173 l_int32  n, sum, i;
1174 
1175     PROCNAME("numaaGetNumberCount");
1176 
1177     if (!naa)
1178         return ERROR_INT("naa not defined", procName, 0);
1179 
1180     n = numaaGetCount(naa);
1181     for (sum = 0, i = 0; i < n; i++) {
1182         na = numaaGetNuma(naa, i, L_CLONE);
1183         sum += numaGetCount(na);
1184         numaDestroy(&na);
1185     }
1186 
1187     return sum;
1188 }
1189 
1190 
1191 /*!
1192  *  numaaGetPtrArray()
1193  *
1194  *      Input:  naa
1195  *      Return: the internal array of ptrs to Numa, or null on error
1196  *
1197  *  Notes:
1198  *      (1) This function is convenient for doing direct manipulation on
1199  *          a fixed size array of Numas.  To do this, it sets the count
1200  *          to the full size of the allocated array of Numa ptrs.
1201  *          The originating Numaa owns this array: DO NOT free it!
1202  *      (2) Intended usage:
1203  *            Numaa *naa = numaaCreate(n);
1204  *            Numa **array = numaaGetPtrArray(naa);
1205  *             ...  [manipulate Numas directly on the array]
1206  *            numaaDestroy(&naa);
1207  *      (3) Cautions:
1208  *           - Do not free this array; it is owned by tne Numaa.
1209  *           - Do not call any functions on the Numaa, other than
1210  *             numaaDestroy() when you're finished with the array.
1211  *             Adding a Numa will force a resize, destroying the ptr array.
1212  *           - Do not address the array outside its allocated size.
1213  *             With the bare array, there are no protections.  If the
1214  *             allocated size is n, array[n] is an error.
1215  */
1216 NUMA **
numaaGetPtrArray(NUMAA * naa)1217 numaaGetPtrArray(NUMAA  *naa)
1218 {
1219     PROCNAME("numaaGetPtrArray");
1220 
1221     if (!naa)
1222         return (NUMA **)ERROR_PTR("naa not defined", procName, NULL);
1223 
1224     naa->n = naa->nalloc;
1225     return naa->numa;
1226 }
1227 
1228 
1229 /*!
1230  *  numaaGetNuma()
1231  *
1232  *      Input:  naa
1233  *              index  (to the index-th numa)
1234  *              accessflag   (L_COPY or L_CLONE)
1235  *      Return: numa, or null on error
1236  */
1237 NUMA *
numaaGetNuma(NUMAA * naa,l_int32 index,l_int32 accessflag)1238 numaaGetNuma(NUMAA   *naa,
1239              l_int32  index,
1240              l_int32  accessflag)
1241 {
1242     PROCNAME("numaaGetNuma");
1243 
1244     if (!naa)
1245         return (NUMA *)ERROR_PTR("naa not defined", procName, NULL);
1246     if (index < 0 || index >= naa->n)
1247         return (NUMA *)ERROR_PTR("index not valid", procName, NULL);
1248 
1249     if (accessflag == L_COPY)
1250         return numaCopy(naa->numa[index]);
1251     else if (accessflag == L_CLONE)
1252         return numaClone(naa->numa[index]);
1253     else
1254         return (NUMA *)ERROR_PTR("invalid accessflag", procName, NULL);
1255 }
1256 
1257 
1258 /*!
1259  *  numaaReplaceNuma()
1260  *
1261  *      Input:  naa
1262  *              index  (to the index-th numa)
1263  *              numa (insert and replace any existing one)
1264  *      Return: 0 if OK, 1 on error
1265  *
1266  *  Notes:
1267  *      (1) Any existing numa is destroyed, and the input one
1268  *          is inserted in its place.
1269  *      (2) If the index is invalid, return 1 (error)
1270  */
1271 l_int32
numaaReplaceNuma(NUMAA * naa,l_int32 index,NUMA * na)1272 numaaReplaceNuma(NUMAA   *naa,
1273                  l_int32  index,
1274                  NUMA    *na)
1275 {
1276 l_int32  n;
1277 
1278     PROCNAME("numaaReplaceNuma");
1279 
1280     if (!naa)
1281         return ERROR_INT("naa not defined", procName, 1);
1282     if (!na)
1283         return ERROR_INT("na not defined", procName, 1);
1284     n = numaaGetCount(naa);
1285     if (index < 0 || index >= n)
1286         return ERROR_INT("index not valid", procName, 1);
1287 
1288     numaDestroy(&naa->numa[index]);
1289     naa->numa[index] = na;
1290     return 0;
1291 }
1292 
1293 
1294 /*!
1295  *  numaaAddNumber()
1296  *
1297  *      Input:  naa
1298  *              index (of numa within numaa)
1299  *              val  (float or int to be added; stored as a float)
1300  *      Return: 0 if OK, 1 on error
1301  *
1302  *  Notes:
1303  *      (1) Adds to an existing numa only.
1304  */
1305 l_int32
numaaAddNumber(NUMAA * naa,l_int32 index,l_float32 val)1306 numaaAddNumber(NUMAA     *naa,
1307                l_int32    index,
1308                l_float32  val)
1309 {
1310 l_int32  n;
1311 NUMA    *na;
1312 
1313     PROCNAME("numaaAddNumber");
1314 
1315     if (!naa)
1316         return ERROR_INT("naa not defined", procName, 1);
1317     n = numaaGetCount(naa);
1318     if (index < 0 || index >= n)
1319         return ERROR_INT("invalid index in naa", procName, 1);
1320 
1321     na = numaaGetNuma(naa, index, L_CLONE);
1322     numaAddNumber(na, val);
1323     numaDestroy(&na);
1324     return 0;
1325 }
1326 
1327 
1328 /*----------------------------------------------------------------------*
1329  *                      Serialize numaa for I/O                         *
1330  *----------------------------------------------------------------------*/
1331 /*!
1332  *  numaaRead()
1333  *
1334  *      Input:  filename
1335  *      Return: naa, or null on error
1336  */
1337 NUMAA *
numaaRead(const char * filename)1338 numaaRead(const char  *filename)
1339 {
1340 FILE   *fp;
1341 NUMAA  *naa;
1342 
1343     PROCNAME("numaaRead");
1344 
1345     if (!filename)
1346         return (NUMAA *)ERROR_PTR("filename not defined", procName, NULL);
1347 
1348     if ((fp = fopenReadStream(filename)) == NULL)
1349         return (NUMAA *)ERROR_PTR("stream not opened", procName, NULL);
1350 
1351     if ((naa = numaaReadStream(fp)) == NULL) {
1352         fclose(fp);
1353         return (NUMAA *)ERROR_PTR("naa not read", procName, NULL);
1354     }
1355 
1356     fclose(fp);
1357     return naa;
1358 }
1359 
1360 
1361 /*!
1362  *  numaaReadStream()
1363  *
1364  *      Input:  stream
1365  *      Return: naa, or null on error
1366  */
1367 NUMAA *
numaaReadStream(FILE * fp)1368 numaaReadStream(FILE  *fp)
1369 {
1370 l_int32    i, n, index, ret, version;
1371 NUMA      *na;
1372 NUMAA     *naa;
1373 
1374     PROCNAME("numaaReadStream");
1375 
1376     if (!fp)
1377         return (NUMAA *)ERROR_PTR("stream not defined", procName, NULL);
1378 
1379     ret = fscanf(fp, "\nNumaa Version %d\n", &version);
1380     if (ret != 1)
1381         return (NUMAA *)ERROR_PTR("not a numa file", procName, NULL);
1382     if (version != NUMA_VERSION_NUMBER)
1383         return (NUMAA *)ERROR_PTR("invalid numaa version", procName, NULL);
1384     fscanf(fp, "Number of numa = %d\n\n", &n);
1385     if ((naa = numaaCreate(n)) == NULL)
1386         return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
1387 
1388     for (i = 0; i < n; i++) {
1389         fscanf(fp, "Numa[%d]:", &index);
1390         if ((na = numaReadStream(fp)) == NULL)
1391             return (NUMAA *)ERROR_PTR("na not made", procName, NULL);
1392         numaaAddNuma(naa, na, L_INSERT);
1393     }
1394 
1395     return naa;
1396 }
1397 
1398 
1399 /*!
1400  *  numaaWrite()
1401  *
1402  *      Input:  filename, naa
1403  *      Return: 0 if OK, 1 on error
1404  */
1405 l_int32
numaaWrite(const char * filename,NUMAA * naa)1406 numaaWrite(const char  *filename,
1407            NUMAA       *naa)
1408 {
1409 FILE  *fp;
1410 
1411     PROCNAME("numaaWrite");
1412 
1413     if (!filename)
1414         return ERROR_INT("filename not defined", procName, 1);
1415     if (!naa)
1416         return ERROR_INT("naa not defined", procName, 1);
1417 
1418     if ((fp = fopen(filename, "w")) == NULL)
1419         return ERROR_INT("stream not opened", procName, 1);
1420     if (numaaWriteStream(fp, naa))
1421         return ERROR_INT("naa not written to stream", procName, 1);
1422     fclose(fp);
1423 
1424     return 0;
1425 }
1426 
1427 
1428 /*!
1429  *  numaaWriteStream()
1430  *
1431  *      Input:  stream, naa
1432  *      Return: 0 if OK, 1 on error
1433  */
1434 l_int32
numaaWriteStream(FILE * fp,NUMAA * naa)1435 numaaWriteStream(FILE   *fp,
1436                  NUMAA  *naa)
1437 {
1438 l_int32  i, n;
1439 NUMA    *na;
1440 
1441     PROCNAME("numaaWriteStream");
1442 
1443     if (!fp)
1444         return ERROR_INT("stream not defined", procName, 1);
1445     if (!naa)
1446         return ERROR_INT("naa not defined", procName, 1);
1447 
1448     n = numaaGetCount(naa);
1449     fprintf(fp, "\nNumaa Version %d\n", NUMA_VERSION_NUMBER);
1450     fprintf(fp, "Number of numa = %d\n\n", n);
1451     for (i = 0; i < n; i++) {
1452         if ((na = numaaGetNuma(naa, i, L_CLONE)) == NULL)
1453             return ERROR_INT("na not found", procName, 1);
1454         fprintf(fp, "Numa[%d]:", i);
1455         numaWriteStream(fp, na);
1456         numaDestroy(&na);
1457     }
1458 
1459     return 0;
1460 }
1461 
1462 
1463 /*--------------------------------------------------------------------------*
1464  *                      Numa2d creation, destruction                        *
1465  *--------------------------------------------------------------------------*/
1466 /*!
1467  *  numa2dCreate()
1468  *
1469  *      Input:  nrows (of 2d array)
1470  *              ncols (of 2d array)
1471  *              initsize (initial size of each allocated numa)
1472  *      Return: numa2d, or null on error
1473  *
1474  *  Notes:
1475  *      (1) The numa2d holds a doubly-indexed array of numa.
1476  *      (2) The numa ptr array is initialized with all ptrs set to NULL.
1477  *      (3) The numas are created only when a number is to be stored
1478  *          at an index (i,j) for which a numa has not yet been made.
1479  */
1480 NUMA2D *
numa2dCreate(l_int32 nrows,l_int32 ncols,l_int32 initsize)1481 numa2dCreate(l_int32  nrows,
1482              l_int32  ncols,
1483              l_int32  initsize)
1484 {
1485 l_int32  i;
1486 NUMA2D  *na2d;
1487 
1488     PROCNAME("numa2dCreate");
1489 
1490     if (nrows <= 1 || ncols <= 1)
1491         return (NUMA2D *)ERROR_PTR("rows, cols not both >= 1", procName, NULL);
1492 
1493     if ((na2d = (NUMA2D *)CALLOC(1, sizeof(NUMA2D))) == NULL)
1494         return (NUMA2D *)ERROR_PTR("na2d not made", procName, NULL);
1495     na2d->nrows = nrows;
1496     na2d->ncols = ncols;
1497     na2d->initsize = initsize;
1498 
1499         /* Set up the 2D array */
1500     if ((na2d->numa = (NUMA ***)CALLOC(nrows, sizeof(NUMA **))) == NULL)
1501         return (NUMA2D *)ERROR_PTR("numa row array not made", procName, NULL);
1502     for (i = 0; i < nrows; i++) {
1503         if ((na2d->numa[i] = (NUMA **)CALLOC(ncols, sizeof(NUMA *))) == NULL)
1504             return (NUMA2D *)ERROR_PTR("numa cols not made", procName, NULL);
1505     }
1506 
1507     return na2d;
1508 }
1509 
1510 
1511 /*!
1512  *  numa2dDestroy()
1513  *
1514  *      Input:  &numa2d (<to be nulled if it exists>)
1515  *      Return: void
1516  */
1517 void
numa2dDestroy(NUMA2D ** pna2d)1518 numa2dDestroy(NUMA2D  **pna2d)
1519 {
1520 l_int32  i, j;
1521 NUMA2D  *na2d;
1522 
1523     PROCNAME("numa2dDestroy");
1524 
1525     if (pna2d == NULL) {
1526         L_WARNING("ptr address is NULL!", procName);
1527         return;
1528     }
1529 
1530     if ((na2d = *pna2d) == NULL)
1531         return;
1532 
1533     for (i = 0; i < na2d->nrows; i++) {
1534         for (j = 0; j < na2d->ncols; j++)
1535             numaDestroy(&na2d->numa[i][j]);
1536         FREE(na2d->numa[i]);
1537     }
1538     FREE(na2d->numa);
1539     FREE(na2d);
1540     *pna2d = NULL;
1541 
1542     return;
1543 }
1544 
1545 
1546 
1547 /*--------------------------------------------------------------------------*
1548  *                               Numa2d accessors                           *
1549  *--------------------------------------------------------------------------*/
1550 /*!
1551  *  numa2dAddNumber()
1552  *
1553  *      Input:  na2d
1554  *              row of 2d array
1555  *              col of 2d array
1556  *              val  (float or int to be added; stored as a float)
1557  *      Return: 0 if OK, 1 on error
1558  */
1559 l_int32
numa2dAddNumber(NUMA2D * na2d,l_int32 row,l_int32 col,l_float32 val)1560 numa2dAddNumber(NUMA2D    *na2d,
1561                 l_int32    row,
1562                 l_int32    col,
1563                 l_float32  val)
1564 {
1565 NUMA  *na;
1566 
1567     PROCNAME("numa2dAddNumber");
1568 
1569     if (!na2d)
1570         return ERROR_INT("na2d not defined", procName, 1);
1571     if (row < 0 || row >= na2d->nrows)
1572         return ERROR_INT("row out of bounds", procName, 1);
1573     if (col < 0 || col >= na2d->ncols)
1574         return ERROR_INT("col out of bounds", procName, 1);
1575 
1576     if ((na = na2d->numa[row][col]) == NULL) {
1577         na = numaCreate(na2d->initsize);
1578         na2d->numa[row][col] = na;
1579     }
1580     numaAddNumber(na, val);
1581     return 0;
1582 }
1583 
1584 
1585 /*!
1586  *  numa2dGetCount()
1587  *
1588  *      Input:  na2d
1589  *              row of 2d array
1590  *              col of 2d array
1591  *      Return: size of numa at [row][col], or 0 if the numa doesn't exist
1592  *              or on error
1593  */
1594 l_int32
numa2dGetCount(NUMA2D * na2d,l_int32 row,l_int32 col)1595 numa2dGetCount(NUMA2D  *na2d,
1596                l_int32  row,
1597                l_int32  col)
1598 {
1599 NUMA  *na;
1600 
1601     PROCNAME("numa2dGetCount");
1602 
1603     if (!na2d)
1604         return ERROR_INT("na2d not defined", procName, 0);
1605     if (row < 0 || row >= na2d->nrows)
1606         return ERROR_INT("row out of bounds", procName, 0);
1607     if (col < 0 || col >= na2d->ncols)
1608         return ERROR_INT("col out of bounds", procName, 0);
1609     if ((na = na2d->numa[row][col]) == NULL)
1610         return 0;
1611     else
1612         return na->n;
1613 }
1614 
1615 
1616 /*!
1617  *  numa2dGetNuma()
1618  *
1619  *      Input:  na2d
1620  *              row of 2d array
1621  *              col of 2d array
1622  *      Return: na (a clone of the numa if it exists) or null if it doesn't
1623  *
1624  *  Notes:
1625  *      (1) This does not give an error if the index is out of bounds.
1626  */
1627 NUMA *
numa2dGetNuma(NUMA2D * na2d,l_int32 row,l_int32 col)1628 numa2dGetNuma(NUMA2D     *na2d,
1629               l_int32     row,
1630               l_int32     col)
1631 {
1632 NUMA  *na;
1633 
1634     PROCNAME("numa2dGetNuma");
1635 
1636     if (!na2d)
1637         return (NUMA *)ERROR_PTR("na2d not defined", procName, NULL);
1638     if (row < 0 || row >= na2d->nrows || col < 0 || col >= na2d->ncols)
1639         return NULL;
1640     if ((na = na2d->numa[row][col]) == NULL)
1641         return NULL;
1642     return numaClone(na);
1643 }
1644 
1645 
1646 /*!
1647  *  numa2dGetFValue()
1648  *
1649  *      Input:  na2d
1650  *              row of 2d array
1651  *              col of 2d array
1652  *              index (into numa)
1653  *              &val (<return> float value)
1654  *      Return: 0 if OK, 1 on error
1655  */
1656 l_int32
numa2dGetFValue(NUMA2D * na2d,l_int32 row,l_int32 col,l_int32 index,l_float32 * pval)1657 numa2dGetFValue(NUMA2D     *na2d,
1658                 l_int32     row,
1659                 l_int32     col,
1660                 l_int32     index,
1661                 l_float32  *pval)
1662 {
1663 NUMA  *na;
1664 
1665     PROCNAME("numa2dGetFValue");
1666 
1667     if (!na2d)
1668         return ERROR_INT("na2d not defined", procName, 1);
1669     if (!pval)
1670         return ERROR_INT("&val not defined", procName, 1);
1671     *pval = 0.0;
1672 
1673     if (row < 0 || row >= na2d->nrows)
1674         return ERROR_INT("row out of bounds", procName, 1);
1675     if (col < 0 || col >= na2d->ncols)
1676         return ERROR_INT("col out of bounds", procName, 1);
1677     if ((na = na2d->numa[row][col]) == NULL)
1678         return ERROR_INT("numa does not exist", procName, 1);
1679 
1680     return numaGetFValue(na, index, pval);
1681 }
1682 
1683 
1684 /*!
1685  *  numa2dGetIValue()
1686  *
1687  *      Input:  na2d
1688  *              row of 2d array
1689  *              col of 2d array
1690  *              index (into numa)
1691  *              &val (<return> integer value)
1692  *      Return: 0 if OK, 1 on error
1693  */
1694 l_int32
numa2dGetIValue(NUMA2D * na2d,l_int32 row,l_int32 col,l_int32 index,l_int32 * pval)1695 numa2dGetIValue(NUMA2D   *na2d,
1696                 l_int32   row,
1697                 l_int32   col,
1698                 l_int32   index,
1699                 l_int32  *pval)
1700 {
1701 NUMA  *na;
1702 
1703     PROCNAME("numa2dGetIValue");
1704 
1705     if (!na2d)
1706         return ERROR_INT("na2d not defined", procName, 1);
1707     if (!pval)
1708         return ERROR_INT("&val not defined", procName, 1);
1709     *pval = 0;
1710 
1711     if (row < 0 || row >= na2d->nrows)
1712         return ERROR_INT("row out of bounds", procName, 1);
1713     if (col < 0 || col >= na2d->ncols)
1714         return ERROR_INT("col out of bounds", procName, 1);
1715     if ((na = na2d->numa[row][col]) == NULL)
1716         return ERROR_INT("numa does not exist", procName, 1);
1717 
1718     return numaGetIValue(na, index, pval);
1719 }
1720 
1721 
1722 /*--------------------------------------------------------------------------*
1723  *               Number array hash: Creation and destruction                *
1724  *--------------------------------------------------------------------------*/
1725 /*!
1726  *  numaHashCreate()
1727  *
1728  *      Input: nbuckets (the number of buckets in the hash table,
1729  *                       which should be prime.)
1730  *             initsize (initial size of each allocated numa; 0 for default)
1731  *      Return: ptr to new nahash, or null on error
1732  *
1733  *  Note: actual numa are created only as required by numaHashAdd()
1734  */
1735 NUMAHASH *
numaHashCreate(l_int32 nbuckets,l_int32 initsize)1736 numaHashCreate(l_int32  nbuckets,
1737                l_int32  initsize)
1738 {
1739 NUMAHASH  *nahash;
1740 
1741     PROCNAME("numaHashCreate");
1742 
1743     if (nbuckets <= 0)
1744         return (NUMAHASH *)ERROR_PTR("negative hash size", procName, NULL);
1745     if ((nahash = (NUMAHASH *)CALLOC(1, sizeof(NUMAHASH))) == NULL)
1746         return (NUMAHASH *)ERROR_PTR("nahash not made", procName, NULL);
1747     if ((nahash->numa = (NUMA **)CALLOC(nbuckets, sizeof(NUMA *))) == NULL) {
1748         FREE(nahash);
1749         return (NUMAHASH *)ERROR_PTR("numa ptr array not made", procName, NULL);
1750     }
1751 
1752     nahash->nbuckets = nbuckets;
1753     nahash->initsize = initsize;
1754     return nahash;
1755 }
1756 
1757 
1758 /*!
1759  *  numaHashDestroy()
1760  *
1761  *      Input:  &nahash (<to be nulled, if it exists>)
1762  *      Return: void
1763  */
1764 void
numaHashDestroy(NUMAHASH ** pnahash)1765 numaHashDestroy(NUMAHASH **pnahash)
1766 {
1767 NUMAHASH  *nahash;
1768 l_int32    i;
1769 
1770     PROCNAME("numaHashDestroy");
1771 
1772     if (pnahash == NULL) {
1773         L_WARNING("ptr address is NULL!", procName);
1774         return;
1775     }
1776 
1777     if ((nahash = *pnahash) == NULL)
1778         return;
1779 
1780     for (i = 0; i < nahash->nbuckets; i++)
1781         numaDestroy(&nahash->numa[i]);
1782     FREE(nahash->numa);
1783     FREE(nahash);
1784     *pnahash = NULL;
1785 }
1786 
1787 
1788 /*--------------------------------------------------------------------------*
1789  *               Number array hash: Add elements and return numas
1790  *--------------------------------------------------------------------------*/
1791 /*!
1792  *  numaHashGetNuma()
1793  *
1794  *      Input:  nahash
1795  *              key  (key to be hashed into a bucket number)
1796  *      Return: ptr to numa
1797  */
1798 NUMA *
numaHashGetNuma(NUMAHASH * nahash,l_uint32 key)1799 numaHashGetNuma(NUMAHASH  *nahash,
1800                 l_uint32   key)
1801 {
1802 l_int32  bucket;
1803 NUMA    *na;
1804 
1805     PROCNAME("numaHashGetNuma");
1806 
1807     if (!nahash)
1808         return (NUMA *)ERROR_PTR("nahash not defined", procName, NULL);
1809     bucket = key % nahash->nbuckets;
1810     na = nahash->numa[bucket];
1811     if (na)
1812         return numaClone(na);
1813     else
1814         return NULL;
1815 }
1816 
1817 /*!
1818  *  numaHashAdd()
1819  *
1820  *      Input:  nahash
1821  *              key  (key to be hashed into a bucket number)
1822  *              value  (float value to be appended to the specific numa)
1823  *      Return: 0 if OK; 1 on error
1824  */
1825 l_int32
numaHashAdd(NUMAHASH * nahash,l_uint32 key,l_float32 value)1826 numaHashAdd(NUMAHASH  *nahash,
1827             l_uint32   key,
1828             l_float32  value)
1829 {
1830 l_int32  bucket;
1831 NUMA    *na;
1832 
1833     PROCNAME("numaHashAdd");
1834 
1835     if (!nahash)
1836         return ERROR_INT("nahash not defined", procName, 1);
1837     if (key < 0)
1838         return ERROR_INT("key < 0", procName, 1);
1839     bucket = key % nahash->nbuckets;
1840     na = nahash->numa[bucket];
1841     if (!na) {
1842         if ((na = numaCreate(nahash->initsize)) == NULL)
1843             return ERROR_INT("na not made", procName, 1);
1844         nahash->numa[bucket] = na;
1845     }
1846     numaAddNumber(na, value);
1847     return 0;
1848 }
1849 
1850 
1851