#include "niml_private.h"
/*-----------------------------------------------------------*/
/*! Holds the table of all registered structs. */
static Htable *ni_struct_table=NULL ;
/*-----------------------------------------------------------*/
/*! Register a struct by its idcode (if it has one). */
void NI_register_struct( void *ndd )
{
NI_struct *nd = (NI_struct *)ndd ;
void *vp ;
/* can't register without idcode */
if( nd == NULL || nd->idcode == NULL ) return ;
/* 1st time in ==> create hash table */
if( ni_struct_table == NULL )
ni_struct_table = new_Htable( 1031 ) ;
/* see if it already is registered */
vp = findin_Htable( nd->idcode , ni_struct_table ) ;
if( vp != NULL ) return ; /* duplicate entry */
/* OK, add it to the table */
addto_Htable( nd->idcode , nd , ni_struct_table ) ;
return ;
}
/*-----------------------------------------------------------*/
/*! Find a struct by its idcode. */
void * NI_find_struct( char *idcode )
{
void *vp ;
if( idcode == NULL ) return NULL ; /* nothing to do */
vp = findin_Htable( idcode , ni_struct_table ) ;
return vp ;
}
/*-----------------------------------------------------------*/
/*! Remove a struct from the table. */
void NI_unregister_struct( void *ndd )
{
NI_struct *nd = (NI_struct *)ndd ;
if( nd == NULL || nd->idcode == NULL ) return ;
removefrom_Htable( nd->idcode , ni_struct_table ) ;
return ;
}
/*-----------------------------------------------------------*/
/*! Return a copy of the pointer to the struct,
also incrementing its reference counter. */
void * NI_pointto_struct( void *ndd )
{
NI_struct *nd = (NI_struct *)ndd ;
if( nd == NULL ) return NULL ;
nd->nref ++ ;
return (void *)nd ;
}
/*-----------------------------------------------------------*/
/* This macro does the basic stuff necessary to delete a
struct from the hash table and from memory. It is used
at the very end of the NI_free_struct() function.
Type specific code is also needed to delete any memory
used by sub-structs or sub-arrays.
-------------------------------------------------------------*/
#undef DELETE_STRUCT
#define DELETE_STRUCT(nq) \
do{ NI_unregister_struct(nq); \
NI_free(nq->idcode) ; \
NI_free(nq->name) ; \
NI_free(nq) ; } while(0)
/*-----------------------------------------------------------*/
/*! Decrement the reference counter, and destroy the struct
(recursively in some cases) if the counter goes to zero.
-------------------------------------------------------------*/
void NI_free_struct( void *ndd )
{
NI_struct *nd = (NI_struct *)ndd ;
if( nd == NULL ) return ;
/* decrementation */
nd->nref -- ;
if( nd->nref > 0 ) return ; /* keep it */
/* OK, blot it from the universe */
switch( nd->type ){ /* N.B.: there is no default */
case NI_STRUCT_TYPE: /* These types have no sub-structs */
case NI_FLOAT_ONE_TYPE: /* or sub-arrays that need deleting */
case NI_AFFINE_3DMAP_TYPE:
case NI_RECT_DOMAIN_TYPE:
DELETE_STRUCT(nd) ;
break ;
case NI_STATISTIC_TYPE:{
NI_statistic *ns = (NI_statistic *)nd ;
NI_index_t ii ;
if( ns->param != NULL ){
for( ii=0 ; ii < ns->param_num ; ii++ )
NI_free_struct( ns->param[ii] ) ; /* recursion */
NI_free(ns->param) ;
}
}
DELETE_STRUCT(nd) ;
break ;
case NI_VECTOR_TYPE:
case NI_BYTE_VECTOR_TYPE:
case NI_SHORT_VECTOR_TYPE:
case NI_INT_VECTOR_TYPE:
case NI_FLOAT_VECTOR_TYPE:
case NI_DOUBLE_VECTOR_TYPE:
case NI_COMPLEX_VECTOR_TYPE:
case NI_RGB_VECTOR_TYPE:
case NI_RGBA_VECTOR_TYPE:{
NI_vector *nv = (NI_vector *)nd ;
NI_free( nv->vec ) ;
NI_free( nv->vec_range ) ;
NI_free( nv->statistic ) ;
}
DELETE_STRUCT(nd) ;
break ;
case NI_STRING_VECTOR_TYPE:{
NI_string_vector *nv = (NI_string_vector *)nd ;
NI_index_t ii ;
if( nv->vec != NULL ){
for( ii=0 ; ii < nv->vec_len ; ii++ )
NI_free( nv->vec[ii] ) ;
NI_free( nv->vec ) ;
}
/* vec_range not used for string vectors */
/* statistic not used for string vectors */
}
DELETE_STRUCT(nd) ;
break ;
case NI_POINTS_DOMAIN_TYPE:{
NI_points_domain *np = (NI_points_domain *)nd ;
NI_free( np->id ) ;
NI_free( np->x ) ;
NI_free( np->y ) ;
NI_free( np->z ) ;
}
DELETE_STRUCT(nd) ;
break ;
case NI_DATASET_TYPE:{
NI_dataset *nn = (NI_dataset *)nd ;
if( nn->vec != NULL ){
NI_index_t nv , ii ;
nv = NI_dataset_vecnum(nn) ;
for( ii=0 ; ii < nv ; ii++ )
NI_free_struct( nn->vec[ii] ) ; /* recursion */
NI_free( nn->vec ) ;
}
NI_free_struct( nn->domain ) ; /* recursion */
}
DELETE_STRUCT(nd) ;
break ;
}
return ;
}
/*-----------------------------------------------------------*/
/* This macro copies the basic elements of a struct,
from struct qold to struct qnew. Of course, the new
struct gets a new idcode. This macro may be used after
creating a new struct with NI_new(), for example.
-------------------------------------------------------------*/
#undef COPY_BASIC_STRUCT
#define COPY_BASIC_STRUCT(qnew,qold) \
do{ (qnew)->type = (qold)->type ; \
(qnew)->nref = 1 ; \
(qnew)->idcode = UNIQ_idcode() ; \
NI_register_struct( (qnew) ) ; \
(qnew)->name = NI_strdup((qold)->name) ; \
} while(0)
/*-----------------------------------------------------------*/
/* This macro makes a new struct of type TTYPE, copies
the basic elements, and points ndnew to the new struct,
for eventual return from NI_copy_struct(). This macro
is used only in that function.
-------------------------------------------------------------*/
#undef DUPLICATE_STRUCT
#define DUPLICATE_STRUCT(TTYPE) \
TTYPE *nn = NI_new(TTYPE) ; \
TTYPE *qq = (TTYPE *)nd ; \
COPY_BASIC_STRUCT(nn,qq) ; \
ndnew = (NI_struct *)nn
/*-----------------------------------------------------------*/
/*! Make a copy of a struct, as opposed to a new
reference (which is what NI_pointto_struct() does).
-------------------------------------------------------------*/
void * NI_copy_struct( void *ndd )
{
NI_struct *nd = (NI_struct *)ndd ;
NI_struct *ndnew=NULL ;
if( nd == NULL ) return NULL ; /* bad input :-( */
switch( nd->type ){ /* N.B.: there is no default */
case NI_STRUCT_TYPE:{
DUPLICATE_STRUCT(NI_struct) ;
}
break ;
case NI_FLOAT_ONE_TYPE:{
DUPLICATE_STRUCT(NI_float_one) ;
nn->val = qq->val ;
}
break ;
case NI_AFFINE_3DMAP_TYPE:{
DUPLICATE_STRUCT(NI_affine_3dmap) ;
nn->mat[0][0] = qq->mat[0][0]; nn->mat[0][1] = qq->mat[0][1];
nn->mat[0][2] = qq->mat[0][2]; nn->mat[0][3] = qq->mat[0][3];
nn->mat[1][0] = qq->mat[1][0]; nn->mat[1][1] = qq->mat[1][1];
nn->mat[1][2] = qq->mat[1][2]; nn->mat[1][3] = qq->mat[1][3];
nn->mat[2][0] = qq->mat[2][0]; nn->mat[2][1] = qq->mat[2][1];
nn->mat[2][2] = qq->mat[2][2]; nn->mat[2][3] = qq->mat[2][3];
nn->mat[3][0] = qq->mat[3][0]; nn->mat[3][1] = qq->mat[3][1];
nn->mat[3][2] = qq->mat[3][2]; nn->mat[3][3] = qq->mat[3][3];
}
break ;
case NI_RECT_DOMAIN_TYPE:{
DUPLICATE_STRUCT(NI_rect_domain) ;
nn->nx = qq->nx; nn->ny = qq->ny; nn->nz = qq->nz; nn->nt = qq->nt;
nn->dx = qq->dx; nn->dy = qq->dy; nn->dz = qq->dz; nn->dt = qq->dt;
nn->xo = qq->xo; nn->yo = qq->yo; nn->zo = qq->zo; nn->to = qq->to;
}
break ;
case NI_STATISTIC_TYPE:{
NI_index_t ii ;
DUPLICATE_STRUCT(NI_statistic) ;
nn->statcode = qq->statcode ;
nn->param_num = qq->param_num ;
if( qq->param != NULL ){
nn->param = NI_malloc(NI_struct*, sizeof(NI_struct *)*nn->param_num) ;
for( ii=0 ; ii < nn->param_num ; ii++ )
nn->param[ii] = (NI_struct *)NI_copy_struct( qq->param[ii] ) ; /* recursion */
} else {
nn->param = NULL ;
}
}
break ;
case NI_VECTOR_TYPE:
case NI_BYTE_VECTOR_TYPE:
case NI_SHORT_VECTOR_TYPE:
case NI_INT_VECTOR_TYPE:
case NI_FLOAT_VECTOR_TYPE:
case NI_DOUBLE_VECTOR_TYPE:
case NI_COMPLEX_VECTOR_TYPE:
case NI_RGB_VECTOR_TYPE:
case NI_RGBA_VECTOR_TYPE:{
NI_index_t ii ;
DUPLICATE_STRUCT(NI_vector) ;
nn->vec_len = qq->vec_len ;
nn->vec_typ = qq->vec_typ ;
if( qq->vec != NULL ){ /* copy array */
ii = nn->vec_len * NI_datatype_size(nn->vec_typ) ;
nn->vec = NI_malloc(void, ii) ;
memcpy( nn->vec , qq->vec , ii ) ;
} else {
nn->vec = NULL ;
}
if( qq->vec_range != NULL ){ /* copy array */
ii = 2 * NI_datatype_size(nn->vec_typ) ;
nn->vec_range = NI_malloc(void, ii) ;
memcpy( nn->vec_range , qq->vec_range , ii ) ;
} else {
nn->vec_range = NULL ;
}
nn->statistic = (NI_statistic *)NI_copy_struct( qq->statistic ) ; /* recursion */
}
break ;
case NI_STRING_VECTOR_TYPE:{
NI_index_t ii ;
DUPLICATE_STRUCT(NI_string_vector) ;
nn->vec_len = qq->vec_len ;
nn->vec_typ = qq->vec_typ ;
if( qq->vec != NULL ){ /* copy array */
nn->vec = NI_malloc(char*, sizeof(char *)*nn->vec_len) ;
for( ii=0 ; ii < nn->vec_len ; ii++ )
nn->vec[ii] = NI_strdup(qq->vec[ii]) ;
} else {
nn->vec = NULL ;
}
nn->vec_range = NULL ; /* string vectors don't use vec_range */
nn->statistic = NULL ;
}
break ;
case NI_POINTS_DOMAIN_TYPE:{
NI_index_t ii ;
DUPLICATE_STRUCT(NI_points_domain) ;
nn->num_node = ii = qq->num_node ;
if( qq->id != NULL ){ /* copy array */
nn->id = NI_malloc(NI_index_t, ii*sizeof(NI_index_t)) ;
memcpy( nn->id , qq->id , ii*sizeof(NI_index_t) ) ;
}
if( qq->x != NULL ){ /* copy array */
nn->x = NI_malloc(float, ii*sizeof(float)) ;
memcpy( nn->x , qq->x , ii*sizeof(float) ) ;
}
if( qq->y != NULL ){ /* copy array */
nn->y = NI_malloc(float, ii*sizeof(float)) ;
memcpy( nn->y , qq->y , ii*sizeof(float) ) ;
}
if( qq->z != NULL ){ /* copy array */
nn->z = NI_malloc(float, ii*sizeof(float)) ;
memcpy( nn->z , qq->z , ii*sizeof(float) ) ;
}
nn->seq = qq->seq; nn->seqbase = qq->seqbase; nn->sorted = qq->sorted;
}
break ;
case NI_DATASET_TYPE:{
DUPLICATE_STRUCT(NI_dataset) ;
nn->num_node = qq->num_node ;
nn->num_val = qq->num_val ;
nn->order = qq->order ;
if( qq->vec != NULL ){
NI_index_t nv , ii ;
nv = NI_dataset_vecnum(nn) ;
nn->vec = NI_malloc(NI_vector*, sizeof(NI_vector *)*nv) ;
for( ii=0 ; ii < nv ; ii++ )
nn->vec[ii] = (NI_vector *)NI_copy_struct( qq->vec[ii] ) ; /* recursion */
} else {
nn->vec = NULL ;
}
nn->domain = (NI_struct *)NI_copy_struct( qq->domain ) ; /* recursion */
}
break ;
}
return (void *)ndnew ;
}
#undef DUPLICATE_STRUCT
syntax highlighted by Code2HTML, v. 0.9.1