• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *          the count field to a larger number (such as the alloc
727  *          size) BEFORE calling this function.
728  */
729 l_float32 *
numaGetFArray(NUMA * na,l_int32 copyflag)730 numaGetFArray(NUMA    *na,
731               l_int32  copyflag)
732 {
733 l_int32     i, n;
734 l_float32  *array;
735 
736     PROCNAME("numaGetFArray");
737 
738     if (!na)
739         return (l_float32 *)ERROR_PTR("na not defined", procName, NULL);
740 
741     if (copyflag == L_NOCOPY)
742         array = na->array;
743     else {  /* copyflag == L_COPY */
744         n = numaGetCount(na);
745         if ((array = (l_float32 *)CALLOC(n, sizeof(l_float32))) == NULL)
746             return (l_float32 *)ERROR_PTR("array not made", procName, NULL);
747         for (i = 0; i < n; i++)
748             array[i] = na->array[i];
749     }
750 
751     return array;
752 }
753 
754 
755 /*!
756  *  numaGetRefCount()
757  *
758  *      Input:  na
759  *      Return: refcount, or UNDEF on error
760  */
761 l_int32
numaGetRefcount(NUMA * na)762 numaGetRefcount(NUMA  *na)
763 {
764     PROCNAME("numaGetRefcount");
765 
766     if (!na)
767         return ERROR_INT("na not defined", procName, UNDEF);
768     return na->refcount;
769 }
770 
771 
772 /*!
773  *  numaChangeRefCount()
774  *
775  *      Input:  na
776  *              delta (change to be applied)
777  *      Return: 0 if OK, 1 on error
778  */
779 l_int32
numaChangeRefcount(NUMA * na,l_int32 delta)780 numaChangeRefcount(NUMA    *na,
781                    l_int32  delta)
782 {
783     PROCNAME("numaChangeRefcount");
784 
785     if (!na)
786         return ERROR_INT("na not defined", procName, 1);
787     na->refcount += delta;
788     return 0;
789 }
790 
791 
792 /*!
793  *  numaGetXParameters()
794  *
795  *      Input:  na
796  *              &startx (<optional return> startx)
797  *              &delx (<optional return> delx)
798  *      Return: 0 if OK, 1 on error
799  */
800 l_int32
numaGetXParameters(NUMA * na,l_float32 * pstartx,l_float32 * pdelx)801 numaGetXParameters(NUMA       *na,
802                    l_float32  *pstartx,
803                    l_float32  *pdelx)
804 {
805     PROCNAME("numaGetXParameters");
806 
807     if (!na)
808         return ERROR_INT("na not defined", procName, 1);
809 
810     if (pstartx) *pstartx = na->startx;
811     if (pdelx) *pdelx = na->delx;
812     return 0;
813 }
814 
815 
816 /*!
817  *  numaSetXParameters()
818  *
819  *      Input:  na
820  *              startx (x value corresponding to na[0])
821  *              delx (difference in x values for the situation where the
822  *                    elements of na correspond to the evaulation of a
823  *                    function at equal intervals of size @delx)
824  *      Return: 0 if OK, 1 on error
825  */
826 l_int32
numaSetXParameters(NUMA * na,l_float32 startx,l_float32 delx)827 numaSetXParameters(NUMA      *na,
828                    l_float32  startx,
829                    l_float32  delx)
830 {
831     PROCNAME("numaSetXParameters");
832 
833     if (!na)
834         return ERROR_INT("na not defined", procName, 1);
835 
836     na->startx = startx;
837     na->delx = delx;
838     return 0;
839 }
840 
841 
842 /*!
843  *  numaCopyXParameters()
844  *
845  *      Input:  nad (destination Numa)
846  *              nas (source Numa)
847  *      Return: 0 if OK, 1 on error
848  */
849 l_int32
numaCopyXParameters(NUMA * nad,NUMA * nas)850 numaCopyXParameters(NUMA  *nad,
851                     NUMA  *nas)
852 {
853 l_float32  start, binsize;
854 
855     PROCNAME("numaCopyXParameters");
856 
857     if (!nas || !nad)
858         return ERROR_INT("nas and nad not both defined", procName, 1);
859 
860     numaGetXParameters(nas, &start, &binsize);
861     numaSetXParameters(nad, start, binsize);
862     return 0;
863 }
864 
865 
866 /*----------------------------------------------------------------------*
867  *                       Serialize numa for I/O                         *
868  *----------------------------------------------------------------------*/
869 /*!
870  *  numaRead()
871  *
872  *      Input:  filename
873  *      Return: na, or null on error
874  */
875 NUMA *
numaRead(const char * filename)876 numaRead(const char  *filename)
877 {
878 FILE  *fp;
879 NUMA  *na;
880 
881     PROCNAME("numaRead");
882 
883     if (!filename)
884         return (NUMA *)ERROR_PTR("filename not defined", procName, NULL);
885 
886     if ((fp = fopenReadStream(filename)) == NULL)
887         return (NUMA *)ERROR_PTR("stream not opened", procName, NULL);
888 
889     if ((na = numaReadStream(fp)) == NULL) {
890         fclose(fp);
891         return (NUMA *)ERROR_PTR("na not read", procName, NULL);
892     }
893 
894     fclose(fp);
895     return na;
896 }
897 
898 
899 /*!
900  *  numaReadStream()
901  *
902  *      Input:  stream
903  *      Return: numa, or null on error
904  */
905 NUMA *
numaReadStream(FILE * fp)906 numaReadStream(FILE  *fp)
907 {
908 l_int32    i, n, index, ret, version;
909 l_float32  val, startx, delx;
910 NUMA      *na;
911 
912     PROCNAME("numaReadStream");
913 
914     if (!fp)
915         return (NUMA *)ERROR_PTR("stream not defined", procName, NULL);
916 
917     ret = fscanf(fp, "\nNuma Version %d\n", &version);
918     if (ret != 1)
919         return (NUMA *)ERROR_PTR("not a numa file", procName, NULL);
920     if (version != NUMA_VERSION_NUMBER)
921         return (NUMA *)ERROR_PTR("invalid numa version", procName, NULL);
922     fscanf(fp, "Number of numbers = %d\n", &n);
923 
924     if ((na = numaCreate(n)) == NULL)
925         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
926 
927     for (i = 0; i < n; i++) {
928         if ((fscanf(fp, "  [%d] = %f\n", &index, &val)) != 2)
929             return (NUMA *)ERROR_PTR("bad input data", procName, NULL);
930         numaAddNumber(na, val);
931     }
932 
933         /* Optional data */
934     if ((fscanf(fp, "startx = %f, delx = %f\n", &startx, &delx)) == 2)
935         numaSetXParameters(na, startx, delx);
936 
937     return na;
938 }
939 
940 
941 /*!
942  *  numaWrite()
943  *
944  *      Input:  filename, na
945  *      Return: 0 if OK, 1 on error
946  */
947 l_int32
numaWrite(const char * filename,NUMA * na)948 numaWrite(const char  *filename,
949           NUMA        *na)
950 {
951 FILE  *fp;
952 
953     PROCNAME("numaWrite");
954 
955     if (!filename)
956         return ERROR_INT("filename not defined", procName, 1);
957     if (!na)
958         return ERROR_INT("na not defined", procName, 1);
959 
960     if ((fp = fopen(filename, "w")) == NULL)
961         return ERROR_INT("stream not opened", procName, 1);
962     if (numaWriteStream(fp, na))
963         return ERROR_INT("na not written to stream", procName, 1);
964     fclose(fp);
965 
966     return 0;
967 }
968 
969 
970 /*!
971  *  numaWriteStream()
972  *
973  *      Input:  stream, na
974  *      Return: 0 if OK, 1 on error
975  */
976 l_int32
numaWriteStream(FILE * fp,NUMA * na)977 numaWriteStream(FILE  *fp,
978                 NUMA  *na)
979 {
980 l_int32    i, n;
981 l_float32  startx, delx;
982 
983     PROCNAME("numaWriteStream");
984 
985     if (!fp)
986         return ERROR_INT("stream not defined", procName, 1);
987     if (!na)
988         return ERROR_INT("na not defined", procName, 1);
989 
990     n = numaGetCount(na);
991     fprintf(fp, "\nNuma Version %d\n", NUMA_VERSION_NUMBER);
992     fprintf(fp, "Number of numbers = %d\n", n);
993     for (i = 0; i < n; i++)
994         fprintf(fp, "  [%d] = %f\n", i, na->array[i]);
995     fprintf(fp, "\n");
996 
997         /* Optional data */
998     numaGetXParameters(na, &startx, &delx);
999     if (startx != 0.0 || delx != 1.0)
1000         fprintf(fp, "startx = %f, delx = %f\n", startx, delx);
1001 
1002     return 0;
1003 }
1004 
1005 
1006 
1007 /*--------------------------------------------------------------------------*
1008  *                     Numaa creation, destruction                          *
1009  *--------------------------------------------------------------------------*/
1010 /*!
1011  *  numaaCreate()
1012  *
1013  *      Input:  size of numa ptr array to be alloc'd (0 for default)
1014  *      Return: naa, or null on error
1015  *
1016  */
1017 NUMAA *
numaaCreate(l_int32 n)1018 numaaCreate(l_int32  n)
1019 {
1020 NUMAA  *naa;
1021 
1022     PROCNAME("numaaCreate");
1023 
1024     if (n <= 0)
1025         n = INITIAL_PTR_ARRAYSIZE;
1026 
1027     if ((naa = (NUMAA *)CALLOC(1, sizeof(NUMAA))) == NULL)
1028         return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
1029     if ((naa->numa = (NUMA **)CALLOC(n, sizeof(NUMA *))) == NULL)
1030         return (NUMAA *)ERROR_PTR("numa ptr array not made", procName, NULL);
1031 
1032     naa->nalloc = n;
1033     naa->n = 0;
1034 
1035     return naa;
1036 }
1037 
1038 
1039 /*!
1040  *  numaaDestroy()
1041  *
1042  *      Input: &numaa <to be nulled if it exists>
1043  *      Return: void
1044  */
1045 void
numaaDestroy(NUMAA ** pnaa)1046 numaaDestroy(NUMAA  **pnaa)
1047 {
1048 l_int32  i;
1049 NUMAA   *naa;
1050 
1051     PROCNAME("numaaDestroy");
1052 
1053     if (pnaa == NULL) {
1054         L_WARNING("ptr address is NULL!", procName);
1055         return;
1056     }
1057 
1058     if ((naa = *pnaa) == NULL)
1059         return;
1060 
1061     for (i = 0; i < naa->n; i++)
1062         numaDestroy(&naa->numa[i]);
1063     FREE(naa->numa);
1064     FREE(naa);
1065     *pnaa = NULL;
1066 
1067     return;
1068 }
1069 
1070 
1071 
1072 /*--------------------------------------------------------------------------*
1073  *                              Add Numa to Numaa                           *
1074  *--------------------------------------------------------------------------*/
1075 /*!
1076  *  numaaAddNuma()
1077  *
1078  *      Input:  naa
1079  *              na   (to be added)
1080  *              copyflag  (L_INSERT, L_COPY, L_CLONE)
1081  *      Return: 0 if OK, 1 on error
1082  */
1083 l_int32
numaaAddNuma(NUMAA * naa,NUMA * na,l_int32 copyflag)1084 numaaAddNuma(NUMAA   *naa,
1085              NUMA    *na,
1086              l_int32  copyflag)
1087 {
1088 l_int32  n;
1089 NUMA    *nac;
1090 
1091     PROCNAME("numaaAddNuma");
1092 
1093     if (!naa)
1094         return ERROR_INT("naa not defined", procName, 1);
1095     if (!na)
1096         return ERROR_INT("na not defined", procName, 1);
1097 
1098     if (copyflag == L_INSERT)
1099         nac = na;
1100     else if (copyflag == L_COPY) {
1101         if ((nac = numaCopy(na)) == NULL)
1102             return ERROR_INT("nac not made", procName, 1);
1103     }
1104     else if (copyflag == L_CLONE)
1105         nac = numaClone(na);
1106     else
1107         return ERROR_INT("invalid copyflag", procName, 1);
1108 
1109     n = numaaGetCount(naa);
1110     if (n >= naa->nalloc)
1111         numaaExtendArray(naa);
1112     naa->numa[n] = nac;
1113     naa->n++;
1114     return 0;
1115 }
1116 
1117 
1118 /*!
1119  *  numaaExtendArray()
1120  *
1121  *      Input:  naa
1122  *      Return: 0 if OK, 1 on error
1123  */
1124 l_int32
numaaExtendArray(NUMAA * naa)1125 numaaExtendArray(NUMAA  *naa)
1126 {
1127     PROCNAME("numaaExtendArray");
1128 
1129     if (!naa)
1130         return ERROR_INT("naa not defined", procName, 1);
1131 
1132     if ((naa->numa = (NUMA **)reallocNew((void **)&naa->numa,
1133                               sizeof(NUMA *) * naa->nalloc,
1134                               2 * sizeof(NUMA *) * naa->nalloc)) == NULL)
1135             return ERROR_INT("new ptr array not returned", procName, 1);
1136 
1137     naa->nalloc *= 2;
1138     return 0;
1139 }
1140 
1141 
1142 /*----------------------------------------------------------------------*
1143  *                           Numaa accessors                            *
1144  *----------------------------------------------------------------------*/
1145 /*!
1146  *  numaaGetCount()
1147  *
1148  *      Input:  naa
1149  *      Return: count (number of numa), or 0 if no numa or on error
1150  */
1151 l_int32
numaaGetCount(NUMAA * naa)1152 numaaGetCount(NUMAA  *naa)
1153 {
1154     PROCNAME("numaaGetCount");
1155 
1156     if (!naa)
1157         return ERROR_INT("naa not defined", procName, 0);
1158     return naa->n;
1159 }
1160 
1161 
1162 /*!
1163  *  numaaGetNumberCount()
1164  *
1165  *      Input:  naa
1166  *      Return: count (number of numbers), or 0 if no numbers or on error
1167  */
1168 l_int32
numaaGetNumberCount(NUMAA * naa)1169 numaaGetNumberCount(NUMAA  *naa)
1170 {
1171 NUMA    *na;
1172 l_int32  n, sum, i;
1173 
1174     PROCNAME("numaaGetNumberCount");
1175 
1176     if (!naa)
1177         return ERROR_INT("naa not defined", procName, 0);
1178 
1179     n = numaaGetCount(naa);
1180     for (sum = 0, i = 0; i < n; i++) {
1181         na = numaaGetNuma(naa, i, L_CLONE);
1182         sum += numaGetCount(na);
1183         numaDestroy(&na);
1184     }
1185 
1186     return sum;
1187 }
1188 
1189 
1190 /*!
1191  *  numaaGetPtrArray()
1192  *
1193  *      Input:  naa
1194  *      Return: the internal array of ptrs to Numa, or null on error
1195  *
1196  *  Notes:
1197  *      (1) This function is convenient for doing direct manipulation on
1198  *          a fixed size array of Numas.  To do this, it sets the count
1199  *          to the full size of the allocated array of Numa ptrs.
1200  *          The originating Numaa owns this array: DO NOT free it!
1201  *      (2) Intended usage:
1202  *            Numaa *naa = numaaCreate(n);
1203  *            Numa **array = numaaGetPtrArray(naa);
1204  *             ...  [manipulate Numas directly on the array]
1205  *            numaaDestroy(&naa);
1206  *      (3) Cautions:
1207  *           - Do not free this array; it is owned by tne Numaa.
1208  *           - Do not call any functions on the Numaa, other than
1209  *             numaaDestroy() when you're finished with the array.
1210  *             Adding a Numa will force a resize, destroying the ptr array.
1211  *           - Do not address the array outside its allocated size.
1212  *             With the bare array, there are no protections.  If the
1213  *             allocated size is n, array[n] is an error.
1214  */
1215 NUMA **
numaaGetPtrArray(NUMAA * naa)1216 numaaGetPtrArray(NUMAA  *naa)
1217 {
1218     PROCNAME("numaaGetPtrArray");
1219 
1220     if (!naa)
1221         return (NUMA **)ERROR_PTR("naa not defined", procName, NULL);
1222 
1223     naa->n = naa->nalloc;
1224     return naa->numa;
1225 }
1226 
1227 
1228 /*!
1229  *  numaaGetNuma()
1230  *
1231  *      Input:  naa
1232  *              index  (to the index-th numa)
1233  *              accessflag   (L_COPY or L_CLONE)
1234  *      Return: numa, or null on error
1235  */
1236 NUMA *
numaaGetNuma(NUMAA * naa,l_int32 index,l_int32 accessflag)1237 numaaGetNuma(NUMAA   *naa,
1238              l_int32  index,
1239              l_int32  accessflag)
1240 {
1241     PROCNAME("numaaGetNuma");
1242 
1243     if (!naa)
1244         return (NUMA *)ERROR_PTR("naa not defined", procName, NULL);
1245     if (index < 0 || index >= naa->n)
1246         return (NUMA *)ERROR_PTR("index not valid", procName, NULL);
1247 
1248     if (accessflag == L_COPY)
1249         return numaCopy(naa->numa[index]);
1250     else if (accessflag == L_CLONE)
1251         return numaClone(naa->numa[index]);
1252     else
1253         return (NUMA *)ERROR_PTR("invalid accessflag", procName, NULL);
1254 }
1255 
1256 
1257 /*!
1258  *  numaaReplaceNuma()
1259  *
1260  *      Input:  naa
1261  *              index  (to the index-th numa)
1262  *              numa (insert and replace any existing one)
1263  *      Return: 0 if OK, 1 on error
1264  *
1265  *  Notes:
1266  *      (1) Any existing numa is destroyed, and the input one
1267  *          is inserted in its place.
1268  *      (2) If the index is invalid, return 1 (error)
1269  */
1270 l_int32
numaaReplaceNuma(NUMAA * naa,l_int32 index,NUMA * na)1271 numaaReplaceNuma(NUMAA   *naa,
1272                  l_int32  index,
1273                  NUMA    *na)
1274 {
1275 l_int32  n;
1276 
1277     PROCNAME("numaaReplaceNuma");
1278 
1279     if (!naa)
1280         return ERROR_INT("naa not defined", procName, 1);
1281     if (!na)
1282         return ERROR_INT("na not defined", procName, 1);
1283     n = numaaGetCount(naa);
1284     if (index < 0 || index >= n)
1285         return ERROR_INT("index not valid", procName, 1);
1286 
1287     numaDestroy(&naa->numa[index]);
1288     naa->numa[index] = na;
1289     return 0;
1290 }
1291 
1292 
1293 /*!
1294  *  numaaAddNumber()
1295  *
1296  *      Input:  naa
1297  *              index (of numa within numaa)
1298  *              val  (float or int to be added; stored as a float)
1299  *      Return: 0 if OK, 1 on error
1300  *
1301  *  Notes:
1302  *      (1) Adds to an existing numa only.
1303  */
1304 l_int32
numaaAddNumber(NUMAA * naa,l_int32 index,l_float32 val)1305 numaaAddNumber(NUMAA     *naa,
1306                l_int32    index,
1307                l_float32  val)
1308 {
1309 l_int32  n;
1310 NUMA    *na;
1311 
1312     PROCNAME("numaaAddNumber");
1313 
1314     if (!naa)
1315         return ERROR_INT("naa not defined", procName, 1);
1316     n = numaaGetCount(naa);
1317     if (index < 0 || index >= n)
1318         return ERROR_INT("invalid index in naa", procName, 1);
1319 
1320     na = numaaGetNuma(naa, index, L_CLONE);
1321     numaAddNumber(na, val);
1322     numaDestroy(&na);
1323     return 0;
1324 }
1325 
1326 
1327 /*----------------------------------------------------------------------*
1328  *                      Serialize numaa for I/O                         *
1329  *----------------------------------------------------------------------*/
1330 /*!
1331  *  numaaRead()
1332  *
1333  *      Input:  filename
1334  *      Return: naa, or null on error
1335  */
1336 NUMAA *
numaaRead(const char * filename)1337 numaaRead(const char  *filename)
1338 {
1339 FILE   *fp;
1340 NUMAA  *naa;
1341 
1342     PROCNAME("numaaRead");
1343 
1344     if (!filename)
1345         return (NUMAA *)ERROR_PTR("filename not defined", procName, NULL);
1346 
1347     if ((fp = fopenReadStream(filename)) == NULL)
1348         return (NUMAA *)ERROR_PTR("stream not opened", procName, NULL);
1349 
1350     if ((naa = numaaReadStream(fp)) == NULL) {
1351         fclose(fp);
1352         return (NUMAA *)ERROR_PTR("naa not read", procName, NULL);
1353     }
1354 
1355     fclose(fp);
1356     return naa;
1357 }
1358 
1359 
1360 /*!
1361  *  numaaReadStream()
1362  *
1363  *      Input:  stream
1364  *      Return: naa, or null on error
1365  */
1366 NUMAA *
numaaReadStream(FILE * fp)1367 numaaReadStream(FILE  *fp)
1368 {
1369 l_int32    i, n, index, ret, version;
1370 NUMA      *na;
1371 NUMAA     *naa;
1372 
1373     PROCNAME("numaaReadStream");
1374 
1375     if (!fp)
1376         return (NUMAA *)ERROR_PTR("stream not defined", procName, NULL);
1377 
1378     ret = fscanf(fp, "\nNumaa Version %d\n", &version);
1379     if (ret != 1)
1380         return (NUMAA *)ERROR_PTR("not a numa file", procName, NULL);
1381     if (version != NUMA_VERSION_NUMBER)
1382         return (NUMAA *)ERROR_PTR("invalid numaa version", procName, NULL);
1383     fscanf(fp, "Number of numa = %d\n\n", &n);
1384     if ((naa = numaaCreate(n)) == NULL)
1385         return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
1386 
1387     for (i = 0; i < n; i++) {
1388         fscanf(fp, "Numa[%d]:", &index);
1389         if ((na = numaReadStream(fp)) == NULL)
1390             return (NUMAA *)ERROR_PTR("na not made", procName, NULL);
1391         numaaAddNuma(naa, na, L_INSERT);
1392     }
1393 
1394     return naa;
1395 }
1396 
1397 
1398 /*!
1399  *  numaaWrite()
1400  *
1401  *      Input:  filename, naa
1402  *      Return: 0 if OK, 1 on error
1403  */
1404 l_int32
numaaWrite(const char * filename,NUMAA * naa)1405 numaaWrite(const char  *filename,
1406            NUMAA       *naa)
1407 {
1408 FILE  *fp;
1409 
1410     PROCNAME("numaaWrite");
1411 
1412     if (!filename)
1413         return ERROR_INT("filename not defined", procName, 1);
1414     if (!naa)
1415         return ERROR_INT("naa not defined", procName, 1);
1416 
1417     if ((fp = fopen(filename, "w")) == NULL)
1418         return ERROR_INT("stream not opened", procName, 1);
1419     if (numaaWriteStream(fp, naa))
1420         return ERROR_INT("naa not written to stream", procName, 1);
1421     fclose(fp);
1422 
1423     return 0;
1424 }
1425 
1426 
1427 /*!
1428  *  numaaWriteStream()
1429  *
1430  *      Input:  stream, naa
1431  *      Return: 0 if OK, 1 on error
1432  */
1433 l_int32
numaaWriteStream(FILE * fp,NUMAA * naa)1434 numaaWriteStream(FILE   *fp,
1435                  NUMAA  *naa)
1436 {
1437 l_int32  i, n;
1438 NUMA    *na;
1439 
1440     PROCNAME("numaaWriteStream");
1441 
1442     if (!fp)
1443         return ERROR_INT("stream not defined", procName, 1);
1444     if (!naa)
1445         return ERROR_INT("naa not defined", procName, 1);
1446 
1447     n = numaaGetCount(naa);
1448     fprintf(fp, "\nNumaa Version %d\n", NUMA_VERSION_NUMBER);
1449     fprintf(fp, "Number of numa = %d\n\n", n);
1450     for (i = 0; i < n; i++) {
1451         if ((na = numaaGetNuma(naa, i, L_CLONE)) == NULL)
1452             return ERROR_INT("na not found", procName, 1);
1453         fprintf(fp, "Numa[%d]:", i);
1454         numaWriteStream(fp, na);
1455         numaDestroy(&na);
1456     }
1457 
1458     return 0;
1459 }
1460 
1461 
1462 /*--------------------------------------------------------------------------*
1463  *                      Numa2d creation, destruction                        *
1464  *--------------------------------------------------------------------------*/
1465 /*!
1466  *  numa2dCreate()
1467  *
1468  *      Input:  nrows (of 2d array)
1469  *              ncols (of 2d array)
1470  *              initsize (initial size of each allocated numa)
1471  *      Return: numa2d, or null on error
1472  *
1473  *  Notes:
1474  *      (1) The numa2d holds a doubly-indexed array of numa.
1475  *      (2) The numa ptr array is initialized with all ptrs set to NULL.
1476  *      (3) The numas are created only when a number is to be stored
1477  *          at an index (i,j) for which a numa has not yet been made.
1478  */
1479 NUMA2D *
numa2dCreate(l_int32 nrows,l_int32 ncols,l_int32 initsize)1480 numa2dCreate(l_int32  nrows,
1481              l_int32  ncols,
1482              l_int32  initsize)
1483 {
1484 l_int32  i;
1485 NUMA2D  *na2d;
1486 
1487     PROCNAME("numa2dCreate");
1488 
1489     if (nrows <= 1 || ncols <= 1)
1490         return (NUMA2D *)ERROR_PTR("rows, cols not both >= 1", procName, NULL);
1491 
1492     if ((na2d = (NUMA2D *)CALLOC(1, sizeof(NUMA2D))) == NULL)
1493         return (NUMA2D *)ERROR_PTR("na2d not made", procName, NULL);
1494     na2d->nrows = nrows;
1495     na2d->ncols = ncols;
1496     na2d->initsize = initsize;
1497 
1498         /* Set up the 2D array */
1499     if ((na2d->numa = (NUMA ***)CALLOC(nrows, sizeof(NUMA **))) == NULL)
1500         return (NUMA2D *)ERROR_PTR("numa row array not made", procName, NULL);
1501     for (i = 0; i < nrows; i++) {
1502         if ((na2d->numa[i] = (NUMA **)CALLOC(ncols, sizeof(NUMA *))) == NULL)
1503             return (NUMA2D *)ERROR_PTR("numa cols not made", procName, NULL);
1504     }
1505 
1506     return na2d;
1507 }
1508 
1509 
1510 /*!
1511  *  numa2dDestroy()
1512  *
1513  *      Input:  &numa2d (<to be nulled if it exists>)
1514  *      Return: void
1515  */
1516 void
numa2dDestroy(NUMA2D ** pna2d)1517 numa2dDestroy(NUMA2D  **pna2d)
1518 {
1519 l_int32  i, j;
1520 NUMA2D  *na2d;
1521 
1522     PROCNAME("numa2dDestroy");
1523 
1524     if (pna2d == NULL) {
1525         L_WARNING("ptr address is NULL!", procName);
1526         return;
1527     }
1528 
1529     if ((na2d = *pna2d) == NULL)
1530         return;
1531 
1532     for (i = 0; i < na2d->nrows; i++) {
1533         for (j = 0; j < na2d->ncols; j++)
1534             numaDestroy(&na2d->numa[i][j]);
1535         FREE(na2d->numa[i]);
1536     }
1537     FREE(na2d->numa);
1538     FREE(na2d);
1539     *pna2d = NULL;
1540 
1541     return;
1542 }
1543 
1544 
1545 
1546 /*--------------------------------------------------------------------------*
1547  *                               Numa2d accessors                           *
1548  *--------------------------------------------------------------------------*/
1549 /*!
1550  *  numa2dAddNumber()
1551  *
1552  *      Input:  na2d
1553  *              row of 2d array
1554  *              col of 2d array
1555  *              val  (float or int to be added; stored as a float)
1556  *      Return: 0 if OK, 1 on error
1557  */
1558 l_int32
numa2dAddNumber(NUMA2D * na2d,l_int32 row,l_int32 col,l_float32 val)1559 numa2dAddNumber(NUMA2D    *na2d,
1560                 l_int32    row,
1561                 l_int32    col,
1562                 l_float32  val)
1563 {
1564 NUMA  *na;
1565 
1566     PROCNAME("numa2dAddNumber");
1567 
1568     if (!na2d)
1569         return ERROR_INT("na2d not defined", procName, 1);
1570     if (row < 0 || row >= na2d->nrows)
1571         return ERROR_INT("row out of bounds", procName, 1);
1572     if (col < 0 || col >= na2d->ncols)
1573         return ERROR_INT("col out of bounds", procName, 1);
1574 
1575     if ((na = na2d->numa[row][col]) == NULL) {
1576         na = numaCreate(na2d->initsize);
1577         na2d->numa[row][col] = na;
1578     }
1579     numaAddNumber(na, val);
1580     return 0;
1581 }
1582 
1583 
1584 /*!
1585  *  numa2dGetCount()
1586  *
1587  *      Input:  na2d
1588  *              row of 2d array
1589  *              col of 2d array
1590  *      Return: size of numa at [row][col], or 0 if the numa doesn't exist
1591  *              or on error
1592  */
1593 l_int32
numa2dGetCount(NUMA2D * na2d,l_int32 row,l_int32 col)1594 numa2dGetCount(NUMA2D  *na2d,
1595                l_int32  row,
1596                l_int32  col)
1597 {
1598 NUMA  *na;
1599 
1600     PROCNAME("numa2dGetCount");
1601 
1602     if (!na2d)
1603         return ERROR_INT("na2d not defined", procName, 0);
1604     if (row < 0 || row >= na2d->nrows)
1605         return ERROR_INT("row out of bounds", procName, 0);
1606     if (col < 0 || col >= na2d->ncols)
1607         return ERROR_INT("col out of bounds", procName, 0);
1608     if ((na = na2d->numa[row][col]) == NULL)
1609         return 0;
1610     else
1611         return na->n;
1612 }
1613 
1614 
1615 /*!
1616  *  numa2dGetNuma()
1617  *
1618  *      Input:  na2d
1619  *              row of 2d array
1620  *              col of 2d array
1621  *      Return: na (a clone of the numa if it exists) or null if it doesn't
1622  *
1623  *  Notes:
1624  *      (1) This does not give an error if the index is out of bounds.
1625  */
1626 NUMA *
numa2dGetNuma(NUMA2D * na2d,l_int32 row,l_int32 col)1627 numa2dGetNuma(NUMA2D     *na2d,
1628               l_int32     row,
1629               l_int32     col)
1630 {
1631 NUMA  *na;
1632 
1633     PROCNAME("numa2dGetNuma");
1634 
1635     if (!na2d)
1636         return (NUMA *)ERROR_PTR("na2d not defined", procName, NULL);
1637     if (row < 0 || row >= na2d->nrows || col < 0 || col >= na2d->ncols)
1638         return NULL;
1639     if ((na = na2d->numa[row][col]) == NULL)
1640         return NULL;
1641     return numaClone(na);
1642 }
1643 
1644 
1645 /*!
1646  *  numa2dGetFValue()
1647  *
1648  *      Input:  na2d
1649  *              row of 2d array
1650  *              col of 2d array
1651  *              index (into numa)
1652  *              &val (<return> float value)
1653  *      Return: 0 if OK, 1 on error
1654  */
1655 l_int32
numa2dGetFValue(NUMA2D * na2d,l_int32 row,l_int32 col,l_int32 index,l_float32 * pval)1656 numa2dGetFValue(NUMA2D     *na2d,
1657                 l_int32     row,
1658                 l_int32     col,
1659                 l_int32     index,
1660                 l_float32  *pval)
1661 {
1662 NUMA  *na;
1663 
1664     PROCNAME("numa2dGetFValue");
1665 
1666     if (!na2d)
1667         return ERROR_INT("na2d not defined", procName, 1);
1668     if (!pval)
1669         return ERROR_INT("&val not defined", procName, 1);
1670     *pval = 0.0;
1671 
1672     if (row < 0 || row >= na2d->nrows)
1673         return ERROR_INT("row out of bounds", procName, 1);
1674     if (col < 0 || col >= na2d->ncols)
1675         return ERROR_INT("col out of bounds", procName, 1);
1676     if ((na = na2d->numa[row][col]) == NULL)
1677         return ERROR_INT("numa does not exist", procName, 1);
1678 
1679     return numaGetFValue(na, index, pval);
1680 }
1681 
1682 
1683 /*!
1684  *  numa2dGetIValue()
1685  *
1686  *      Input:  na2d
1687  *              row of 2d array
1688  *              col of 2d array
1689  *              index (into numa)
1690  *              &val (<return> integer value)
1691  *      Return: 0 if OK, 1 on error
1692  */
1693 l_int32
numa2dGetIValue(NUMA2D * na2d,l_int32 row,l_int32 col,l_int32 index,l_int32 * pval)1694 numa2dGetIValue(NUMA2D   *na2d,
1695                 l_int32   row,
1696                 l_int32   col,
1697                 l_int32   index,
1698                 l_int32  *pval)
1699 {
1700 NUMA  *na;
1701 
1702     PROCNAME("numa2dGetIValue");
1703 
1704     if (!na2d)
1705         return ERROR_INT("na2d not defined", procName, 1);
1706     if (!pval)
1707         return ERROR_INT("&val not defined", procName, 1);
1708     *pval = 0;
1709 
1710     if (row < 0 || row >= na2d->nrows)
1711         return ERROR_INT("row out of bounds", procName, 1);
1712     if (col < 0 || col >= na2d->ncols)
1713         return ERROR_INT("col out of bounds", procName, 1);
1714     if ((na = na2d->numa[row][col]) == NULL)
1715         return ERROR_INT("numa does not exist", procName, 1);
1716 
1717     return numaGetIValue(na, index, pval);
1718 }
1719 
1720 
1721 /*--------------------------------------------------------------------------*
1722  *               Number array hash: Creation and destruction                *
1723  *--------------------------------------------------------------------------*/
1724 /*!
1725  *  numaHashCreate()
1726  *
1727  *      Input: nbuckets (the number of buckets in the hash table,
1728  *                       which should be prime.)
1729  *             initsize (initial size of each allocated numa; 0 for default)
1730  *      Return: ptr to new nahash, or null on error
1731  *
1732  *  Note: actual numa are created only as required by numaHashAdd()
1733  */
1734 NUMAHASH *
numaHashCreate(l_int32 nbuckets,l_int32 initsize)1735 numaHashCreate(l_int32  nbuckets,
1736                l_int32  initsize)
1737 {
1738 NUMAHASH  *nahash;
1739 
1740     PROCNAME("numaHashCreate");
1741 
1742     if (nbuckets <= 0)
1743         return (NUMAHASH *)ERROR_PTR("negative hash size", procName, NULL);
1744     if ((nahash = (NUMAHASH *)CALLOC(1, sizeof(NUMAHASH))) == NULL)
1745         return (NUMAHASH *)ERROR_PTR("nahash not made", procName, NULL);
1746     if ((nahash->numa = (NUMA **)CALLOC(nbuckets, sizeof(NUMA *))) == NULL) {
1747         FREE(nahash);
1748         return (NUMAHASH *)ERROR_PTR("numa ptr array not made", procName, NULL);
1749     }
1750 
1751     nahash->nbuckets = nbuckets;
1752     nahash->initsize = initsize;
1753     return nahash;
1754 }
1755 
1756 
1757 /*!
1758  *  numaHashDestroy()
1759  *
1760  *      Input:  &nahash (<to be nulled, if it exists>)
1761  *      Return: void
1762  */
1763 void
numaHashDestroy(NUMAHASH ** pnahash)1764 numaHashDestroy(NUMAHASH **pnahash)
1765 {
1766 NUMAHASH  *nahash;
1767 l_int32    i;
1768 
1769     PROCNAME("numaHashDestroy");
1770 
1771     if (pnahash == NULL) {
1772         L_WARNING("ptr address is NULL!", procName);
1773         return;
1774     }
1775 
1776     if ((nahash = *pnahash) == NULL)
1777         return;
1778 
1779     for (i = 0; i < nahash->nbuckets; i++)
1780         numaDestroy(&nahash->numa[i]);
1781     FREE(nahash->numa);
1782     FREE(nahash);
1783     *pnahash = NULL;
1784 }
1785 
1786 
1787 /*--------------------------------------------------------------------------*
1788  *               Number array hash: Add elements and return numas
1789  *--------------------------------------------------------------------------*/
1790 /*!
1791  *  numaHashGetNuma()
1792  *
1793  *      Input:  nahash
1794  *              key  (key to be hashed into a bucket number)
1795  *      Return: ptr to numa
1796  */
1797 NUMA *
numaHashGetNuma(NUMAHASH * nahash,l_uint32 key)1798 numaHashGetNuma(NUMAHASH  *nahash,
1799                 l_uint32   key)
1800 {
1801 l_int32  bucket;
1802 NUMA    *na;
1803 
1804     PROCNAME("numaHashGetNuma");
1805 
1806     if (!nahash)
1807         return (NUMA *)ERROR_PTR("nahash not defined", procName, NULL);
1808     bucket = key % nahash->nbuckets;
1809     na = nahash->numa[bucket];
1810     if (na)
1811         return numaClone(na);
1812     else
1813         return NULL;
1814 }
1815 
1816 /*!
1817  *  numaHashAdd()
1818  *
1819  *      Input:  nahash
1820  *              key  (key to be hashed into a bucket number)
1821  *              value  (float value to be appended to the specific numa)
1822  *      Return: 0 if OK; 1 on error
1823  */
1824 l_int32
numaHashAdd(NUMAHASH * nahash,l_uint32 key,l_float32 value)1825 numaHashAdd(NUMAHASH  *nahash,
1826             l_uint32   key,
1827             l_float32  value)
1828 {
1829 l_int32  bucket;
1830 NUMA    *na;
1831 
1832     PROCNAME("numaHashAdd");
1833 
1834     if (!nahash)
1835         return ERROR_INT("nahash not defined", procName, 1);
1836     if (key < 0)
1837         return ERROR_INT("key < 0", procName, 1);
1838     bucket = key % nahash->nbuckets;
1839     na = nahash->numa[bucket];
1840     if (!na) {
1841         if ((na = numaCreate(nahash->initsize)) == NULL)
1842             return ERROR_INT("na not made", procName, 1);
1843         nahash->numa[bucket] = na;
1844     }
1845     numaAddNumber(na, value);
1846     return 0;
1847 }
1848 
1849 
1850