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.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 #include <stdint.h> /* C99 5.2.4.2 Numerical limits */
31 #include <limits.h> /* C99 5.2.4.2 Numerical limits */
32 #include <lttng/ust-endian.h> /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */
34 /* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
35 #define _bt_piecewise_rshift(_v, _shift) \
37 __typeof__(_v) ___v = (_v); \
38 __typeof__(_shift) ___shift = (_shift); \
39 unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \
40 unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \
43 ___v >>= sizeof(___v) * CHAR_BIT - 1; \
47 #define _bt_piecewise_lshift(_v, _shift) \
49 __typeof__(_v) ___v = (_v); \
50 __typeof__(_shift) ___shift = (_shift); \
51 unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \
52 unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \
55 ___v <<= sizeof(___v) * CHAR_BIT - 1; \
59 #define _bt_is_signed_type(type) ((type) -1 < (type) 0)
61 #define _bt_unsigned_cast(type, v) \
63 (sizeof(v) < sizeof(type)) ? \
64 ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
69 * bt_bitfield_write - write integer to a bitfield in native endianness
71 * Save integer to the bitfield, which starts at the "start" bit, has "len"
73 * The inside of a bitfield is from high bits to low bits.
74 * Uses native endianness.
75 * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
76 * For signed "v", sign-extend v if bitfield is larger than v.
78 * On little endian, bytes are placed from the less significant to the most
79 * significant. Also, consecutive bitfields are placed from lower bits to higher
82 * On big endian, bytes are places from most significant to less significant.
83 * Also, consecutive bitfields are placed from higher to lower bits.
86 #define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \
88 __typeof__(_v) __v = (_v); \
89 type *__ptr = (void *) (_ptr); \
90 unsigned long __start = (_start), __length = (_length); \
92 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
93 unsigned long start_unit, end_unit, this_unit; \
94 unsigned long end, cshift; /* cshift is "complement shift" */ \
99 end = __start + __length; \
100 start_unit = __start / ts; \
101 end_unit = (end + (ts - 1)) / ts; \
103 /* Trim v high bits */ \
104 if (__length < sizeof(__v) * CHAR_BIT) \
105 __v &= ~((~(__typeof__(__v)) 0) << __length); \
107 /* We can now append v with a simple "or", shift it piece-wise */ \
108 this_unit = start_unit; \
109 if (start_unit == end_unit - 1) { \
110 mask = ~((~(type) 0) << (__start % ts)); \
112 mask |= (~(type) 0) << (end % ts); \
113 cmask = (type) __v << (__start % ts); \
115 __ptr[this_unit] &= mask; \
116 __ptr[this_unit] |= cmask; \
119 if (__start % ts) { \
120 cshift = __start % ts; \
121 mask = ~((~(type) 0) << cshift); \
122 cmask = (type) __v << cshift; \
124 __ptr[this_unit] &= mask; \
125 __ptr[this_unit] |= cmask; \
126 __v = _bt_piecewise_rshift(__v, ts - cshift); \
127 __start += ts - cshift; \
130 for (; this_unit < end_unit - 1; this_unit++) { \
131 __ptr[this_unit] = (type) __v; \
132 __v = _bt_piecewise_rshift(__v, ts); \
136 mask = (~(type) 0) << (end % ts); \
137 cmask = (type) __v; \
139 __ptr[this_unit] &= mask; \
140 __ptr[this_unit] |= cmask; \
142 __ptr[this_unit] = (type) __v; \
145 #define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \
147 __typeof__(_v) __v = (_v); \
148 type *__ptr = (void *) (_ptr); \
149 unsigned long __start = (_start), __length = (_length); \
151 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
152 unsigned long start_unit, end_unit, this_unit; \
153 unsigned long end, cshift; /* cshift is "complement shift" */ \
158 end = __start + __length; \
159 start_unit = __start / ts; \
160 end_unit = (end + (ts - 1)) / ts; \
162 /* Trim v high bits */ \
163 if (__length < sizeof(__v) * CHAR_BIT) \
164 __v &= ~((~(__typeof__(__v)) 0) << __length); \
166 /* We can now append v with a simple "or", shift it piece-wise */ \
167 this_unit = end_unit - 1; \
168 if (start_unit == end_unit - 1) { \
169 mask = ~((~(type) 0) << ((ts - (end % ts)) % ts)); \
171 mask |= (~((type) 0)) << (ts - (__start % ts)); \
172 cmask = (type) __v << ((ts - (end % ts)) % ts); \
174 __ptr[this_unit] &= mask; \
175 __ptr[this_unit] |= cmask; \
180 mask = ~((~(type) 0) << (ts - cshift)); \
181 cmask = (type) __v << (ts - cshift); \
183 __ptr[this_unit] &= mask; \
184 __ptr[this_unit] |= cmask; \
185 __v = _bt_piecewise_rshift(__v, cshift); \
189 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
190 __ptr[this_unit] = (type) __v; \
191 __v = _bt_piecewise_rshift(__v, ts); \
194 if (__start % ts) { \
195 mask = (~(type) 0) << (ts - (__start % ts)); \
196 cmask = (type) __v; \
198 __ptr[this_unit] &= mask; \
199 __ptr[this_unit] |= cmask; \
201 __ptr[this_unit] = (type) __v; \
205 * bt_bitfield_write - write integer to a bitfield in native endianness
206 * bt_bitfield_write_le - write integer to a bitfield in little endian
207 * bt_bitfield_write_be - write integer to a bitfield in big endian
210 #if (BYTE_ORDER == LITTLE_ENDIAN)
212 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
213 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
215 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
216 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
218 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
219 _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v)
221 #elif (BYTE_ORDER == BIG_ENDIAN)
223 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
224 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
226 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
227 _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v)
229 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
230 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
232 #else /* (BYTE_ORDER == PDP_ENDIAN) */
234 #error "Byte order not supported"
238 #define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
240 __typeof__(*(_vptr)) *__vptr = (_vptr); \
241 __typeof__(*__vptr) __v; \
242 type *__ptr = (void *) (_ptr); \
243 unsigned long __start = (_start), __length = (_length); \
245 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
246 unsigned long start_unit, end_unit, this_unit; \
247 unsigned long end, cshift; /* cshift is "complement shift" */ \
254 end = __start + __length; \
255 start_unit = __start / ts; \
256 end_unit = (end + (ts - 1)) / ts; \
258 this_unit = end_unit - 1; \
259 if (_bt_is_signed_type(__typeof__(__v)) \
260 && (__ptr[this_unit] & ((type) 1 << ((end % ts ? : ts) - 1)))) \
261 __v = ~(__typeof__(__v)) 0; \
264 if (start_unit == end_unit - 1) { \
265 cmask = __ptr[this_unit]; \
266 cmask >>= (__start % ts); \
267 if ((end - __start) % ts) { \
268 mask = ~((~(type) 0) << (end - __start)); \
271 __v = _bt_piecewise_lshift(__v, end - __start); \
272 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
278 mask = ~((~(type) 0) << cshift); \
279 cmask = __ptr[this_unit]; \
281 __v = _bt_piecewise_lshift(__v, cshift); \
282 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
286 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
287 __v = _bt_piecewise_lshift(__v, ts); \
288 __v |= _bt_unsigned_cast(__typeof__(__v), __ptr[this_unit]);\
291 if (__start % ts) { \
292 mask = ~((~(type) 0) << (ts - (__start % ts))); \
293 cmask = __ptr[this_unit]; \
294 cmask >>= (__start % ts); \
296 __v = _bt_piecewise_lshift(__v, ts - (__start % ts)); \
297 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
299 __v = _bt_piecewise_lshift(__v, ts); \
300 __v |= _bt_unsigned_cast(__typeof__(__v), __ptr[this_unit]);\
305 #define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
307 __typeof__(*(_vptr)) *__vptr = (_vptr); \
308 __typeof__(*__vptr) __v; \
309 type *__ptr = (void *) (_ptr); \
310 unsigned long __start = (_start), __length = (_length); \
312 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
313 unsigned long start_unit, end_unit, this_unit; \
314 unsigned long end, cshift; /* cshift is "complement shift" */ \
321 end = __start + __length; \
322 start_unit = __start / ts; \
323 end_unit = (end + (ts - 1)) / ts; \
325 this_unit = start_unit; \
326 if (_bt_is_signed_type(__typeof__(__v)) \
327 && (__ptr[this_unit] & ((type) 1 << (ts - (__start % ts) - 1)))) \
328 __v = ~(__typeof__(__v)) 0; \
331 if (start_unit == end_unit - 1) { \
332 cmask = __ptr[this_unit]; \
333 cmask >>= (ts - (end % ts)) % ts; \
334 if ((end - __start) % ts) { \
335 mask = ~((~(type) 0) << (end - __start)); \
338 __v = _bt_piecewise_lshift(__v, end - __start); \
339 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
343 if (__start % ts) { \
344 cshift = __start % ts; \
345 mask = ~((~(type) 0) << (ts - cshift)); \
346 cmask = __ptr[this_unit]; \
348 __v = _bt_piecewise_lshift(__v, ts - cshift); \
349 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
350 __start += ts - cshift; \
353 for (; this_unit < end_unit - 1; this_unit++) { \
354 __v = _bt_piecewise_lshift(__v, ts); \
355 __v |= _bt_unsigned_cast(__typeof__(__v), __ptr[this_unit]);\
359 mask = ~((~(type) 0) << (end % ts)); \
360 cmask = __ptr[this_unit]; \
361 cmask >>= ts - (end % ts); \
363 __v = _bt_piecewise_lshift(__v, end % ts); \
364 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
366 __v = _bt_piecewise_lshift(__v, ts); \
367 __v |= _bt_unsigned_cast(__typeof__(__v), __ptr[this_unit]);\
373 * bt_bitfield_read - read integer from a bitfield in native endianness
374 * bt_bitfield_read_le - read integer from a bitfield in little endian
375 * bt_bitfield_read_be - read integer from a bitfield in big endian
378 #if (BYTE_ORDER == LITTLE_ENDIAN)
380 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
381 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
383 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
384 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
386 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
387 _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr)
389 #elif (BYTE_ORDER == BIG_ENDIAN)
391 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
392 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
394 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
395 _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr)
397 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
398 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
400 #else /* (BYTE_ORDER == PDP_ENDIAN) */
402 #error "Byte order not supported"
406 #endif /* _BABELTRACE_BITFIELD_H */
This page took 0.037009 seconds and 4 git commands to generate.