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