mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-31 06:12:22 -06:00
1849 lines
46 KiB
C
1849 lines
46 KiB
C
/*====================================================================*
|
|
- 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;
|
|
}
|
|
|
|
|