diff options
Diffstat (limited to 'src/H5Tconv.c')
-rw-r--r-- | src/H5Tconv.c | 317 |
1 files changed, 308 insertions, 9 deletions
diff --git a/src/H5Tconv.c b/src/H5Tconv.c index 2ba0e32..4915b22 100644 --- a/src/H5Tconv.c +++ b/src/H5Tconv.c @@ -24,6 +24,13 @@ typedef struct H5T_conv_struct_t { size_t *memb_nelmts; /*member element count */ } H5T_conv_struct_t; +/* Conversion data for H5T_conv_enum() */ +typedef struct H5T_enum_struct_t { + intn base; /*lowest `in' value */ + intn length; /*num elements in arrays */ + intn *src2dst; /*map from src to dst index */ +} H5T_enum_struct_t; + /* Conversion data for the hardware conversion functions */ typedef struct H5T_conv_hw_t { hsize_t s_aligned; /*number source elements aligned */ @@ -336,7 +343,7 @@ static intn interface_initialize_g = 0; } \ } #else -# define CI_PRINT_STATS /*void*/ +# define CI_PRINT_STATS(STYPE,DTYPE) /*void*/ #endif /*------------------------------------------------------------------------- @@ -543,8 +550,8 @@ H5T_conv_struct_init (H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata) /* * Insure that members are sorted. */ - H5T_sort_by_offset (src); - H5T_sort_by_offset (dst); + H5T_sort_value(src); + H5T_sort_value(dst); /* * Build a mapping from source member number to destination member @@ -582,8 +589,8 @@ H5T_conv_struct_init (H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata) */ for (i=0; i<src->u.compnd.nmembs; i++) { if (src2dst[i]>=0) { - H5T_member_t *src_memb = src->u.compnd.memb + i; - H5T_member_t *dst_memb = dst->u.compnd.memb + src2dst[i]; + H5T_cmemb_t *src_memb = src->u.compnd.memb + i; + H5T_cmemb_t *dst_memb = dst->u.compnd.memb + src2dst[i]; if (src_memb->ndims != dst_memb->ndims) { HRETURN_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "source and dest members have incompatible " @@ -687,8 +694,8 @@ H5T_conv_struct(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, H5T_t *src = NULL; /*source data type */ H5T_t *dst = NULL; /*destination data type */ intn *src2dst = NULL; /*maps src member to dst member */ - H5T_member_t *src_memb = NULL; /*source struct member descript.*/ - H5T_member_t *dst_memb = NULL; /*destination struct memb desc. */ + H5T_cmemb_t *src_memb = NULL; /*source struct member descript.*/ + H5T_cmemb_t *dst_memb = NULL; /*destination struct memb desc. */ size_t offset; /*byte offset wrt struct */ size_t src_delta, dst_delta; /*source & destination stride */ uintn elmtno; @@ -754,8 +761,8 @@ H5T_conv_struct(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, /* * Insure that members are sorted. */ - H5T_sort_by_offset (src); - H5T_sort_by_offset (dst); + H5T_sort_value(src); + H5T_sort_value(dst); src2dst = priv->src2dst; /* @@ -861,6 +868,298 @@ H5T_conv_struct(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, /*------------------------------------------------------------------------- + * Function: H5T_conv_enum_init + * + * Purpose: Initialize information for H5T_conv_enum(). + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Monday, January 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_conv_enum_init(H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata) +{ + H5T_enum_struct_t *priv=NULL; /*private conversion data */ + intn n; /*src value cast as native int */ + intn domain[2]; /*min and max source values */ + intn *map=NULL; /*map from src value to dst idx */ + intn length; /*nelmts in map array */ + herr_t ret_value=FAIL; /*return value */ + intn i, j; /*counters */ + + FUNC_ENTER(H5T_conv_enum_init, FAIL); + + cdata->need_bkg = H5T_BKG_NO; + if (NULL==(priv=cdata->priv=H5MM_calloc(sizeof(*priv)))) { + HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed"); + } + if (0==src->u.enumer.nmembs) { + HRETURN(SUCCEED); + } + + /* + * Check that the source symbol names are a subset of the destination + * symbol names and build a map from source member index to destination + * member index. + */ + H5T_sort_name(src); + H5T_sort_name(dst); + if (NULL==(priv->src2dst=H5MM_malloc(src->u.enumer.nmembs*sizeof(int)))) { + HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed");; + } + for (i=0, j=0; + i<src->u.enumer.nmembs && j<dst->u.enumer.nmembs; + i++, j++) { + while (j<dst->u.enumer.nmembs && + HDstrcmp(src->u.enumer.name[i], dst->u.enumer.name[j])) j++; + if (j>=dst->u.enumer.nmembs) { + HRETURN_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, + "source type is not a subset of destination type"); + } + priv->src2dst[i] = j; + } + + /* + * The conversion function will use an O(log N) lookup method for each + * value converted. However, if all of the following constraints are met + * then we can build a perfect hash table and use an O(1) lookup method. + * + * A: The source data type size matches one of our native data type + * sizes. + * + * B: After casting the source value bit pattern to a native type + * the size of the range of values is less than 20% larger than + * the number of values. + * + * If this special case is met then we use the source bit pattern cast as + * a native integer type as an index into the `val2dst'. The values of + * that array are the index numbers in the destination type or negative + * if the entry is unused. + */ + if (1==src->size || sizeof(short)==src->size || sizeof(int)==src->size) { + for (i=0; i<src->u.enumer.nmembs; i++) { + if (1==src->size) { + n = *((signed char*)(src->u.enumer.value+i)); + } else if (sizeof(short)==src->size) { + n = *((short*)(src->u.enumer.value+i*src->size)); + } else { + n = *((int*)(src->u.enumer.value+i*src->size)); + } + if (0==i) { + domain[0] = domain[1] = n; + } else { + domain[0] = MIN(domain[0], n); + domain[1] = MAX(domain[1], n); + } + } + + length = (domain[1]-domain[0])+1; + if (src->u.enumer.nmembs<2 || + (double)length/src->u.enumer.nmembs<1.2) { + priv->base = domain[0]; + priv->length = length; + if (NULL==(map=H5MM_malloc(length*sizeof(int)))) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed"); + } + for (i=0; i<length; i++) map[i] = -1; /*entry unused*/ + for (i=0; i<src->u.enumer.nmembs; i++) { + if (1==src->size) { + n = *((signed char*)(src->u.enumer.value+i)); + } else if (sizeof(short)==src->size) { + n = *((short*)(src->u.enumer.value+i*src->size)); + } else { + n = *((int*)(src->u.enumer.value+i*src->size)); + } + n -= priv->base; + assert(n>=0 && n<priv->length); + assert(map[n]<0); + map[n] = priv->src2dst[i]; + } + + /* + * Replace original src2dst array with our new one. The original + * was indexed by source member number while the new one is + * indexed by source values. + */ + H5MM_xfree(priv->src2dst); + priv->src2dst = map; + HGOTO_DONE(SUCCEED); + } + } + ret_value = SUCCEED; + + done: + if (ret_value<0 && priv) { + H5MM_xfree(priv->src2dst); + H5MM_xfree(priv); + cdata->priv = NULL; + } + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5T_conv_enum + * + * Purpose: Converts one type of enumerated data to another. + * + * Return: Success: Non-negative + * + * Failure: negative + * + * Programmer: Robb Matzke + * Monday, January 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5T_conv_enum(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, + size_t nelmts, void *_buf, void __unused__ *bkg) +{ + uint8_t *buf = (uint8_t*)_buf; /*cast for pointer arithmetic */ + H5T_t *src=NULL, *dst=NULL; /*src and dst data types */ + uint8_t *s=NULL, *d=NULL; /*src and dst BUF pointers */ + intn src_delta, dst_delta; /*conversion strides */ + intn n; /*src value cast as native int */ + size_t i; /*counters */ + H5T_enum_struct_t *priv = (H5T_enum_struct_t*)(cdata->priv); + + FUNC_ENTER(H5T_conv_enum, FAIL); + switch (cdata->command) { + case H5T_CONV_INIT: + /* + * Determine if this conversion function applies to the conversion + * path SRC_ID->DST_ID. If not return failure; otherwise initialize + * the `priv' field of `cdata' with information about the underlying + * integer conversion. + */ + if (H5I_DATATYPE != H5I_get_type(src_id) || + NULL == (src = H5I_object(src_id)) || + H5I_DATATYPE != H5I_get_type(dst_id) || + NULL == (dst = H5I_object(dst_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type"); + } + assert (H5T_ENUM==src->type); + assert (H5T_ENUM==dst->type); + if (H5T_conv_enum_init(src, dst, cdata)<0) { + HRETURN_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, + "unable to initialize private data"); + } + break; + + case H5T_CONV_FREE: +#ifdef H5T_DEBUG + if (H5DEBUG(T)) { + fprintf(H5DEBUG(T), " Using %s mapping function (%s)\n", + priv->length?"O(N)":"O(N log N)", "N==nelmts"); + } +#endif + if (priv) { + H5MM_xfree(priv->src2dst); + H5MM_xfree(priv); + } + cdata->priv = NULL; + break; + + case H5T_CONV_CONV: + if (H5I_DATATYPE != H5I_get_type(src_id) || + NULL == (src = H5I_object(src_id)) || + H5I_DATATYPE != H5I_get_type(dst_id) || + NULL == (dst = H5I_object(dst_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type"); + } + assert (H5T_ENUM==src->type); + assert (H5T_ENUM==dst->type); + H5T_sort_name(src); + H5T_sort_name(dst); + + /* + * Direction of conversion. + */ + if (dst->size <= src->size) { + src_delta = src->size; + dst_delta = dst->size; + s = d = buf; + } else { + src_delta = -(src->size); + dst_delta = -(dst->size); + s = buf + (nelmts-1) * src->size; + d = buf + (nelmts-1) * dst->size; + } + + for (i=0; i<nelmts; i++, s+=src_delta, d+=dst_delta) { + if (priv->length) { + /* Use O(1) lookup */ + if (1==src->size) { + n = *((signed char*)s); + } else if (sizeof(short)==src->size) { + n = *((short*)s); + } else { + n = *((int*)s); + } + if (n<0 || n>=priv->length || priv->src2dst[n]<0) { + if (!H5T_overflow_g || + (H5T_overflow_g)(src_id, dst_id, s, d)<0) { + HDmemset(d, 0xff, dst->size); + } + } else { + HDmemcpy(d, + dst->u.enumer.value+priv->src2dst[n]*dst->size, + dst->size); + } + } else { + /* Use O(log N) lookup */ + int lt = 0; + int rt = src->u.enumer.nmembs; + int md, cmp; + while (lt<rt) { + md = (lt+rt)/2; + cmp = HDmemcmp(s, src->u.enumer.value+md*src->size, + src->size); + if (cmp<0) { + rt = md; + } else if (cmp>0) { + lt = md+1; + } else { + break; + } + } + if (lt>=rt) { + if (!H5T_overflow_g || + (H5T_overflow_g)(src_id, dst_id, s, d)<0) { + HDmemset(d, 0xff, dst->size); + } + } else { + HDmemcpy(d, + dst->u.enumer.value+priv->src2dst[md]*dst->size, + dst->size); + } + } + } + break; + + default: + /* Some other command we don't know about yet.*/ + HRETURN_ERROR (H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, + "unknown conversion command"); + } + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- * Function: H5T_conv_i_i * * Purpose: Convert one integer type to another. This is the catch-all |