ef5453c29be2397b225126daa8b2515abdb33c61
[lttng-ust.git] / include / lttng / 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 * 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
27 * SOFTWARE.
28 */
29
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 */
33
34 /* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
35 #define _bt_piecewise_rshift(_v, _shift) \
36 ({ \
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); \
41 \
42 for (; sb; sb--) \
43 ___v >>= sizeof(___v) * CHAR_BIT - 1; \
44 ___v >>= final; \
45 })
46
47 #define _bt_piecewise_lshift(_v, _shift) \
48 ({ \
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); \
53 \
54 for (; sb; sb--) \
55 ___v <<= sizeof(___v) * CHAR_BIT - 1; \
56 ___v <<= final; \
57 })
58
59 #define _bt_is_signed_type(type) ((type) -1 < (type) 0)
60
61 #define _bt_unsigned_cast(type, v) \
62 ({ \
63 (sizeof(v) < sizeof(type)) ? \
64 ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
65 (type) (v); \
66 })
67
68 /*
69 * bt_bitfield_write - write integer to a bitfield in native endianness
70 *
71 * Save integer to the bitfield, which starts at the "start" bit, has "len"
72 * bits.
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.
77 *
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
80 * bits.
81 *
82 * On big endian, bytes are places from most significant to less significant.
83 * Also, consecutive bitfields are placed from higher to lower bits.
84 */
85
86 #define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \
87 do { \
88 __typeof__(_v) __v = (_v); \
89 type *__ptr = (void *) (_ptr); \
90 unsigned long __start = (_start), __length = (_length); \
91 type mask, cmask; \
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" */ \
95 \
96 if (!__length) \
97 break; \
98 \
99 end = __start + __length; \
100 start_unit = __start / ts; \
101 end_unit = (end + (ts - 1)) / ts; \
102 \
103 /* Trim v high bits */ \
104 if (__length < sizeof(__v) * CHAR_BIT) \
105 __v &= ~((~(__typeof__(__v)) 0) << __length); \
106 \
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)); \
111 if (end % ts) \
112 mask |= (~(type) 0) << (end % ts); \
113 cmask = (type) __v << (__start % ts); \
114 cmask &= ~mask; \
115 __ptr[this_unit] &= mask; \
116 __ptr[this_unit] |= cmask; \
117 break; \
118 } \
119 if (__start % ts) { \
120 cshift = __start % ts; \
121 mask = ~((~(type) 0) << cshift); \
122 cmask = (type) __v << cshift; \
123 cmask &= ~mask; \
124 __ptr[this_unit] &= mask; \
125 __ptr[this_unit] |= cmask; \
126 __v = _bt_piecewise_rshift(__v, ts - cshift); \
127 __start += ts - cshift; \
128 this_unit++; \
129 } \
130 for (; this_unit < end_unit - 1; this_unit++) { \
131 __ptr[this_unit] = (type) __v; \
132 __v = _bt_piecewise_rshift(__v, ts); \
133 __start += ts; \
134 } \
135 if (end % ts) { \
136 mask = (~(type) 0) << (end % ts); \
137 cmask = (type) __v; \
138 cmask &= ~mask; \
139 __ptr[this_unit] &= mask; \
140 __ptr[this_unit] |= cmask; \
141 } else \
142 __ptr[this_unit] = (type) __v; \
143 } while (0)
144
145 #define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \
146 do { \
147 __typeof__(_v) __v = (_v); \
148 type *__ptr = (void *) (_ptr); \
149 unsigned long __start = (_start), __length = (_length); \
150 type mask, cmask; \
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" */ \
154 \
155 if (!__length) \
156 break; \
157 \
158 end = __start + __length; \
159 start_unit = __start / ts; \
160 end_unit = (end + (ts - 1)) / ts; \
161 \
162 /* Trim v high bits */ \
163 if (__length < sizeof(__v) * CHAR_BIT) \
164 __v &= ~((~(__typeof__(__v)) 0) << __length); \
165 \
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)); \
170 if (__start % ts) \
171 mask |= (~((type) 0)) << (ts - (__start % ts)); \
172 cmask = (type) __v << ((ts - (end % ts)) % ts); \
173 cmask &= ~mask; \
174 __ptr[this_unit] &= mask; \
175 __ptr[this_unit] |= cmask; \
176 break; \
177 } \
178 if (end % ts) { \
179 cshift = end % ts; \
180 mask = ~((~(type) 0) << (ts - cshift)); \
181 cmask = (type) __v << (ts - cshift); \
182 cmask &= ~mask; \
183 __ptr[this_unit] &= mask; \
184 __ptr[this_unit] |= cmask; \
185 __v = _bt_piecewise_rshift(__v, cshift); \
186 end -= cshift; \
187 this_unit--; \
188 } \
189 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
190 __ptr[this_unit] = (type) __v; \
191 __v = _bt_piecewise_rshift(__v, ts); \
192 end -= ts; \
193 } \
194 if (__start % ts) { \
195 mask = (~(type) 0) << (ts - (__start % ts)); \
196 cmask = (type) __v; \
197 cmask &= ~mask; \
198 __ptr[this_unit] &= mask; \
199 __ptr[this_unit] |= cmask; \
200 } else \
201 __ptr[this_unit] = (type) __v; \
202 } while (0)
203
204 /*
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
208 */
209
210 #if (BYTE_ORDER == LITTLE_ENDIAN)
211
212 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
213 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
214
215 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
216 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
217
218 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
219 _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v)
220
221 #elif (BYTE_ORDER == BIG_ENDIAN)
222
223 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
224 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
225
226 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
227 _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v)
228
229 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
230 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
231
232 #else /* (BYTE_ORDER == PDP_ENDIAN) */
233
234 #error "Byte order not supported"
235
236 #endif
237
238 #define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
239 do { \
240 __typeof__(*(_vptr)) *__vptr = (_vptr); \
241 __typeof__(*__vptr) __v; \
242 type *__ptr = (void *) (_ptr); \
243 unsigned long __start = (_start), __length = (_length); \
244 type mask, cmask; \
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" */ \
248 \
249 if (!__length) { \
250 *__vptr = 0; \
251 break; \
252 } \
253 \
254 end = __start + __length; \
255 start_unit = __start / ts; \
256 end_unit = (end + (ts - 1)) / ts; \
257 \
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; \
262 else \
263 __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)); \
269 cmask &= mask; \
270 } \
271 __v = _bt_piecewise_lshift(__v, end - __start); \
272 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
273 *__vptr = __v; \
274 break; \
275 } \
276 if (end % ts) { \
277 cshift = end % ts; \
278 mask = ~((~(type) 0) << cshift); \
279 cmask = __ptr[this_unit]; \
280 cmask &= mask; \
281 __v = _bt_piecewise_lshift(__v, cshift); \
282 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
283 end -= cshift; \
284 this_unit--; \
285 } \
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]);\
289 end -= ts; \
290 } \
291 if (__start % ts) { \
292 mask = ~((~(type) 0) << (ts - (__start % ts))); \
293 cmask = __ptr[this_unit]; \
294 cmask >>= (__start % ts); \
295 cmask &= mask; \
296 __v = _bt_piecewise_lshift(__v, ts - (__start % ts)); \
297 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
298 } else { \
299 __v = _bt_piecewise_lshift(__v, ts); \
300 __v |= _bt_unsigned_cast(__typeof__(__v), __ptr[this_unit]);\
301 } \
302 *__vptr = __v; \
303 } while (0)
304
305 #define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
306 do { \
307 __typeof__(*(_vptr)) *__vptr = (_vptr); \
308 __typeof__(*__vptr) __v; \
309 type *__ptr = (void *) (_ptr); \
310 unsigned long __start = (_start), __length = (_length); \
311 type mask, cmask; \
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" */ \
315 \
316 if (!__length) { \
317 *__vptr = 0; \
318 break; \
319 } \
320 \
321 end = __start + __length; \
322 start_unit = __start / ts; \
323 end_unit = (end + (ts - 1)) / ts; \
324 \
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; \
329 else \
330 __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)); \
336 cmask &= mask; \
337 } \
338 __v = _bt_piecewise_lshift(__v, end - __start); \
339 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
340 *__vptr = __v; \
341 break; \
342 } \
343 if (__start % ts) { \
344 cshift = __start % ts; \
345 mask = ~((~(type) 0) << (ts - cshift)); \
346 cmask = __ptr[this_unit]; \
347 cmask &= mask; \
348 __v = _bt_piecewise_lshift(__v, ts - cshift); \
349 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
350 __start += ts - cshift; \
351 this_unit++; \
352 } \
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]);\
356 __start += ts; \
357 } \
358 if (end % ts) { \
359 mask = ~((~(type) 0) << (end % ts)); \
360 cmask = __ptr[this_unit]; \
361 cmask >>= ts - (end % ts); \
362 cmask &= mask; \
363 __v = _bt_piecewise_lshift(__v, end % ts); \
364 __v |= _bt_unsigned_cast(__typeof__(__v), cmask); \
365 } else { \
366 __v = _bt_piecewise_lshift(__v, ts); \
367 __v |= _bt_unsigned_cast(__typeof__(__v), __ptr[this_unit]);\
368 } \
369 *__vptr = __v; \
370 } while (0)
371
372 /*
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
376 */
377
378 #if (BYTE_ORDER == LITTLE_ENDIAN)
379
380 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
381 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
382
383 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
384 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
385
386 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
387 _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr)
388
389 #elif (BYTE_ORDER == BIG_ENDIAN)
390
391 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
392 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
393
394 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
395 _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr)
396
397 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
398 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
399
400 #else /* (BYTE_ORDER == PDP_ENDIAN) */
401
402 #error "Byte order not supported"
403
404 #endif
405
406 #endif /* _BABELTRACE_BITFIELD_H */
This page took 0.036283 seconds and 3 git commands to generate.