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