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