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