waveview/lib/array.c

335 lines
7.2 KiB
C
Raw Permalink Normal View History

2022-09-24 17:47:18 -04:00
/*
* array.c - array interface functions
*
* include LICENSE
*/
#include <stdio.h>
#include <string.h>
#include <strmem.h>
#include <array.h>
#ifdef TRACE_MEM
#include <tracemem.h>
#endif
/*
*** \brief Allocates memory for a new Array object.
*/
Array *array_new( int elSize, int count )
{
Array *ary;
ary = app_new0(Array, 1);
array_construct( ary, elSize, count );
app_class_overload_destroy( (AppClass *) ary, array_destroy );
return ary;
}
/** \brief Constructor for the Array object. */
void array_construct( Array *ary, int elSize, int count )
{
app_class_construct( (AppClass *) ary );
if (count == 0 ){
count = DEF_ELEM_COUNT;
} else if ( count < 0 ){
count = app_power_of_2(count);
}
if (elSize == 0 ){
elSize = sizeof(char *); /* sizeof pointer */
}
ary->nAlloc = count;
ary->elSize = elSize;
/*
* always keep a null element at the end of array
* actual allocated = nAlloc + 1, but usable is nAlloc
*/
ary->ptr = app_malloc0 ( elSize * (count + 1) );
/*
* default function to destroy an element
* Must be overloaded for non AppClass element : char *, dlist *
*/
ary->destroyFunc = (ElmDestroyFP_func) app_class_unref ;
}
/** \brief Destructor for the Array object. */
void array_destroy(void *ary)
{
Array *this = (Array *) ary;
if (ary == NULL) {
return;
}
array_tbl_delete_all(this);
app_free(this->ptr);
app_class_destroy( ary );
}
void array_tbl_delete_all(Array *ary)
{
int i;
void **pptr;
ElmDestroyFP_func func = ary->destroyFunc;
if ( func ) {
for ( i = 0 ; i < ary->nelem ; i++ ){
/* pointer of type void used in arithmetic wpointer arith */
pptr = (void *)((char *) ary->ptr + (i * ary->elSize));
if ( *pptr ){
func ( *pptr );
}
}
}
ary->nelem = 0;
}
void array_set_elem_destroyFunc(Array *ary, ElmDestroyFP_func func)
{
ary->destroyFunc = (ElmDestroyFP_func) func;
}
void *array_table_get(Array *ary)
{
return ary->ptr ;
}
void *array_tbl_get(Array *ary, int index)
{
if ( index >= ary->nelem) {
msg_error ( "Index %d >= Nb elem %d", index, ary->nelem);
return NULL;
}
void **pptr = (void **) ary->ptr;
return pptr[index] ;
}
/*
* suppress the element in array and destroy it
*/
void array_tbl_delete(Array *ary, int index)
{
if ( index >= ary->nelem) {
msg_error ( "Index %d > Nb elem %d", index, ary->nelem);
return;
}
void **pptr = (void **) ary->ptr;
if ( pptr[index] ){
ary->destroyFunc ( pptr[index] );
}
memmove ( &pptr[index], &pptr[index + 1], ary->elSize * (ary->nelem - index));
ary->nelem--;
}
/*
* get the element and remove it from array without destroying the element
*/
void *array_tbl_remove(Array *ary, int index)
{
if ( index >= ary->nelem) {
msg_error ( "Index %d > Nb elem %d", index, ary->nelem);
return NULL;
}
void **pptr = (void **) ary->ptr;
void *ptr = pptr[index] ;
memmove ( &pptr[index], &pptr[index + 1], ary->elSize * (ary->nelem - index));
ary->nelem--;
return ptr ;
}
/*
* allocate 1 more to always get a free element set to null
*/
void array_tbl_expand(Array *ary, int n)
{
if ( n > ary->nAlloc ) {
ary->nAlloc <<= 1;
ary->ptr = app_realloc(ary->ptr, ary->elSize * (ary->nAlloc + 1));
memset((char *) ary->ptr + (ary->nelem * ary->elSize), 0,
ary->elSize * ( ary->nAlloc + 1 - ary->nelem) );
}
}
void array_tbl_add(Array *ary, void *elPtr)
{
array_tbl_expand(ary, ary->nelem + 1);
void **pptr = (void **) ary->ptr;
pptr[ary->nelem++] = elPtr;
}
/*
* insert before index
*/
void array_tbl_insert(Array *ary, void *elPtr, int index)
{
if ( index > ary->nelem) {
msg_error ( "Index %d > Nb elem %d", index, ary->nelem);
return;
}
array_tbl_expand(ary, ary->nelem + 1);
void **pptr = (void **) ary->ptr;
memmove ( &pptr[index + 1], &pptr[index], ary->elSize * (ary->nelem - index));
pptr[index] = elPtr;
ary->nelem++;
}
/*
* replace element at index
* return the old element
*/
void *array_tbl_replace(Array *ary, void *elPtr, int index)
{
if ( index >= ary->nelem) {
/* just add it */
array_tbl_add(ary, elPtr);
// msg_error ( "Index %d > Nb elem %d", index, ary->nelem);
return NULL;
}
void **pptr = (void **) ary->ptr;
void *ptr = pptr[index] ;
pptr[index] = elPtr;
return ptr ;
}
/*
* replace the element with the new one
* and kill the old one
*/
void array_tbl_replace_kill(Array *ary, void *elPtr, int index)
{
void *ptr = array_tbl_replace(ary, elPtr, index) ;
if ( ptr ) {
ary->destroyFunc ( ptr ) ;
}
}
int array_tbl_index(Array *ary, void *elPtr)
{
int i;
void **pptr = (void **) ary->ptr;
for ( i = 0 ; i < ary->nelem ; i++ ){
if ( pptr[i] == elPtr ) {
return i;
}
}
return -1;
}
void array_set_nelem (Array *ary, int nelem)
{
ary->nelem = nelem;
return ;
}
int array_get_nelem (Array *ary)
{
return ary->nelem ;
}
/** \brief Lookup an item in the array.
*
* Walk the array pointed to by ary and return a pointer to the data if
* found. If not found, return NULL.
*
* \param ary The array to be iterated.
* \param data The data to be passed to the func when it is applied.
* \param cmp A function to be used for comparing the items.
*
* \return A pointer to the data found, or NULL if not found.
*
* Warning: element list Must be sorted before creating the table
*/
AppClass *array_lookup_sorted( Array *ary, AppClass *data, ArrayFP_Cmp cmp, int *index )
{
int i;
int ret;
int lo ;
int hi ;
AppClass *entry ;
if (cmp == NULL) {
msg_fatal( "compare function not specified" );
}
lo = 0;
hi = ary->nelem;
while (lo != hi) {
i = (hi + lo) / 2 ;
entry = (AppClass *) array_tbl_get( ary, i );
ret = (*cmp)(entry, data);
if ( ret > 0 ) { /* entry->symbol > symbol */
hi = i;
} else if ( ret < 0 ) { /* entry->symbol < symbol */
lo = i + 1;
} else { /* entry->symbol == symbol */
/* symbol found */
if ( index ){
*index = i;
}
return entry;
}
}
if ( index ){
*index = lo;
}
return NULL;
}
/*
* lookup an unsorted list
*/
AppClass *array_lookup( Array *ary, AppClass *data, ArrayFP_Cmp cmp, int *index )
{
int i;
AppClass *entry ;
if (cmp == NULL) {
msg_fatal( "compare function not specified" );
}
for ( i = 0; i < ary->nelem ; i++) {
entry = (AppClass *) array_tbl_get( ary, i );
if ( entry && (*cmp)(entry, data) == 0 ) { /* entry->symbol == symbol */
/* symbol found */
if ( index ){
*index = i;
}
return entry;
}
}
return NULL;
}
void array_sort(Array *ary, ArraySortFP_Cmp cmp_func )
{
qsort( ary->ptr, ary->nelem, ary->elSize, cmp_func);
}
void array_iterator(Array *ary, ArrayFP_Iter iter_func, void *user_data)
{
int i;
AppClass *entry ;
for ( i = 0; i < ary->nelem ; i++) {
entry = (AppClass *) array_tbl_get( ary, i );
if ( entry ){
(*iter_func)(entry, user_data);
}
}
}