Update stream packet and event headers
[deliverable/lttng-modules.git] / lib / bitfield.h
1 #ifndef _BABELTRACE_BITFIELD_H
2 #define _BABELTRACE_BITFIELD_H
3
4 /*
5 * BabelTrace
6 *
7 * Bitfields read/write functions.
8 *
9 * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 *
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:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 */
21
22 #include "ltt-endian.h"
23
24 #ifndef CHAR_BIT
25 #define CHAR_BIT 8
26 #endif
27
28 /* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
29 #define _bt_piecewise_rshift(_v, _shift) \
30 ({ \
31 typeof(_v) ___v = (_v); \
32 typeof(_shift) ___shift = (_shift); \
33 unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \
34 unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \
35 \
36 for (; sb; sb--) \
37 ___v >>= sizeof(___v) * CHAR_BIT - 1; \
38 ___v >>= final; \
39 })
40
41 #define _bt_piecewise_lshift(_v, _shift) \
42 ({ \
43 typeof(_v) ___v = (_v); \
44 typeof(_shift) ___shift = (_shift); \
45 unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \
46 unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \
47 \
48 for (; sb; sb--) \
49 ___v <<= sizeof(___v) * CHAR_BIT - 1; \
50 ___v <<= final; \
51 })
52
53 #define _bt_is_signed_type(type) (((type)(-1)) < 0)
54
55 #define _bt_unsigned_cast(type, v) \
56 ({ \
57 (sizeof(v) < sizeof(type)) ? \
58 ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
59 (type) (v); \
60 })
61
62 /*
63 * bt_bitfield_write - write integer to a bitfield in native endianness
64 *
65 * Save integer to the bitfield, which starts at the "start" bit, has "len"
66 * bits.
67 * The inside of a bitfield is from high bits to low bits.
68 * Uses native endianness.
69 * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
70 * For signed "v", sign-extend v if bitfield is larger than v.
71 *
72 * On little endian, bytes are placed from the less significant to the most
73 * significant. Also, consecutive bitfields are placed from lower bits to higher
74 * bits.
75 *
76 * On big endian, bytes are places from most significant to less significant.
77 * Also, consecutive bitfields are placed from higher to lower bits.
78 */
79
80 #define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \
81 do { \
82 typeof(_v) __v = (_v); \
83 type *__ptr = (void *) (_ptr); \
84 unsigned long __start = (_start), __length = (_length); \
85 type mask, cmask; \
86 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
87 unsigned long start_unit, end_unit, this_unit; \
88 unsigned long end, cshift; /* cshift is "complement shift" */ \
89 \
90 if (!__length) \
91 break; \
92 \
93 end = __start + __length; \
94 start_unit = __start / ts; \
95 end_unit = (end + (ts - 1)) / ts; \
96 \
97 /* Trim v high bits */ \
98 if (__length < sizeof(__v) * CHAR_BIT) \
99 __v &= ~((~(typeof(__v)) 0) << __length); \
100 \
101 /* We can now append v with a simple "or", shift it piece-wise */ \
102 this_unit = start_unit; \
103 if (start_unit == end_unit - 1) { \
104 mask = ~((~(type) 0) << (__start % ts)); \
105 if (end % ts) \
106 mask |= (~(type) 0) << (end % ts); \
107 cmask = (type) __v << (__start % ts); \
108 cmask &= ~mask; \
109 __ptr[this_unit] &= mask; \
110 __ptr[this_unit] |= cmask; \
111 break; \
112 } \
113 if (__start % ts) { \
114 cshift = __start % ts; \
115 mask = ~((~(type) 0) << cshift); \
116 cmask = (type) __v << cshift; \
117 cmask &= ~mask; \
118 __ptr[this_unit] &= mask; \
119 __ptr[this_unit] |= cmask; \
120 __v = _bt_piecewise_rshift(__v, ts - cshift); \
121 __start += ts - cshift; \
122 this_unit++; \
123 } \
124 for (; this_unit < end_unit - 1; this_unit++) { \
125 __ptr[this_unit] = (type) __v; \
126 __v = _bt_piecewise_rshift(__v, ts); \
127 __start += ts; \
128 } \
129 if (end % ts) { \
130 mask = (~(type) 0) << (end % ts); \
131 cmask = (type) __v; \
132 cmask &= ~mask; \
133 __ptr[this_unit] &= mask; \
134 __ptr[this_unit] |= cmask; \
135 } else \
136 __ptr[this_unit] = (type) __v; \
137 } while (0)
138
139 #define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \
140 do { \
141 typeof(_v) __v = (_v); \
142 type *__ptr = (void *) (_ptr); \
143 unsigned long __start = (_start), __length = (_length); \
144 type mask, cmask; \
145 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
146 unsigned long start_unit, end_unit, this_unit; \
147 unsigned long end, cshift; /* cshift is "complement shift" */ \
148 \
149 if (!__length) \
150 break; \
151 \
152 end = __start + __length; \
153 start_unit = __start / ts; \
154 end_unit = (end + (ts - 1)) / ts; \
155 \
156 /* Trim v high bits */ \
157 if (__length < sizeof(__v) * CHAR_BIT) \
158 __v &= ~((~(typeof(__v)) 0) << __length); \
159 \
160 /* We can now append v with a simple "or", shift it piece-wise */ \
161 this_unit = end_unit - 1; \
162 if (start_unit == end_unit - 1) { \
163 mask = ~((~(type) 0) << ((ts - (end % ts)) % ts)); \
164 if (__start % ts) \
165 mask |= (~((type) 0)) << (ts - (__start % ts)); \
166 cmask = (type) __v << ((ts - (end % ts)) % ts); \
167 cmask &= ~mask; \
168 __ptr[this_unit] &= mask; \
169 __ptr[this_unit] |= cmask; \
170 break; \
171 } \
172 if (end % ts) { \
173 cshift = end % ts; \
174 mask = ~((~(type) 0) << (ts - cshift)); \
175 cmask = (type) __v << (ts - cshift); \
176 cmask &= ~mask; \
177 __ptr[this_unit] &= mask; \
178 __ptr[this_unit] |= cmask; \
179 __v = _bt_piecewise_rshift(__v, cshift); \
180 end -= cshift; \
181 this_unit--; \
182 } \
183 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
184 __ptr[this_unit] = (type) __v; \
185 __v = _bt_piecewise_rshift(__v, ts); \
186 end -= ts; \
187 } \
188 if (__start % ts) { \
189 mask = (~(type) 0) << (ts - (__start % ts)); \
190 cmask = (type) __v; \
191 cmask &= ~mask; \
192 __ptr[this_unit] &= mask; \
193 __ptr[this_unit] |= cmask; \
194 } else \
195 __ptr[this_unit] = (type) __v; \
196 } while (0)
197
198 /*
199 * bt_bitfield_write - write integer to a bitfield in native endianness
200 * bt_bitfield_write_le - write integer to a bitfield in little endian
201 * bt_bitfield_write_be - write integer to a bitfield in big endian
202 */
203
204 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
205
206 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
207 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
208
209 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
210 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
211
212 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
213 _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v)
214
215 #elif (__BYTE_ORDER == __BIG_ENDIAN)
216
217 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
218 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
219
220 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
221 _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v)
222
223 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
224 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
225
226 #else /* (BYTE_ORDER == PDP_ENDIAN) */
227
228 #error "Byte order not supported"
229
230 #endif
231
232 #define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
233 do { \
234 typeof(*(_vptr)) *__vptr = (_vptr); \
235 typeof(*__vptr) __v; \
236 type *__ptr = (void *) (_ptr); \
237 unsigned long __start = (_start), __length = (_length); \
238 type mask, cmask; \
239 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
240 unsigned long start_unit, end_unit, this_unit; \
241 unsigned long end, cshift; /* cshift is "complement shift" */ \
242 \
243 if (!__length) { \
244 *__vptr = 0; \
245 break; \
246 } \
247 \
248 end = __start + __length; \
249 start_unit = __start / ts; \
250 end_unit = (end + (ts - 1)) / ts; \
251 \
252 this_unit = end_unit - 1; \
253 if (_bt_is_signed_type(typeof(__v)) \
254 && (__ptr[this_unit] & ((type) 1 << ((end % ts ? : ts) - 1)))) \
255 __v = ~(typeof(__v)) 0; \
256 else \
257 __v = 0; \
258 if (start_unit == end_unit - 1) { \
259 cmask = __ptr[this_unit]; \
260 cmask >>= (__start % ts); \
261 if ((end - __start) % ts) { \
262 mask = ~((~(type) 0) << (end - __start)); \
263 cmask &= mask; \
264 } \
265 __v = _bt_piecewise_lshift(__v, end - __start); \
266 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
267 *__vptr = __v; \
268 break; \
269 } \
270 if (end % ts) { \
271 cshift = end % ts; \
272 mask = ~((~(type) 0) << cshift); \
273 cmask = __ptr[this_unit]; \
274 cmask &= mask; \
275 __v = _bt_piecewise_lshift(__v, cshift); \
276 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
277 end -= cshift; \
278 this_unit--; \
279 } \
280 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
281 __v = _bt_piecewise_lshift(__v, ts); \
282 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
283 end -= ts; \
284 } \
285 if (__start % ts) { \
286 mask = ~((~(type) 0) << (ts - (__start % ts))); \
287 cmask = __ptr[this_unit]; \
288 cmask >>= (__start % ts); \
289 cmask &= mask; \
290 __v = _bt_piecewise_lshift(__v, ts - (__start % ts)); \
291 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
292 } else { \
293 __v = _bt_piecewise_lshift(__v, ts); \
294 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
295 } \
296 *__vptr = __v; \
297 } while (0)
298
299 #define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
300 do { \
301 typeof(*(_vptr)) *__vptr = (_vptr); \
302 typeof(*__vptr) __v; \
303 type *__ptr = (void *) (_ptr); \
304 unsigned long __start = (_start), __length = (_length); \
305 type mask, cmask; \
306 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
307 unsigned long start_unit, end_unit, this_unit; \
308 unsigned long end, cshift; /* cshift is "complement shift" */ \
309 \
310 if (!__length) { \
311 *__vptr = 0; \
312 break; \
313 } \
314 \
315 end = __start + __length; \
316 start_unit = __start / ts; \
317 end_unit = (end + (ts - 1)) / ts; \
318 \
319 this_unit = start_unit; \
320 if (_bt_is_signed_type(typeof(__v)) \
321 && (__ptr[this_unit] & ((type) 1 << (ts - (__start % ts) - 1)))) \
322 __v = ~(typeof(__v)) 0; \
323 else \
324 __v = 0; \
325 if (start_unit == end_unit - 1) { \
326 cmask = __ptr[this_unit]; \
327 cmask >>= (ts - (end % ts)) % ts; \
328 if ((end - __start) % ts) { \
329 mask = ~((~(type) 0) << (end - __start)); \
330 cmask &= mask; \
331 } \
332 __v = _bt_piecewise_lshift(__v, end - __start); \
333 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
334 *__vptr = __v; \
335 break; \
336 } \
337 if (__start % ts) { \
338 cshift = __start % ts; \
339 mask = ~((~(type) 0) << (ts - cshift)); \
340 cmask = __ptr[this_unit]; \
341 cmask &= mask; \
342 __v = _bt_piecewise_lshift(__v, ts - cshift); \
343 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
344 __start += ts - cshift; \
345 this_unit++; \
346 } \
347 for (; this_unit < end_unit - 1; this_unit++) { \
348 __v = _bt_piecewise_lshift(__v, ts); \
349 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
350 __start += ts; \
351 } \
352 if (end % ts) { \
353 mask = ~((~(type) 0) << (end % ts)); \
354 cmask = __ptr[this_unit]; \
355 cmask >>= ts - (end % ts); \
356 cmask &= mask; \
357 __v = _bt_piecewise_lshift(__v, end % ts); \
358 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
359 } else { \
360 __v = _bt_piecewise_lshift(__v, ts); \
361 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
362 } \
363 *__vptr = __v; \
364 } while (0)
365
366 /*
367 * bt_bitfield_read - read integer from a bitfield in native endianness
368 * bt_bitfield_read_le - read integer from a bitfield in little endian
369 * bt_bitfield_read_be - read integer from a bitfield in big endian
370 */
371
372 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
373
374 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
375 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
376
377 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
378 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
379
380 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
381 _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr)
382
383 #elif (__BYTE_ORDER == __BIG_ENDIAN)
384
385 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
386 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
387
388 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
389 _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr)
390
391 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
392 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
393
394 #else /* (__BYTE_ORDER == __PDP_ENDIAN) */
395
396 #error "Byte order not supported"
397
398 #endif
399
400 #endif /* _BABELTRACE_BITFIELD_H */
This page took 0.094539 seconds and 5 git commands to generate.