Document side_ptr_get can be used as r or lvalue
[libside.git] / include / side / macros.h
CommitLineData
f611d0c3
MD
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 */
5
67337c4a
MD
6#ifndef _SIDE_MACROS_H
7#define _SIDE_MACROS_H
f611d0c3 8
6e46f5e6 9#include <stddef.h>
8e87e437 10#include <limits.h>
2e197497
MD
11#include <stdint.h>
12#include <side/endian.h>
6e46f5e6 13
f611d0c3
MD
14/* Helper macros */
15
67337c4a 16#define SIDE_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
f611d0c3
MD
17
18/*
67337c4a 19 * Compound literals with static storage are needed by SIDE
f611d0c3
MD
20 * instrumentation.
21 * Compound literals are part of the C99 and C11 standards, but not
22 * part of the C++ standards. They are supported by most C++ compilers
23 * though.
24 *
25 * Example use:
26 * static struct mystruct *var = LTTNG_UST_COMPOUND_LITERAL(struct mystruct, { 1, 2, 3 });
27 */
67337c4a 28#define SIDE_COMPOUND_LITERAL(type, ...) (type[]) { __VA_ARGS__ }
f611d0c3 29
67337c4a
MD
30#define side_likely(x) __builtin_expect(!!(x), 1)
31#define side_unlikely(x) __builtin_expect(!!(x), 0)
f611d0c3 32
67337c4a 33#define SIDE_PARAM(...) __VA_ARGS__
f611d0c3 34
441235e7
MD
35#define side_offsetofend(type, member) \
36 (offsetof(type, member) + sizeof(((type *)0)->member))
37
d0ee69ff
MD
38/*
39 * SIDE_PARAM_SELECT_ARG1
40 *
41 * Select second argument. Use inside macros to implement optional last
42 * macro argument, such as:
43 *
44 * #define macro(_a, _b, _c, _optional...) \
45 * SIDE_PARAM_SELECT_ARG1(_, ##_optional, do_default_macro())
46 *
47 * This macro is far from pretty, but attempts to create a cleaner layer
48 * on top fails for various reasons:
49 *
50 * - The libside API needs to use the default argument selection as an
51 * argument to itself (recursively), e.g. for fields and for types, so
52 * using the argument selection within an extra layer of macro fails
53 * because the extra layer cannot expand recursively.
54 * - Attempts to make the extra layer of macro support recursion through
55 * another layer of macros which expands all arguments failed because
56 * the optional argument may contain commas, and is therefore expanded
57 * into multiple arguments before argument selection, which fails to
58 * select the optional argument content after its first comma.
59 */
60#define SIDE_PARAM_SELECT_ARG1(_arg0, _arg1, ...) _arg1
61
2e197497
MD
62/*
63 * Compile time assertion.
64 * - predicate: boolean expression to evaluate,
65 * - msg: string to print to the user on failure when `static_assert()` is
66 * supported,
67 * - c_identifier_msg: message to be included in the typedef to emulate a
68 * static assertion. This parameter must be a valid C identifier as it will
69 * be used as a typedef name.
70 */
71#ifdef __cplusplus
72#define side_static_assert(predicate, msg, c_identifier_msg) \
73 static_assert(predicate, msg)
74#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
75#define side_static_assert(predicate, msg, c_identifier_msg) \
76 _Static_assert(predicate, msg)
77#else
78/*
79 * Evaluates the predicate and emit a compilation error on failure.
80 *
81 * If the predicate evaluates to true, this macro emits a function
82 * prototype with an argument type which is an array of size 0.
83 *
84 * If the predicate evaluates to false, this macro emits a function
85 * prototype with an argument type which is an array of negative size
86 * which is invalid in C and forces a compiler error. The
87 * c_identifier_msg parameter is used as the argument identifier so it
88 * is printed to the user when the error is reported.
89 */
90#define side_static_assert(predicate, msg, c_identifier_msg) \
91 void side_static_assert_proto(char c_identifier_msg[2*!!(predicate)-1])
92#endif
93
b59abc69 94/*
67337c4a 95 * side_container_of - Get the address of an object containing a field.
b59abc69
MD
96 *
97 * @ptr: pointer to the field.
98 * @type: type of the object.
99 * @member: name of the field within the object.
100 */
67337c4a 101#define side_container_of(ptr, type, member) \
b59abc69
MD
102 __extension__ \
103 ({ \
104 const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \
105 (type *)((char *)__ptr - offsetof(type, member)); \
106 })
107
67337c4a 108#define side_struct_field_sizeof(_struct, _field) \
88bab79c 109 sizeof(((_struct * )NULL)->_field)
8e87e437 110
2e197497
MD
111#define SIDE_PACKED __attribute__((packed))
112
113#define side_padding(bytes) char padding[bytes]
114
115#define side_check_size(_type, _len) \
116 side_static_assert(sizeof(_type) == (_len), \
117 "Unexpected size for type: `" #_type "`", \
118 unexpected_size_for_type_##_type)
119
326c676c
MD
120/*
121 * The side_ptr macros allow defining a pointer type which is suitable
2e197497
MD
122 * for use by 32-bit, 64-bit and 128-bit kernels without compatibility
123 * code, while preserving information about the pointer type.
326c676c 124 *
2e197497
MD
125 * Those pointers are stored as 128-bit integers, and the type of the
126 * actual pointer is kept alongside with the 128-bit pointer value in a
326c676c 127 * 0-len array within a union.
326c676c 128 */
a0c2ee26
MD
129
130#if (SIDE_BYTE_ORDER == SIDE_LITTLE_ENDIAN)
131# define SIDE_U128_PTR_IDX(n) (n)
132#else
133# define SIDE_U128_PTR_IDX(n) ((16 / __SIZEOF_POINTER__) - (n) - 1)
134#endif
135
136#define side_raw_ptr_t(_type) \
326c676c 137 union { \
a0c2ee26 138 _type v[16 / __SIZEOF_POINTER__]; \
326c676c 139 }
a0c2ee26 140
9ed8d6be 141/* side_ptr_get() can be used as rvalue or lvalue. */
a0c2ee26
MD
142#define side_ptr_get(_field) (_field).v[SIDE_U128_PTR_IDX(0)]
143
144#if (__SIZEOF_POINTER__ == 4)
326c676c
MD
145# define side_ptr_set(_field, _ptr) \
146 do { \
a0c2ee26
MD
147 (_field).v[SIDE_U128_PTR_IDX(0)] = (_ptr); \
148 (_field).v[SIDE_U128_PTR_IDX(1)] = 0; \
149 (_field).v[SIDE_U128_PTR_IDX(2)] = 0; \
150 (_field).v[SIDE_U128_PTR_IDX(3)] = 0; \
326c676c 151 } while (0)
2e197497
MD
152
153/* Keep the correct field init order to make old g++ happy. */
154# if (SIDE_BYTE_ORDER == SIDE_LITTLE_ENDIAN)
155# define SIDE_PTR_INIT(...) \
156 { \
157 .v = { \
a0c2ee26
MD
158 [0] = (__VA_ARGS__), \
159 [1] = 0, \
160 [2] = 0, \
161 [3] = 0, \
2e197497
MD
162 }, \
163 }
164# else
165# define SIDE_PTR_INIT(...) \
166 { \
167 .v = { \
a0c2ee26
MD
168 [0] = 0, \
169 [1] = 0, \
170 [2] = 0, \
171 [3] = (__VA_ARGS__), \
2e197497
MD
172 }, \
173 }
174# endif
a0c2ee26
MD
175#elif (__SIZEOF_POINTER__ == 8)
176# define side_ptr_set(_field, _ptr) \
177 do { \
178 (_field).v[SIDE_U128_PTR_IDX(0)] = (_ptr); \
179 (_field).v[SIDE_U128_PTR_IDX(1)] = 0; \
180 } while (0)
181
182/* Keep the correct field init order to make old g++ happy. */
183# if (SIDE_BYTE_ORDER == SIDE_LITTLE_ENDIAN)
184# define SIDE_PTR_INIT(...) \
185 { \
186 .v = { \
187 [0] = (__VA_ARGS__), \
188 [1] = 0, \
189 }, \
326c676c 190 }
a0c2ee26
MD
191# else
192# define SIDE_PTR_INIT(...) \
193 { \
194 .v = { \
195 [0] = 0, \
196 [1] = (__VA_ARGS__), \
197 }, \
198 }
199# endif
200#elif (__SIZEOF_POINTER__ == 16)
326c676c
MD
201# define side_ptr_set(_field, _ptr) \
202 do { \
a0c2ee26 203 (_field).v[SIDE_U128_PTR_IDX(0)] = (_ptr); \
326c676c 204 } while (0)
a0c2ee26
MD
205
206# define SIDE_PTR_INIT(...) \
207 { \
208 .v = { \
209 [0] = (__VA_ARGS__), \
210 }, \
211 }
2e197497
MD
212#else
213# error "Unsupported pointer size"
326c676c
MD
214#endif
215
2e197497
MD
216#define side_ptr_t(_type) side_raw_ptr_t(_type *)
217#define side_func_ptr_t(_type) side_raw_ptr_t(_type)
218
219side_static_assert(sizeof(side_ptr_t(int)) == 16,
220 "Unexpected size for side_ptr_t",
221 unexpected_size_side_ptr_t);
0e2cd351 222
f2a90e2a
MD
223/*
224 * side_enum_t allows defining fixed-sized enumerations while preserving
225 * typing information.
226 */
227#define side_enum_t(_enum_type, _size_type) \
228 union { \
229 _size_type v; \
2e197497
MD
230 struct { \
231 _enum_type t[0]; \
232 } SIDE_PACKED s; \
f2a90e2a
MD
233 }
234
235#define side_enum_get(_field) \
2e197497 236 ((__typeof__((_field).s.t[0]))(_field).v)
f2a90e2a
MD
237
238#define side_enum_set(_field, _v) \
239 do { \
240 (_field).v = (_v); \
241 } while (0)
242
243#define SIDE_ENUM_INIT(...) { .v = (__VA_ARGS__) }
244
67337c4a 245#endif /* _SIDE_MACROS_H */
This page took 0.036484 seconds and 4 git commands to generate.