/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic HDF5 document set and * * is linked from the top-level documents page. It can also be found at * * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Module Info: Operations on bit vectors. A bit vector is an array of bytes * with the least-significant bits in the first byte. That is, * the bytes are in little-endian order. */ #define H5T_PACKAGE /*suppress error about including H5Tpkg */ #include "H5private.h" /*generic functions */ #include "H5Eprivate.h" /*error handling */ #include "H5Iprivate.h" /*ID functions */ #include "H5MMprivate.h" /* Memory management */ #include "H5Tpkg.h" /*data-type functions */ /*------------------------------------------------------------------------- * Function: H5T_bit_copy * * Purpose: Copies bits from one vector to another. * * Return: void * * Programmer: Robb Matzke * Wednesday, June 10, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void H5T_bit_copy (uint8_t *dst, size_t dst_offset, const uint8_t *src, size_t src_offset, size_t size) { int shift; unsigned mask_lo, mask_hi; int s_idx, d_idx; /* * Normalize the offset to be a byte number and a bit offset within that * byte. */ s_idx = (int)src_offset / 8; d_idx = (int)dst_offset / 8; src_offset %= 8; dst_offset %= 8; /* * Get things rolling. This means copying bits until we're aligned on a * source byte. This the following example, five bits are copied to the * destination. * * src[s_idx] * +---------------+---------------+ * |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| * +---------------+---------------+ * ... : : : : : | | | | | * ... v v v v v V V V V V * ...+---------------+---------------+ * ...|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| * ...+---------------+---------------+ * dst[d_idx+1] dst[d_idx] */ while (src_offset && size>0) { unsigned nbits = (unsigned)MIN3 (size, 8-dst_offset, 8-src_offset); unsigned mask = (1<>src_offset)&mask) << dst_offset; src_offset += nbits; if (src_offset>=8) { s_idx++; src_offset %= 8; } dst_offset += nbits; if (dst_offset>=8) { d_idx++; dst_offset %= 8; } size -= nbits; } /* * The middle bits. We are aligned on a source byte which needs to be * copied to two (or one in the degenerate case) destination bytes. * * src[s_idx] * +---------------+ * |7 6 5 4 3 2 1 0| * +---------------+ * | | | | | | | | * V V V V V V V V * +---------------+---------------+ * |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| * +---------------+---------------+ * dst[d_idx+1] dst[d_idx] * * * Calculate shifts and masks. See diagrams below. MASK_LO in this * example is 0x1f (the low five bits) and MASK_HI is 0xe0 (the high three * bits). SHIFT is three since the source must be shifted right three bits * to line up with the destination. */ shift = (int)dst_offset; mask_lo = (1<<(8-shift))-1; mask_hi = (~mask_lo) & 0xff; for (/*void*/; size>8; size-=8, d_idx++, s_idx++) { if (shift) { dst[d_idx+0] &= ~(mask_lo<>(8-shift)); dst[d_idx+1] |= (src[s_idx] & mask_hi) >> (8-shift); } else { dst[d_idx] = src[s_idx]; } } /* Finish up */ while (size>0) { unsigned nbits = (unsigned)MIN3 (size, 8-dst_offset, 8-src_offset); unsigned mask = (1<>src_offset)&mask) << dst_offset; src_offset += nbits; if (src_offset>=8) { s_idx++; src_offset %= 8; } dst_offset += nbits; if (dst_offset>=8) { d_idx++; dst_offset %= 8; } size -= nbits; } } /*------------------------------------------------------------------------- * Function: H5T_bit_shift * * Purpose: Simulation of hardware shifting. Shifts a bit vector * in a way similar to shifting a variable value, like * value <<= 3, or value >>= 16. SHIFT_DIST is positive for * left shift, negative for right shift. The bit vector starts * at OFFSET and is SIZE long. The caller has to make sure * SIZE+OFFSET doesn't exceed the size of BUF. * * For example, if we have a bit sequence 00011100, offset=2, * size=3, shift_dist=2, the result will be 00010000. * * Return: void * * Programmer: Raymond Lu * Monday, April 12, 2004 * * Modifications: * *------------------------------------------------------------------------- */ void H5T_bit_shift (uint8_t *buf, ssize_t shift_dist, size_t offset, size_t size) { uint8_t *tmp_buf; FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5T_bit_shift); /* Sanity check */ assert(buf); assert(size); if(!shift_dist) goto done; if((size_t)ABS(shift_dist) >= size) { H5T_bit_set(buf, offset, size, 0); goto done; } tmp_buf = (uint8_t*)H5MM_calloc(size/8+1); assert(tmp_buf); /* Shift vector by making copies */ if(shift_dist > 0) { /* left shift */ /* Copy part to be shifted to a temporary buffer */ H5T_bit_copy (tmp_buf, 0, buf, offset, (size_t)(size-shift_dist)); /* Copy it back to the original buffer */ H5T_bit_copy (buf, offset+shift_dist, tmp_buf, 0, (size_t)(size-shift_dist)); /* Zero-set the left part*/ H5T_bit_set(buf, offset, (size_t)shift_dist, 0); } else { /* right shift */ shift_dist = - shift_dist; H5T_bit_copy(tmp_buf, 0, buf, offset+shift_dist, (size_t)(size-shift_dist)); H5T_bit_copy (buf, offset, tmp_buf, 0, (size_t)(size-shift_dist)); H5T_bit_set(buf, offset+size-shift_dist, (size_t)shift_dist, 0); } /* Free temporary buffer */ H5MM_xfree(tmp_buf); done: FUNC_LEAVE_NOAPI_VOID } /*------------------------------------------------------------------------- * Function: H5T_bit_get_d * * Purpose: Return a small bit sequence as a number. Bit vector starts * at OFFSET and is SIZE bits long. * * Return: Success: The bit sequence interpretted as an unsigned * integer. * * Failure: 0 * * Programmer: Robb Matzke * Tuesday, June 23, 1998 * * Modifications: * *------------------------------------------------------------------------- */ hsize_t H5T_bit_get_d (uint8_t *buf, size_t offset, size_t size) { hsize_t val=0; size_t i, hs; hsize_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOFUNC(H5T_bit_get_d); assert (8*sizeof(val)>=size); H5T_bit_copy ((uint8_t*)&val, 0, buf, offset, size); switch (H5T_native_order_g) { case H5T_ORDER_LE: break; case H5T_ORDER_BE: for (i=0, hs=sizeof(val)/2; i=size); switch (H5T_native_order_g) { case H5T_ORDER_LE: break; case H5T_ORDER_BE: for (i=0, hs=sizeof(val)/2; i=8) { buf[idx++] = value ? 0xff : 0x00; size -= 8; } /* The last partial byte */ if (size) { if (value) { buf[idx] |= (1<0; iu++, size--) { if (value==(hbool_t)((buf[idx]>>iu) & 0x01)) HGOTO_DONE(8*idx+(ssize_t)iu - base); } offset = 0; idx++; } /* Middle */ while (size>=8) { if ((value?0x00:0xff)!=buf[idx]) { for (i=0; i<8; i++) { if (value==(hbool_t)((buf[idx]>>i) & 0x01)) HGOTO_DONE(8*idx+i - base); } } size -= 8; idx++; } /* End */ for (i=0; i<(ssize_t)size; i++) { if (value==(hbool_t)((buf[idx]>>i) & 0x01)) HGOTO_DONE(8*idx+i - base); } break; case H5T_BIT_MSB: /* Calculate index */ idx = (ssize_t)((offset+size-1) / 8); offset %= 8; /* Beginning */ if (size>8-offset && (offset+size)%8) { for (iu=(offset+size)%8; iu>0; --iu, --size) { if (value==(hbool_t)((buf[idx]>>(iu-1)) & 0x01)) HGOTO_DONE(8*idx+(ssize_t)(iu-1) - base); } --idx; } /* Middle */ while (size>=8) { if ((value?0x00:0xff)!=buf[idx]) { for (i=7; i>=0; --i) { if (value==(hbool_t)((buf[idx]>>i) & 0x01)) HGOTO_DONE(8*idx+i - base); } } size -= 8; --idx; } /* End */ if (size>0) { for (iu=offset+size; iu>offset; --iu) { if (value==(hbool_t)((buf[idx]>>(iu-1)) & 0x01)) HGOTO_DONE(8*idx+(ssize_t)(iu-1) - base); } } break; } done: FUNC_LEAVE_NOAPI(ret_value); } /*------------------------------------------------------------------------- * Function: H5T_bit_inc * * Purpose: Increment part of a bit field by adding 1. The bit field * starts with bit position START and is SIZE bits long. * * Return: Success: The carry-out value. One if overflows, * zero otherwise. * * Failure: Negative * * Programmer: Robb Matzke * Friday, June 26, 1998 * * Modifications: * *------------------------------------------------------------------------- */ htri_t H5T_bit_inc(uint8_t *buf, size_t start, size_t size) { size_t idx = start / 8; unsigned carry = 1; unsigned acc, mask; /* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5T_bit_inc); assert(buf); start %= 8; /* The first partial byte */ if (start) { if (size+start<8) mask = (1<>start) & mask; acc += 1; carry = acc & (1<=8) { acc = buf[idx]; acc += 1; carry = acc & 0x100; buf[idx] = acc & 0xff; idx++; size -= 8; } /* The last bits */ if (carry && size>0) { mask = (1< idx) { /*bit sequence doesn't end in the same byte as starts*/ /* Example: a sequence like 11000100 and start = 3. We substract 00001000 from * it and get 10111100. If a sequence is 00000111, we do right shift for START * bits and get 00000000. So we need to borrow from higher byte when we substract * 00001000. */ if(!(buf[idx] >> pos)) borrow = 1; buf[idx] -= 1 << pos; idx++; size -= (8 - pos); } else { /* bit sequence ends in the same byte as starts */ /* Example: a sequence like 11000100 and pos=3, size=3. We substract 00001000 * and get 10111100. A bit is borrowed from 6th bit(buf[idx]>>6=00000010, tmp>>6=00000011, * not equal). We need to put this bit back by increment 1000000. */ tmp = buf[idx]; buf[idx] -= 1 << pos; if((buf[idx] >> (pos+size)) != tmp >> (pos+size)) { buf[idx] += 1 << (pos+size); borrow = 1; } goto done; } /* The middle bytes */ while (borrow && size>=8) { if(buf[idx]) borrow = 0; buf[idx] -= 1; idx++; size -= 8; } /* The last partial byte */ if (borrow && size>0) { /* Similar to the first byte case, where sequence ends in the same byte as starts */ tmp = buf[idx]; buf[idx] -= 1; if((buf[idx] >> size) != tmp >> size) buf[idx] += 1 << size; } done: FUNC_LEAVE_NOAPI(borrow ? TRUE : FALSE); } /*------------------------------------------------------------------------- * Function: H5T_bit_neg * * Purpose: negate part of a bit sequence. The bit * field starts with bit position START and is SIZE bits long. * * Return: void * * Programmer: Raymond Lu * March 19, 2004 * * Modifications: * *------------------------------------------------------------------------- */ void H5T_bit_neg(uint8_t *buf, size_t start, size_t size) { size_t idx = start / 8; size_t pos = start % 8; uint8_t tmp; /* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5T_bit_neg); assert(buf); assert(size); /* The first partial byte */ tmp = buf[idx]; tmp = ~tmp; /* Simply copy the negated bit field back to the original byte */ if((size+start-1)/8 > idx) { /*bit sequence doesn't end in the same byte as starts*/ H5T_bit_copy (&(buf[idx]), pos, &tmp, pos, (8-pos)); idx++; size -= (8 - pos); } else { /* bit sequence ends in the same byte as starts */ H5T_bit_copy (&(buf[idx]), pos, &tmp, pos, size); goto done; } /* The middle bytes */ while (size>=8) { buf[idx] = ~(buf[idx]); idx++; size -= 8; } /* The last partial byte */ if (size>0) { /* Similar to the first byte case, where sequence ends in the same byte as starts */ tmp = buf[idx]; tmp = ~tmp; H5T_bit_copy (&(buf[idx]), 0, &tmp, 0, size); } done: FUNC_LEAVE_NOAPI_VOID }