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