1 #ifndef _BABELTRACE_BITFIELD_H
2 #define _BABELTRACE_BITFIELD_H
7 * Bitfields read/write functions.
9 * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
22 #include <stdint.h> /* C99 5.2.4.2 Numerical limits */
23 #include <limits.h> /* C99 5.2.4.2 Numerical limits */
24 #include <endian.h> /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */
27 /* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
28 #define _bt_piecewise_rshift(v, shift) \
30 unsigned long sb = (shift) / (sizeof(v) * CHAR_BIT - 1); \
31 unsigned long final = (shift) % (sizeof(v) * CHAR_BIT - 1); \
35 _v >>= sizeof(v) * CHAR_BIT - 1; \
39 #define _bt_piecewise_lshift(v, shift) \
41 unsigned long sb = (shift) / (sizeof(v) * CHAR_BIT - 1); \
42 unsigned long final = (shift) % (sizeof(v) * CHAR_BIT - 1); \
46 _v <<= sizeof(v) * CHAR_BIT - 1; \
50 #define _bt_is_signed_type(type) (((type)(-1)) < 0)
52 #define _bt_unsigned_cast(type, v) \
54 (sizeof(v) < sizeof(type)) ? \
55 ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
60 * bt_bitfield_write - write integer to a bitfield in native endianness
62 * Save integer to the bitfield, which starts at the "start" bit, has "len"
64 * The inside of a bitfield is from high bits to low bits.
65 * Uses native endianness.
66 * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
67 * For signed "v", sign-extend v if bitfield is larger than v.
69 * On little endian, bytes are placed from the less significant to the most
70 * significant. Also, consecutive bitfields are placed from lower bits to higher
73 * On big endian, bytes are places from most significant to less significant.
74 * Also, consecutive bitfields are placed from higher to lower bits.
77 #define _bt_bitfield_write_le(ptr, _start, _length, _v) \
79 typeof(_v) v = (_v); \
80 typeof(*(ptr)) mask, cmask; \
81 unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
82 unsigned long start = (_start), length = (_length); \
83 unsigned long start_unit, end_unit, this_unit; \
84 unsigned long end, cshift; /* cshift is "complement shift" */ \
89 end = start + length; \
90 start_unit = start / ts; \
91 end_unit = (end + (ts - 1)) / ts; \
93 /* Trim v high bits */ \
94 if (length < sizeof(v) * CHAR_BIT) \
95 v &= ~((~(typeof(v)) 0) << length); \
97 /* We can now append v with a simple "or", shift it piece-wise */ \
98 this_unit = start_unit; \
99 if (start_unit == end_unit - 1) { \
100 mask = ~((~(typeof(*(ptr))) 0) << (start % ts)); \
102 mask |= (~(typeof(*(ptr))) 0) << (end % ts); \
103 cmask = (typeof(*(ptr))) v << (start % ts); \
105 (ptr)[this_unit] &= mask; \
106 (ptr)[this_unit] |= cmask; \
110 cshift = start % ts; \
111 mask = ~((~(typeof(*(ptr))) 0) << cshift); \
112 cmask = (typeof(*(ptr))) v << cshift; \
114 (ptr)[this_unit] &= mask; \
115 (ptr)[this_unit] |= cmask; \
116 v = _bt_piecewise_rshift(v, ts - cshift); \
117 start += ts - cshift; \
120 for (; this_unit < end_unit - 1; this_unit++) { \
121 (ptr)[this_unit] = (typeof(*(ptr))) v; \
122 v = _bt_piecewise_rshift(v, ts); \
126 mask = (~(typeof(*(ptr))) 0) << (end % ts); \
127 cmask = (typeof(*(ptr))) v; \
129 (ptr)[this_unit] &= mask; \
130 (ptr)[this_unit] |= cmask; \
132 (ptr)[this_unit] = (typeof(*(ptr))) v; \
135 #define _bt_bitfield_write_be(ptr, _start, _length, _v) \
137 typeof(_v) v = (_v); \
138 typeof(*(ptr)) mask, cmask; \
139 unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
140 unsigned long start = _start, length = _length; \
141 unsigned long start_unit, end_unit, this_unit; \
142 unsigned long end, cshift; /* cshift is "complement shift" */ \
147 end = start + length; \
148 start_unit = start / ts; \
149 end_unit = (end + (ts - 1)) / ts; \
151 /* Trim v high bits */ \
152 if (length < sizeof(v) * CHAR_BIT) \
153 v &= ~((~(typeof(v)) 0) << length); \
155 /* We can now append v with a simple "or", shift it piece-wise */ \
156 this_unit = end_unit - 1; \
157 if (start_unit == end_unit - 1) { \
158 mask = ~((~(typeof(*(ptr))) 0) << ((ts - (end % ts)) % ts)); \
160 mask |= (~((typeof(*(ptr))) 0)) << (ts - (start % ts)); \
161 cmask = (typeof(*(ptr))) v << ((ts - (end % ts)) % ts); \
163 (ptr)[this_unit] &= mask; \
164 (ptr)[this_unit] |= cmask; \
169 mask = ~((~(typeof(*(ptr))) 0) << (ts - cshift)); \
170 cmask = (typeof(*(ptr))) v << (ts - cshift); \
172 (ptr)[this_unit] &= mask; \
173 (ptr)[this_unit] |= cmask; \
174 v = _bt_piecewise_rshift(v, cshift); \
178 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
179 (ptr)[this_unit] = (typeof(*(ptr))) v; \
180 v = _bt_piecewise_rshift(v, ts); \
184 mask = (~(typeof(*(ptr))) 0) << (ts - (start % ts)); \
185 cmask = (typeof(*(ptr))) v; \
187 (ptr)[this_unit] &= mask; \
188 (ptr)[this_unit] |= cmask; \
190 (ptr)[this_unit] = (typeof(*(ptr))) v; \
194 * bt_bitfield_write - write integer to a bitfield in native endianness
195 * bt_bitfield_write_le - write integer to a bitfield in little endian
196 * bt_bitfield_write_be - write integer to a bitfield in big endian
199 #if (BYTE_ORDER == LITTLE_ENDIAN)
201 #define bt_bitfield_write(ptr, _start, _length, _v) \
202 _bt_bitfield_write_le(ptr, _start, _length, _v)
204 #define bt_bitfield_write_le(ptr, _start, _length, _v) \
205 _bt_bitfield_write_le(ptr, _start, _length, _v)
207 #define bt_bitfield_write_be(ptr, _start, _length, _v) \
208 _bt_bitfield_write_be((unsigned char *) (ptr), _start, _length, _v)
210 #elif (BYTE_ORDER == BIG_ENDIAN)
212 #define bt_bitfield_write(ptr, _start, _length, _v) \
213 _bt_bitfield_write_be(ptr, _start, _length, _v)
215 #define bt_bitfield_write_le(ptr, _start, _length, _v) \
216 _bt_bitfield_write_le((unsigned char *) (ptr), _start, _length, _v)
218 #define bt_bitfield_write_be(ptr, _start, _length, _v) \
219 _bt_bitfield_write_be(ptr, _start, _length, _v)
221 #else /* (BYTE_ORDER == PDP_ENDIAN) */
223 #error "Byte order not supported"
227 #define _bt_bitfield_read_le(ptr, _start, _length, vptr) \
230 typeof(*(ptr)) mask, cmask; \
231 unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
232 unsigned long start = _start, length = _length; \
233 unsigned long start_unit, end_unit, this_unit; \
234 unsigned long end, cshift; /* cshift is "complement shift" */ \
241 end = start + length; \
242 start_unit = start / ts; \
243 end_unit = (end + (ts - 1)) / ts; \
245 this_unit = end_unit - 1; \
246 if (_bt_is_signed_type(typeof(v)) \
247 && ((ptr)[this_unit] & ((typeof(*(ptr))) 1 << ((end % ts ? : ts) - 1)))) \
248 v = ~(typeof(v)) 0; \
251 if (start_unit == end_unit - 1) { \
252 cmask = (ptr)[this_unit]; \
253 cmask >>= (start % ts); \
254 if ((end - start) % ts) { \
255 mask = ~((~(typeof(*(ptr))) 0) << (end - start)); \
258 v = _bt_piecewise_lshift(v, end - start); \
259 v |= _bt_unsigned_cast(typeof(v), cmask); \
265 mask = ~((~(typeof(*(ptr))) 0) << cshift); \
266 cmask = (ptr)[this_unit]; \
268 v = _bt_piecewise_lshift(v, cshift); \
269 v |= _bt_unsigned_cast(typeof(v), cmask); \
273 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
274 v = _bt_piecewise_lshift(v, ts); \
275 v |= _bt_unsigned_cast(typeof(v), (ptr)[this_unit]); \
279 mask = ~((~(typeof(*(ptr))) 0) << (ts - (start % ts))); \
280 cmask = (ptr)[this_unit]; \
281 cmask >>= (start % ts); \
283 v = _bt_piecewise_lshift(v, ts - (start % ts)); \
284 v |= _bt_unsigned_cast(typeof(v), cmask); \
286 v = _bt_piecewise_lshift(v, ts); \
287 v |= _bt_unsigned_cast(typeof(v), (ptr)[this_unit]); \
292 #define _bt_bitfield_read_be(ptr, _start, _length, vptr) \
295 typeof(*(ptr)) mask, cmask; \
296 unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
297 unsigned long start = _start, length = _length; \
298 unsigned long start_unit, end_unit, this_unit; \
299 unsigned long end, cshift; /* cshift is "complement shift" */ \
306 end = start + length; \
307 start_unit = start / ts; \
308 end_unit = (end + (ts - 1)) / ts; \
310 this_unit = start_unit; \
311 if (_bt_is_signed_type(typeof(v)) \
312 && ((ptr)[this_unit] & ((typeof(*(ptr))) 1 << (ts - (start % ts) - 1)))) \
313 v = ~(typeof(v)) 0; \
316 if (start_unit == end_unit - 1) { \
317 cmask = (ptr)[this_unit]; \
318 cmask >>= (ts - (end % ts)) % ts; \
319 if ((end - start) % ts) { \
320 mask = ~((~(typeof(*(ptr))) 0) << (end - start)); \
323 v = _bt_piecewise_lshift(v, end - start); \
324 v |= _bt_unsigned_cast(typeof(v), cmask); \
329 mask = ~((~(typeof(*(ptr))) 0) << (ts - (start % ts))); \
330 cmask = (ptr)[this_unit]; \
332 v = _bt_piecewise_lshift(v, ts - (start % ts)); \
333 v |= _bt_unsigned_cast(typeof(v), cmask); \
334 start += ts - (start % ts); \
337 for (; this_unit < end_unit - 1; this_unit++) { \
338 v = _bt_piecewise_lshift(v, ts); \
339 v |= _bt_unsigned_cast(typeof(v), (ptr)[this_unit]); \
343 mask = ~((~(typeof(*(ptr))) 0) << (end % ts)); \
344 cmask = (ptr)[this_unit]; \
345 cmask >>= ts - (end % ts); \
347 v = _bt_piecewise_lshift(v, end % ts); \
348 v |= _bt_unsigned_cast(typeof(v), cmask); \
350 v = _bt_piecewise_lshift(v, ts); \
351 v |= _bt_unsigned_cast(typeof(v), (ptr)[this_unit]); \
357 * bt_bitfield_read - read integer from a bitfield in native endianness
358 * bt_bitfield_read_le - read integer from a bitfield in little endian
359 * bt_bitfield_read_be - read integer from a bitfield in big endian
362 #if (BYTE_ORDER == LITTLE_ENDIAN)
364 #define bt_bitfield_read(ptr, _start, _length, _vptr) \
365 _bt_bitfield_read_le(ptr, _start, _length, _vptr)
367 #define bt_bitfield_read_le(ptr, _start, _length, _vptr) \
368 _bt_bitfield_read_le(ptr, _start, _length, _vptr)
370 #define bt_bitfield_read_be(ptr, _start, _length, _vptr) \
371 _bt_bitfield_read_be((const unsigned char *) (ptr), _start, _length, _vptr)
373 #elif (BYTE_ORDER == BIG_ENDIAN)
375 #define bt_bitfield_read(ptr, _start, _length, _vptr) \
376 _bt_bitfield_read_be(ptr, _start, _length, _vptr)
378 #define bt_bitfield_read_le(ptr, _start, _length, _vptr) \
379 _bt_bitfield_read_le((const unsigned char *) (ptr), _start, _length, _vptr)
381 #define bt_bitfield_read_be(ptr, _start, _length, _vptr) \
382 _bt_bitfield_read_be(ptr, _start, _length, _vptr)
384 #else /* (BYTE_ORDER == PDP_ENDIAN) */
386 #error "Byte order not supported"
390 #endif /* _BABELTRACE_BITFIELD_H */
This page took 0.060529 seconds and 4 git commands to generate.