X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=include%2Fbabeltrace%2Fbitfield.h;h=c0e4c0adccddf312af59cd94f61915e9f036c9a1;hb=51950aa03c51638d9710abfc1976429fa661c7d0;hp=449923c2a801ae1569c9da8d42f943494269e44c;hpb=6a7b33456f65d964463e4bab4eff318da7f0a4c1;p=babeltrace.git diff --git a/include/babeltrace/bitfield.h b/include/babeltrace/bitfield.h index 449923c2..c0e4c0ad 100644 --- a/include/babeltrace/bitfield.h +++ b/include/babeltrace/bitfield.h @@ -2,11 +2,7 @@ #define _BABELTRACE_BITFIELD_H /* - * BabelTrace - * - * Bitfields read/write functions. - * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010-2019 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -17,44 +13,192 @@ * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include /* C99 5.2.4.2 Numerical limits */ -#include /* C99 5.2.4.2 Numerical limits */ -#include /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ -#include - -/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */ -#define _bt_piecewise_rshift(v, shift) \ -({ \ - unsigned long sb = (shift) / (sizeof(v) * CHAR_BIT - 1); \ - unsigned long final = (shift) % (sizeof(v) * CHAR_BIT - 1); \ - typeof(v) _v = (v); \ - \ - for (; sb; sb--) \ - _v >>= sizeof(v) * CHAR_BIT - 1; \ - _v >>= final; \ -}) - -#define _bt_piecewise_lshift(v, shift) \ -({ \ - unsigned long sb = (shift) / (sizeof(v) * CHAR_BIT - 1); \ - unsigned long final = (shift) % (sizeof(v) * CHAR_BIT - 1); \ - typeof(v) _v = (v); \ - \ - for (; sb; sb--) \ - _v <<= sizeof(v) * CHAR_BIT - 1; \ - _v <<= final; \ -}) +#include /* C99 7.16 bool type */ +#include /* C99 5.2.4.2 Numerical limits */ +#include /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ + +/* + * This header strictly follows the C99 standard, except for use of the + * compiler-specific __typeof__. + */ + +/* + * This bitfield header requires the compiler representation of signed + * integers to be two's complement. + */ +#if (-1 != ~0) +#error "bitfield.h requires the compiler representation of signed integers to be two's complement." +#endif + +/* + * _bt_is_signed_type() willingly generates comparison of unsigned + * expression < 0, which is always false. Silence compiler warnings. + */ +#ifdef __GNUC__ +# define _BT_DIAG_PUSH _Pragma("GCC diagnostic push") +# define _BT_DIAG_POP _Pragma("GCC diagnostic pop") + +# define _BT_DIAG_STRINGIFY_1(x) #x +# define _BT_DIAG_STRINGIFY(x) _BT_DIAG_STRINGIFY_1(x) + +# define _BT_DIAG_IGNORE(option) \ + _Pragma(_BT_DIAG_STRINGIFY(GCC diagnostic ignored option)) +# define _BT_DIAG_IGNORE_TYPE_LIMITS _BT_DIAG_IGNORE("-Wtype-limits") +#else +# define _BT_DIAG_PUSH +# define _BT_DIAG_POP +# define _BT_DIAG_IGNORE +#endif -#define _bt_is_signed_type(type) (((type)(-1)) < 0) +#define _bt_is_signed_type(type) ((type) -1 < (type) 0) -#define _bt_unsigned_cast(type, v) \ -({ \ - (sizeof(v) < sizeof(type)) ? \ - ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \ - (type) (v); \ -}) +/* + * Produce a build-time error if the condition `cond` is non-zero. + * Evaluates as a size_t expression. + */ +#define _BT_BUILD_ASSERT(cond) \ + sizeof(struct { int f:(2 * !!(cond) - 1); }) + +/* + * Cast value `v` to an unsigned integer of the same size as `v`. + */ +#define _bt_cast_value_to_unsigned(v) \ + (sizeof(v) == sizeof(uint8_t) ? (uint8_t) (v) : \ + sizeof(v) == sizeof(uint16_t) ? (uint16_t) (v) : \ + sizeof(v) == sizeof(uint32_t) ? (uint32_t) (v) : \ + sizeof(v) == sizeof(uint64_t) ? (uint64_t) (v) : \ + _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t))) + +/* + * Cast value `v` to an unsigned integer type of the size of type `type` + * *without* sign-extension. + * + * The unsigned cast ensures that we're not shifting a negative value, + * which is undefined in C. However, this limits the maximum type size + * of `type` to 64-bit. Generate a compile-time error if the size of + * `type` is larger than 64-bit. + */ +#define _bt_cast_value_to_unsigned_type(type, v) \ + (sizeof(type) == sizeof(uint8_t) ? \ + (uint8_t) _bt_cast_value_to_unsigned(v) : \ + sizeof(type) == sizeof(uint16_t) ? \ + (uint16_t) _bt_cast_value_to_unsigned(v) : \ + sizeof(type) == sizeof(uint32_t) ? \ + (uint32_t) _bt_cast_value_to_unsigned(v) : \ + sizeof(type) == sizeof(uint64_t) ? \ + (uint64_t) _bt_cast_value_to_unsigned(v) : \ + _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t))) + +/* + * _bt_fill_mask evaluates to a "type" integer with all bits set. + */ +#define _bt_fill_mask(type) ((type) ~(type) 0) + +/* + * Left shift a value `v` of `shift` bits. + * + * The type of `v` can be signed or unsigned integer. + * The value of `shift` must be less than the size of `v` (in bits), + * otherwise the behavior is undefined. + * Evaluates to the result of the shift operation. + * + * According to the C99 standard, left shift of a left hand-side signed + * type is undefined if it has a negative value or if the result cannot + * be represented in the result type. This bitfield header discards the + * bits that are left-shifted beyond the result type representation, + * which is the behavior of an unsigned type left shift operation. + * Therefore, always perform left shift on an unsigned type. + * + * This macro should not be used if `shift` can be greater or equal than + * the bitwidth of `v`. See `_bt_safe_lshift`. + */ +#define _bt_lshift(v, shift) \ + ((__typeof__(v)) (_bt_cast_value_to_unsigned(v) << (shift))) + +/* + * Generate a mask of type `type` with the `length` least significant bits + * cleared, and the most significant bits set. + */ +#define _bt_make_mask_complement(type, length) \ + _bt_lshift(_bt_fill_mask(type), length) + +/* + * Generate a mask of type `type` with the `length` least significant bits + * set, and the most significant bits cleared. + */ +#define _bt_make_mask(type, length) \ + ((type) ~_bt_make_mask_complement(type, length)) + +/* + * Right shift a value `v` of `shift` bits. + * + * The type of `v` can be signed or unsigned integer. + * The value of `shift` must be less than the size of `v` (in bits), + * otherwise the behavior is undefined. + * Evaluates to the result of the shift operation. + * + * According to the C99 standard, right shift of a left hand-side signed + * type which has a negative value is implementation defined. This + * bitfield header relies on the right shift implementation carrying the + * sign bit. If the compiler implementation has a different behavior, + * emulate carrying the sign bit. + * + * This macro should not be used if `shift` can be greater or equal than + * the bitwidth of `v`. See `_bt_safe_rshift`. + */ +#if ((-1 >> 1) == -1) +#define _bt_rshift(v, shift) ((v) >> (shift)) +#else +#define _bt_rshift(v, shift) \ + ((__typeof__(v)) ((_bt_cast_value_to_unsigned(v) >> (shift)) | \ + ((v) < 0 ? _bt_make_mask_complement(__typeof__(v), \ + sizeof(v) * CHAR_BIT - (shift)) : 0))) +#endif + +/* + * Right shift a signed or unsigned integer with `shift` value being an + * arbitrary number of bits. `v` is modified by this macro. The shift + * is transformed into a sequence of `_nr_partial_shifts` consecutive + * shift operations, each of a number of bits smaller than the bitwidth + * of `v`, ending with a shift of the number of left over bits. + */ +#define _bt_safe_rshift(v, shift) \ +do { \ + unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \ + unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \ + \ + for (; _nr_partial_shifts; _nr_partial_shifts--) \ + (v) = _bt_rshift(v, sizeof(v) * CHAR_BIT - 1); \ + (v) = _bt_rshift(v, _leftover_bits); \ +} while (0) + +/* + * Left shift a signed or unsigned integer with `shift` value being an + * arbitrary number of bits. `v` is modified by this macro. The shift + * is transformed into a sequence of `_nr_partial_shifts` consecutive + * shift operations, each of a number of bits smaller than the bitwidth + * of `v`, ending with a shift of the number of left over bits. + */ +#define _bt_safe_lshift(v, shift) \ +do { \ + unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \ + unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \ + \ + for (; _nr_partial_shifts; _nr_partial_shifts--) \ + (v) = _bt_lshift(v, sizeof(v) * CHAR_BIT - 1); \ + (v) = _bt_lshift(v, _leftover_bits); \ +} while (0) /* * bt_bitfield_write - write integer to a bitfield in native endianness @@ -74,120 +218,122 @@ * Also, consecutive bitfields are placed from higher to lower bits. */ -#define _bt_bitfield_write_le(ptr, _start, _length, _v) \ +#define _bt_bitfield_write_le(ptr, type, start, length, v) \ do { \ - typeof(_v) v = (_v); \ - typeof(*(ptr)) mask, cmask; \ - unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ - unsigned long start = (_start), length = (_length); \ - unsigned long start_unit, end_unit, this_unit; \ - unsigned long end, cshift; /* cshift is "complement shift" */ \ + __typeof__(v) _v = (v); \ + type *_ptr = (void *) (ptr); \ + unsigned long _start = (start), _length = (length); \ + type _mask, _cmask; \ + unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long _start_unit, _end_unit, _this_unit; \ + unsigned long _end, _cshift; /* _cshift is "complement shift" */ \ \ - if (!length) \ + if (!_length) \ break; \ \ - end = start + length; \ - start_unit = start / ts; \ - end_unit = (end + (ts - 1)) / ts; \ + _end = _start + _length; \ + _start_unit = _start / _ts; \ + _end_unit = (_end + (_ts - 1)) / _ts; \ \ /* Trim v high bits */ \ - if (length < sizeof(v) * CHAR_BIT) \ - v &= ~((~(typeof(v)) 0) << length); \ + if (_length < sizeof(_v) * CHAR_BIT) \ + _v &= _bt_make_mask(__typeof__(_v), _length); \ \ /* We can now append v with a simple "or", shift it piece-wise */ \ - this_unit = start_unit; \ - if (start_unit == end_unit - 1) { \ - mask = ~((~(typeof(*(ptr))) 0) << (start % ts)); \ - if (end % ts) \ - mask |= (~(typeof(*(ptr))) 0) << (end % ts); \ - cmask = (typeof(*(ptr))) v << (start % ts); \ - cmask &= ~mask; \ - (ptr)[this_unit] &= mask; \ - (ptr)[this_unit] |= cmask; \ + _this_unit = _start_unit; \ + if (_start_unit == _end_unit - 1) { \ + _mask = _bt_make_mask(type, _start % _ts); \ + if (_end % _ts) \ + _mask |= _bt_make_mask_complement(type, _end % _ts); \ + _cmask = _bt_lshift((type) (_v), _start % _ts); \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ break; \ } \ - if (start % ts) { \ - cshift = start % ts; \ - mask = ~((~(typeof(*(ptr))) 0) << cshift); \ - cmask = (typeof(*(ptr))) v << cshift; \ - cmask &= ~mask; \ - (ptr)[this_unit] &= mask; \ - (ptr)[this_unit] |= cmask; \ - v = _bt_piecewise_rshift(v, ts - cshift); \ - start += ts - cshift; \ - this_unit++; \ + if (_start % _ts) { \ + _cshift = _start % _ts; \ + _mask = _bt_make_mask(type, _cshift); \ + _cmask = _bt_lshift((type) (_v), _cshift); \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ + _bt_safe_rshift(_v, _ts - _cshift); \ + _start += _ts - _cshift; \ + _this_unit++; \ } \ - for (; this_unit < end_unit - 1; this_unit++) { \ - (ptr)[this_unit] = (typeof(*(ptr))) v; \ - v = _bt_piecewise_rshift(v, ts); \ - start += ts; \ + for (; _this_unit < _end_unit - 1; _this_unit++) { \ + _ptr[_this_unit] = (type) _v; \ + _bt_safe_rshift(_v, _ts); \ + _start += _ts; \ } \ - if (end % ts) { \ - mask = (~(typeof(*(ptr))) 0) << (end % ts); \ - cmask = (typeof(*(ptr))) v; \ - cmask &= ~mask; \ - (ptr)[this_unit] &= mask; \ - (ptr)[this_unit] |= cmask; \ + if (_end % _ts) { \ + _mask = _bt_make_mask_complement(type, _end % _ts); \ + _cmask = (type) _v; \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ } else \ - (ptr)[this_unit] = (typeof(*(ptr))) v; \ + _ptr[_this_unit] = (type) _v; \ } while (0) -#define _bt_bitfield_write_be(ptr, _start, _length, _v) \ +#define _bt_bitfield_write_be(ptr, type, start, length, v) \ do { \ - typeof(_v) v = (_v); \ - typeof(*(ptr)) mask, cmask; \ - unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ - unsigned long start = _start, length = _length; \ - unsigned long start_unit, end_unit, this_unit; \ - unsigned long end, cshift; /* cshift is "complement shift" */ \ + __typeof__(v) _v = (v); \ + type *_ptr = (void *) (ptr); \ + unsigned long _start = (start), _length = (length); \ + type _mask, _cmask; \ + unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long _start_unit, _end_unit, _this_unit; \ + unsigned long _end, _cshift; /* _cshift is "complement shift" */ \ \ - if (!length) \ + if (!_length) \ break; \ \ - end = start + length; \ - start_unit = start / ts; \ - end_unit = (end + (ts - 1)) / ts; \ + _end = _start + _length; \ + _start_unit = _start / _ts; \ + _end_unit = (_end + (_ts - 1)) / _ts; \ \ /* Trim v high bits */ \ - if (length < sizeof(v) * CHAR_BIT) \ - v &= ~((~(typeof(v)) 0) << length); \ + if (_length < sizeof(_v) * CHAR_BIT) \ + _v &= _bt_make_mask(__typeof__(_v), _length); \ \ /* We can now append v with a simple "or", shift it piece-wise */ \ - this_unit = end_unit - 1; \ - if (start_unit == end_unit - 1) { \ - mask = ~((~(typeof(*(ptr))) 0) << ((ts - (end % ts)) % ts)); \ - if (start % ts) \ - mask |= (~((typeof(*(ptr))) 0)) << (ts - (start % ts)); \ - cmask = (typeof(*(ptr))) v << ((ts - (end % ts)) % ts); \ - cmask &= ~mask; \ - (ptr)[this_unit] &= mask; \ - (ptr)[this_unit] |= cmask; \ + _this_unit = _end_unit - 1; \ + if (_start_unit == _end_unit - 1) { \ + _mask = _bt_make_mask(type, (_ts - (_end % _ts)) % _ts); \ + if (_start % _ts) \ + _mask |= _bt_make_mask_complement(type, _ts - (_start % _ts)); \ + _cmask = _bt_lshift((type) (_v), (_ts - (_end % _ts)) % _ts); \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ break; \ } \ - if (end % ts) { \ - cshift = end % ts; \ - mask = ~((~(typeof(*(ptr))) 0) << (ts - cshift)); \ - cmask = (typeof(*(ptr))) v << (ts - cshift); \ - cmask &= ~mask; \ - (ptr)[this_unit] &= mask; \ - (ptr)[this_unit] |= cmask; \ - v = _bt_piecewise_rshift(v, cshift); \ - end -= cshift; \ - this_unit--; \ + if (_end % _ts) { \ + _cshift = _end % _ts; \ + _mask = _bt_make_mask(type, _ts - _cshift); \ + _cmask = _bt_lshift((type) (_v), _ts - _cshift); \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ + _bt_safe_rshift(_v, _cshift); \ + _end -= _cshift; \ + _this_unit--; \ } \ - for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ - (ptr)[this_unit] = (typeof(*(ptr))) v; \ - v = _bt_piecewise_rshift(v, ts); \ - end -= ts; \ + for (; (long) _this_unit >= (long) _start_unit + 1; _this_unit--) { \ + _ptr[_this_unit] = (type) _v; \ + _bt_safe_rshift(_v, _ts); \ + _end -= _ts; \ } \ - if (start % ts) { \ - mask = (~(typeof(*(ptr))) 0) << (ts - (start % ts)); \ - cmask = (typeof(*(ptr))) v; \ - cmask &= ~mask; \ - (ptr)[this_unit] &= mask; \ - (ptr)[this_unit] |= cmask; \ + if (_start % _ts) { \ + _mask = _bt_make_mask_complement(type, _ts - (_start % _ts)); \ + _cmask = (type) _v; \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ } else \ - (ptr)[this_unit] = (typeof(*(ptr))) v; \ + _ptr[_this_unit] = (type) _v; \ } while (0) /* @@ -198,25 +344,25 @@ do { \ #if (BYTE_ORDER == LITTLE_ENDIAN) -#define bt_bitfield_write(ptr, _start, _length, _v) \ - _bt_bitfield_write_le(ptr, _start, _length, _v) +#define bt_bitfield_write(ptr, type, start, length, v) \ + _bt_bitfield_write_le(ptr, type, start, length, v) + +#define bt_bitfield_write_le(ptr, type, start, length, v) \ + _bt_bitfield_write_le(ptr, type, start, length, v) -#define bt_bitfield_write_le(ptr, _start, _length, _v) \ - _bt_bitfield_write_le(ptr, _start, _length, _v) - -#define bt_bitfield_write_be(ptr, _start, _length, _v) \ - _bt_bitfield_write_be((unsigned char *) (ptr), _start, _length, _v) +#define bt_bitfield_write_be(ptr, type, start, length, v) \ + _bt_bitfield_write_be(ptr, unsigned char, start, length, v) #elif (BYTE_ORDER == BIG_ENDIAN) -#define bt_bitfield_write(ptr, _start, _length, _v) \ - _bt_bitfield_write_be(ptr, _start, _length, _v) +#define bt_bitfield_write(ptr, type, start, length, v) \ + _bt_bitfield_write_be(ptr, type, start, length, v) -#define bt_bitfield_write_le(ptr, _start, _length, _v) \ - _bt_bitfield_write_le((unsigned char *) (ptr), _start, _length, _v) - -#define bt_bitfield_write_be(ptr, _start, _length, _v) \ - _bt_bitfield_write_be(ptr, _start, _length, _v) +#define bt_bitfield_write_le(ptr, type, start, length, v) \ + _bt_bitfield_write_le(ptr, unsigned char, start, length, v) + +#define bt_bitfield_write_be(ptr, type, start, length, v) \ + _bt_bitfield_write_be(ptr, type, start, length, v) #else /* (BYTE_ORDER == PDP_ENDIAN) */ @@ -224,133 +370,148 @@ do { \ #endif -#define _bt_bitfield_read_le(ptr, _start, _length, vptr) \ +#define _bt_bitfield_read_le(ptr, type, start, length, vptr) \ do { \ - typeof(*(vptr)) v; \ - typeof(*(ptr)) mask, cmask; \ - unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ - unsigned long start = _start, length = _length; \ - unsigned long start_unit, end_unit, this_unit; \ - unsigned long end, cshift; /* cshift is "complement shift" */ \ + __typeof__(*(vptr)) *_vptr = (vptr); \ + __typeof__(*_vptr) _v; \ + type *_ptr = (void *) (ptr); \ + unsigned long _start = (start), _length = (length); \ + type _mask, _cmask; \ + unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long _start_unit, _end_unit, _this_unit; \ + unsigned long _end, _cshift; /* _cshift is "complement shift" */ \ + bool _is_signed_type; \ \ - if (!length) { \ - *(vptr) = 0; \ + if (!_length) { \ + *_vptr = 0; \ break; \ } \ \ - end = start + length; \ - start_unit = start / ts; \ - end_unit = (end + (ts - 1)) / ts; \ + _end = _start + _length; \ + _start_unit = _start / _ts; \ + _end_unit = (_end + (_ts - 1)) / _ts; \ \ - this_unit = end_unit - 1; \ - if (_bt_is_signed_type(typeof(v)) \ - && ((ptr)[this_unit] & ((typeof(*(ptr))) 1 << ((end % ts ? : ts) - 1)))) \ - v = ~(typeof(v)) 0; \ + _this_unit = _end_unit - 1; \ + _BT_DIAG_PUSH \ + _BT_DIAG_IGNORE_TYPE_LIMITS \ + _is_signed_type = _bt_is_signed_type(__typeof__(_v)); \ + _BT_DIAG_POP \ + if (_is_signed_type \ + && (_ptr[_this_unit] & _bt_lshift((type) 1, (_end % _ts ? _end % _ts : _ts) - 1))) \ + _v = ~(__typeof__(_v)) 0; \ else \ - v = 0; \ - if (start_unit == end_unit - 1) { \ - cmask = (ptr)[this_unit]; \ - cmask >>= (start % ts); \ - if ((end - start) % ts) { \ - mask = ~((~(typeof(*(ptr))) 0) << (end - start)); \ - cmask &= mask; \ + _v = 0; \ + if (_start_unit == _end_unit - 1) { \ + _cmask = _ptr[_this_unit]; \ + _cmask = _bt_rshift(_cmask, _start % _ts); \ + if ((_end - _start) % _ts) { \ + _mask = _bt_make_mask(type, _end - _start); \ + _cmask &= _mask; \ } \ - v = _bt_piecewise_lshift(v, end - start); \ - v |= _bt_unsigned_cast(typeof(v), cmask); \ - *(vptr) = v; \ + _bt_safe_lshift(_v, _end - _start); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ + *_vptr = _v; \ break; \ } \ - if (end % ts) { \ - cshift = end % ts; \ - mask = ~((~(typeof(*(ptr))) 0) << cshift); \ - cmask = (ptr)[this_unit]; \ - cmask &= mask; \ - v = _bt_piecewise_lshift(v, cshift); \ - v |= _bt_unsigned_cast(typeof(v), cmask); \ - end -= cshift; \ - this_unit--; \ + if (_end % _ts) { \ + _cshift = _end % _ts; \ + _mask = _bt_make_mask(type, _cshift); \ + _cmask = _ptr[_this_unit]; \ + _cmask &= _mask; \ + _bt_safe_lshift(_v, _cshift); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ + _end -= _cshift; \ + _this_unit--; \ } \ - for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ - v = _bt_piecewise_lshift(v, ts); \ - v |= _bt_unsigned_cast(typeof(v), (ptr)[this_unit]); \ - end -= ts; \ + for (; (long) _this_unit >= (long) _start_unit + 1; _this_unit--) { \ + _bt_safe_lshift(_v, _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \ + _end -= _ts; \ } \ - if (start % ts) { \ - mask = ~((~(typeof(*(ptr))) 0) << (ts - (start % ts))); \ - cmask = (ptr)[this_unit]; \ - cmask >>= (start % ts); \ - cmask &= mask; \ - v = _bt_piecewise_lshift(v, ts - (start % ts)); \ - v |= _bt_unsigned_cast(typeof(v), cmask); \ + if (_start % _ts) { \ + _mask = _bt_make_mask(type, _ts - (_start % _ts)); \ + _cmask = _ptr[_this_unit]; \ + _cmask = _bt_rshift(_cmask, _start % _ts); \ + _cmask &= _mask; \ + _bt_safe_lshift(_v, _ts - (_start % _ts)); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ } else { \ - v = _bt_piecewise_lshift(v, ts); \ - v |= _bt_unsigned_cast(typeof(v), (ptr)[this_unit]); \ + _bt_safe_lshift(_v, _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \ } \ - *(vptr) = v; \ + *_vptr = _v; \ } while (0) -#define _bt_bitfield_read_be(ptr, _start, _length, vptr) \ +#define _bt_bitfield_read_be(ptr, type, start, length, vptr) \ do { \ - typeof(*(vptr)) v; \ - typeof(*(ptr)) mask, cmask; \ - unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ - unsigned long start = _start, length = _length; \ - unsigned long start_unit, end_unit, this_unit; \ - unsigned long end, cshift; /* cshift is "complement shift" */ \ + __typeof__(*(vptr)) *_vptr = (vptr); \ + __typeof__(*_vptr) _v; \ + type *_ptr = (void *) (ptr); \ + unsigned long _start = (start), _length = (length); \ + type _mask, _cmask; \ + unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long _start_unit, _end_unit, _this_unit; \ + unsigned long _end, _cshift; /* _cshift is "complement shift" */ \ + bool _is_signed_type; \ \ - if (!length) { \ - *(vptr) = 0; \ + if (!_length) { \ + *_vptr = 0; \ break; \ } \ \ - end = start + length; \ - start_unit = start / ts; \ - end_unit = (end + (ts - 1)) / ts; \ + _end = _start + _length; \ + _start_unit = _start / _ts; \ + _end_unit = (_end + (_ts - 1)) / _ts; \ \ - this_unit = start_unit; \ - if (_bt_is_signed_type(typeof(v)) \ - && ((ptr)[this_unit] & ((typeof(*(ptr))) 1 << (ts - (start % ts) - 1)))) \ - v = ~(typeof(v)) 0; \ + _this_unit = _start_unit; \ + _BT_DIAG_PUSH \ + _BT_DIAG_IGNORE_TYPE_LIMITS \ + _is_signed_type = _bt_is_signed_type(__typeof__(_v)); \ + _BT_DIAG_POP \ + if (_is_signed_type \ + && (_ptr[_this_unit] & _bt_lshift((type) 1, _ts - (_start % _ts) - 1))) \ + _v = ~(__typeof__(_v)) 0; \ else \ - v = 0; \ - if (start_unit == end_unit - 1) { \ - cmask = (ptr)[this_unit]; \ - cmask >>= (ts - (end % ts)) % ts; \ - if ((end - start) % ts) { \ - mask = ~((~(typeof(*(ptr))) 0) << (end - start)); \ - cmask &= mask; \ + _v = 0; \ + if (_start_unit == _end_unit - 1) { \ + _cmask = _ptr[_this_unit]; \ + _cmask = _bt_rshift(_cmask, (_ts - (_end % _ts)) % _ts); \ + if ((_end - _start) % _ts) { \ + _mask = _bt_make_mask(type, _end - _start); \ + _cmask &= _mask; \ } \ - v = _bt_piecewise_lshift(v, end - start); \ - v |= _bt_unsigned_cast(typeof(v), cmask); \ - *(vptr) = v; \ + _bt_safe_lshift(_v, _end - _start); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ + *_vptr = _v; \ break; \ } \ - if (start % ts) { \ - mask = ~((~(typeof(*(ptr))) 0) << (ts - (start % ts))); \ - cmask = (ptr)[this_unit]; \ - cmask &= mask; \ - v = _bt_piecewise_lshift(v, ts - (start % ts)); \ - v |= _bt_unsigned_cast(typeof(v), cmask); \ - start += ts - (start % ts); \ - this_unit++; \ + if (_start % _ts) { \ + _cshift = _start % _ts; \ + _mask = _bt_make_mask(type, _ts - _cshift); \ + _cmask = _ptr[_this_unit]; \ + _cmask &= _mask; \ + _bt_safe_lshift(_v, _ts - _cshift); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ + _start += _ts - _cshift; \ + _this_unit++; \ } \ - for (; this_unit < end_unit - 1; this_unit++) { \ - v = _bt_piecewise_lshift(v, ts); \ - v |= _bt_unsigned_cast(typeof(v), (ptr)[this_unit]); \ - start += ts; \ + for (; _this_unit < _end_unit - 1; _this_unit++) { \ + _bt_safe_lshift(_v, _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \ + _start += _ts; \ } \ - if (end % ts) { \ - mask = ~((~(typeof(*(ptr))) 0) << (end % ts)); \ - cmask = (ptr)[this_unit]; \ - cmask >>= ts - (end % ts); \ - cmask &= mask; \ - v = _bt_piecewise_lshift(v, end % ts); \ - v |= _bt_unsigned_cast(typeof(v), cmask); \ + if (_end % _ts) { \ + _mask = _bt_make_mask(type, _end % _ts); \ + _cmask = _ptr[_this_unit]; \ + _cmask = _bt_rshift(_cmask, _ts - (_end % _ts)); \ + _cmask &= _mask; \ + _bt_safe_lshift(_v, _end % _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ } else { \ - v = _bt_piecewise_lshift(v, ts); \ - v |= _bt_unsigned_cast(typeof(v), (ptr)[this_unit]); \ + _bt_safe_lshift(_v, _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \ } \ - *(vptr) = v; \ + *_vptr = _v; \ } while (0) /* @@ -361,25 +522,25 @@ do { \ #if (BYTE_ORDER == LITTLE_ENDIAN) -#define bt_bitfield_read(ptr, _start, _length, _vptr) \ - _bt_bitfield_read_le(ptr, _start, _length, _vptr) +#define bt_bitfield_read(ptr, type, start, length, vptr) \ + _bt_bitfield_read_le(ptr, type, start, length, vptr) + +#define bt_bitfield_read_le(ptr, type, start, length, vptr) \ + _bt_bitfield_read_le(ptr, type, start, length, vptr) -#define bt_bitfield_read_le(ptr, _start, _length, _vptr) \ - _bt_bitfield_read_le(ptr, _start, _length, _vptr) - -#define bt_bitfield_read_be(ptr, _start, _length, _vptr) \ - _bt_bitfield_read_be((const unsigned char *) (ptr), _start, _length, _vptr) +#define bt_bitfield_read_be(ptr, type, start, length, vptr) \ + _bt_bitfield_read_be(ptr, unsigned char, start, length, vptr) #elif (BYTE_ORDER == BIG_ENDIAN) -#define bt_bitfield_read(ptr, _start, _length, _vptr) \ - _bt_bitfield_read_be(ptr, _start, _length, _vptr) +#define bt_bitfield_read(ptr, type, start, length, vptr) \ + _bt_bitfield_read_be(ptr, type, start, length, vptr) + +#define bt_bitfield_read_le(ptr, type, start, length, vptr) \ + _bt_bitfield_read_le(ptr, unsigned char, start, length, vptr) -#define bt_bitfield_read_le(ptr, _start, _length, _vptr) \ - _bt_bitfield_read_le((const unsigned char *) (ptr), _start, _length, _vptr) - -#define bt_bitfield_read_be(ptr, _start, _length, _vptr) \ - _bt_bitfield_read_be(ptr, _start, _length, _vptr) +#define bt_bitfield_read_be(ptr, type, start, length, vptr) \ + _bt_bitfield_read_be(ptr, type, start, length, vptr) #else /* (BYTE_ORDER == PDP_ENDIAN) */