Coverage Report

Created: 2024-06-18 06:05

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