summaryrefslogtreecommitdiffstats
path: root/src/H5Tconv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Tconv.c')
-rw-r--r--src/H5Tconv.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/src/H5Tconv.c b/src/H5Tconv.c
index 862c19a..cd7a301 100644
--- a/src/H5Tconv.c
+++ b/src/H5Tconv.c
@@ -2935,6 +2935,7 @@ H5T_conv_i_i (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, hsize_t nelmts,
}
} else if (src->u.atomic.prec<dst->u.atomic.prec) {
H5T_bit_copy (d, dst->u.atomic.offset, s, src->u.atomic.offset, src->u.atomic.prec);
+ /* Why is it set to TRUE? */
H5T_bit_set (d, dst->u.atomic.offset+src->u.atomic.prec, dst->u.atomic.prec-src->u.atomic.prec, TRUE);
} else {
H5T_bit_copy (d, dst->u.atomic.offset, s, src->u.atomic.offset, dst->u.atomic.prec);
@@ -8363,3 +8364,384 @@ H5T_conv_i32le_f64le (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
done:
FUNC_LEAVE_NOAPI(ret_value);
}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_conv_f_i
+ *
+ * Purpose: Convert one floating-point type to an integer. This is
+ * the catch-all function for float-integer conversions and
+ * is probably not particularly fast.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, Jan 21, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_conv_f_i (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, hsize_t nelmts,
+ size_t buf_stride, size_t UNUSED bkg_stride, void *buf, void UNUSED *bkg,
+ hid_t UNUSED dxpl_id)
+{
+ /* Traversal-related variables */
+ H5T_t *src_p; /*source data type */
+ H5T_t *dst_p; /*destination data type */
+ H5T_atomic_t src; /*atomic source info */
+ H5T_atomic_t dst; /*atomic destination info */
+ int direction; /*forward or backward traversal */
+ hsize_t elmtno; /*element number */
+ size_t half_size; /*half the type size */
+ hsize_t olap; /*num overlapping elements */
+ ssize_t bitno; /*bit number */
+ uint8_t *s, *sp, *d, *dp; /*source and dest traversal ptrs*/
+ uint8_t dbuf[64]; /*temp destination buffer */
+
+ /* Conversion-related variables */
+ hssize_t expo; /*source exponent */
+ hssize_t mant; /*source mantissa */
+ hssize_t sign; /*source sign bit value */
+ uint8_t *int_buf; /*buffer for temporary value */
+ size_t buf_size; /*buffer size for temporary value */
+ size_t msize; /*mantissa size after restored implied 1 */
+ size_t i; /*miscellaneous counters */
+ size_t first; /*first bit(MSB) in an integer */
+ ssize_t sfirst; /*a signed version of `first' */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5T_conv_f_i, FAIL);
+
+ switch (cdata->command) {
+ case H5T_CONV_INIT:
+ if (NULL==(src_p=H5I_object(src_id)) ||
+ NULL==(dst_p=H5I_object(dst_id)))
+ HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type");
+ src = src_p->u.atomic;
+ dst = dst_p->u.atomic;
+ if (H5T_ORDER_LE!=src.order && H5T_ORDER_BE!=src.order)
+ HGOTO_ERROR (H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order");
+ if (dst_p->size>sizeof(dbuf))
+ HGOTO_ERROR (H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "destination size is too large");
+ if (8*sizeof(expo)-1<src.u.f.esize)
+ HGOTO_ERROR (H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "exponent field is too large");
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ case H5T_CONV_CONV:
+ /* Get the data types */
+ if (NULL==(src_p=H5I_object(src_id)) ||
+ NULL==(dst_p=H5I_object(dst_id)))
+ HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type");
+ src = src_p->u.atomic;
+ dst = dst_p->u.atomic;
+
+ /*
+ * Do we process the values from beginning to end or vice versa? Also,
+ * how many of the elements have the source and destination areas
+ * overlapping?
+ */
+ if (src_p->size==dst_p->size || buf_stride) {
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ olap = nelmts;
+ } else if (src_p->size>=dst_p->size) {
+ double olap_d = HDceil((double)(dst_p->size)/
+ (double)(src_p->size-dst_p->size));
+ olap = (size_t)olap_d;
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ } else {
+ double olap_d = HDceil((double)(src_p->size)/
+ (double)(dst_p->size-src_p->size));
+ olap = (size_t)olap_d;
+ sp = (uint8_t*)buf + (nelmts-1) * src_p->size;
+ dp = (uint8_t*)buf + (nelmts-1) * dst_p->size;
+ direction = -1;
+ }
+
+ /* Allocate enough space for the buffer holding temporary
+ * converted value
+ */
+ buf_size = (int)pow(2, src.u.f.esize) / 8 + 1;
+ int_buf = (uint8_t*)HDcalloc(buf_size, 1);
+
+ /* The conversion loop */
+ for (elmtno=0; elmtno<nelmts; elmtno++) {
+ /*
+ * If the source and destination buffers overlap then use a
+ * temporary buffer for the destination.
+ */
+ if (direction>0) {
+ s = sp;
+ d = elmtno<olap ? dbuf : dp;
+ } else {
+ s = sp;
+ d = elmtno+olap >= nelmts ? dbuf : dp;
+ }
+#ifndef NDEBUG
+ /* I don't quite trust the overlap calculations yet --rpm */
+ if (d==dbuf) {
+ assert ((dp>=sp && dp<sp+src_p->size) ||
+ (sp>=dp && sp<dp+dst_p->size));
+ } else {
+ assert ((dp<sp && dp+dst_p->size<=sp) ||
+ (sp<dp && sp+src_p->size<=dp));
+ }
+#endif
+ /*
+ * Put the data in little endian order so our loops aren't so
+ * complicated. We'll do all the conversion stuff assuming
+ * little endian and then we'll fix the order at the end.
+ */
+ if (H5T_ORDER_BE==src.order) {
+ half_size = src_p->size/2;
+ for (i=0; i<half_size; i++) {
+ uint8_t tmp = s[src_p->size-(i+1)];
+ s[src_p->size-(i+1)] = s[i];
+ s[i] = tmp;
+ }
+ }
+
+ /*zero-set all destination bits*/
+ H5T_bit_set (d, dst.offset, dst.prec, FALSE);
+
+ /*
+ * Find the sign bit value of the source.
+ */
+ sign = H5T_bit_get_d(s, src.prec-1, 1);
+
+ /*
+ * Check for special cases: +0, -0, +Inf, -Inf, NaN
+ */
+ if (H5T_bit_find (s, src.u.f.mpos, src.u.f.msize,
+ H5T_BIT_LSB, TRUE)<0) {
+ if (H5T_bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, TRUE)<0) {
+ /* +0 or -0 */
+ /* Set all bits to zero */
+ goto padding;
+ } else if (H5T_bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, FALSE)<0) {
+ /* +Infinity or -Infinity */
+ if(sign) { /* -Infinity */
+ if (H5T_SGN_2==dst.u.i.sign)
+ H5T_bit_set (d, dst.prec-1, 1, TRUE);
+ } else { /* +Infinity */
+ if (H5T_SGN_NONE==dst.u.i.sign)
+ H5T_bit_set (d, dst.offset, dst.prec, TRUE);
+ else if (H5T_SGN_2==dst.u.i.sign)
+ H5T_bit_set (d, dst.offset, dst.prec-1, TRUE);
+ }
+ goto padding;
+ }
+ } else if (H5T_bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, FALSE)<0) {
+ /*
+ * NaN. There are many NaN values, so we just set all bits to zero.
+ */
+ goto padding;
+ }
+
+ /*
+ * Get the exponent as an unsigned quantity from the section of
+ * the source bit field where it's located. Not expecting
+ * exponent to be greater than the maximal value of hssize_t.
+ */
+ expo = H5T_bit_get_d(s, src.u.f.epos, src.u.f.esize);
+
+ /*
+ * Calculate the true source exponent by adjusting according to
+ * the source exponent bias.
+ */
+ if (0==expo || H5T_NORM_NONE==src.u.f.norm) {
+ /*Don't get this part*/
+ bitno = H5T_bit_find(s, src.u.f.mpos, src.u.f.msize,
+ H5T_BIT_MSB, TRUE);
+ assert(bitno>=0);
+ expo -= (src.u.f.ebias-1) + (src.u.f.msize-bitno);
+ } else if (H5T_NORM_IMPLIED==src.u.f.norm) {
+ expo -= src.u.f.ebias;
+ } else {
+ assert("normalization method not implemented yet" && 0);
+ HDabort();
+ }
+
+ /*
+ * Get the mantissa as bit vector from the section of
+ * the source bit field where it's located.
+ * Keep the little-endian order in the buffer.
+ * A sequence 0x01020304 will be like in the buffer,
+ * 04 03 02 01
+ * | | | |
+ * V V V V
+ * buf[0] buf[1] buf[2] buf[3]
+ */
+ H5T_bit_copy(int_buf, 0, s, src.u.f.mpos, src.u.f.msize);
+
+ /*
+ * Restore the implicit bit for mantissa if it's implied.
+ * Equivalent to mantissa |= (hsize_t)1<<src.u.f.msize.
+ */
+ if (H5T_NORM_IMPLIED==src.u.f.norm) {
+ H5T_bit_inc(int_buf, src.u.f.msize, 8*buf_size-src.u.f.msize);
+ msize = src.u.f.msize + 1;
+ } else
+ msize = src.u.f.msize;
+
+ /* Keep the print commands for future debugging */
+ /*fprintf(stderr, "expo=%ld ", expo);
+ fprintf(stderr, "src.u.f.msize=%d ", src.u.f.msize);
+ fprintf(stderr, "mant=0x%016x\n", mant);*/
+
+ /*
+ * Shift mantissa part by exponent minus mantissa size(right shift),
+ * or by mantissa size minus exponent(left shift).
+ */
+ if( H5T_NORM_IMPLIED==src.u.f.norm) {
+ H5T_bit_shift(int_buf, expo - src.u.f.msize, buf_size);
+ } else if(H5T_NORM_NONE==src.u.f.norm) {
+ /* How to do this? */
+ }
+
+ /*fprintf(stderr, "int_buf=");
+ for(i=0; i<buf_size; i++)
+ fprintf(stderr, "%02x ", int_buf[i]);
+ fprintf(stderr, "\n");*/
+
+ /* Convert to integer representation if negative.
+ * equivalent to ~(value - 1).
+ */
+ if(sign) {
+ H5T_bit_dec(int_buf, 0, 8*buf_size);
+ /*fprintf(stderr, "decremented int_buf=");
+ for(i=0; i<buf_size; i++)
+ fprintf(stderr, "%02x ", int_buf[i]);
+ fprintf(stderr, "\n");*/
+
+ H5T_bit_neg(int_buf, 0, 8*buf_size);
+ /*fprintf(stderr, "negated int_buf=");
+ for(i=0; i<buf_size; i++)
+ fprintf(stderr, "%02x ", int_buf[i]);
+ fprintf(stderr, "\n");*/
+ }
+
+ /*
+ * What is the bit position for the most significant bit(MSB) of S
+ * which is set?
+ */
+ sfirst = H5T_bit_find(int_buf, 0, 8*buf_size, H5T_BIT_MSB, TRUE);
+ first = (size_t)sfirst;
+ /*fprintf(stderr, " first=%d\n", first);*/
+
+ if(sfirst < 0) {
+ /*
+ * The source has no bits set and must therefore be zero.
+ * Set the destination to zero - nothing to do.
+ */
+ } else if (H5T_SGN_NONE==dst.u.i.sign) {
+ /*
+ * Destination is unsigned. If the source value is greater
+ * than the maximal destination value then it overflows, the
+ * destination will be set to the maximum possible value. When the
+ * source is negative, underflow happens. Set the destination to be
+ * zero.
+ */
+ if(!sign) {
+ if (first>=dst.prec) {
+ /*overflow*/
+ if (!H5T_overflow_g || (H5T_overflow_g)(src_id, dst_id, s, d)<0) {
+ H5T_bit_set (d, dst.offset, dst.prec, TRUE);
+ }
+ } else if (first <dst.prec) {
+ /*copy source value into it*/
+ H5T_bit_copy (d, dst.offset, int_buf, 0, first+1);
+ }
+ }
+ } else if (H5T_SGN_2==dst.u.i.sign) {
+ if(sign) { /*negative*/
+ /* if overflows, do nothing except turn on the sign bit
+ * because 0x80...00 is the biggest negative value.
+ */
+ if(first < dst.prec-1)
+ H5T_bit_copy (d, dst.offset, int_buf, 0, first+1);
+
+ H5T_bit_set (d, (dst.offset + dst.prec-1), 1, TRUE);
+ } else { /*positive*/
+ if (first >= dst.prec-1) {
+ /*overflow*/
+ if (!H5T_overflow_g || (H5T_overflow_g)(src_id, dst_id, s, d)<0) {
+ H5T_bit_set (d, dst.offset, dst.prec-1, TRUE);
+ }
+ } else if(first < dst.prec-1) {
+ H5T_bit_copy (d, dst.offset, int_buf, 0, first+1);
+ }
+ }
+ }
+
+ /*fprintf(stderr, "dst.offset=%d, d=0x", dst.offset);
+ for(i=0; i<dst.prec/8; i++)
+ fprintf(stderr, "%02x ", d[i]);
+ fprintf(stderr, "\n");*/
+
+ padding:
+ /*
+ * Set padding areas in destination.
+ */
+ if (dst.offset>0) {
+ assert (H5T_PAD_ZERO==dst.lsb_pad || H5T_PAD_ONE==dst.lsb_pad);
+ H5T_bit_set (d, 0, dst.offset, (hbool_t)(H5T_PAD_ONE==dst.lsb_pad));
+ }
+ if (dst.offset+dst.prec!=8*dst_p->size) {
+ assert (H5T_PAD_ZERO==dst.msb_pad || H5T_PAD_ONE==dst.msb_pad);
+ H5T_bit_set (d, dst.offset+dst.prec,
+ 8*dst_p->size - (dst.offset+ dst.prec),
+ (hbool_t)(H5T_PAD_ONE==dst.msb_pad));
+ }
+
+ /*
+ * Put the destination in the correct byte order. See note at
+ * beginning of loop.
+ */
+ if (H5T_ORDER_BE==dst.order) {
+ half_size = dst_p->size/2;
+ for (i=0; i<half_size; i++) {
+ uint8_t tmp = d[dst_p->size-(i+1)];
+ d[dst_p->size-(i+1)] = d[i];
+ d[i] = tmp;
+ }
+ }
+
+ /*
+ * If we had used a temporary buffer for the destination then we
+ * should copy the value to the true destination buffer.
+ */
+ if (d==dbuf)
+ HDmemcpy (dp, d, dst_p->size);
+ if (buf_stride) {
+ sp += direction * buf_stride;
+ dp += direction * buf_stride;
+ } else {
+ sp += direction * src_p->size;
+ dp += direction * dst_p->size;
+ }
+
+ HDmemset(int_buf, 0, buf_size);
+ }
+
+ HDfree(int_buf);
+
+ break;
+
+ default:
+ HGOTO_ERROR (H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command");
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+}