blob: 70a00bc786d222e8219e62b3636419700f18eaad [file] [log] [blame]
/*====================================================================*
- Copyright (C) 2001 Leptonica. All rights reserved.
- This software is distributed in the hope that it will be
- useful, but with NO WARRANTY OF ANY KIND.
- No author or distributor accepts responsibility to anyone for the
- consequences of using this software, or for whether it serves any
- particular purpose or works at all, unless he or she says so in
- writing. Everyone is granted permission to copy, modify and
- redistribute this source code, for commercial or non-commercial
- purposes, with the following restrictions: (1) the origin of this
- source code must not be misrepresented; (2) modified versions must
- be plainly marked as such; and (3) this notice may not be removed
- or altered from any source or modified source distribution.
*====================================================================*/
/*
* numabasic.c
*
* Numa creation, destruction, copy, clone, etc.
* NUMA *numaCreate()
* NUMA *numaCreateFromIArray()
* void *numaDestroy()
* NUMA *numaCopy()
* NUMA *numaClone()
* l_int32 numaEmpty()
*
* Add/remove number (float or integer)
* l_int32 numaAddNumber()
* l_int32 numaExtendArray()
* l_int32 numaInsertNumber()
* l_int32 numaRemoveNumber()
* l_int32 numaReplaceNumber()
*
* Numa accessors
* l_int32 numaGetCount()
* l_int32 numaSetCount()
* l_int32 numaGetIValue()
* l_int32 numaGetFValue()
* l_int32 numaSetValue()
* l_int32 numaShiftValue()
* l_int32 *numaGetIArray()
* l_float32 *numaGetFArray()
* l_int32 numaGetRefcount()
* l_int32 numaChangeRefcount()
* l_int32 numaGetXParameters()
* l_int32 numaSetXParameters()
* l_int32 numaCopyXParameters()
*
* Serialize numa for I/O
* l_int32 numaRead()
* l_int32 numaReadStream()
* l_int32 numaWrite()
* l_int32 numaWriteStream()
*
* Numaa creation, destruction
* NUMAA *numaaCreate()
* void *numaaDestroy()
*
* Add Numa to Numaa
* l_int32 numaaAddNuma()
* l_int32 numaaExtendArray()
*
* Numaa accessors
* l_int32 numaaGetCount()
* l_int32 numaaGetNumberCount()
* NUMA **numaaGetPtrArray()
* NUMA *numaaGetNuma()
* NUMA *numaaReplaceNuma()
* l_int32 numaaAddNumber()
*
* Serialize numaa for I/O
* l_int32 numaaRead()
* l_int32 numaaReadStream()
* l_int32 numaaWrite()
* l_int32 numaaWriteStream()
*
* Numa2d creation, destruction
* NUMA2D *numa2dCreate()
* void *numa2dDestroy()
*
* Numa2d Accessors
* l_int32 numa2dAddNumber()
* l_int32 numa2dGetCount()
* NUMA *numa2dGetNuma()
* l_int32 numa2dGetFValue()
* l_int32 numa2dGetIValue()
*
* NumaHash creation, destruction
* NUMAHASH *numaHashCreate()
* void *numaHashDestroy()
*
* NumaHash Accessors
* NUMA *numaHashGetNuma()
* void *numaHashAdd()
*
* (1) The numa is a struct, not an array. Always use the accessors
* in this file, never the fields directly.
*
* (2) The number array holds l_float32 values. It can also
* be used to store l_int32 values.
*
* (3) Storing and retrieving numbers:
*
* * to append a new number to the array, use numaAddNumber(). If
* the number is an int, it will will automatically be converted
* to l_float32 and stored.
*
* * to reset a value stored in the array, use numaSetValue().
*
* * to increment or decrement a value stored in the array,
* use numaShiftValue().
*
* * to obtain a value from the array, use either numaGetIValue()
* or numaGetFValue(), depending on whether you are retrieving
* an integer or a float. This avoids doing an explicit cast,
* such as
* (a) return a l_float32 and cast it to an l_int32
* (b) cast the return directly to (l_float32 *) to
* satisfy the function prototype, as in
* numaGetFValue(na, index, (l_float32 *)&ival); [ugly!]
*
* (4) int <--> float conversions:
*
* Tradition dictates that type conversions go automatically from
* l_int32 --> l_float32, even though it is possible to lose
* precision for large integers, whereas you must cast (l_int32)
* to go from l_float32 --> l_int32 because you're truncating
* to the integer value.
*
* (5) As with other arrays in leptonica, the numa has both an allocated
* size and a count of the stored numbers. When you add a number, it
* goes on the end of the array, and causes a realloc if the array
* is already filled. However, in situations where you want to
* add numbers randomly into an array, such as when you build a
* histogram, you must set the count of stored numbers in advance.
* This is done with numaSetCount(). If you set a count larger
* than the allocated array, it does a realloc to the size requested.
*
* (6) In situations where the data in a numa correspond to a function
* y(x), the values can be either at equal spacings in x or at
* arbitrary spacings. For the former, we can represent all x values
* by two parameters: startx (corresponding to y[0]) and delx
* for the change in x for adjacent values y[i] and y[i+1].
* startx and delx are initialized to 0.0 and 1.0, rsp.
* For arbitrary spacings, we use a second numa, and the two
* numas are typically denoted nay and nax.
*
* (7) The numa is also the basic struct used for histograms. Every numa
* has startx and delx fields, initialized to 0.0 and 1.0, that can
* be used to represent the "x" value for the location of the
* first bin and the bin width, respectively. Accessors are the
* numa*XParameters() functions. All functions that make numa
* histograms must set these fields properly, and many functions
* that use numa histograms rely on the correctness of these values.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "allheaders.h"
static const l_int32 INITIAL_PTR_ARRAYSIZE = 50; /* n'importe quoi */
/*--------------------------------------------------------------------------*
* Numa creation, destruction, copy, clone, etc. *
*--------------------------------------------------------------------------*/
/*!
* numaCreate()
*
* Input: size of number array to be alloc'd (0 for default)
* Return: na, or null on error
*/
NUMA *
numaCreate(l_int32 n)
{
NUMA *na;
PROCNAME("numaCreate");
if (n <= 0)
n = INITIAL_PTR_ARRAYSIZE;
if ((na = (NUMA *)CALLOC(1, sizeof(NUMA))) == NULL)
return (NUMA *)ERROR_PTR("na not made", procName, NULL);
if ((na->array = (l_float32 *)CALLOC(n, sizeof(l_float32))) == NULL)
return (NUMA *)ERROR_PTR("number array not made", procName, NULL);
na->nalloc = n;
na->n = 0;
na->refcount = 1;
na->startx = 0.0;
na->delx = 1.0;
return na;
}
/*!
* numaCreateFromIArray()
*
* Input: int array
* size (of the array)
* Return: na, or null on error
*
* Notes:
* (1) This just copies the data from the int array into the numa.
* (2) The input array is NOT owned by the numa.
*/
NUMA *
numaCreateFromIArray(l_int32 *array,
l_int32 size)
{
l_int32 i;
NUMA *na;
PROCNAME("numaCreateFromIArray");
if (!array)
return (NUMA *)ERROR_PTR("array not defined", procName, NULL);
na = numaCreate(size);
for (i = 0; i < size; i++)
numaAddNumber(na, array[i]);
return na;
}
/*!
* numaDestroy()
*
* Input: &na (<to be nulled if it exists>)
* Return: void
*
* Notes:
* (1) Decrements the ref count and, if 0, destroys the numa.
* (2) Always nulls the input ptr.
*/
void
numaDestroy(NUMA **pna)
{
NUMA *na;
PROCNAME("numaDestroy");
if (pna == NULL) {
L_WARNING("ptr address is NULL", procName);
return;
}
if ((na = *pna) == NULL)
return;
/* Decrement the ref count. If it is 0, destroy the numa. */
numaChangeRefcount(na, -1);
if (numaGetRefcount(na) <= 0) {
if (na->array)
FREE(na->array);
FREE(na);
}
*pna = NULL;
return;
}
/*!
* numaCopy()
*
* Input: na
* Return: copy of numa, or null on error
*/
NUMA *
numaCopy(NUMA *na)
{
l_int32 i;
NUMA *cna;
PROCNAME("numaCopy");
if (!na)
return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
if ((cna = numaCreate(na->nalloc)) == NULL)
return (NUMA *)ERROR_PTR("cna not made", procName, NULL);
cna->startx = na->startx;
cna->delx = na->delx;
for (i = 0; i < na->n; i++)
numaAddNumber(cna, na->array[i]);
return cna;
}
/*!
* numaClone()
*
* Input: na
* Return: ptr to same numa, or null on error
*/
NUMA *
numaClone(NUMA *na)
{
PROCNAME("numaClone");
if (!na)
return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
numaChangeRefcount(na, 1);
return na;
}
/*!
* numaEmpty()
*
* Input: na
* Return: 0 if OK; 1 on error
*
* Notes:
* (1) This does not change the allocation of the array.
* It just clears the number of stored numbers, so that
* the array appears to be empty.
*/
l_int32
numaEmpty(NUMA *na)
{
PROCNAME("numaEmpty");
if (!na)
return ERROR_INT("na not defined", procName, 1);
na->n = 0;
return 0;
}
/*--------------------------------------------------------------------------*
* Number array: add number and extend array *
*--------------------------------------------------------------------------*/
/*!
* numaAddNumber()
*
* Input: na
* val (float or int to be added; stored as a float)
* Return: 0 if OK, 1 on error
*/
l_int32
numaAddNumber(NUMA *na,
l_float32 val)
{
l_int32 n;
PROCNAME("numaAddNumber");
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
if (n >= na->nalloc)
numaExtendArray(na);
na->array[n] = val;
na->n++;
return 0;
}
/*!
* numaExtendArray()
*
* Input: na
* Return: 0 if OK, 1 on error
*/
l_int32
numaExtendArray(NUMA *na)
{
PROCNAME("numaExtendArray");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if ((na->array = (l_float32 *)reallocNew((void **)&na->array,
sizeof(l_float32) * na->nalloc,
2 * sizeof(l_float32) * na->nalloc)) == NULL)
return ERROR_INT("new ptr array not returned", procName, 1);
na->nalloc *= 2;
return 0;
}
/*!
* numaInsertNumber()
*
* Input: na
* index (location in na to insert new value)
* val (float32 or integer to be added)
* Return: 0 if OK, 1 on error
*
* Notes:
* (1) This shifts na[i] --> na[i + 1] for all i >= index,
* and then inserts val as na[index].
* (2) It should not be used repeatedly on large arrays,
* because the function is O(n).
*
*/
l_int32
numaInsertNumber(NUMA *na,
l_int32 index,
l_float32 val)
{
l_int32 i, n;
PROCNAME("numaInsertNumber");
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
if (index < 0 || index > n)
return ERROR_INT("index not in {0...n}", procName, 1);
if (n >= na->nalloc)
numaExtendArray(na);
for (i = n; i > index; i--)
na->array[i] = na->array[i - 1];
na->array[index] = val;
na->n++;
return 0;
}
/*!
* numaRemoveNumber()
*
* Input: na
* index (element to be removed)
* Return: 0 if OK, 1 on error
*
* Notes:
* (1) This shifts na[i] --> na[i - 1] for all i > index.
* (2) It should not be used repeatedly on large arrays,
* because the function is O(n).
*/
l_int32
numaRemoveNumber(NUMA *na,
l_int32 index)
{
l_int32 i, n;
PROCNAME("numaRemoveNumber");
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
if (index < 0 || index >= n)
return ERROR_INT("index not in {0...n - 1}", procName, 1);
for (i = index + 1; i < n; i++)
na->array[i - 1] = na->array[i];
na->n--;
return 0;
}
/*!
* numaReplaceNumber()
*
* Input: na
* index (element to be replaced)
* val (new value to replace old one)
* Return: 0 if OK, 1 on error
*/
l_int32
numaReplaceNumber(NUMA *na,
l_int32 index,
l_float32 val)
{
l_int32 n;
PROCNAME("numaReplaceNumber");
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
if (index < 0 || index >= n)
return ERROR_INT("index not in {0...n - 1}", procName, 1);
na->array[index] = val;
return 0;
}
/*----------------------------------------------------------------------*
* Numa accessors *
*----------------------------------------------------------------------*/
/*!
* numaGetCount()
*
* Input: na
* Return: count, or 0 if no numbers or on error
*/
l_int32
numaGetCount(NUMA *na)
{
PROCNAME("numaGetCount");
if (!na)
return ERROR_INT("na not defined", procName, 0);
return na->n;
}
/*!
* numaSetCount()
*
* Input: na
* newcount
* Return: 0 if OK, 1 on error
*
* Notes:
* (1) If newcount <= na->nalloc, this resets na->n.
* Using newcount = 0 is equivalent to numaEmpty().
* (2) If newcount > na->nalloc, this causes a realloc
* to a size na->nalloc = newcount.
* (3) All the previously unused values in na are set to 0.0.
*/
l_int32
numaSetCount(NUMA *na,
l_int32 newcount)
{
PROCNAME("numaSetCount");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (newcount > na->nalloc) {
if ((na->array = (l_float32 *)reallocNew((void **)&na->array,
sizeof(l_float32) * na->nalloc,
sizeof(l_float32) * newcount)) == NULL)
return ERROR_INT("new ptr array not returned", procName, 1);
na->nalloc = newcount;
}
na->n = newcount;
return 0;
}
/*!
* numaGetFValue()
*
* Input: na
* index (into numa)
* &val (<return> float value; 0.0 on error)
* Return: 0 if OK; 1 on error
*
* Notes:
* (1) Caller may need to check the function return value to
* decide if a 0.0 in the returned ival is valid.
*/
l_int32
numaGetFValue(NUMA *na,
l_int32 index,
l_float32 *pval)
{
PROCNAME("numaGetFValue");
if (!pval)
return ERROR_INT("&val not defined", procName, 1);
*pval = 0.0;
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (index < 0 || index >= na->n)
return ERROR_INT("index not valid", procName, 1);
*pval = na->array[index];
return 0;
}
/*!
* numaGetIValue()
*
* Input: na
* index (into numa)
* &ival (<return> integer value; 0 on error)
* Return: 0 if OK; 1 on error
*
* Notes:
* (1) Caller may need to check the function return value to
* decide if a 0 in the returned ival is valid.
*/
l_int32
numaGetIValue(NUMA *na,
l_int32 index,
l_int32 *pival)
{
l_float32 val;
PROCNAME("numaGetIValue");
if (!pival)
return ERROR_INT("&ival not defined", procName, 1);
*pival = 0;
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (index < 0 || index >= na->n)
return ERROR_INT("index not valid", procName, 1);
val = na->array[index];
*pival = (l_int32)(val + L_SIGN(val) * 0.5);
return 0;
}
/*!
* numaSetValue()
*
* Input: na
* index (to element to be set)
* val (to set element)
* Return: 0 if OK; 1 on error
*/
l_int32
numaSetValue(NUMA *na,
l_int32 index,
l_float32 val)
{
PROCNAME("numaSetValue");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (index < 0 || index >= na->n)
return ERROR_INT("index not valid", procName, 1);
na->array[index] = val;
return 0;
}
/*!
* numaShiftValue()
*
* Input: na
* index (to element to change relative to the current value)
* diff (increment if diff > 0 or decrement if diff < 0)
* Return: 0 if OK; 1 on error
*/
l_int32
numaShiftValue(NUMA *na,
l_int32 index,
l_float32 diff)
{
PROCNAME("numaShiftValue");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (index < 0 || index >= na->n)
return ERROR_INT("index not valid", procName, 1);
na->array[index] += diff;
return 0;
}
/*!
* numaGetIArray()
*
* Input: na
* Return: a copy of the bare internal array, integerized
* by rounding, or null on error
* Notes:
* (1) A copy of the array is always made, because we need to
* generate an integer array from the bare float array.
* The caller is responsible for freeing the array.
* (2) The array size is determined by the number of stored numbers,
* not by the size of the allocated array in the Numa.
* (3) This function is provided to simplify calculations
* using the bare internal array, rather than continually
* calling accessors on the numa. It is typically used
* on an array of size 256.
*/
l_int32 *
numaGetIArray(NUMA *na)
{
l_int32 i, n, ival;
l_int32 *array;
PROCNAME("numaGetIArray");
if (!na)
return (l_int32 *)ERROR_PTR("na not defined", procName, NULL);
n = numaGetCount(na);
if ((array = (l_int32 *)CALLOC(n, sizeof(l_int32))) == NULL)
return (l_int32 *)ERROR_PTR("array not made", procName, NULL);
for (i = 0; i < n; i++) {
numaGetIValue(na, i, &ival);
array[i] = ival;
}
return array;
}
/*!
* numaGetFArray()
*
* Input: na
* copyflag (L_NOCOPY or L_COPY)
* Return: either the bare internal array or a copy of it,
* or null on error
*
* Notes:
* (1) If copyflag == L_COPY, it makes a copy which the caller
* is responsible for freeing. Otherwise, it operates
* directly on the bare array of the numa.
* (2) Very important: for L_NOCOPY, any writes to the array
* will be in the numa. Do not write beyond the size of
* the count field, because it will not be accessable
* from the numa! If necessary, be sure to set the count
* the count field to a larger number (such as the alloc
* size) BEFORE calling this function.
*/
l_float32 *
numaGetFArray(NUMA *na,
l_int32 copyflag)
{
l_int32 i, n;
l_float32 *array;
PROCNAME("numaGetFArray");
if (!na)
return (l_float32 *)ERROR_PTR("na not defined", procName, NULL);
if (copyflag == L_NOCOPY)
array = na->array;
else { /* copyflag == L_COPY */
n = numaGetCount(na);
if ((array = (l_float32 *)CALLOC(n, sizeof(l_float32))) == NULL)
return (l_float32 *)ERROR_PTR("array not made", procName, NULL);
for (i = 0; i < n; i++)
array[i] = na->array[i];
}
return array;
}
/*!
* numaGetRefCount()
*
* Input: na
* Return: refcount, or UNDEF on error
*/
l_int32
numaGetRefcount(NUMA *na)
{
PROCNAME("numaGetRefcount");
if (!na)
return ERROR_INT("na not defined", procName, UNDEF);
return na->refcount;
}
/*!
* numaChangeRefCount()
*
* Input: na
* delta (change to be applied)
* Return: 0 if OK, 1 on error
*/
l_int32
numaChangeRefcount(NUMA *na,
l_int32 delta)
{
PROCNAME("numaChangeRefcount");
if (!na)
return ERROR_INT("na not defined", procName, 1);
na->refcount += delta;
return 0;
}
/*!
* numaGetXParameters()
*
* Input: na
* &startx (<optional return> startx)
* &delx (<optional return> delx)
* Return: 0 if OK, 1 on error
*/
l_int32
numaGetXParameters(NUMA *na,
l_float32 *pstartx,
l_float32 *pdelx)
{
PROCNAME("numaGetXParameters");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (pstartx) *pstartx = na->startx;
if (pdelx) *pdelx = na->delx;
return 0;
}
/*!
* numaSetXParameters()
*
* Input: na
* startx (x value corresponding to na[0])
* delx (difference in x values for the situation where the
* elements of na correspond to the evaulation of a
* function at equal intervals of size @delx)
* Return: 0 if OK, 1 on error
*/
l_int32
numaSetXParameters(NUMA *na,
l_float32 startx,
l_float32 delx)
{
PROCNAME("numaSetXParameters");
if (!na)
return ERROR_INT("na not defined", procName, 1);
na->startx = startx;
na->delx = delx;
return 0;
}
/*!
* numaCopyXParameters()
*
* Input: nad (destination Numa)
* nas (source Numa)
* Return: 0 if OK, 1 on error
*/
l_int32
numaCopyXParameters(NUMA *nad,
NUMA *nas)
{
l_float32 start, binsize;
PROCNAME("numaCopyXParameters");
if (!nas || !nad)
return ERROR_INT("nas and nad not both defined", procName, 1);
numaGetXParameters(nas, &start, &binsize);
numaSetXParameters(nad, start, binsize);
return 0;
}
/*----------------------------------------------------------------------*
* Serialize numa for I/O *
*----------------------------------------------------------------------*/
/*!
* numaRead()
*
* Input: filename
* Return: na, or null on error
*/
NUMA *
numaRead(const char *filename)
{
FILE *fp;
NUMA *na;
PROCNAME("numaRead");
if (!filename)
return (NUMA *)ERROR_PTR("filename not defined", procName, NULL);
if ((fp = fopenReadStream(filename)) == NULL)
return (NUMA *)ERROR_PTR("stream not opened", procName, NULL);
if ((na = numaReadStream(fp)) == NULL) {
fclose(fp);
return (NUMA *)ERROR_PTR("na not read", procName, NULL);
}
fclose(fp);
return na;
}
/*!
* numaReadStream()
*
* Input: stream
* Return: numa, or null on error
*/
NUMA *
numaReadStream(FILE *fp)
{
l_int32 i, n, index, ret, version;
l_float32 val, startx, delx;
NUMA *na;
PROCNAME("numaReadStream");
if (!fp)
return (NUMA *)ERROR_PTR("stream not defined", procName, NULL);
ret = fscanf(fp, "\nNuma Version %d\n", &version);
if (ret != 1)
return (NUMA *)ERROR_PTR("not a numa file", procName, NULL);
if (version != NUMA_VERSION_NUMBER)
return (NUMA *)ERROR_PTR("invalid numa version", procName, NULL);
fscanf(fp, "Number of numbers = %d\n", &n);
if ((na = numaCreate(n)) == NULL)
return (NUMA *)ERROR_PTR("na not made", procName, NULL);
for (i = 0; i < n; i++) {
if ((fscanf(fp, " [%d] = %f\n", &index, &val)) != 2)
return (NUMA *)ERROR_PTR("bad input data", procName, NULL);
numaAddNumber(na, val);
}
/* Optional data */
if ((fscanf(fp, "startx = %f, delx = %f\n", &startx, &delx)) == 2)
numaSetXParameters(na, startx, delx);
return na;
}
/*!
* numaWrite()
*
* Input: filename, na
* Return: 0 if OK, 1 on error
*/
l_int32
numaWrite(const char *filename,
NUMA *na)
{
FILE *fp;
PROCNAME("numaWrite");
if (!filename)
return ERROR_INT("filename not defined", procName, 1);
if (!na)
return ERROR_INT("na not defined", procName, 1);
if ((fp = fopen(filename, "w")) == NULL)
return ERROR_INT("stream not opened", procName, 1);
if (numaWriteStream(fp, na))
return ERROR_INT("na not written to stream", procName, 1);
fclose(fp);
return 0;
}
/*!
* numaWriteStream()
*
* Input: stream, na
* Return: 0 if OK, 1 on error
*/
l_int32
numaWriteStream(FILE *fp,
NUMA *na)
{
l_int32 i, n;
l_float32 startx, delx;
PROCNAME("numaWriteStream");
if (!fp)
return ERROR_INT("stream not defined", procName, 1);
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
fprintf(fp, "\nNuma Version %d\n", NUMA_VERSION_NUMBER);
fprintf(fp, "Number of numbers = %d\n", n);
for (i = 0; i < n; i++)
fprintf(fp, " [%d] = %f\n", i, na->array[i]);
fprintf(fp, "\n");
/* Optional data */
numaGetXParameters(na, &startx, &delx);
if (startx != 0.0 || delx != 1.0)
fprintf(fp, "startx = %f, delx = %f\n", startx, delx);
return 0;
}
/*--------------------------------------------------------------------------*
* Numaa creation, destruction *
*--------------------------------------------------------------------------*/
/*!
* numaaCreate()
*
* Input: size of numa ptr array to be alloc'd (0 for default)
* Return: naa, or null on error
*
*/
NUMAA *
numaaCreate(l_int32 n)
{
NUMAA *naa;
PROCNAME("numaaCreate");
if (n <= 0)
n = INITIAL_PTR_ARRAYSIZE;
if ((naa = (NUMAA *)CALLOC(1, sizeof(NUMAA))) == NULL)
return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
if ((naa->numa = (NUMA **)CALLOC(n, sizeof(NUMA *))) == NULL)
return (NUMAA *)ERROR_PTR("numa ptr array not made", procName, NULL);
naa->nalloc = n;
naa->n = 0;
return naa;
}
/*!
* numaaDestroy()
*
* Input: &numaa <to be nulled if it exists>
* Return: void
*/
void
numaaDestroy(NUMAA **pnaa)
{
l_int32 i;
NUMAA *naa;
PROCNAME("numaaDestroy");
if (pnaa == NULL) {
L_WARNING("ptr address is NULL!", procName);
return;
}
if ((naa = *pnaa) == NULL)
return;
for (i = 0; i < naa->n; i++)
numaDestroy(&naa->numa[i]);
FREE(naa->numa);
FREE(naa);
*pnaa = NULL;
return;
}
/*--------------------------------------------------------------------------*
* Add Numa to Numaa *
*--------------------------------------------------------------------------*/
/*!
* numaaAddNuma()
*
* Input: naa
* na (to be added)
* copyflag (L_INSERT, L_COPY, L_CLONE)
* Return: 0 if OK, 1 on error
*/
l_int32
numaaAddNuma(NUMAA *naa,
NUMA *na,
l_int32 copyflag)
{
l_int32 n;
NUMA *nac;
PROCNAME("numaaAddNuma");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (copyflag == L_INSERT)
nac = na;
else if (copyflag == L_COPY) {
if ((nac = numaCopy(na)) == NULL)
return ERROR_INT("nac not made", procName, 1);
}
else if (copyflag == L_CLONE)
nac = numaClone(na);
else
return ERROR_INT("invalid copyflag", procName, 1);
n = numaaGetCount(naa);
if (n >= naa->nalloc)
numaaExtendArray(naa);
naa->numa[n] = nac;
naa->n++;
return 0;
}
/*!
* numaaExtendArray()
*
* Input: naa
* Return: 0 if OK, 1 on error
*/
l_int32
numaaExtendArray(NUMAA *naa)
{
PROCNAME("numaaExtendArray");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
if ((naa->numa = (NUMA **)reallocNew((void **)&naa->numa,
sizeof(NUMA *) * naa->nalloc,
2 * sizeof(NUMA *) * naa->nalloc)) == NULL)
return ERROR_INT("new ptr array not returned", procName, 1);
naa->nalloc *= 2;
return 0;
}
/*----------------------------------------------------------------------*
* Numaa accessors *
*----------------------------------------------------------------------*/
/*!
* numaaGetCount()
*
* Input: naa
* Return: count (number of numa), or 0 if no numa or on error
*/
l_int32
numaaGetCount(NUMAA *naa)
{
PROCNAME("numaaGetCount");
if (!naa)
return ERROR_INT("naa not defined", procName, 0);
return naa->n;
}
/*!
* numaaGetNumberCount()
*
* Input: naa
* Return: count (number of numbers), or 0 if no numbers or on error
*/
l_int32
numaaGetNumberCount(NUMAA *naa)
{
NUMA *na;
l_int32 n, sum, i;
PROCNAME("numaaGetNumberCount");
if (!naa)
return ERROR_INT("naa not defined", procName, 0);
n = numaaGetCount(naa);
for (sum = 0, i = 0; i < n; i++) {
na = numaaGetNuma(naa, i, L_CLONE);
sum += numaGetCount(na);
numaDestroy(&na);
}
return sum;
}
/*!
* numaaGetPtrArray()
*
* Input: naa
* Return: the internal array of ptrs to Numa, or null on error
*
* Notes:
* (1) This function is convenient for doing direct manipulation on
* a fixed size array of Numas. To do this, it sets the count
* to the full size of the allocated array of Numa ptrs.
* The originating Numaa owns this array: DO NOT free it!
* (2) Intended usage:
* Numaa *naa = numaaCreate(n);
* Numa **array = numaaGetPtrArray(naa);
* ... [manipulate Numas directly on the array]
* numaaDestroy(&naa);
* (3) Cautions:
* - Do not free this array; it is owned by tne Numaa.
* - Do not call any functions on the Numaa, other than
* numaaDestroy() when you're finished with the array.
* Adding a Numa will force a resize, destroying the ptr array.
* - Do not address the array outside its allocated size.
* With the bare array, there are no protections. If the
* allocated size is n, array[n] is an error.
*/
NUMA **
numaaGetPtrArray(NUMAA *naa)
{
PROCNAME("numaaGetPtrArray");
if (!naa)
return (NUMA **)ERROR_PTR("naa not defined", procName, NULL);
naa->n = naa->nalloc;
return naa->numa;
}
/*!
* numaaGetNuma()
*
* Input: naa
* index (to the index-th numa)
* accessflag (L_COPY or L_CLONE)
* Return: numa, or null on error
*/
NUMA *
numaaGetNuma(NUMAA *naa,
l_int32 index,
l_int32 accessflag)
{
PROCNAME("numaaGetNuma");
if (!naa)
return (NUMA *)ERROR_PTR("naa not defined", procName, NULL);
if (index < 0 || index >= naa->n)
return (NUMA *)ERROR_PTR("index not valid", procName, NULL);
if (accessflag == L_COPY)
return numaCopy(naa->numa[index]);
else if (accessflag == L_CLONE)
return numaClone(naa->numa[index]);
else
return (NUMA *)ERROR_PTR("invalid accessflag", procName, NULL);
}
/*!
* numaaReplaceNuma()
*
* Input: naa
* index (to the index-th numa)
* numa (insert and replace any existing one)
* Return: 0 if OK, 1 on error
*
* Notes:
* (1) Any existing numa is destroyed, and the input one
* is inserted in its place.
* (2) If the index is invalid, return 1 (error)
*/
l_int32
numaaReplaceNuma(NUMAA *naa,
l_int32 index,
NUMA *na)
{
l_int32 n;
PROCNAME("numaaReplaceNuma");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaaGetCount(naa);
if (index < 0 || index >= n)
return ERROR_INT("index not valid", procName, 1);
numaDestroy(&naa->numa[index]);
naa->numa[index] = na;
return 0;
}
/*!
* numaaAddNumber()
*
* Input: naa
* index (of numa within numaa)
* val (float or int to be added; stored as a float)
* Return: 0 if OK, 1 on error
*
* Notes:
* (1) Adds to an existing numa only.
*/
l_int32
numaaAddNumber(NUMAA *naa,
l_int32 index,
l_float32 val)
{
l_int32 n;
NUMA *na;
PROCNAME("numaaAddNumber");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
n = numaaGetCount(naa);
if (index < 0 || index >= n)
return ERROR_INT("invalid index in naa", procName, 1);
na = numaaGetNuma(naa, index, L_CLONE);
numaAddNumber(na, val);
numaDestroy(&na);
return 0;
}
/*----------------------------------------------------------------------*
* Serialize numaa for I/O *
*----------------------------------------------------------------------*/
/*!
* numaaRead()
*
* Input: filename
* Return: naa, or null on error
*/
NUMAA *
numaaRead(const char *filename)
{
FILE *fp;
NUMAA *naa;
PROCNAME("numaaRead");
if (!filename)
return (NUMAA *)ERROR_PTR("filename not defined", procName, NULL);
if ((fp = fopenReadStream(filename)) == NULL)
return (NUMAA *)ERROR_PTR("stream not opened", procName, NULL);
if ((naa = numaaReadStream(fp)) == NULL) {
fclose(fp);
return (NUMAA *)ERROR_PTR("naa not read", procName, NULL);
}
fclose(fp);
return naa;
}
/*!
* numaaReadStream()
*
* Input: stream
* Return: naa, or null on error
*/
NUMAA *
numaaReadStream(FILE *fp)
{
l_int32 i, n, index, ret, version;
NUMA *na;
NUMAA *naa;
PROCNAME("numaaReadStream");
if (!fp)
return (NUMAA *)ERROR_PTR("stream not defined", procName, NULL);
ret = fscanf(fp, "\nNumaa Version %d\n", &version);
if (ret != 1)
return (NUMAA *)ERROR_PTR("not a numa file", procName, NULL);
if (version != NUMA_VERSION_NUMBER)
return (NUMAA *)ERROR_PTR("invalid numaa version", procName, NULL);
fscanf(fp, "Number of numa = %d\n\n", &n);
if ((naa = numaaCreate(n)) == NULL)
return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
for (i = 0; i < n; i++) {
fscanf(fp, "Numa[%d]:", &index);
if ((na = numaReadStream(fp)) == NULL)
return (NUMAA *)ERROR_PTR("na not made", procName, NULL);
numaaAddNuma(naa, na, L_INSERT);
}
return naa;
}
/*!
* numaaWrite()
*
* Input: filename, naa
* Return: 0 if OK, 1 on error
*/
l_int32
numaaWrite(const char *filename,
NUMAA *naa)
{
FILE *fp;
PROCNAME("numaaWrite");
if (!filename)
return ERROR_INT("filename not defined", procName, 1);
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
if ((fp = fopen(filename, "w")) == NULL)
return ERROR_INT("stream not opened", procName, 1);
if (numaaWriteStream(fp, naa))
return ERROR_INT("naa not written to stream", procName, 1);
fclose(fp);
return 0;
}
/*!
* numaaWriteStream()
*
* Input: stream, naa
* Return: 0 if OK, 1 on error
*/
l_int32
numaaWriteStream(FILE *fp,
NUMAA *naa)
{
l_int32 i, n;
NUMA *na;
PROCNAME("numaaWriteStream");
if (!fp)
return ERROR_INT("stream not defined", procName, 1);
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
n = numaaGetCount(naa);
fprintf(fp, "\nNumaa Version %d\n", NUMA_VERSION_NUMBER);
fprintf(fp, "Number of numa = %d\n\n", n);
for (i = 0; i < n; i++) {
if ((na = numaaGetNuma(naa, i, L_CLONE)) == NULL)
return ERROR_INT("na not found", procName, 1);
fprintf(fp, "Numa[%d]:", i);
numaWriteStream(fp, na);
numaDestroy(&na);
}
return 0;
}
/*--------------------------------------------------------------------------*
* Numa2d creation, destruction *
*--------------------------------------------------------------------------*/
/*!
* numa2dCreate()
*
* Input: nrows (of 2d array)
* ncols (of 2d array)
* initsize (initial size of each allocated numa)
* Return: numa2d, or null on error
*
* Notes:
* (1) The numa2d holds a doubly-indexed array of numa.
* (2) The numa ptr array is initialized with all ptrs set to NULL.
* (3) The numas are created only when a number is to be stored
* at an index (i,j) for which a numa has not yet been made.
*/
NUMA2D *
numa2dCreate(l_int32 nrows,
l_int32 ncols,
l_int32 initsize)
{
l_int32 i;
NUMA2D *na2d;
PROCNAME("numa2dCreate");
if (nrows <= 1 || ncols <= 1)
return (NUMA2D *)ERROR_PTR("rows, cols not both >= 1", procName, NULL);
if ((na2d = (NUMA2D *)CALLOC(1, sizeof(NUMA2D))) == NULL)
return (NUMA2D *)ERROR_PTR("na2d not made", procName, NULL);
na2d->nrows = nrows;
na2d->ncols = ncols;
na2d->initsize = initsize;
/* Set up the 2D array */
if ((na2d->numa = (NUMA ***)CALLOC(nrows, sizeof(NUMA **))) == NULL)
return (NUMA2D *)ERROR_PTR("numa row array not made", procName, NULL);
for (i = 0; i < nrows; i++) {
if ((na2d->numa[i] = (NUMA **)CALLOC(ncols, sizeof(NUMA *))) == NULL)
return (NUMA2D *)ERROR_PTR("numa cols not made", procName, NULL);
}
return na2d;
}
/*!
* numa2dDestroy()
*
* Input: &numa2d (<to be nulled if it exists>)
* Return: void
*/
void
numa2dDestroy(NUMA2D **pna2d)
{
l_int32 i, j;
NUMA2D *na2d;
PROCNAME("numa2dDestroy");
if (pna2d == NULL) {
L_WARNING("ptr address is NULL!", procName);
return;
}
if ((na2d = *pna2d) == NULL)
return;
for (i = 0; i < na2d->nrows; i++) {
for (j = 0; j < na2d->ncols; j++)
numaDestroy(&na2d->numa[i][j]);
FREE(na2d->numa[i]);
}
FREE(na2d->numa);
FREE(na2d);
*pna2d = NULL;
return;
}
/*--------------------------------------------------------------------------*
* Numa2d accessors *
*--------------------------------------------------------------------------*/
/*!
* numa2dAddNumber()
*
* Input: na2d
* row of 2d array
* col of 2d array
* val (float or int to be added; stored as a float)
* Return: 0 if OK, 1 on error
*/
l_int32
numa2dAddNumber(NUMA2D *na2d,
l_int32 row,
l_int32 col,
l_float32 val)
{
NUMA *na;
PROCNAME("numa2dAddNumber");
if (!na2d)
return ERROR_INT("na2d not defined", procName, 1);
if (row < 0 || row >= na2d->nrows)
return ERROR_INT("row out of bounds", procName, 1);
if (col < 0 || col >= na2d->ncols)
return ERROR_INT("col out of bounds", procName, 1);
if ((na = na2d->numa[row][col]) == NULL) {
na = numaCreate(na2d->initsize);
na2d->numa[row][col] = na;
}
numaAddNumber(na, val);
return 0;
}
/*!
* numa2dGetCount()
*
* Input: na2d
* row of 2d array
* col of 2d array
* Return: size of numa at [row][col], or 0 if the numa doesn't exist
* or on error
*/
l_int32
numa2dGetCount(NUMA2D *na2d,
l_int32 row,
l_int32 col)
{
NUMA *na;
PROCNAME("numa2dGetCount");
if (!na2d)
return ERROR_INT("na2d not defined", procName, 0);
if (row < 0 || row >= na2d->nrows)
return ERROR_INT("row out of bounds", procName, 0);
if (col < 0 || col >= na2d->ncols)
return ERROR_INT("col out of bounds", procName, 0);
if ((na = na2d->numa[row][col]) == NULL)
return 0;
else
return na->n;
}
/*!
* numa2dGetNuma()
*
* Input: na2d
* row of 2d array
* col of 2d array
* Return: na (a clone of the numa if it exists) or null if it doesn't
*
* Notes:
* (1) This does not give an error if the index is out of bounds.
*/
NUMA *
numa2dGetNuma(NUMA2D *na2d,
l_int32 row,
l_int32 col)
{
NUMA *na;
PROCNAME("numa2dGetNuma");
if (!na2d)
return (NUMA *)ERROR_PTR("na2d not defined", procName, NULL);
if (row < 0 || row >= na2d->nrows || col < 0 || col >= na2d->ncols)
return NULL;
if ((na = na2d->numa[row][col]) == NULL)
return NULL;
return numaClone(na);
}
/*!
* numa2dGetFValue()
*
* Input: na2d
* row of 2d array
* col of 2d array
* index (into numa)
* &val (<return> float value)
* Return: 0 if OK, 1 on error
*/
l_int32
numa2dGetFValue(NUMA2D *na2d,
l_int32 row,
l_int32 col,
l_int32 index,
l_float32 *pval)
{
NUMA *na;
PROCNAME("numa2dGetFValue");
if (!na2d)
return ERROR_INT("na2d not defined", procName, 1);
if (!pval)
return ERROR_INT("&val not defined", procName, 1);
*pval = 0.0;
if (row < 0 || row >= na2d->nrows)
return ERROR_INT("row out of bounds", procName, 1);
if (col < 0 || col >= na2d->ncols)
return ERROR_INT("col out of bounds", procName, 1);
if ((na = na2d->numa[row][col]) == NULL)
return ERROR_INT("numa does not exist", procName, 1);
return numaGetFValue(na, index, pval);
}
/*!
* numa2dGetIValue()
*
* Input: na2d
* row of 2d array
* col of 2d array
* index (into numa)
* &val (<return> integer value)
* Return: 0 if OK, 1 on error
*/
l_int32
numa2dGetIValue(NUMA2D *na2d,
l_int32 row,
l_int32 col,
l_int32 index,
l_int32 *pval)
{
NUMA *na;
PROCNAME("numa2dGetIValue");
if (!na2d)
return ERROR_INT("na2d not defined", procName, 1);
if (!pval)
return ERROR_INT("&val not defined", procName, 1);
*pval = 0;
if (row < 0 || row >= na2d->nrows)
return ERROR_INT("row out of bounds", procName, 1);
if (col < 0 || col >= na2d->ncols)
return ERROR_INT("col out of bounds", procName, 1);
if ((na = na2d->numa[row][col]) == NULL)
return ERROR_INT("numa does not exist", procName, 1);
return numaGetIValue(na, index, pval);
}
/*--------------------------------------------------------------------------*
* Number array hash: Creation and destruction *
*--------------------------------------------------------------------------*/
/*!
* numaHashCreate()
*
* Input: nbuckets (the number of buckets in the hash table,
* which should be prime.)
* initsize (initial size of each allocated numa; 0 for default)
* Return: ptr to new nahash, or null on error
*
* Note: actual numa are created only as required by numaHashAdd()
*/
NUMAHASH *
numaHashCreate(l_int32 nbuckets,
l_int32 initsize)
{
NUMAHASH *nahash;
PROCNAME("numaHashCreate");
if (nbuckets <= 0)
return (NUMAHASH *)ERROR_PTR("negative hash size", procName, NULL);
if ((nahash = (NUMAHASH *)CALLOC(1, sizeof(NUMAHASH))) == NULL)
return (NUMAHASH *)ERROR_PTR("nahash not made", procName, NULL);
if ((nahash->numa = (NUMA **)CALLOC(nbuckets, sizeof(NUMA *))) == NULL) {
FREE(nahash);
return (NUMAHASH *)ERROR_PTR("numa ptr array not made", procName, NULL);
}
nahash->nbuckets = nbuckets;
nahash->initsize = initsize;
return nahash;
}
/*!
* numaHashDestroy()
*
* Input: &nahash (<to be nulled, if it exists>)
* Return: void
*/
void
numaHashDestroy(NUMAHASH **pnahash)
{
NUMAHASH *nahash;
l_int32 i;
PROCNAME("numaHashDestroy");
if (pnahash == NULL) {
L_WARNING("ptr address is NULL!", procName);
return;
}
if ((nahash = *pnahash) == NULL)
return;
for (i = 0; i < nahash->nbuckets; i++)
numaDestroy(&nahash->numa[i]);
FREE(nahash->numa);
FREE(nahash);
*pnahash = NULL;
}
/*--------------------------------------------------------------------------*
* Number array hash: Add elements and return numas
*--------------------------------------------------------------------------*/
/*!
* numaHashGetNuma()
*
* Input: nahash
* key (key to be hashed into a bucket number)
* Return: ptr to numa
*/
NUMA *
numaHashGetNuma(NUMAHASH *nahash,
l_uint32 key)
{
l_int32 bucket;
NUMA *na;
PROCNAME("numaHashGetNuma");
if (!nahash)
return (NUMA *)ERROR_PTR("nahash not defined", procName, NULL);
bucket = key % nahash->nbuckets;
na = nahash->numa[bucket];
if (na)
return numaClone(na);
else
return NULL;
}
/*!
* numaHashAdd()
*
* Input: nahash
* key (key to be hashed into a bucket number)
* value (float value to be appended to the specific numa)
* Return: 0 if OK; 1 on error
*/
l_int32
numaHashAdd(NUMAHASH *nahash,
l_uint32 key,
l_float32 value)
{
l_int32 bucket;
NUMA *na;
PROCNAME("numaHashAdd");
if (!nahash)
return ERROR_INT("nahash not defined", procName, 1);
if (key < 0)
return ERROR_INT("key < 0", procName, 1);
bucket = key % nahash->nbuckets;
na = nahash->numa[bucket];
if (!na) {
if ((na = numaCreate(nahash->initsize)) == NULL)
return ERROR_INT("na not made", procName, 1);
nahash->numa[bucket] = na;
}
numaAddNumber(na, value);
return 0;
}