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