#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